1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
|
#pragma once
#include "StarMovementController.hpp"
#include "StarPlatformerAStarTypes.hpp"
#include "StarAnchorableEntity.hpp"
#include "StarGameTimers.hpp"
namespace Star {
STAR_EXCEPTION(ActorMovementControllerException, MovementControllerException);
STAR_CLASS(ActorMovementController);
STAR_CLASS(PathController);
struct ActorJumpProfile {
ActorJumpProfile();
ActorJumpProfile(Json const& config);
Json toJson() const;
ActorJumpProfile merge(ActorJumpProfile const& rhs) const;
Maybe<float> jumpSpeed;
Maybe<float> jumpControlForce;
Maybe<float> jumpInitialPercentage;
// If this is greater than 0.0, jump hold time is limited by this factor.
Maybe<float> jumpHoldTime;
// If this is greater than 0.0, then the total jump time for *all jumps in a
// multi jump set* is limited by this factor.
Maybe<float> jumpTotalHoldTime;
Maybe<bool> multiJump;
Maybe<float> reJumpDelay;
Maybe<bool> autoJump;
Maybe<bool> collisionCancelled;
};
DataStream& operator>>(DataStream& ds, ActorJumpProfile& movementParameters);
DataStream& operator<<(DataStream& ds, ActorJumpProfile const& movementParameters);
// A not-quite superset of MovementParameters, with some fields from
// MovementParameters ignored because they make no sense, and other fields
// expanded out to different cases based on Actor specific things.
struct ActorMovementParameters {
// Load sensible defaults from a config file.
static ActorMovementParameters sensibleDefaults();
// Construct parameters from config with only those specified in the config
// set, if any.
explicit ActorMovementParameters(Json const& config = Json());
Json toJson() const;
// Merge the given set of movement parameters on top of this one, with any
// set parameters in rhs overwriting the ones in this set.
ActorMovementParameters merge(ActorMovementParameters const& rhs) const;
Maybe<float> mass;
Maybe<float> gravityMultiplier;
Maybe<float> liquidBuoyancy;
Maybe<float> airBuoyancy;
Maybe<float> bounceFactor;
Maybe<bool> stopOnFirstBounce;
Maybe<bool> enableSurfaceSlopeCorrection;
Maybe<float> slopeSlidingFactor;
Maybe<float> maxMovementPerStep;
Maybe<float> maximumCorrection;
Maybe<float> speedLimit;
Maybe<PolyF> standingPoly;
Maybe<PolyF> crouchingPoly;
Maybe<bool> stickyCollision;
Maybe<float> stickyForce;
Maybe<float> walkSpeed;
Maybe<float> runSpeed;
Maybe<float> flySpeed;
Maybe<float> airFriction;
Maybe<float> liquidFriction;
Maybe<float> minimumLiquidPercentage;
Maybe<float> liquidImpedance;
Maybe<float> normalGroundFriction;
Maybe<float> ambulatingGroundFriction;
Maybe<float> groundForce;
Maybe<float> airForce;
Maybe<float> liquidForce;
ActorJumpProfile airJumpProfile;
ActorJumpProfile liquidJumpProfile;
Maybe<float> fallStatusSpeedMin;
Maybe<int> fallThroughSustainFrames;
Maybe<float> maximumPlatformCorrection;
Maybe<float> maximumPlatformCorrectionVelocityFactor;
Maybe<StringSet> physicsEffectCategories;
Maybe<float> groundMovementMinimumSustain;
Maybe<float> groundMovementMaximumSustain;
Maybe<float> groundMovementCheckDistance;
Maybe<bool> collisionEnabled;
Maybe<bool> frictionEnabled;
Maybe<bool> gravityEnabled;
Maybe<float> pathExploreRate;
};
DataStream& operator>>(DataStream& ds, ActorMovementParameters& movementParameters);
DataStream& operator<<(DataStream& ds, ActorMovementParameters const& movementParameters);
// A set of normalized values that act as "modifiers" or "bonuses" to movement,
// and can be combined sensibly. A modifier of 0.0 represents a 0% change, a
// modifier of 0.2 represents a 20% increase, and a modifier of -0.2 represents
// a 20% decrease. Also includes some flags that disable functionality
// combined with logical OR.
struct ActorMovementModifiers {
explicit ActorMovementModifiers(Json const& config = Json());
Json toJson() const;
// Combines each modifier value through addition.
ActorMovementModifiers combine(ActorMovementModifiers const& rhs) const;
float groundMovementModifier;
float liquidMovementModifier;
float speedModifier;
float airJumpModifier;
float liquidJumpModifier;
bool runningSuppressed;
bool jumpingSuppressed;
// Suppresses left, right, down, crouch, jump, and fly controls
bool movementSuppressed;
bool facingSuppressed;
};
DataStream& operator>>(DataStream& ds, ActorMovementModifiers& movementModifiers);
DataStream& operator<<(DataStream& ds, ActorMovementModifiers const& movementModifiers);
class ActorMovementController : public MovementController {
public:
// Constructs an ActorMovementController with parameters loaded from sensible
// defaults, and the given parameters (if any) applied on top of them.
explicit ActorMovementController(ActorMovementParameters const& parameters = ActorMovementParameters());
// Currently active parameters.
ActorMovementParameters const& baseParameters() const;
// Apply any set parameters from the given set on top of the current set.
void updateBaseParameters(ActorMovementParameters const& parameters);
// Reset the parameters from the sensible defaults, and apply the given
// parameters (if any) on top of them.
void resetBaseParameters(ActorMovementParameters const& parameters = ActorMovementParameters());
// Currently active modifiers.
ActorMovementModifiers const& baseModifiers() const;
// Combine the given modifiers with the already active modifiers.
void updateBaseModifiers(ActorMovementModifiers const& modifiers);
// Reset all modifiers to the given values
void resetBaseModifiers(ActorMovementModifiers const& modifiers = ActorMovementModifiers());
// Stores and loads position, velocity, rotation, movingDirection,
// facingDirection, and crouching
Json storeState() const;
void loadState(Json const& state);
// Optionaly anchor this ActorMovementController to the given
// AnchorableEntity. position, rotation, and facing direction will be set
// based on the entity anchor alone every tick, and on slaved
// ActorMovementControllers it will be updated based on the actual slave-side
// AnchorableEntity state.
void setAnchorState(EntityAnchorState anchorState);
void resetAnchorState();
Maybe<EntityAnchorState> anchorState() const;
EntityAnchorConstPtr entityAnchor() const;
// ActorMovementController position and rotation honor the entity anchor, if
// an anchor is set.
Vec2F position() const;
float xPosition() const;
float yPosition() const;
float rotation() const;
PolyF collisionBody() const;
RectF localBoundBox() const;
RectF collisionBoundBox() const;
bool walking() const;
bool running() const;
Direction movingDirection() const;
Direction facingDirection() const;
bool crouching() const;
bool flying() const;
bool falling() const;
bool canJump() const;
bool jumping() const;
// Slightly different than onGround, in that this is sustained for a few
// extra frames of movement before it becomes false.
bool groundMovement() const;
bool liquidMovement() const;
bool pathfinding() const;
// Basic direct physics controls that can be called multiple times per
// update and will be combined.
void controlRotation(float rotationRate);
void controlAcceleration(Vec2F const& acceleration);
void controlForce(Vec2F const& force);
void controlApproachVelocity(Vec2F const& targetVelocity, float maxControlForce);
void controlApproachVelocityAlongAngle(float angle, float targetVelocity, float maxControlForce, bool positiveOnly = false);
void controlApproachXVelocity(float targetXVelocity, float maxControlForce);
void controlApproachYVelocity(float targetYVelocity, float maxControlForce);
// Apply ActorMovementParameters / ActorMovementModifiers only as long as
// the controls are active. Can be called multiple times per update and
// will be combined.
void controlParameters(ActorMovementParameters const& parameters);
void controlModifiers(ActorMovementModifiers const& modifiers);
// Higher level movement controls that use forces defined in the
// ActorMovementParameters. Calling more than once per update will override
// previous calls.
void controlMove(Direction direction, bool run = true);
void controlFace(Direction direction);
void controlDown();
void controlCrouch();
void controlJump(bool jumpEvenIfUnable = false);
void controlFly(Vec2F const& velocity);
Maybe<pair<Vec2F, bool>> pathMove(Vec2F const& pathPosition, bool run = false, Maybe<PlatformerAStar::Parameters> const& parameters = {});
Maybe<pair<Vec2F, bool>> controlPathMove(Vec2F const& pathPosition, bool run = false, Maybe<PlatformerAStar::Parameters> const& parameters = {});
// Used for user controller input.
void setMoveSpeedMultiplier(float multiplier = 1.0f);
// Clears all control data.
void clearControls();
// Integrates the ActorMovementController and applies all
// the control data and clears it for the next step.
void tickMaster(float dt);
void tickSlave(float dt);
private:
struct ApproachVelocityCommand {
Vec2F targetVelocity;
float maxControlForce;
};
struct ApproachVelocityAlongAngleCommand {
float alongAngle;
float targetVelocity;
float maxControlForce;
bool positiveOnly;
};
void applyMCParameters(ActorMovementParameters const& parameters);
void doSetAnchorState(Maybe<EntityAnchorState> anchorState);
ActorMovementParameters m_baseParameters;
ActorMovementModifiers m_baseModifiers;
// State data
NetElementBool m_walking;
NetElementBool m_running;
NetElementEnum<Direction> m_movingDirection;
NetElementEnum<Direction> m_facingDirection;
NetElementBool m_crouching;
NetElementBool m_flying;
NetElementBool m_falling;
NetElementBool m_canJump;
NetElementBool m_jumping;
NetElementBool m_groundMovement;
NetElementBool m_liquidMovement;
NetElementData<Maybe<EntityAnchorState>> m_anchorState;
EntityAnchorConstPtr m_entityAnchor;
// Command data
float m_controlRotationRate;
Vec2F m_controlAcceleration;
Vec2F m_controlForce;
List<ApproachVelocityCommand> m_controlApproachVelocities;
List<ApproachVelocityAlongAngleCommand> m_controlApproachVelocityAlongAngles;
Maybe<Direction> m_controlMove;
Maybe<Direction> m_controlFace;
bool m_controlRun;
bool m_controlCrouch;
bool m_controlDown;
bool m_controlJump;
bool m_controlJumpAnyway;
Maybe<Vec2F> m_controlFly;
Maybe<pair<Vec2F, bool>> m_controlPathMove;
Maybe<pair<Vec2F, bool>> m_pathMoveResult;
PathControllerPtr m_pathController;
ActorMovementParameters m_controlParameters;
ActorMovementModifiers m_controlModifiers;
// Internal state data
int m_fallThroughSustain;
bool m_lastControlJump;
bool m_lastControlDown;
float m_moveSpeedMultiplier;
GameTimer m_reJumpTimer;
Maybe<GameTimer> m_jumpHoldTimer;
GameTimer m_groundMovementSustainTimer;
// Target horizontal velocity for walking / running
float m_targetHorizontalAmbulatingVelocity;
};
class PathController {
public:
PathController(World* world);
PlatformerAStar::Parameters const& parameters();
void setParameters(PlatformerAStar::Parameters const& parameters);
void reset();
bool pathfinding() const;
Maybe<Vec2F> targetPosition() const;
Maybe<Direction> facing() const;
Maybe<PlatformerAStar::Action> curAction() const;
// return true for reaching goal, false for failing to find path, nothing for running
Maybe<bool> findPath(ActorMovementController& movementController, Vec2F const& targetPosition);
Maybe<bool> move(ActorMovementController& movementController, ActorMovementParameters const& parameters, ActorMovementModifiers const& modifiers, bool run, float dt);
private:
bool validateEdge(ActorMovementController& movementController, PlatformerAStar::Edge const& edge);
bool movingCollision(ActorMovementController& movementController, PolyF const& collisionPoly);
private:
bool onGround(ActorMovementController const& movementController, Vec2F const& position, CollisionSet const& collisionSet) const;
World* m_world;
PlatformerAStar::Parameters m_parameters;
Maybe<Vec2F> m_startPosition;
Maybe<Vec2F> m_targetPosition;
PlatformerAStar::PathFinderPtr m_pathFinder;
Maybe<Direction> m_controlFace;
size_t m_edgeIndex;
float m_edgeTimer;
Maybe<PlatformerAStar::Path> m_path;
};
}
|