diff options
author | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
---|---|---|
committer | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
commit | 6352e8e3196f78388b6c771073f9e03eaa612673 (patch) | |
tree | e23772f79a7fbc41bc9108951e9e136857484bf4 /source/game/StarMovementController.hpp | |
parent | 6741a057e5639280d85d0f88ba26f000baa58f61 (diff) |
everything everywhere
all at once
Diffstat (limited to 'source/game/StarMovementController.hpp')
-rw-r--r-- | source/game/StarMovementController.hpp | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/source/game/StarMovementController.hpp b/source/game/StarMovementController.hpp new file mode 100644 index 0000000..a60b0c9 --- /dev/null +++ b/source/game/StarMovementController.hpp @@ -0,0 +1,297 @@ +#ifndef STAR_MOVEMENT_CONTROLLER_HPP +#define STAR_MOVEMENT_CONTROLLER_HPP + +#include "StarJson.hpp" +#include "StarMaybe.hpp" +#include "StarNetElementSystem.hpp" +#include "StarWorld.hpp" +#include "StarPhysicsEntity.hpp" + +namespace Star { + +STAR_EXCEPTION(MovementControllerException, StarException); + +STAR_CLASS(MovementController); + +// List of all movement parameters that define a specific sort of movable +// object. Each parameter is optional so that this structure can be used to +// selectively merge a specific set of parameters on top of another. +struct MovementParameters { + // Load sensible defaults from a config file. + static MovementParameters sensibleDefaults(); + + // Construct parameters from config with only those specified in the config + // set, if any. + MovementParameters(Json const& config = Json()); + + // Merge the given set of movement parameters on top of this one, with any + // set parameters in rhs overwriting the ones in this set. + MovementParameters merge(MovementParameters const& rhs) const; + + Json toJson() const; + + Maybe<float> mass; + Maybe<float> gravityMultiplier; + Maybe<float> liquidBuoyancy; + Maybe<float> airBuoyancy; + Maybe<float> bounceFactor; + // If set to true, during an update that has more than one internal movement + // step, the movement will stop on the first bounce. + Maybe<bool> stopOnFirstBounce; + // Cheat when sliding on the ground, by trying to correct upwards before + // other directions (within a set limit). Allows smooth sliding along + // horizontal ground without losing horizontal speed. + Maybe<bool> enableSurfaceSlopeCorrection; + Maybe<float> slopeSlidingFactor; + Maybe<float> maxMovementPerStep; + Maybe<float> maximumCorrection; + Maybe<float> speedLimit; + Maybe<float> discontinuityThreshold; + + Maybe<PolyF> collisionPoly; + + Maybe<bool> stickyCollision; + Maybe<float> stickyForce; + + Maybe<float> airFriction; + Maybe<float> liquidFriction; + Maybe<float> groundFriction; + + Maybe<bool> collisionEnabled; + Maybe<bool> frictionEnabled; + Maybe<bool> gravityEnabled; + + Maybe<bool> ignorePlatformCollision; + Maybe<float> maximumPlatformCorrection; + Maybe<float> maximumPlatformCorrectionVelocityFactor; + + Maybe<StringSet> physicsEffectCategories; + + Maybe<int> restDuration; +}; + +DataStream& operator>>(DataStream& ds, MovementParameters& movementParameters); +DataStream& operator<<(DataStream& ds, MovementParameters const& movementParameters); + +class MovementController : public NetElementGroup { +public: + // Constructs a MovementController with parameters loaded from sensible + // defaults, and the given parameters (if any) applied on top of them. + explicit MovementController(MovementParameters const& parameters = MovementParameters()); + + MovementParameters const& parameters() const; + + // Apply any set parameters from the given set on top of the current set. + void applyParameters(MovementParameters const& parameters); + + // Reset the parameters from the sensible defaults, and apply the given + // parameters (if any) on top of them. + void resetParameters(MovementParameters const& parameters = MovementParameters()); + + // Stores and loads position, velocity, and rotation. + Json storeState() const; + void loadState(Json const& state); + + // Currently active mass parameter + float mass() const; + + // Currently active collisionPoly parameter + PolyF const& collisionPoly() const; + + Vec2F position() const; + float xPosition() const; + float yPosition() const; + + Vec2F velocity() const; + float xVelocity() const; + float yVelocity() const; + + float rotation() const; + + // CollisionPoly rotated and translated by position + PolyF collisionBody() const; + + // Gets the bounding box of the collisionPoly() rotated by current rotation, + // but not translated into world space + RectF localBoundBox() const; + + // Shorthand for getting the bound box of the current collisionBody() + RectF collisionBoundBox() const; + + // Is the collision body colliding with any collision geometry. + bool isColliding() const; + // Is the collision body colliding with special "Null" collision blocks. + bool isNullColliding() const; + + // Is the body currently stuck in an un-solvable collision. + bool isCollisionStuck() const; + + // If this body is sticking, this is the angle toward the surface it's stuck to + Maybe<float> stickingDirection() const; + + // From 0.0 to 1.0, the amount of the collision body (or if the collision + // body is null, just the center position) that is in liquid. + float liquidPercentage() const; + + // Returns the liquid that the body is most in, if any + LiquidId liquidId() const; + + bool onGround() const; + bool zeroG() const; + + bool atWorldLimit(bool bottomOnly = false) const; + + void setPosition(Vec2F position); + void setXPosition(float xPosition); + void setYPosition(float yPosition); + + void translate(Vec2F const& direction); + + void setVelocity(Vec2F velocity); + void setXVelocity(float xVelocity); + void setYVelocity(float yVelocity); + + void addMomentum(Vec2F const& momentum); + + void setRotation(float angle); + + // Apply one timestep of rotation. + void rotate(float rotationRate); + + // Apply one timestep of acceleration. + void accelerate(Vec2F const& acceleration); + + // Apply one timestep of force. + void force(Vec2F const& force); + + // Apply up to the maxControlForce of force to approach the given velocity. + void approachVelocity(Vec2F const& targetVelocity, float maxControlForce); + + // Approach a velocity in the given angle, ignoring the component of velocity + // normal to that angle. If positiveOnly is true, then only approaches the + // velocity by applying force in the direction of the given angle, never + // opposite it, so avoids slowing down. + void approachVelocityAlongAngle(float angle, float targetVelocity, float maxControlForce, bool positiveOnly = false); + + // Shorthand for approachVelocityAlongAngle with 0 and pi/2. + void approachXVelocity(float targetXVelocity, float maxControlForce); + void approachYVelocity(float targetYVelocity, float maxControlForce); + + void init(World* world); + void uninit(); + + // Integrates the ActorMovementController one WorldTimestep and applies all + // forces. + void tickMaster(); + + // Does not integrate, only tracks master state and updates non-networked + // fields based on local data + void tickSlave(); + + void setIgnorePhysicsEntities(Set<EntityId> ignorePhysicsEntities); + // iterate over all physics entity collision polys in the region, iteration stops if the callback returns false + void forEachMovingCollision(RectF const& region, function<bool(MovingCollisionId, PhysicsMovingCollision, PolyF, RectF)> callback); + +protected: + // forces the movement controller onGround status, used when manually controlling movement outside the movement controller + void updateForceRegions(); + void updateLiquidPercentage(); + void setOnGround(bool onGround); + + // whether force regions were applied in the last update + bool appliedForceRegion() const; + // The collision correction applied during the most recent update, if any. + Vec2F collisionCorrection() const; + // Horizontal slope of the ground the collision body has collided with, if + // any. + Vec2F surfaceSlope() const; + // Velocity of the surface that the body is resting on, if any + Vec2F surfaceVelocity() const; + + World* world(); + +private: + struct CollisionResult { + Vec2F movement; + Vec2F correction; + Maybe<MovingCollisionId> surfaceMovingCollisionId; + bool isStuck; + bool onGround; + Vec2F groundSlope; + CollisionKind collisionKind; + }; + + struct CollisionSeparation { + Vec2F correction; + bool solutionFound; + Maybe<MovingCollisionId> movingCollisionId; + CollisionKind collisionKind; + }; + + struct CollisionPoly { + PolyF poly; + RectF polyBounds; + Vec2F sortPosition; + Maybe<MovingCollisionId> movingCollisionId; + CollisionKind collisionKind; + float sortDistance; + }; + + static CollisionKind maxOrNullCollision(CollisionKind a, CollisionKind b); + static CollisionResult collisionMove(List<CollisionPoly>& collisionPolys, PolyF const& body, Vec2F const& movement, + bool ignorePlatforms, bool enableSurfaceSlopeCorrection, float maximumCorrection, float maximumPlatformCorrection, Vec2F sortCenter); + static CollisionSeparation collisionSeparate(List<CollisionPoly>& collisionPolys, PolyF const& poly, + bool ignorePlatforms, float maximumPlatformCorrection, Vec2F const& sortCenter, bool upward, float separationTolerance); + + void updateParameters(MovementParameters parameters); + void updatePositionInterpolators(); + + void queryCollisions(RectF const& region); + + float gravity(); + + MovementParameters m_parameters; + + World* m_world; + + Set<EntityId> m_ignorePhysicsEntities; + + NetElementData<PolyF> m_collisionPoly; + NetElementFloat m_mass; + NetElementFloat m_xPosition; + NetElementFloat m_yPosition; + NetElementFloat m_xVelocity; + NetElementFloat m_yVelocity; + NetElementFloat m_rotation; + + NetElementBool m_colliding; + NetElementBool m_collisionStuck; + NetElementBool m_nullColliding; + NetElementData<Maybe<float>> m_stickingDirection; + NetElementBool m_onGround; + NetElementBool m_zeroG; + + float m_liquidPercentage; + LiquidId m_liquidId; + + NetElementData<Maybe<MovingCollisionId>> m_surfaceMovingCollision; + NetElementFloat m_xRelativeSurfaceMovingCollisionPosition; + NetElementFloat m_yRelativeSurfaceMovingCollisionPosition; + + bool m_appliedForceRegion; + Vec2F m_collisionCorrection; + Vec2F m_surfaceSlope; + Vec2F m_surfaceMovingCollisionPosition; + Vec2F m_surfaceVelocity; + Vec2F m_environmentVelocity; + + bool m_resting; + int m_restTicks; + + List<CollisionPoly> m_workingCollisions; + List<PolyF> m_collisionBuffers; +}; + +} + +#endif |