GLDCE.pas 34 KB

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