2
// This unit is part of the GLScene Engine https://github.com/glscene
6
- Add a DCEManager to you form and configure its properties
7
- Add a Dynamic Collision Behavior to you object
8
- Add a Static Collision behaviour to objects which yours will collide
9
- You can choose the shape of your static object
11
- csFreeform MUST BE A TGLFreeform, otherwise will raise errors
12
- csTerrain MUST BE A TGLTerrainRenderer, same condition above
13
- Active: Disable or enable the behaviour for this object
14
- Friction: is a value aprox. between 0 (no friction) and 100 (no movement)
15
- Layer: An object collides only with lower or equal layers
16
- Size: is used for Ellipsoids (Radius) / Boxes (Dimensions)
17
- Solid: Object still generate collision events but it doesn't "block" the dynamic object
18
- UseGravity: You can disable the gravity for that object
19
- SlideOrBounce: The object can bounce like a ball or slide like an FPS
20
- BounceFactor: Restituition factor, 1 means that it will bounce forever
31
GLScene, GLXCollection, GLVectorGeometry, GLVectorLists, GLVectorFileObjects,
32
GLCrossPlatform, GLDCEMisc, GLEllipseCollision,
33
GLTerrainRenderer, GLCoordinates, GLBaseClasses, GLManager, GLVectorTypes;
36
{Only csEllipsoid can have dynamic behaviour}
37
TDCEShape = (csEllipsoid, csBox, csFreeform, csTerrain);
39
{ Indicates which type of layer comparison is made when trying to detect
40
collisions between 2 bodies (A and B). Possible values are:
41
ccsDCEStandard: Collides bodies if A.layer <= B.layer
42
ccsCollisionStandard: Collides bodies if either A or B have
43
layer equal to zero or if their layers are different.
44
ccsHybrid: Collides bodies if either one of the previous
45
checks would pass (i.e. if the layer of either body is
46
equal to 0 or if A.layer <= B.layer) *and* if both
47
layers are positive (that is, turns off collision
48
for bodies whose layer is < 0)
51
TDCECollisionSelection = (ccsDCEStandard, ccsCollisionStandard, ccsHybrid); // gak:20041119
53
TDCECollision = record
54
Position: TAffineVector;
55
Normal: TAffineVector; //Surface normal
56
Bounce: TAffineVector; //Surface reflection
58
RootCollision:boolean;//gak:20041119
59
Distance:single;//gak:20041119
63
TGLDCEDynamic = class;
65
TDCECollisionEvent = procedure (Sender : TObject; object1, object2 : TGLBaseSceneObject;
66
CollisionInfo: TDCECollision) of object;
67
TDCEObjectCollisionEvent = procedure (Sender : TObject; ObjectCollided : TGLBaseSceneObject;
68
CollisionInfo: TDCECollision) of object;
70
TGLDCEManager = class (TComponent)
76
FWorldDirection: TGLCoordinates; //Used to calculate jumps f.i.
78
FMovimentScale: Single;
79
FStandardiseLayers : TDCECollisionSelection;
81
FOnCollision : TDCECollisionEvent;
82
procedure SetWorldDirection(const Value: TGLCoordinates);
83
procedure SetWorldScale(const Value: Single);
84
function GetDynamicCount: Integer;
85
function GetStaticCount: Integer;
88
procedure RegisterStatic(aClient : TGLDCEStatic);
89
procedure DeRegisterStatic(aClient : TGLDCEStatic);
90
procedure DeRegisterAllStatics;
91
procedure RegisterDynamic(aClient : TGLDCEDynamic);
92
procedure DeRegisterDynamic(aClient : TGLDCEDynamic);
93
procedure DeRegisterAllDynamics;
96
constructor Create(AOwner: TComponent); override;
97
destructor Destroy; override;
98
//Moves the body by the distance and returns the average friction
99
function MoveByDistance(var Body: TGLDCEDynamic; deltaS, deltaAbsS: TAffineVector): Single;
100
procedure Step(deltaTime: Double);
101
property DynamicCount: Integer read GetDynamicCount;
102
property StaticCount: Integer read GetStaticCount;
105
property Gravity : Single read FGravity write FGravity;
106
property WorldDirection : TGLCoordinates read FWorldDirection write SetWorldDirection;
107
property WorldScale : Single read FWorldScale write SetWorldScale;
108
property MovimentScale : Single read FMovimentScale write FMovimentScale;
109
Property StandardiseLayers: TDCECollisionSelection read FStandardiseLayers write FStandardiseLayers; //gak:20041119
110
Property ManualStep: Boolean read FManualStep write FManualStep;
111
property OnCollision : TDCECollisionEvent read FOnCollision write FOnCollision;
114
TGLDCEStatic = class (TGLBehaviour)
117
FManager : TGLDCEManager;
118
FManagerName : String; // NOT persistent, temporarily used for persistence
121
FLayer: Integer; //Collides only with lower or equal layers
122
FSolid: Boolean; //Collide and slide if true, otherwise it "walk thru walls"
123
FFriction: Single; //0 (no friction); 100 (no movement)
124
FBounceFactor: Single; //0 (don't bounce); 1 (bounce forever)
125
FSize: TGLCoordinates;
127
FOnCollision : TDCEObjectCollisionEvent;
128
procedure SetShape(const Value: TDCEShape);
129
procedure SetFriction(const Value: Single);
130
procedure SetBounceFactor(const Value: Single);
131
procedure SetSize(const Value: TGLCoordinates);
134
procedure SetManager(const val : TGLDCEManager);
135
procedure WriteToFiler(writer : TWriter); override;
136
procedure ReadFromFiler(reader : TReader); override;
137
procedure Loaded; override;
140
constructor Create(aOwner : TGLXCollection); override;
141
destructor Destroy; override;
142
procedure Assign(Source: TPersistent); override;
143
class function FriendlyName : String; override;
144
class function FriendlyDescription : String; override;
145
property OnCollision : TDCEObjectCollisionEvent read FOnCollision write FOnCollision;
148
property Active : Boolean read FActive write FActive;
149
property Manager : TGLDCEManager read FManager write SetManager;
150
property Shape : TDCEShape read FShape write SetShape;
151
property Layer : Integer read FLayer write FLayer;
152
property Solid : Boolean read FSolid write FSolid;
153
property Friction : Single read FFriction write SetFriction;
154
property BounceFactor : Single read FBounceFactor write SetBounceFactor;
155
property Size : TGLCoordinates read FSize write SetSize;
158
TDCESlideOrBounce = (csbSlide,csbBounce);
160
TGLDCEDynamic = class (TGLBehaviour)
163
FManager : TGLDCEManager;
164
FManagerName : String; // NOT persistent, temporarily used for persistence
166
FUseGravity: Boolean;
167
FLayer: Integer; //Collides only with lower or equal layers
168
FSolid: Boolean; //Collide and slide if true, otherwise it "walk thru walls"
169
FFriction: Single; //0 (no friction); 100 (no movement)
170
FBounceFactor: Single; //0 (don't bounce); 1 (bounce forever)
171
FSize: TGLCoordinates;
172
FMaxRecursionDepth:byte;//gak20041119 //Number of iterations of the collision method
173
FSlideOrBounce:TDCESlideOrBounce;//gak20041122
175
FAccel: TAffineVector; //Current acceleration
176
FSpeed: TAffineVector; //Current speed
177
FAbsAccel: TAffineVector; //Current absolute accel
178
FAbsSpeed: TAffineVector; //Current absolute speed
179
FGravSpeed: TAffineVector; //Current gravity speed
180
FTotalFriction: Single; //Current sum of all contatcs friction
182
FGroundNormal: TAffineVector;
183
FJumpHeight, FJumpForce,FJumpSpeed: Single;
186
FOnCollision : TDCEObjectCollisionEvent;
187
procedure SetFriction(const Value: Single);
188
procedure SetBounceFactor(const Value: Single);
189
procedure SetSize(const Value: TGLCoordinates);
192
procedure SetManager(const val : TGLDCEManager);
193
procedure WriteToFiler(writer : TWriter); override;
194
procedure ReadFromFiler(reader : TReader); override;
195
procedure Loaded; override;
198
constructor Create(aOwner : TGLXCollection); override;
199
destructor Destroy; override;
200
procedure Assign(Source: TPersistent); override;
201
class function FriendlyName : String; override;
202
class function FriendlyDescription : String; override;
203
procedure ApplyAccel(NewAccel: TAffineVector); overload;
204
procedure ApplyAccel(x,y,z: Single); overload;
205
procedure ApplyAbsAccel(NewAccel: TAffineVector); overload;
206
procedure ApplyAbsAccel(x,y,z: Single); overload;
208
procedure StopAbsAccel;
209
procedure Jump(jHeight, jSpeed: Single);
210
procedure Move(deltaS: TAffineVector; deltaTime: Double);
211
procedure MoveTo(Position: TAffineVector; Amount: Single); // gak:20041119
212
procedure DoMove(deltaTime: Double);
213
procedure DoProgress(const progressTime : TProgressTimes); override;
215
property Speed : TAffineVector read FSpeed write FSpeed;
216
property InGround : Boolean read FInGround;
217
property MaxRecursionDepth:byte read FMaxRecursionDepth write FMaxRecursionDepth;//gak20041119
218
property OnCollision : TDCEObjectCollisionEvent read FOnCollision write FOnCollision;
221
property Active : Boolean read FActive write FActive;
222
property Manager : TGLDCEManager read FManager write SetManager;
223
property UseGravity : Boolean read FUseGravity write FUseGravity;
224
property Layer : Integer read FLayer write FLayer;
225
property Solid : Boolean read FSolid write FSolid;
226
property Friction : Single read FFriction write SetFriction;
227
property BounceFactor : Single read FBounceFactor write SetBounceFactor;
228
property Size : TGLCoordinates read FSize write SetSize;
229
property SlideOrBounce:TDCESlideOrBounce read FSlideOrBounce write FSlideOrBounce;//gak20041122
232
function GetOrCreateDCEStatic(behaviours : TGLBehaviours) : TGLDCEStatic; overload;
233
function GetOrCreateDCEStatic(obj : TGLBaseSceneObject) : TGLDCEStatic; overload;
235
function GetOrCreateDCEDynamic(behaviours : TGLBehaviours) : TGLDCEDynamic; overload;
236
function GetOrCreateDCEDynamic(obj : TGLBaseSceneObject) : TGLDCEDynamic; overload;
240
function RotateVectorByObject(Obj: TGLBaseSceneObject; v: TAffineVector): TAffineVector;
244
SetVector(result,VectorTransform(v2, Obj.Matrix));
247
constructor TGLDCEManager.Create(AOwner: TComponent);
249
inherited Create(AOwner);
250
FStatics:=TList.Create;
251
FDynamics:=TList.Create;
253
FWorldDirection:=TGLCoordinates.CreateInitialized(Self, YHmgVector, csVector);
256
FStandardiseLayers := ccsDCEStandard;
257
FManualStep := False;
258
RegisterManager(Self);
263
destructor TGLDCEManager.Destroy;
265
DeRegisterAllStatics;
266
DeRegisterAllDynamics;
267
DeRegisterManager(Self);
270
FWorldDirection.Free;
274
function TGLDCEManager.GetDynamicCount: Integer;
276
result := FDynamics.Count;
279
function TGLDCEManager.GetStaticCount: Integer;
281
result := FStatics.Count;
284
function TGLDCEManager.MoveByDistance(var Body: TGLDCEDynamic; deltaS, deltaAbsS: TAffineVector): Single;
286
//Friction and bounce
287
TotalFriction, bounce,f,m,restitution: Single;
288
ContactList: TIntegerList;
289
//Temporary properties (Static or Dynamic)
290
tFriction, tBounceFactor: Single;
291
tObject: TGLBaseSceneObject;
293
ColInfo: TDCECollision;
294
lastobj:integer;//gak:20041119
297
CanCollide,GravCollided: boolean;
298
//Vars used to calculate high velocities
299
ColRange,MaxRange: Single;
300
dCR,dT,deltaCR: Double;
302
//Set collider parameters
303
MP.Radius := Body.Size.AsAffineVector;
304
MP.Position := AffineVectorMake(Body.OwnerBaseSceneObject.AbsolutePosition);
305
MP.Velocity := deltaS;
306
MP.Gravity := deltaAbsS;
307
MP.ObjectInfo.Solid := Body.Solid;
308
MP.UnitScale := FWorldScale;
309
MP.MaxRecursionDepth := Body.MaxRecursionDepth; //gak://20041119
310
//Get collision range, if it is too big separate into small pieces
311
ECSetCollisionRange(MP);
312
ColRange := MP.CollisionRange;
314
MaxRange := MaxXYZComponent(MP.Radius)*2.1;
315
SetLength(MP.Contacts,0);
316
GravCollided := False; //Is colliding with the ground
317
Body.FGroundNormal := NullVector;
318
while deltaCR>0 do begin
319
if deltaCR>MaxRange then begin
321
deltaCR:=deltaCR-MaxRange;
326
dT := dCR / ColRange;
327
MP.Velocity := VectorScale(deltaS,dT);
328
MP.Gravity := VectorScale(deltaAbsS, dT);
330
ECSetCollisionRange(MP);
331
ECResetColliders(MP);
333
//For each static collider
334
for i:=0 to FStatics.Count-1 do
335
with TGLDCEStatic(FStatics[i]) do
340
case FStandardiseLayers of
341
ccsDCEStandard: CanCollide := (Layer <= Body.Layer);
342
ccsCollisionStandard: CanCollide := (layer = 0) or (body.layer = 0) or (layer <> body.layer);
343
ccsHybrid: CanCollide := ( (layer = 0) or (body.layer = 0) or (Layer <= Body.Layer) ) and (layer>=0) and (body.layer>=0);
346
//Add colliders to move pack
350
csFreeform: ECAddFreeForm(MP,OwnerBaseSceneObject,Solid,i);
351
csEllipsoid: ECAddEllipsoid(MP,AffineVectorMake(OwnerBaseSceneObject.AbsolutePosition),
352
Size.AsAffineVector,Solid,i);
353
csBox: ECAddBox(MP,OwnerBaseSceneObject,Size.AsAffineVector,Solid,i);
354
csTerrain: ECAddTerrain(MP,TGLTerrainRenderer(OwnerBaseSceneObject),FWorldScale*2,Solid,i);
360
//For each dynamic collider add a static ellipsoid
361
for i:=0 to FDynamics.Count-1 do
362
with TGLDCEDynamic(FDynamics[i]) do
365
if (Active) and (TGLDCEDynamic(FDynamics[i]) <> Body) then
366
case FStandardiseLayers of
367
ccsDCEStandard: CanCollide := (Layer <= Body.Layer);
368
ccsCollisionStandard: CanCollide := (layer = 0) or (body.layer = 0) or (layer <> body.layer);
369
ccsHybrid: CanCollide := ( (layer = 0) or (body.layer = 0) or (Layer <= Body.Layer) ) and (layer>=0) and (body.layer>=0);
371
//Add collider to move pack
372
//To differ from static it is added with a negative ID (id < 0)
374
ECAddEllipsoid(MP,AffineVectorMake(OwnerBaseSceneObject.AbsolutePosition),
375
Size.AsAffineVector,Solid,-1-i);
380
if MP.GravityCollided then
382
GravCollided := True;
383
Body.FGroundNormal := Mp.GroundNormal;
385
MP.Position := MP.ResultPos;
389
Body.OwnerBaseSceneObject.AbsolutePosition := VectorMake(MP.ResultPos);
390
Body.FInGround := GravCollided;
392
//Generate events and calculate average friction
393
lastobj := -1;//gak:20041119
394
TotalFriction := Body.Friction;
395
ContactList := TIntegerList.Create;
398
for i := 0 to High(MP.Contacts) do
401
oi := Contacts[i].ObjectInfo.ObjectID;
403
//Don't repeat objects with same ID
404
if ContactList.IndexOf(oi) >= 0 then Continue
405
else ContactList.Add(oi);
407
//Check if it is static or dynamic
410
tFriction := TGLDCEDynamic(FDynamics[abs(oi) - 1]).Friction;
411
tBounceFactor := TGLDCEDynamic(FDynamics[abs(oi) - 1]).BounceFactor;
412
tObject := TGLDCEDynamic(FDynamics[abs(oi) - 1]).OwnerBaseSceneObject;
415
tFriction := TGLDCEStatic(FStatics[oi]).Friction;
416
tBounceFactor := TGLDCEStatic(FStatics[oi]).BounceFactor;
417
tObject := TGLDCEStatic(FStatics[oi]).OwnerBaseSceneObject;
420
TotalFriction := TotalFriction + tFriction;
421
ColInfo.Position := Contacts[i].Position;
422
ColInfo.Normal := Contacts[i].SurfaceNormal;
423
ColInfo.Bounce := VectorNormalize(VectorReflect(VectorAdd(deltaS,deltaAbsS), ColInfo.Normal));
424
ColInfo.Nearest := oi = MP.NearestObject;
427
if (Body.SlideOrBounce = csbBounce) and ColInfo.Nearest then
429
bounce:=VectorDotProduct(Body.FSpeed, ColInfo.Normal);
430
if bounce<0 then begin
431
restitution := (Body.BounceFactor + tBounceFactor) / 2;
432
m := VectorLength(Body.FSpeed);
433
f := -bounce/VectorNorm(ColInfo.Normal)*(1+restitution);
434
CombineVector(Body.FSpeed,ColInfo.Normal,f);
436
if VectorLength(Body.FSpeed) > m * 2 then
437
Body.FSpeed := NullVector;
440
bounce:=VectorDotProduct(Body.FAbsSpeed, ColInfo.Normal);
441
if bounce<0 then begin
442
restitution := (Body.BounceFactor + tBounceFactor) / 2;
443
m := VectorLength(Body.FAbsSpeed);
444
f := -bounce/VectorNorm(ColInfo.Normal)*(1+restitution);
445
CombineVector(Body.FAbsSpeed,ColInfo.Normal,f);
447
if VectorLength(Body.FAbsSpeed) > m * 2 then
448
Body.FAbsSpeed := NullVector;
451
bounce:=VectorDotProduct(Body.FGravSpeed, ColInfo.Normal);
452
if bounce<0 then begin
453
restitution := (Body.BounceFactor + tBounceFactor) / 2;
454
m := VectorLength(Body.FGravSpeed);
455
f := -bounce/VectorNorm(ColInfo.Normal)*(1+restitution);
456
CombineVector(Body.FGravSpeed,ColInfo.Normal,f);
458
if VectorLength(Body.FGravSpeed) > m * 2 then
459
Body.FGravSpeed := NullVector;
465
colinfo.RootCollision := (lastobj <> oi);
466
colInfo.Distance := Contacts[i].Distance;
470
if Assigned(FOnCollision) then
471
FOnCollision(Self,Body.OwnerBaseSceneObject,tObject,ColInfo);
472
if Assigned(Body.FOnCollision) then
473
Body.FOnCollision(Self,tObject,ColInfo);
474
if Assigned(Body.FOnCollision) then
475
Body.FOnCollision(Self,tObject,ColInfo);
476
//If the collided object is static trigger its event
477
if (oi >= 0) and Assigned(TGLDCEStatic(FStatics[oi]).FOnCollision) then
478
TGLDCEStatic(FStatics[oi]).FOnCollision(Self,Body.OwnerBaseSceneObject,ColInfo);
483
result := TotalFriction;
486
procedure TGLDCEManager.Step(deltaTime: Double);
489
if deltaTime > 0.1 then deltaTime := 0.1;
490
for i := 0 to FDynamics.Count-1 do
491
with TGLDCEDynamic(FDynamics[i]) do
492
if Active then DoMove(deltaTime);
495
procedure TGLDCEManager.SetWorldDirection(const Value: TGLCoordinates);
497
FWorldDirection := Value;
498
FWorldDirection.Normalize;
501
procedure TGLDCEManager.SetWorldScale(const Value: Single);
503
if Value = 0 then FWorldScale := 0.001
504
else if Value < 0 then FWorldScale := abs(Value)
505
else FWorldScale := Value;
508
procedure TGLDCEManager.RegisterStatic(aClient : TGLDCEStatic);
510
if Assigned(aClient) then
511
if FStatics.IndexOf(aClient)<0 then begin
512
FStatics.Add(aClient);
513
aClient.FManager:=Self;
517
procedure TGLDCEManager.DeRegisterStatic(aClient : TGLDCEStatic);
519
if Assigned(aClient) then begin
520
aClient.FManager:=nil;
521
FStatics.Remove(aClient);
525
procedure TGLDCEManager.DeRegisterAllStatics;
529
// Fast deregistration
530
for i:=0 to FStatics.Count-1 do
531
TGLDCEStatic(FStatics[i]).FManager:=nil;
537
procedure TGLDCEManager.RegisterDynamic(aClient : TGLDCEDynamic);
539
if Assigned(aClient) then
540
if FDynamics.IndexOf(aClient)<0 then begin
541
FDynamics.Add(aClient);
542
aClient.FManager:=Self;
546
procedure TGLDCEManager.DeRegisterDynamic(aClient : TGLDCEDynamic);
548
if Assigned(aClient) then begin
549
aClient.FManager:=nil;
550
FDynamics.Remove(aClient);
554
procedure TGLDCEManager.DeRegisterAllDynamics;
558
// Fast deregistration
559
for i:=0 to FDynamics.Count-1 do
560
TGLDCEDynamic(FDynamics[i]).FManager:=nil;
566
procedure TGLDCEStatic.Assign(Source: TPersistent);
568
if Source is TGLDCEStatic then begin
569
Active := TGLDCEStatic(Source).Active;
570
Manager:=TGLDCEStatic(Source).Manager;
571
Shape := TGLDCEStatic(Source).Shape;
572
Layer := TGLDCEStatic(Source).Layer;
573
Solid := TGLDCEStatic(Source).Solid;
574
Size.Assign(TGLDCEStatic(Source).Size);
575
Friction := TGLDCEStatic(Source).Friction;
576
BounceFactor := TGLDCEStatic(Source).BounceFactor;
578
inherited Assign(Source);
581
constructor TGLDCEStatic.Create(aOwner: TGLXCollection);
583
inherited Create(aOwner);
585
FSize:=TGLCoordinates.CreateInitialized(Self, XYZHmgVector, csVector);
586
FShape := csEllipsoid;
592
destructor TGLDCEStatic.Destroy;
599
class function TGLDCEStatic.FriendlyDescription: String;
601
Result:='Static Collision-detection registration';
604
class function TGLDCEStatic.FriendlyName: String;
606
Result:='DCE Static Collider';
609
procedure TGLDCEStatic.Loaded;
614
if FManagerName<>'' then begin
615
mng:=FindManager(TGLDCEManager, FManagerName);
616
if Assigned(mng) then
617
Manager:=TGLDCEManager(mng);
622
procedure TGLDCEStatic.WriteToFiler(writer: TWriter);
625
// ArchiveVersion 1, added inherited call
628
if Assigned(FManager) then
629
WriteString(FManager.GetNamePath)
630
else WriteString('');
631
WriteInteger(Integer(FShape));
632
WriteInteger(FLayer);
633
WriteBoolean(FSolid);
634
WriteBoolean(FActive);
635
WriteSingle(FFriction);
636
WriteSingle(FBounceFactor);
637
FSize.WriteToFiler(writer);
641
procedure TGLDCEStatic.ReadFromFiler(reader: TReader);
643
archiveVersion : Integer;
646
archiveVersion:=ReadInteger;
647
Assert(archiveVersion in [0..1]);
648
if archiveVersion >=1 then
650
FManagerName:=ReadString;
652
FShape := TDCEShape(ReadInteger);
653
FLayer := ReadInteger;
654
FSolid := ReadBoolean;
655
FActive := ReadBoolean;
656
FFriction := ReadSingle;
657
FBounceFactor := ReadSingle;
658
FSize.ReadFromFiler(reader);
662
procedure TGLDCEStatic.SetBounceFactor(const Value: Single);
664
FBounceFactor := Value;
665
if FBounceFactor < 0 then FBounceFactor := 0;
666
if FBounceFactor > 1 then FBounceFactor := 1;
669
procedure TGLDCEStatic.SetFriction(const Value: Single);
672
if FFriction < 0 then FFriction := 0;
673
if FFriction > 100 then FFriction := 100;
676
procedure TGLDCEStatic.SetManager(const val: TGLDCEManager);
678
if val<>FManager then begin
679
if Assigned(FManager) then
680
FManager.DeRegisterStatic(Self);
681
if Assigned(val) then
682
val.RegisterStatic(Self);
686
procedure TGLDCEStatic.SetShape(const Value: TDCEShape);
691
procedure TGLDCEStatic.SetSize(const Value: TGLCoordinates);
694
if FSize.X <= 0 then FSize.X := 0.1;
695
if FSize.Y <= 0 then FSize.Y := 0.1;
696
if FSize.Z <= 0 then FSize.Z := 0.1;
701
procedure TGLDCEDynamic.ApplyAccel(NewAccel: TAffineVector);
703
AddVector(FAccel, NewAccel);
706
procedure TGLDCEDynamic.ApplyAccel(x,y,z: Single);
708
AddVector(FAccel, AffineVectorMake(x,y,z));
711
procedure TGLDCEDynamic.ApplyAbsAccel(NewAccel: TAffineVector);
713
AddVector(FAbsAccel, NewAccel);
716
procedure TGLDCEDynamic.ApplyAbsAccel(x,y,z: Single);
718
AddVector(FAbsAccel, AffineVectorMake(x,y,z));
721
procedure TGLDCEDynamic.StopAccel;
723
SetVector(FAccel, NullVector);
726
procedure TGLDCEDynamic.StopAbsAccel;
728
SetVector(FAbsAccel, NullVector);
731
procedure TGLDCEDynamic.Assign(Source: TPersistent);
733
if Source is TGLDCEDynamic then begin
734
Manager:=TGLDCEDynamic(Source).Manager;
735
Active := TGLDCEDynamic(Source).Active;
736
UseGravity := TGLDCEDynamic(Source).UseGravity;
737
Layer := TGLDCEDynamic(Source).Layer;
738
Solid := TGLDCEDynamic(Source).Solid;
739
Size.Assign(TGLDCEDynamic(Source).Size);
740
Friction := TGLDCEDynamic(Source).Friction;
741
BounceFactor := TGLDCEDynamic(Source).BounceFactor;
742
SlideOrBounce := TGLDCEDynamic(Source).SlideOrBounce;
743
MaxRecursionDepth := TGLDCEDynamic(Source).MaxRecursionDepth;
745
inherited Assign(Source);
748
constructor TGLDCEDynamic.Create(aOwner: TGLXCollection);
750
inherited Create(aOwner);
753
FSize:=TGLCoordinates.CreateInitialized(Self, XYZHmgVector, csVector);
757
FMaxRecursionDepth := 5; //gak:20041119
758
FSlideOrBounce := csbSlide; // gak:20041122
761
FAccel := NullVector;
762
FAbsAccel := NullVector;
763
FSpeed := NullVector;
764
FAbsSpeed := NullVector;
765
FGravSpeed := NullVector;
768
destructor TGLDCEDynamic.Destroy;
775
procedure TGLDCEDynamic.DoMove(deltaTime: Double);
776
var fGround,fAir, G: Single;
777
v, deltaS, deltaAbsS: TAffineVector;
779
procedure Accel(var aSpeed: TAffineVector; aFric: Single; aForce: TAffineVector);
781
ScaleVector(aForce, deltaTime);
782
ScaleVector(aSpeed, aFric);
783
aSpeed := VectorAdd(aForce, aSpeed);
788
if (FSlideOrBounce = csbBounce) then
789
FAccel := RotateVectorByObject(OwnerBaseSceneObject, FAccel);
792
fGround := 1 - deltaTime * FTotalFriction;
793
if fGround < 0 then fGround := 0;
796
fAir := 1 - deltaTime * FFriction;
797
if fAir < 0 then fAir := 0;
799
if FUseGravity and (not FInGround) then ScaleVector(FAccel,0.01);
801
//v = TIME * force + max(1-TIME*Friction,0) * v;
802
Accel(FSpeed, fGround, FAccel);
803
Accel(FAbsSpeed, fGround, FAbsAccel);
804
{FSpeed[0] := deltaTime * FAccel[0] + fGround * FSpeed[0];
805
FSpeed[1] := deltaTime * FAccel[1] + fGround * FSpeed[1];
806
FSpeed[2] := deltaTime * FAccel[2] + fGround * FSpeed[2];
808
FAbsSpeed[0] := deltaTime * FAbsAccel[0] + fGround * FAbsSpeed[0];
809
FAbsSpeed[1] := deltaTime * FAbsAccel[1] + fGround * FAbsSpeed[1];
810
FAbsSpeed[2] := deltaTime * FAbsAccel[2] + fGround * FAbsSpeed[2];}
814
//Calculate gravity acceleration
817
G := FManager.Gravity * abs(1-VectorDotProduct(FGroundNormal,FManager.WorldDirection.AsAffineVector))
818
else G := FManager.Gravity;
820
if FJumping then G := 0;
821
v := VectorScale(FManager.WorldDirection.AsAffineVector,g);
823
Accel(FGravSpeed, fAir, v);
824
{FGravSpeed[0] := deltaTime * v[0] + fAir * FGravSpeed[0];
825
FGravSpeed[1] := deltaTime * v[1] + fAir * FGravSpeed[1];
826
FGravSpeed[2] := deltaTime * v[2] + fAir * FGravSpeed[2];}
828
FGravSpeed := NullVector;
832
FJumpSpeed := FJumpForce;
833
FJumpHeight := FJumpHeight - (FJumpSpeed * deltaTime);
834
FJumping := FJumpHeight > 0;
835
if FJumping then FGravSpeed := NullVector
837
v := VectorScale(FManager.WorldDirection.AsAffineVector,FJumpSpeed);
838
AddVector(FGravSpeed, v);
843
//s = s0 + vt (add relative speed)
844
if FSlideOrBounce = csbBounce then
847
deltaS := RotateVectorByObject(OwnerBaseSceneObject, FSpeed);
849
AddVector(deltaS, FAbsSpeed);
851
v := VectorScale(FManager.WorldDirection.AsAffineVector,FJumpSpeed);
852
AddVector(deltaS, v);
853
//The absolute space must be only the gravity so it can calculate when it is in the ground
854
deltaAbsS := FGravSpeed;
856
ScaleVector(deltaS,deltaTime);
857
ScaleVector(deltaAbsS,deltaTime);
859
//Returns the friction of all collided objects
860
FTotalFriction := FManager.MoveByDistance(Self, deltaS, deltaAbsS);
862
FAccel := NullVector;
863
FAbsAccel := NullVector;
866
procedure TGLDCEDynamic.DoProgress(const progressTime: TProgressTimes);
868
inherited doProgress(progressTime);
869
assert(assigned(manager), 'DCE Manager not assigned to behaviour.');
871
if (not FManager.ManualStep) and FActive then
873
if progressTime.deltaTime > 0.1 then DoMove(0.1)
874
else DoMove(progressTime.deltaTime);
878
class function TGLDCEDynamic.FriendlyDescription: String;
880
Result:='Dynamic Collision-detection registration';
883
class function TGLDCEDynamic.FriendlyName: String;
885
Result:='DCE Dynamic Collider';
888
procedure TGLDCEDynamic.Jump(jHeight, jSpeed: Single);
890
if (not FJumping) and (FInGround)
891
and (VectorDotProduct(FGroundNormal,FManager.WorldDirection.AsAffineVector) > 0.5) then
893
FJumpHeight := jHeight;
894
FJumpForce := jSpeed;
895
FJumpSpeed := FJumpForce;
898
AddVector(FAbsSpeed, RotateVectorByObject(OwnerBaseSceneObject, FSpeed));
899
FSpeed := NullVector;
903
procedure TGLDCEDynamic.Loaded;
908
if FManagerName<>'' then begin
909
mng:=FindManager(TGLDCEManager, FManagerName);
910
if Assigned(mng) then
911
Manager:=TGLDCEManager(mng);
916
procedure TGLDCEDynamic.Move(deltaS: TAffineVector; deltaTime: Double);
918
ScaleVector(deltaS, deltaTime);
919
FManager.MoveByDistance(Self, NullVector, deltaS);
922
procedure TGLDCEDynamic.MoveTo(Position: TAffineVector; Amount: Single);
924
SubtractVector(Position, AffineVectorMake(OwnerBaseSceneObject.AbsolutePosition));
926
Move(position,Amount);
929
procedure TGLDCEDynamic.WriteToFiler(writer: TWriter);
932
// ArchiveVersion 1, added inherited call
935
if Assigned(FManager) then
936
WriteString(FManager.GetNamePath)
937
else WriteString('');
938
WriteInteger(FLayer);
939
WriteBoolean(FSolid);
940
WriteBoolean(FActive);
941
WriteBoolean(FUseGravity);
942
WriteSingle(FFriction);
943
WriteSingle(FBounceFactor);
944
//gak:20041122 - start
945
writeinteger(FMaxRecursionDepth);
946
writeinteger(ord(FSlideOrBounce));
948
FSize.WriteToFiler(writer);
952
procedure TGLDCEDynamic.ReadFromFiler(reader: TReader);
954
archiveVersion : Integer;
957
archiveVersion:=ReadInteger;
958
Assert(archiveVersion in [0..1]);
959
if archiveVersion >=1 then
961
FManagerName:=ReadString;
963
FLayer := ReadInteger;
964
FSolid := ReadBoolean;
965
FActive := ReadBoolean;
966
FUseGravity := ReadBoolean;
967
FFriction := ReadSingle;
968
FBounceFactor := ReadSingle;
969
//gak:20041122 - start
970
FMaxRecursionDepth := readinteger;
971
FSlideOrBounce := TDCESlideOrBounce(readinteger);
973
FSize.ReadFromFiler(reader);
977
procedure TGLDCEDynamic.SetBounceFactor(const Value: Single);
979
FBounceFactor := Value;
980
if FBounceFactor < 0 then FBounceFactor := 0;
981
if FBounceFactor > 1 then FBounceFactor := 1;
984
procedure TGLDCEDynamic.SetFriction(const Value: Single);
987
if FFriction < 0 then FFriction := 0;
988
if FFriction > 100 then FFriction := 100;
991
procedure TGLDCEDynamic.SetManager(const val: TGLDCEManager);
993
if val<>FManager then begin
994
if Assigned(FManager) then
995
FManager.DeRegisterDynamic(Self);
996
if Assigned(val) then
997
val.RegisterDynamic(Self);
1001
procedure TGLDCEDynamic.SetSize(const Value: TGLCoordinates);
1003
FSize.Assign(Value);
1004
if FSize.X <= 0 then FSize.X := 0.1;
1005
if FSize.Y <= 0 then FSize.Y := 0.1;
1006
if FSize.Z <= 0 then FSize.Z := 0.1;
1009
// ----------------------------------------------------------------
1011
function GetOrCreateDCEStatic(behaviours : TGLBehaviours) : TGLDCEStatic;
1015
i:=behaviours.IndexOfClass(TGLDCEStatic);
1017
Result:=TGLDCEStatic(behaviours[i])
1018
else Result:=TGLDCEStatic.Create(behaviours);
1021
function GetOrCreateDCEStatic(obj : TGLBaseSceneObject) : TGLDCEStatic;
1023
Result:=GetOrCreateDCEStatic(obj.Behaviours);
1026
function GetOrCreateDCEDynamic(behaviours : TGLBehaviours) : TGLDCEDynamic;
1030
i:=behaviours.IndexOfClass(TGLDCEDynamic);
1032
Result:=TGLDCEDynamic(behaviours[i])
1033
else Result:=TGLDCEDynamic.Create(behaviours);
1036
function GetOrCreateDCEDynamic(obj : TGLBaseSceneObject) : TGLDCEDynamic;
1038
Result:=GetOrCreateDCEDynamic(obj.Behaviours);
1044
// ------------------------------------------------------------------
1046
// class registrations
1047
RegisterXCollectionItemClass(TGLDCEStatic);
1048
RegisterXCollectionItemClass(TGLDCEDynamic);
1052
UnregisterXCollectionItemClass(TGLDCEStatic);
1053
UnregisterXCollectionItemClass(TGLDCEDynamic);