GXS.DCE.pas 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128
  1. // *
  2. // The graphics engine GXScene https://github.com/glscene
  3. //
  4. unit GXS.DCE;
  5. (*
  6. How to use:
  7. - Add a DCEManager to you form and configure its properties
  8. - Add a Dynamic Collision Behavior to you object
  9. - Add a Static Collision behaviour to objects which yours will collide
  10. - You can choose the shape of your static object
  11. - csEllipsoid, csBox
  12. - csFreeform MUST BE A TgxFreeform, otherwise will raise errors
  13. - csTerrain MUST BE A TgxTerrainRenderer, same condition above
  14. - Active: Disable or enable the behaviour for this object
  15. - Friction: is a value aprox. between 0 (no friction) and 100 (no movement)
  16. - Layer: An object collides only with lower or equal layers
  17. - Size: is used for Ellipsoids (Radius) / Boxes (Dimensions)
  18. - Solid: Object still generate collision events but it doesn't "block" the dynamic object
  19. - UseGravity: You can disable the gravity for that object
  20. - SlideOrBounce: The object can bounce like a ball or slide like an FPS
  21. - BounceFactor: Restituition factor, 1 means that it will bounce forever
  22. *)
  23. interface
  24. {$I Stage.Defines.inc}
  25. uses
  26. System.Classes,
  27. System.SysUtils,
  28. GXS.XCollection,
  29. Stage.VectorGeometry,
  30. GXS.VectorLists,
  31. GXS.BaseClasses,
  32. Stage.Manager,
  33. Stage.VectorTypes,
  34. Stage.Strings,
  35. GXS.Coordinates,
  36. GXS.Scene,
  37. GXS.VectorFileObjects,
  38. GXS.DCEMisc,
  39. GXS.EllipseCollision,
  40. GXS.TerrainRenderer;
  41. type
  42. // Only csEllipsoid can have dynamic behaviour
  43. TgxDCEShape = (csEllipsoid, csBox, csFreeform, csTerrain);
  44. (* Indicates which type of layer comparison is made when trying to detect
  45. collisions between 2 bodies (A and B). Possible values are:
  46. ccsDCEStandard: Collides bodies if A.layer <= B.layer
  47. ccsCollisionStandard: Collides bodies if either A or B have
  48. layer equal to zero or if their layers are different.
  49. ccsHybrid: Collides bodies if either one of the previous
  50. checks would pass (i.e. if the layer of either body is
  51. equal to 0 or if A.layer <= B.layer) *and* if both
  52. layers are positive (that is, turns off collision
  53. for bodies whose layer is < 0) *)
  54. TgxDCECollisionSelection = (ccsDCEStandard, ccsCollisionStandard, ccsHybrid);
  55. TgxDCECollision = record
  56. Position: TAffineVector;
  57. Normal: TAffineVector; // Surface normal
  58. Bounce: TAffineVector; // Surface reflection
  59. Nearest: Boolean;
  60. RootCollision: Boolean;
  61. Distance: single;
  62. end;
  63. TgxDCEStatic = class;
  64. TgxDCEDynamic = class;
  65. TgxDCECollisionEvent = procedure(Sender: TObject;
  66. object1, object2: TgxBaseSceneObject; CollisionInfo: TgxDCECollision)
  67. of object;
  68. TgxDCEObjectCollisionEvent = procedure(Sender: TObject;
  69. ObjectCollided: TgxBaseSceneObject; CollisionInfo: TgxDCECollision) of object;
  70. TgxDCEManager = class(TComponent)
  71. private
  72. FStatics: TList;
  73. FDynamics: TList;
  74. FGravity: single;
  75. FWorldDirection: TgxCoordinates; // Used to calculate jumps f.i.
  76. FWorldScale: single;
  77. FMovimentScale: single;
  78. FStandardiseLayers: TgxDCECollisionSelection;
  79. FManualStep: Boolean;
  80. FOnCollision: TgxDCECollisionEvent;
  81. procedure SetWorldDirection(const Value: TgxCoordinates);
  82. procedure SetWorldScale(const Value: single);
  83. function GetDynamicCount: Integer;
  84. function GetStaticCount: Integer;
  85. protected
  86. procedure RegisterStatic(aClient: TgxDCEStatic);
  87. procedure DeRegisterStatic(aClient: TgxDCEStatic);
  88. procedure DeRegisterAllStatics;
  89. procedure RegisterDynamic(aClient: TgxDCEDynamic);
  90. procedure DeRegisterDynamic(aClient: TgxDCEDynamic);
  91. procedure DeRegisterAllDynamics;
  92. public
  93. constructor Create(AOwner: TComponent); override;
  94. destructor Destroy; override;
  95. // Moves the body by the distance and returns the average friction
  96. function MoveByDistance(var Body: TgxDCEDynamic;
  97. deltaS, deltaAbsS: TAffineVector): single;
  98. procedure Step(deltaTime: Double);
  99. property DynamicCount: Integer read GetDynamicCount;
  100. property StaticCount: Integer read GetStaticCount;
  101. published
  102. property Gravity: single read FGravity write FGravity;
  103. property WorldDirection: TgxCoordinates read FWorldDirection write SetWorldDirection;
  104. property WorldScale: single read FWorldScale write SetWorldScale;
  105. property MovimentScale: single read FMovimentScale write FMovimentScale;
  106. Property StandardiseLayers: TgxDCECollisionSelection read FStandardiseLayers write FStandardiseLayers;
  107. Property ManualStep: Boolean read FManualStep write FManualStep;
  108. property OnCollision: TgxDCECollisionEvent read FOnCollision write FOnCollision;
  109. end;
  110. TgxDCEStatic = class(TgxBehaviour)
  111. private
  112. FManager: TgxDCEManager;
  113. FManagerName: String; // NOT persistent, temporarily used for persistence
  114. FActive: Boolean;
  115. FShape: TgxDCEShape;
  116. // Collides only with lower or equal layers
  117. FLayer: Integer;
  118. // Collide and slide if true, otherwise it "walk thru walls"
  119. FSolid: Boolean;
  120. FFriction: single; // 0 (no friction); 100 (no movement)
  121. FBounceFactor: single; // 0 (don't bounce); 1 (bounce forever)
  122. FSize: TgxCoordinates;
  123. // Events
  124. FOnCollision: TgxDCEObjectCollisionEvent;
  125. procedure SetShape(const Value: TgxDCEShape);
  126. procedure SetFriction(const Value: single);
  127. procedure SetBounceFactor(const Value: single);
  128. procedure SetSize(const Value: TgxCoordinates);
  129. protected
  130. procedure SetManager(const val: TgxDCEManager);
  131. procedure WriteToFiler(writer: TWriter); override;
  132. procedure ReadFromFiler(reader: TReader); override;
  133. procedure Loaded; override;
  134. public
  135. constructor Create(AOwner: TXCollection); override;
  136. destructor Destroy; override;
  137. procedure Assign(Source: TPersistent); override;
  138. class function FriendlyName: String; override;
  139. class function FriendlyDescription: String; override;
  140. property OnCollision: TgxDCEObjectCollisionEvent read FOnCollision write FOnCollision;
  141. published
  142. property Active: Boolean read FActive write FActive;
  143. property Manager: TgxDCEManager read FManager write SetManager;
  144. property Shape: TgxDCEShape read FShape write SetShape;
  145. property Layer: Integer read FLayer write FLayer;
  146. property Solid: Boolean read FSolid write FSolid;
  147. property Friction: single read FFriction write SetFriction;
  148. property BounceFactor: single read FBounceFactor write SetBounceFactor;
  149. property Size: TgxCoordinates read FSize write SetSize;
  150. end;
  151. TgxDCESlideOrBounce = (csbSlide, csbBounce);
  152. TgxDCEDynamic = class(TgxBehaviour)
  153. private
  154. FManager: TgxDCEManager;
  155. FManagerName: String; // NOT persistent, temporarily used for persistence
  156. FActive: Boolean;
  157. FUseGravity: Boolean;
  158. FLayer: Integer; // Collides only with lower or equal layers
  159. FSolid: Boolean;
  160. // Collide and slide if true, otherwise it "walk thru walls"
  161. FFriction: single; // 0 (no friction); 100 (no movement)
  162. FBounceFactor: single; // 0 (don't bounce); 1 (bounce forever)
  163. FSize: TgxCoordinates;
  164. //Number of iterations of the collision method
  165. FMaxRecursionDepth: byte;
  166. FSlideOrBounce: TgxDCESlideOrBounce; // gak20041122
  167. // Movement
  168. FAccel: TAffineVector; // Current acceleration
  169. FSpeed: TAffineVector; // Current speed
  170. FAbsAccel: TAffineVector; // Current absolute accel
  171. FAbsSpeed: TAffineVector; // Current absolute speed
  172. FGravSpeed: TAffineVector; // Current gravity speed
  173. FTotalFriction: single; // Current sum of all contatcs friction
  174. FInGround: Boolean;
  175. FGroundNormal: TAffineVector;
  176. FJumpHeight, FJumpForce, FJumpSpeed: single;
  177. FJumping: Boolean;
  178. // Events
  179. FOnCollision: TgxDCEObjectCollisionEvent;
  180. procedure SetFriction(const Value: single);
  181. procedure SetBounceFactor(const Value: single);
  182. procedure SetSize(const Value: TgxCoordinates);
  183. protected
  184. procedure SetManager(const val: TgxDCEManager);
  185. procedure WriteToFiler(writer: TWriter); override;
  186. procedure ReadFromFiler(reader: TReader); override;
  187. procedure Loaded; override;
  188. public
  189. constructor Create(AOwner: TXCollection); override;
  190. destructor Destroy; override;
  191. procedure Assign(Source: TPersistent); override;
  192. class function FriendlyName: String; override;
  193. class function FriendlyDescription: String; override;
  194. procedure ApplyAccel(NewAccel: TAffineVector); overload;
  195. procedure ApplyAccel(x, y, z: single); overload;
  196. procedure ApplyAbsAccel(NewAccel: TAffineVector); overload;
  197. procedure ApplyAbsAccel(x, y, z: single); overload;
  198. procedure StopAccel;
  199. procedure StopAbsAccel;
  200. procedure Jump(jHeight, jSpeed: single);
  201. procedure Move(deltaS: TAffineVector; deltaTime: Double);
  202. procedure MoveTo(Position: TAffineVector; Amount: single);
  203. procedure DoMove(deltaTime: Double);
  204. procedure DoProgress(const progressTime: TgxProgressTimes); override;
  205. // Runtime only
  206. property Speed: TAffineVector read FSpeed write FSpeed;
  207. property InGround: Boolean read FInGround;
  208. property MaxRecursionDepth: byte read FMaxRecursionDepth write FMaxRecursionDepth;
  209. property OnCollision: TgxDCEObjectCollisionEvent read FOnCollision write FOnCollision;
  210. published
  211. property Active: Boolean read FActive write FActive;
  212. property Manager: TgxDCEManager read FManager write SetManager;
  213. property UseGravity: Boolean read FUseGravity write FUseGravity;
  214. property Layer: Integer read FLayer write FLayer;
  215. property Solid: Boolean read FSolid write FSolid;
  216. property Friction: single read FFriction write SetFriction;
  217. property BounceFactor: single read FBounceFactor write SetBounceFactor;
  218. property Size: TgxCoordinates read FSize write SetSize;
  219. property SlideOrBounce: TgxDCESlideOrBounce read FSlideOrBounce write FSlideOrBounce;
  220. end;
  221. function GetOrCreateDCEStatic(behaviours: TgxBehaviours): TgxDCEStatic; overload;
  222. function GetOrCreateDCEStatic(obj: TgxBaseSceneObject): TgxDCEStatic; overload;
  223. function GetOrCreateDCEDynamic(behaviours: TgxBehaviours): TgxDCEDynamic; overload;
  224. function GetOrCreateDCEDynamic(obj: TgxBaseSceneObject): TgxDCEDynamic; overload;
  225. implementation // ------------------------------------------------------------
  226. function RotateVectorByObject(obj: TgxBaseSceneObject; v: TAffineVector): TAffineVector;
  227. var
  228. v2: TVector4f;
  229. begin
  230. SetVector(v2, v);
  231. SetVector(result, VectorTransform(v2, obj.Matrix^));
  232. end;
  233. constructor TgxDCEManager.Create(AOwner: TComponent);
  234. begin
  235. inherited Create(AOwner);
  236. FStatics := TList.Create;
  237. FDynamics := TList.Create;
  238. FGravity := 0;
  239. FWorldDirection := TgxCoordinates.CreateInitialized(Self, YHmgVector, csVector);
  240. FWorldScale := 1;
  241. FMovimentScale := 1;
  242. FStandardiseLayers := ccsDCEStandard;
  243. FManualStep := False;
  244. RegisterManager(Self);
  245. end;
  246. destructor TgxDCEManager.Destroy;
  247. begin
  248. DeRegisterAllStatics;
  249. DeRegisterAllDynamics;
  250. DeRegisterManager(Self);
  251. FStatics.Free;
  252. FDynamics.Free;
  253. FWorldDirection.Free;
  254. inherited Destroy;
  255. end;
  256. function TgxDCEManager.GetDynamicCount: Integer;
  257. begin
  258. result := FDynamics.Count;
  259. end;
  260. function TgxDCEManager.GetStaticCount: Integer;
  261. begin
  262. result := FStatics.Count;
  263. end;
  264. function TgxDCEManager.MoveByDistance(var Body: TgxDCEDynamic;
  265. deltaS, deltaAbsS: TAffineVector): single;
  266. var
  267. // Friction and bounce
  268. TotalFriction, Bounce, f, m, restitution: single;
  269. ContactList: TgxIntegerList;
  270. // Temporary properties (Static or Dynamic)
  271. tFriction, tBounceFactor: single;
  272. TObject: TgxBaseSceneObject;
  273. // Collision results
  274. ColInfo: TgxDCECollision;
  275. lastobj: Integer;
  276. i, oi: Integer;
  277. MP: TECMovePack;
  278. CanCollide, GravCollided: Boolean;
  279. // Vars used to calculate high velocities
  280. ColRange, MaxRange: single;
  281. dCR, dT, deltaCR: Double;
  282. begin
  283. // Set collider parameters
  284. MP.Radius := Body.Size.AsAffineVector;
  285. MP.Position := AffineVectorMake(Body.OwnerBaseSceneObject.AbsolutePosition);
  286. MP.Velocity := deltaS;
  287. MP.Gravity := deltaAbsS;
  288. MP.ObjectInfo.Solid := Body.Solid;
  289. MP.UnitScale := FWorldScale;
  290. MP.MaxRecursionDepth := Body.MaxRecursionDepth;
  291. // Get collision range, if it is too big separate into small pieces
  292. ECSetCollisionRange(MP);
  293. ColRange := MP.CollisionRange;
  294. deltaCR := ColRange;
  295. MaxRange := MaxXYZComponent(MP.Radius) * 2.1;
  296. SetLength(MP.Contacts, 0);
  297. GravCollided := False; // Is colliding with the ground
  298. Body.FGroundNormal := NullVector;
  299. while deltaCR > 0 do
  300. begin
  301. if deltaCR > MaxRange then
  302. begin
  303. dCR := MaxRange;
  304. deltaCR := deltaCR - MaxRange;
  305. end
  306. else
  307. begin
  308. dCR := deltaCR;
  309. deltaCR := 0;
  310. end;
  311. dT := dCR / ColRange;
  312. MP.Velocity := VectorScale(deltaS, dT);
  313. MP.Gravity := VectorScale(deltaAbsS, dT);
  314. ECSetCollisionRange(MP);
  315. ECResetColliders(MP);
  316. // For each static collider
  317. for i := 0 to FStatics.Count - 1 do
  318. with TgxDCEStatic(FStatics[i]) do
  319. begin
  320. CanCollide := False;
  321. if (Active) then
  322. case FStandardiseLayers of
  323. ccsDCEStandard:
  324. CanCollide := (Layer <= Body.Layer);
  325. ccsCollisionStandard:
  326. CanCollide := (Layer = 0) or (Body.Layer = 0) or
  327. (Layer <> Body.Layer);
  328. ccsHybrid:
  329. CanCollide := ((Layer = 0) or (Body.Layer = 0) or
  330. (Layer <= Body.Layer)) and (Layer >= 0) and (Body.Layer >= 0);
  331. end;
  332. // Add colliders to move pack
  333. if CanCollide then
  334. begin
  335. case Shape of
  336. csFreeform:
  337. ECAddFreeForm(MP, OwnerBaseSceneObject, Solid, i);
  338. csEllipsoid:
  339. ECAddEllipsoid(MP,
  340. AffineVectorMake(OwnerBaseSceneObject.AbsolutePosition),
  341. Size.AsAffineVector, Solid, i);
  342. csBox:
  343. ECAddBox(MP, OwnerBaseSceneObject, Size.AsAffineVector, Solid, i);
  344. csTerrain:
  345. ECAddTerrain(MP, TgxTerrainRenderer(OwnerBaseSceneObject),
  346. FWorldScale * 2, Solid, i);
  347. end;
  348. end;
  349. end;
  350. // For each dynamic collider add a static ellipsoid
  351. for i := 0 to FDynamics.Count - 1 do
  352. with TgxDCEDynamic(FDynamics[i]) do
  353. begin
  354. CanCollide := False;
  355. if (Active) and (TgxDCEDynamic(FDynamics[i]) <> Body) then
  356. case FStandardiseLayers of
  357. ccsDCEStandard:
  358. CanCollide := (Layer <= Body.Layer);
  359. ccsCollisionStandard:
  360. CanCollide := (Layer = 0) or (Body.Layer = 0) or
  361. (Layer <> Body.Layer);
  362. ccsHybrid:
  363. CanCollide := ((Layer = 0) or (Body.Layer = 0) or
  364. (Layer <= Body.Layer)) and (Layer >= 0) and (Body.Layer >= 0);
  365. end;
  366. // Add collider to move pack
  367. // To differ from static it is added with a negative ID (id < 0)
  368. if CanCollide then
  369. ECAddEllipsoid(MP,
  370. AffineVectorMake(OwnerBaseSceneObject.AbsolutePosition),
  371. Size.AsAffineVector, Solid, -1 - i);
  372. end;
  373. CollideAndSlide(MP);
  374. if MP.GravityCollided then
  375. begin
  376. GravCollided := True;
  377. Body.FGroundNormal := MP.GroundNormal;
  378. end;
  379. MP.Position := MP.ResultPos;
  380. end;
  381. // Set the result
  382. Body.OwnerBaseSceneObject.AbsolutePosition := VectorMake(MP.ResultPos);
  383. Body.FInGround := GravCollided;
  384. // Generate events and calculate average friction
  385. lastobj := -1;
  386. TotalFriction := Body.Friction;
  387. ContactList := TgxIntegerList.Create;
  388. try
  389. for i := 0 to High(MP.Contacts) do
  390. with MP do
  391. begin
  392. oi := Contacts[i].ObjectInfo.ObjectID;
  393. // Don't repeat objects with same ID
  394. if ContactList.IndexOf(oi) >= 0 then
  395. Continue
  396. else
  397. ContactList.Add(oi);
  398. // Check if it is static or dynamic
  399. if oi < 0 then
  400. begin
  401. tFriction := TgxDCEDynamic(FDynamics[abs(oi) - 1]).Friction;
  402. tBounceFactor := TgxDCEDynamic(FDynamics[abs(oi) - 1]).BounceFactor;
  403. TObject := TgxDCEDynamic(FDynamics[abs(oi) - 1]).OwnerBaseSceneObject;
  404. end
  405. else
  406. begin
  407. tFriction := TgxDCEStatic(FStatics[oi]).Friction;
  408. tBounceFactor := TgxDCEStatic(FStatics[oi]).BounceFactor;
  409. TObject := TgxDCEStatic(FStatics[oi]).OwnerBaseSceneObject;
  410. end;
  411. TotalFriction := TotalFriction + tFriction;
  412. ColInfo.Position := Contacts[i].Position;
  413. ColInfo.Normal := Contacts[i].SurfaceNormal;
  414. ColInfo.Bounce := VectorNormalize
  415. (VectorReflect(VectorAdd(deltaS, deltaAbsS), ColInfo.Normal));
  416. ColInfo.Nearest := oi = MP.NearestObject;
  417. // Calculate bounce
  418. if (Body.SlideOrBounce = csbBounce) and ColInfo.Nearest then
  419. begin
  420. Bounce := VectorDotProduct(Body.FSpeed, ColInfo.Normal);
  421. if Bounce < 0 then
  422. begin
  423. restitution := (Body.BounceFactor + tBounceFactor) / 2;
  424. m := VectorLength(Body.FSpeed);
  425. f := -Bounce / VectorNorm(ColInfo.Normal) * (1 + restitution);
  426. CombineVector(Body.FSpeed, ColInfo.Normal, f);
  427. // Limit bounce speed
  428. if VectorLength(Body.FSpeed) > m * 2 then
  429. Body.FSpeed := NullVector;
  430. end;
  431. Bounce := VectorDotProduct(Body.FAbsSpeed, ColInfo.Normal);
  432. if Bounce < 0 then
  433. begin
  434. restitution := (Body.BounceFactor + tBounceFactor) / 2;
  435. m := VectorLength(Body.FAbsSpeed);
  436. f := -Bounce / VectorNorm(ColInfo.Normal) * (1 + restitution);
  437. CombineVector(Body.FAbsSpeed, ColInfo.Normal, f);
  438. // Limit
  439. if VectorLength(Body.FAbsSpeed) > m * 2 then
  440. Body.FAbsSpeed := NullVector;
  441. end;
  442. Bounce := VectorDotProduct(Body.FGravSpeed, ColInfo.Normal);
  443. if Bounce < 0 then
  444. begin
  445. restitution := (Body.BounceFactor + tBounceFactor) / 2;
  446. m := VectorLength(Body.FGravSpeed);
  447. f := -Bounce / VectorNorm(ColInfo.Normal) * (1 + restitution);
  448. CombineVector(Body.FGravSpeed, ColInfo.Normal, f);
  449. // Limit
  450. if VectorLength(Body.FGravSpeed) > m * 2 then
  451. Body.FGravSpeed := NullVector;
  452. end;
  453. end;
  454. ColInfo.RootCollision := (lastobj <> oi);
  455. ColInfo.Distance := Contacts[i].Distance;
  456. lastobj := oi;
  457. if Assigned(FOnCollision) then
  458. FOnCollision(Self, Body.OwnerBaseSceneObject, TObject, ColInfo);
  459. if Assigned(Body.FOnCollision) then
  460. Body.FOnCollision(Self, TObject, ColInfo);
  461. if Assigned(Body.FOnCollision) then
  462. Body.FOnCollision(Self, TObject, ColInfo);
  463. // If the collided object is static trigger its event
  464. if (oi >= 0) and Assigned(TgxDCEStatic(FStatics[oi]).FOnCollision) then
  465. TgxDCEStatic(FStatics[oi]).FOnCollision(Self,
  466. Body.OwnerBaseSceneObject, ColInfo);
  467. end;
  468. finally
  469. ContactList.Free;
  470. end;
  471. result := TotalFriction;
  472. end;
  473. procedure TgxDCEManager.Step(deltaTime: Double);
  474. var
  475. i: Integer;
  476. begin
  477. if deltaTime > 0.1 then
  478. deltaTime := 0.1;
  479. for i := 0 to FDynamics.Count - 1 do
  480. with TgxDCEDynamic(FDynamics[i]) do
  481. if Active then
  482. DoMove(deltaTime);
  483. end;
  484. procedure TgxDCEManager.SetWorldDirection(const Value: TgxCoordinates);
  485. begin
  486. FWorldDirection := Value;
  487. FWorldDirection.Normalize;
  488. end;
  489. procedure TgxDCEManager.SetWorldScale(const Value: single);
  490. begin
  491. if Value = 0 then
  492. FWorldScale := 0.001
  493. else if Value < 0 then
  494. FWorldScale := abs(Value)
  495. else
  496. FWorldScale := Value;
  497. end;
  498. procedure TgxDCEManager.RegisterStatic(aClient: TgxDCEStatic);
  499. begin
  500. if Assigned(aClient) then
  501. if FStatics.IndexOf(aClient) < 0 then
  502. begin
  503. FStatics.Add(aClient);
  504. aClient.FManager := Self;
  505. end;
  506. end;
  507. procedure TgxDCEManager.DeRegisterStatic(aClient: TgxDCEStatic);
  508. begin
  509. if Assigned(aClient) then
  510. begin
  511. aClient.FManager := nil;
  512. FStatics.Remove(aClient);
  513. end;
  514. end;
  515. procedure TgxDCEManager.DeRegisterAllStatics;
  516. var
  517. i: Integer;
  518. begin
  519. // Fast deregistration
  520. for i := 0 to FStatics.Count - 1 do
  521. TgxDCEStatic(FStatics[i]).FManager := nil;
  522. FStatics.Clear;
  523. end;
  524. procedure TgxDCEManager.RegisterDynamic(aClient: TgxDCEDynamic);
  525. begin
  526. if Assigned(aClient) then
  527. if FDynamics.IndexOf(aClient) < 0 then
  528. begin
  529. FDynamics.Add(aClient);
  530. aClient.FManager := Self;
  531. end;
  532. end;
  533. procedure TgxDCEManager.DeRegisterDynamic(aClient: TgxDCEDynamic);
  534. begin
  535. if Assigned(aClient) then
  536. begin
  537. aClient.FManager := nil;
  538. FDynamics.Remove(aClient);
  539. end;
  540. end;
  541. procedure TgxDCEManager.DeRegisterAllDynamics;
  542. var
  543. i: Integer;
  544. begin
  545. // Fast deregistration
  546. for i := 0 to FDynamics.Count - 1 do
  547. TgxDCEDynamic(FDynamics[i]).FManager := nil;
  548. FDynamics.Clear;
  549. end;
  550. //---------------------------------------
  551. // TgxDCEStatic
  552. //---------------------------------------
  553. procedure TgxDCEStatic.Assign(Source: TPersistent);
  554. begin
  555. if Source is TgxDCEStatic then
  556. begin
  557. Active := TgxDCEStatic(Source).Active;
  558. Manager := TgxDCEStatic(Source).Manager;
  559. Shape := TgxDCEStatic(Source).Shape;
  560. Layer := TgxDCEStatic(Source).Layer;
  561. Solid := TgxDCEStatic(Source).Solid;
  562. Size.Assign(TgxDCEStatic(Source).Size);
  563. Friction := TgxDCEStatic(Source).Friction;
  564. BounceFactor := TgxDCEStatic(Source).BounceFactor;
  565. end;
  566. inherited Assign(Source);
  567. end;
  568. constructor TgxDCEStatic.Create(AOwner: TXCollection);
  569. begin
  570. inherited Create(AOwner);
  571. FActive := True;
  572. FSize := TgxCoordinates.CreateInitialized(Self, XYZHmgVector, csVector);
  573. FShape := csEllipsoid;
  574. FSolid := True;
  575. FFriction := 1;
  576. FBounceFactor := 0;
  577. end;
  578. destructor TgxDCEStatic.Destroy;
  579. begin
  580. Manager := nil;
  581. FSize.Free;
  582. inherited Destroy;
  583. end;
  584. class function TgxDCEStatic.FriendlyDescription: String;
  585. begin
  586. result := 'Static Collision-detection registration';
  587. end;
  588. class function TgxDCEStatic.FriendlyName: String;
  589. begin
  590. result := 'DCE Static Collider';
  591. end;
  592. procedure TgxDCEStatic.Loaded;
  593. var
  594. mng: TComponent;
  595. begin
  596. inherited;
  597. if FManagerName <> '' then
  598. begin
  599. mng := FindManager(TgxDCEManager, FManagerName);
  600. if Assigned(mng) then
  601. Manager := TgxDCEManager(mng);
  602. FManagerName := '';
  603. end;
  604. end;
  605. procedure TgxDCEStatic.WriteToFiler(writer: TWriter);
  606. begin
  607. with writer do
  608. begin
  609. // ArchiveVersion 1, added inherited call
  610. WriteInteger(1);
  611. inherited;
  612. if Assigned(FManager) then
  613. WriteString(FManager.GetNamePath)
  614. else
  615. WriteString('');
  616. WriteInteger(Integer(FShape));
  617. WriteInteger(FLayer);
  618. WriteBoolean(FSolid);
  619. WriteBoolean(FActive);
  620. WriteSingle(FFriction);
  621. WriteSingle(FBounceFactor);
  622. FSize.WriteToFiler(writer);
  623. end;
  624. end;
  625. procedure TgxDCEStatic.ReadFromFiler(reader: TReader);
  626. var
  627. archiveVersion: Integer;
  628. begin
  629. with reader do
  630. begin
  631. archiveVersion := ReadInteger;
  632. Assert(archiveVersion in [0 .. 1]);
  633. if archiveVersion >= 1 then
  634. inherited;
  635. FManagerName := ReadString;
  636. Manager := nil;
  637. FShape := TgxDCEShape(ReadInteger);
  638. FLayer := ReadInteger;
  639. FSolid := ReadBoolean;
  640. FActive := ReadBoolean;
  641. FFriction := ReadSingle;
  642. FBounceFactor := ReadSingle;
  643. FSize.ReadFromFiler(reader);
  644. end;
  645. end;
  646. procedure TgxDCEStatic.SetBounceFactor(const Value: single);
  647. begin
  648. FBounceFactor := Value;
  649. if FBounceFactor < 0 then
  650. FBounceFactor := 0;
  651. if FBounceFactor > 1 then
  652. FBounceFactor := 1;
  653. end;
  654. procedure TgxDCEStatic.SetFriction(const Value: single);
  655. begin
  656. FFriction := Value;
  657. if FFriction < 0 then
  658. FFriction := 0;
  659. if FFriction > 100 then
  660. FFriction := 100;
  661. end;
  662. procedure TgxDCEStatic.SetManager(const val: TgxDCEManager);
  663. begin
  664. if val <> FManager then
  665. begin
  666. if Assigned(FManager) then
  667. FManager.DeRegisterStatic(Self);
  668. if Assigned(val) then
  669. val.RegisterStatic(Self);
  670. end;
  671. end;
  672. procedure TgxDCEStatic.SetShape(const Value: TgxDCEShape);
  673. begin
  674. FShape := Value;
  675. end;
  676. procedure TgxDCEStatic.SetSize(const Value: TgxCoordinates);
  677. begin
  678. FSize.Assign(Value);
  679. if FSize.x <= 0 then
  680. FSize.x := 0.1;
  681. if FSize.y <= 0 then
  682. FSize.y := 0.1;
  683. if FSize.z <= 0 then
  684. FSize.z := 0.1;
  685. end;
  686. //-------------------------------------
  687. // TgxDCEDynamic
  688. //-------------------------------------
  689. procedure TgxDCEDynamic.ApplyAccel(NewAccel: TAffineVector);
  690. begin
  691. AddVector(FAccel, NewAccel);
  692. end;
  693. procedure TgxDCEDynamic.ApplyAccel(x, y, z: single);
  694. begin
  695. AddVector(FAccel, AffineVectorMake(x, y, z));
  696. end;
  697. procedure TgxDCEDynamic.ApplyAbsAccel(NewAccel: TAffineVector);
  698. begin
  699. AddVector(FAbsAccel, NewAccel);
  700. end;
  701. procedure TgxDCEDynamic.ApplyAbsAccel(x, y, z: single);
  702. begin
  703. AddVector(FAbsAccel, AffineVectorMake(x, y, z));
  704. end;
  705. procedure TgxDCEDynamic.StopAccel;
  706. begin
  707. SetVector(FAccel, NullVector);
  708. end;
  709. procedure TgxDCEDynamic.StopAbsAccel;
  710. begin
  711. SetVector(FAbsAccel, NullVector);
  712. end;
  713. procedure TgxDCEDynamic.Assign(Source: TPersistent);
  714. begin
  715. if Source is TgxDCEDynamic then
  716. begin
  717. Manager := TgxDCEDynamic(Source).Manager;
  718. Active := TgxDCEDynamic(Source).Active;
  719. UseGravity := TgxDCEDynamic(Source).UseGravity;
  720. Layer := TgxDCEDynamic(Source).Layer;
  721. Solid := TgxDCEDynamic(Source).Solid;
  722. Size.Assign(TgxDCEDynamic(Source).Size);
  723. Friction := TgxDCEDynamic(Source).Friction;
  724. BounceFactor := TgxDCEDynamic(Source).BounceFactor;
  725. SlideOrBounce := TgxDCEDynamic(Source).SlideOrBounce;
  726. MaxRecursionDepth := TgxDCEDynamic(Source).MaxRecursionDepth;
  727. end;
  728. inherited Assign(Source);
  729. end;
  730. constructor TgxDCEDynamic.Create(AOwner: TXCollection);
  731. begin
  732. inherited Create(AOwner);
  733. FActive := True;
  734. FUseGravity := True;
  735. FSize := TgxCoordinates.CreateInitialized(Self, XYZHmgVector, csVector);
  736. FSolid := True;
  737. FFriction := 1;
  738. FBounceFactor := 0;
  739. FMaxRecursionDepth := 5;
  740. FSlideOrBounce := csbSlide;
  741. FInGround := False;
  742. FAccel := NullVector;
  743. FAbsAccel := NullVector;
  744. FSpeed := NullVector;
  745. FAbsSpeed := NullVector;
  746. FGravSpeed := NullVector;
  747. end;
  748. destructor TgxDCEDynamic.Destroy;
  749. begin
  750. Manager := nil;
  751. FSize.Free;
  752. inherited Destroy;
  753. end;
  754. procedure TgxDCEDynamic.DoMove(deltaTime: Double);
  755. var
  756. fGround, fAir, G: single;
  757. v, deltaS, deltaAbsS: TAffineVector;
  758. procedure Accel(var aSpeed: TAffineVector; aFric: single;
  759. aForce: TAffineVector);
  760. begin
  761. ScaleVector(aForce, deltaTime);
  762. ScaleVector(aSpeed, aFric);
  763. aSpeed := VectorAdd(aForce, aSpeed);
  764. end;
  765. begin
  766. if (FSlideOrBounce = csbBounce) then
  767. FAccel := RotateVectorByObject(OwnerBaseSceneObject, FAccel);
  768. // Ground friction
  769. fGround := 1 - deltaTime * FTotalFriction;
  770. if fGround < 0 then
  771. fGround := 0;
  772. // Air friction
  773. fAir := 1 - deltaTime * FFriction;
  774. if fAir < 0 then
  775. fAir := 0;
  776. if FUseGravity and (not FInGround) then
  777. ScaleVector(FAccel, 0.01);
  778. // v = TIME * force + max(1-TIME*Friction,0) * v;
  779. Accel(FSpeed, fGround, FAccel);
  780. Accel(FAbsSpeed, fGround, FAbsAccel);
  781. (* FSpeed[0] := deltaTime * FAccel[0] + fGround * FSpeed[0];
  782. FSpeed[1] := deltaTime * FAccel[1] + fGround * FSpeed[1];
  783. FSpeed[2] := deltaTime * FAccel[2] + fGround * FSpeed[2];
  784. FAbsSpeed[0] := deltaTime * FAbsAccel[0] + fGround * FAbsSpeed[0];
  785. FAbsSpeed[1] := deltaTime * FAbsAccel[1] + fGround * FAbsSpeed[1];
  786. FAbsSpeed[2] := deltaTime * FAbsAccel[2] + fGround * FAbsSpeed[2]; *)
  787. if FUseGravity then
  788. begin
  789. // Calculate gravity acceleration
  790. if FInGround then
  791. G := FManager.Gravity * abs(1 - VectorDotProduct(FGroundNormal,
  792. FManager.WorldDirection.AsAffineVector))
  793. else
  794. G := FManager.Gravity;
  795. if FJumping then
  796. G := 0;
  797. v := VectorScale(FManager.WorldDirection.AsAffineVector, G);
  798. Accel(FGravSpeed, fAir, v);
  799. (* FGravSpeed[0] := deltaTime * v[0] + fAir * FGravSpeed[0];
  800. FGravSpeed[1] := deltaTime * v[1] + fAir * FGravSpeed[1];
  801. FGravSpeed[2] := deltaTime * v[2] + fAir * FGravSpeed[2]; *)
  802. end
  803. else
  804. FGravSpeed := NullVector;
  805. if FJumping then
  806. begin
  807. FJumpSpeed := FJumpForce;
  808. FJumpHeight := FJumpHeight - (FJumpSpeed * deltaTime);
  809. FJumping := FJumpHeight > 0;
  810. if FJumping then
  811. FGravSpeed := NullVector
  812. else
  813. begin
  814. v := VectorScale(FManager.WorldDirection.AsAffineVector, FJumpSpeed);
  815. AddVector(FGravSpeed, v);
  816. FJumpForce := 0;
  817. FJumpSpeed := 0;
  818. end;
  819. end;
  820. // s = s0 + vt (add relative speed)
  821. if FSlideOrBounce = csbBounce then
  822. deltaS := FSpeed
  823. else
  824. deltaS := RotateVectorByObject(OwnerBaseSceneObject, FSpeed);
  825. // Add absolute speed
  826. AddVector(deltaS, FAbsSpeed);
  827. // Add jump speed
  828. v := VectorScale(FManager.WorldDirection.AsAffineVector, FJumpSpeed);
  829. AddVector(deltaS, v);
  830. // The absolute space must be only the gravity so it can calculate when it is in the ground
  831. deltaAbsS := FGravSpeed;
  832. ScaleVector(deltaS, deltaTime);
  833. ScaleVector(deltaAbsS, deltaTime);
  834. // Returns the friction of all collided objects
  835. FTotalFriction := FManager.MoveByDistance(Self, deltaS, deltaAbsS);
  836. FAccel := NullVector;
  837. FAbsAccel := NullVector;
  838. end;
  839. procedure TgxDCEDynamic.DoProgress(const progressTime: TgxProgressTimes);
  840. begin
  841. inherited DoProgress(progressTime);
  842. Assert(Assigned(Manager), 'DCE Manager not assigned to behaviour.');
  843. if (not FManager.ManualStep) and FActive then
  844. begin
  845. if progressTime.deltaTime > 0.1 then
  846. DoMove(0.1)
  847. else
  848. DoMove(progressTime.deltaTime);
  849. end;
  850. end;
  851. class function TgxDCEDynamic.FriendlyDescription: String;
  852. begin
  853. Result := 'Dynamic Collision-detection registration';
  854. end;
  855. class function TgxDCEDynamic.FriendlyName: String;
  856. begin
  857. Result := 'DCE Dynamic Collider';
  858. end;
  859. procedure TgxDCEDynamic.Jump(jHeight, jSpeed: single);
  860. begin
  861. if (not FJumping) and (FInGround) and
  862. (VectorDotProduct(FGroundNormal, FManager.WorldDirection.AsAffineVector)
  863. > 0.5) then
  864. begin
  865. FJumpHeight := jHeight;
  866. FJumpForce := jSpeed;
  867. FJumpSpeed := FJumpForce;
  868. FJumping := True;
  869. FInGround := False;
  870. AddVector(FAbsSpeed, RotateVectorByObject(OwnerBaseSceneObject, FSpeed));
  871. FSpeed := NullVector;
  872. end;
  873. end;
  874. procedure TgxDCEDynamic.Loaded;
  875. var
  876. mng: TComponent;
  877. begin
  878. inherited;
  879. if FManagerName <> '' then
  880. begin
  881. mng := FindManager(TgxDCEManager, FManagerName);
  882. if Assigned(mng) then
  883. Manager := TgxDCEManager(mng);
  884. FManagerName := '';
  885. end;
  886. end;
  887. procedure TgxDCEDynamic.Move(deltaS: TAffineVector; deltaTime: Double);
  888. begin
  889. ScaleVector(deltaS, deltaTime);
  890. FManager.MoveByDistance(Self, NullVector, deltaS);
  891. end;
  892. procedure TgxDCEDynamic.MoveTo(Position: TAffineVector; Amount: single);
  893. begin
  894. SubtractVector(Position,
  895. AffineVectorMake(OwnerBaseSceneObject.AbsolutePosition));
  896. Move(Position, Amount);
  897. end;
  898. procedure TgxDCEDynamic.WriteToFiler(writer: TWriter);
  899. begin
  900. with writer do
  901. begin
  902. // ArchiveVersion 1, added inherited call
  903. WriteInteger(1);
  904. inherited;
  905. if Assigned(FManager) then
  906. WriteString(FManager.GetNamePath)
  907. else
  908. WriteString('');
  909. WriteInteger(FLayer);
  910. WriteBoolean(FSolid);
  911. WriteBoolean(FActive);
  912. WriteBoolean(FUseGravity);
  913. WriteSingle(FFriction);
  914. WriteSingle(FBounceFactor);
  915. WriteInteger(FMaxRecursionDepth);
  916. WriteInteger(ord(FSlideOrBounce));
  917. FSize.WriteToFiler(writer);
  918. end;
  919. end;
  920. procedure TgxDCEDynamic.ReadFromFiler(reader: TReader);
  921. var
  922. archiveVersion: Integer;
  923. begin
  924. with reader do
  925. begin
  926. archiveVersion := ReadInteger;
  927. Assert(archiveVersion in [0 .. 1]);
  928. if archiveVersion >= 1 then
  929. inherited;
  930. FManagerName := ReadString;
  931. Manager := nil;
  932. FLayer := ReadInteger;
  933. FSolid := ReadBoolean;
  934. FActive := ReadBoolean;
  935. FUseGravity := ReadBoolean;
  936. FFriction := ReadSingle;
  937. FBounceFactor := ReadSingle;
  938. FMaxRecursionDepth := ReadInteger;
  939. FSlideOrBounce := TgxDCESlideOrBounce(ReadInteger);
  940. FSize.ReadFromFiler(reader);
  941. end;
  942. end;
  943. procedure TgxDCEDynamic.SetBounceFactor(const Value: single);
  944. begin
  945. FBounceFactor := Value;
  946. if FBounceFactor < 0 then
  947. FBounceFactor := 0;
  948. if FBounceFactor > 1 then
  949. FBounceFactor := 1;
  950. end;
  951. procedure TgxDCEDynamic.SetFriction(const Value: single);
  952. begin
  953. FFriction := Value;
  954. if FFriction < 0 then
  955. FFriction := 0;
  956. if FFriction > 100 then
  957. FFriction := 100;
  958. end;
  959. procedure TgxDCEDynamic.SetManager(const val: TgxDCEManager);
  960. begin
  961. if val <> FManager then
  962. begin
  963. if Assigned(FManager) then
  964. FManager.DeRegisterDynamic(Self);
  965. if Assigned(val) then
  966. val.RegisterDynamic(Self);
  967. end;
  968. end;
  969. procedure TgxDCEDynamic.SetSize(const Value: TgxCoordinates);
  970. begin
  971. FSize.Assign(Value);
  972. if FSize.x <= 0 then
  973. FSize.x := 0.1;
  974. if FSize.y <= 0 then
  975. FSize.y := 0.1;
  976. if FSize.z <= 0 then
  977. FSize.z := 0.1;
  978. end;
  979. // ----------------------------------------------------------------
  980. function GetOrCreateDCEStatic(behaviours: TgxBehaviours): TgxDCEStatic;
  981. var
  982. i: Integer;
  983. begin
  984. i := behaviours.IndexOfClass(TgxDCEStatic);
  985. if i >= 0 then
  986. result := TgxDCEStatic(behaviours[i])
  987. else
  988. result := TgxDCEStatic.Create(behaviours);
  989. end;
  990. function GetOrCreateDCEStatic(obj: TgxBaseSceneObject): TgxDCEStatic;
  991. begin
  992. result := GetOrCreateDCEStatic(obj.behaviours);
  993. end;
  994. function GetOrCreateDCEDynamic(behaviours: TgxBehaviours): TgxDCEDynamic;
  995. var
  996. i: Integer;
  997. begin
  998. i := behaviours.IndexOfClass(TgxDCEDynamic);
  999. if i >= 0 then
  1000. result := TgxDCEDynamic(behaviours[i])
  1001. else
  1002. result := TgxDCEDynamic.Create(behaviours);
  1003. end;
  1004. function GetOrCreateDCEDynamic(obj: TgxBaseSceneObject): TgxDCEDynamic;
  1005. begin
  1006. result := GetOrCreateDCEDynamic(obj.behaviours);
  1007. end;
  1008. initialization // ------------------------------------------------------------
  1009. RegisterXCollectionItemClass(TgxDCEStatic);
  1010. RegisterXCollectionItemClass(TgxDCEDynamic);
  1011. finalization // --------------------------------------------------------------
  1012. UnregisterXCollectionItemClass(TgxDCEStatic);
  1013. UnregisterXCollectionItemClass(TgxDCEDynamic);
  1014. end.