GLS.Vehicles.pas 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078
  1. //
  2. // The graphics GaLaXy Engine. The unit of GLScene
  3. //
  4. unit GLS.Vehicles;
  5. (*
  6. Implements Object Steerining Behaviours as in
  7. "Steering Behaviors For Autonomous Characters" by Craig Reynolds.
  8. Collision Code is based in GLS.Collision.
  9. *)
  10. interface
  11. uses
  12. System.Types,
  13. System.Classes,
  14. System.Contnrs,
  15. System.SysUtils,
  16. System.Math,
  17. Stage.VectorGeometry,
  18. Stage.VectorTypes,
  19. Stage.Manager,
  20. Stage.Keyboard,
  21. GLS.Scene,
  22. GLS.Coordinates,
  23. GLS.Behaviours,
  24. GLS.Collision,
  25. GLS.Cadencer,
  26. GLS.VectorFileObjects,
  27. GLS.BaseClasses,
  28. GLS.XCollection;
  29. type
  30. TGLSteerBehaviours = (sbhSeek, sbhFlee, sbhPursuit, sbhEvasion, sbhOffsetPursuit, sbhArrival,
  31. sbhObstacleAvoidance, sbhWander);
  32. TGLSteeringBehaviours = set of TGLSteerBehaviours;
  33. TGLBVehicle = class;
  34. TGLVehicleManager = class;
  35. TGLBaseSteerBehaviour = class;
  36. TGLSteerBehaviourClass = class of TGLBaseSteerBehaviour;
  37. // TGLBaseSteerBehaviour - Base Class for implementing Steering Behaviours
  38. TGLBaseSteerBehaviour = class(TComponent)
  39. private
  40. FVehicle: TGLBVehicle;
  41. FSteerRatio: Single;
  42. protected
  43. procedure SetVehicle(const AValue: TGLBVehicle); virtual;
  44. public
  45. constructor Create(AOwner: TComponent); override;
  46. procedure ApplySteerForce; virtual; abstract;
  47. property Vehicle: TGLBVehicle read FVehicle write SetVehicle;
  48. property Ratio: Single read FSteerRatio write FSteerRatio;
  49. end;
  50. // TGLWanderSteer - Implementation of Wander Steering Behaviour
  51. TGLWanderSteer = class(TGLBaseSteerBehaviour)
  52. private
  53. FWanderModifier: TGLVector;
  54. FRate, FStrength: Double;
  55. protected
  56. procedure SetVehicle(const AValue: TGLBVehicle); override;
  57. public
  58. constructor Create(AOwner: TComponent); override;
  59. procedure ApplySteerForce; override;
  60. property Rate: Double read FRate write FRate;
  61. property Strength: Double read FStrength write FStrength;
  62. property WanderModifier: TGLVector read FWanderModifier write FWanderModifier;
  63. end;
  64. // TGLSeekSteer - Implementation of Seek Steering Behaviour
  65. TGLSeekSteer = class(TGLBaseSteerBehaviour)
  66. private
  67. FTarget: TGLBaseSceneObject;
  68. FTurnRate: Single;
  69. procedure SetTarget(const Value: TGLBaseSceneObject);
  70. protected
  71. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  72. public
  73. constructor Create(AOwner: TComponent); override;
  74. procedure ApplySteerForce; override;
  75. property Target: TGLBaseSceneObject read FTarget write SetTarget;
  76. end;
  77. // TGLFleeSteer
  78. TGLFleeSteer = class(TGLBaseSteerBehaviour)
  79. private
  80. FTarget: TGLBaseSceneObject;
  81. procedure SetTarget(const Value: TGLBaseSceneObject);
  82. protected
  83. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  84. public
  85. constructor Create(AOwner: TComponent); override;
  86. procedure ApplySteerForce; override;
  87. property Target: TGLBaseSceneObject read FTarget write SetTarget;
  88. end;
  89. // TGLPursueSteer
  90. TGLPursueSteer = class(TGLBaseSteerBehaviour)
  91. private
  92. FTarget: TGLBaseSceneObject;
  93. procedure SetTarget(const Value: TGLBaseSceneObject);
  94. protected
  95. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  96. public
  97. constructor Create(AOwner: TComponent); override;
  98. procedure ApplySteerForce; override;
  99. property Target: TGLBaseSceneObject read FTarget write SetTarget;
  100. end;
  101. // TGLWorldCollisionSteer
  102. TGLWorldCollisionSteer = class(TGLBaseSteerBehaviour)
  103. private
  104. FMap: TGLFreeForm;
  105. FCollided: Boolean;
  106. oldPosition, velocity: TGLVector;
  107. FTurnRate: Single;
  108. procedure SetMap(const Value: TGLFreeForm);
  109. protected
  110. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  111. function SphereSweepAndSlide(freeform: TGLFreeForm; SphereStart: TGLVector;
  112. var velocity, newPosition: TGLVector; sphereRadius: Single): Boolean;
  113. procedure SetVehicle(const AValue: TGLBVehicle); override;
  114. public
  115. constructor Create(AOwner: TComponent); override;
  116. procedure ApplySteerForce; override;
  117. property Map: TGLFreeForm read FMap write SetMap;
  118. property Collided: Boolean read FCollided;
  119. property TurnRate: Single read FTurnRate write FTurnRate;
  120. end;
  121. // TGLBVehicle
  122. TGLBVehicle = class(TGLBehaviour)
  123. private
  124. FSteerUpdateInterval: Double;
  125. FMass: Integer;
  126. FSpeed, FMaxForce, FMaxSpeed: Double;
  127. FUp, FVelocity, FAccumulator: TGLCoordinates;
  128. FProgressTime: TGLProgressTimes;
  129. FAccumulatedTime: Double;
  130. FManager: TGLVehicleManager;
  131. FGroupIndex: Integer;
  132. FManagerName: String; // NOT persistent, temporarily used for persistence
  133. FSteerBehaviours: TObjectList;
  134. FGLSteeringBehaviours: TGLSteeringBehaviours;
  135. FSeekSteer: TGLSeekSteer;
  136. FWanderSteer: TGLWanderSteer;
  137. FPursueSteer: TGLPursueSteer;
  138. FFleeSteer: TGLFleeSteer;
  139. FWorldCollisionSteer: TGLWorldCollisionSteer;
  140. FCollisionObject: TGLBaseSceneObject;
  141. protected
  142. procedure SetGLSteeringBehaviours(const Value: TGLSteeringBehaviours);
  143. procedure SetManager(const Value: TGLVehicleManager);
  144. procedure SetGroupIndex(const Value: Integer);
  145. function GetVelocity: TGLCoordinates;
  146. procedure SetVelocity(const Value: TGLCoordinates);
  147. function GetSpeed: Double;
  148. procedure SetSpeed(const Value: Double);
  149. procedure WriteToFiler(writer: TWriter); override;
  150. procedure ReadFromFiler(reader: TReader); override;
  151. procedure Loaded; override;
  152. public
  153. constructor Create(AOwner: TXCollection); override;
  154. destructor Destroy; override;
  155. procedure Assign(Source: TPersistent); override;
  156. class function FriendlyName: String; override;
  157. class function FriendlyDescription: String; override;
  158. procedure DoProgress(const progressTime: TGLProgressTimes); override;
  159. procedure DoSteering;
  160. property progressTime: TGLProgressTimes read FProgressTime write FProgressTime;
  161. property AccumulatedTime: Double read FAccumulatedTime write FAccumulatedTime;
  162. property CollisionObject: TGLBaseSceneObject read FCollisionObject write FCollisionObject;
  163. property Accumulator: TGLCoordinates read FAccumulator;
  164. property Flee: TGLFleeSteer read FFleeSteer write FFleeSteer;
  165. property Seek: TGLSeekSteer read FSeekSteer write FSeekSteer;
  166. property Pursue: TGLPursueSteer read FPursueSteer write FPursueSteer;
  167. property Wander: TGLWanderSteer read FWanderSteer write FWanderSteer;
  168. property WorldCollision: TGLWorldCollisionSteer read FWorldCollisionSteer
  169. write FWorldCollisionSteer;
  170. published
  171. property Manager: TGLVehicleManager read FManager write SetManager;
  172. property GroupIndex: Integer read FGroupIndex write SetGroupIndex;
  173. property Mass: Integer read FMass write FMass;
  174. // property Velocity: TGLCoordinates read GetVelocity write SetVelocity;
  175. property MaxForce: Double read FMaxForce write FMaxForce;
  176. property MaxSpeed: Double read FMaxSpeed write FMaxSpeed;
  177. property Speed: Double read GetSpeed write SetSpeed;
  178. property SteeringBehaviours: TGLSteeringBehaviours read FGLSteeringBehaviours
  179. write SetGLSteeringBehaviours;
  180. property SteerUpdateInterval: Double read FSteerUpdateInterval write FSteerUpdateInterval;
  181. property SteerBehaviours: TObjectList read FSteerBehaviours write FSteerBehaviours;
  182. property Up: TGLCoordinates read FUp write FUp;
  183. end;
  184. // Manager of Vehicles
  185. TGLVehicleManager = class(TComponent)
  186. private
  187. FSteerInterval: Double;
  188. FClients: TList;
  189. FCadencer: TGLCadencer;
  190. FWorldCollisionMap: TGLFreeForm;
  191. procedure SetCadencer(const Value: TGLCadencer);
  192. function GetCadencer: TGLCadencer;
  193. procedure SetSteerInterval(const Value: Double);
  194. procedure SetWorldCollisionMap(const Value: TGLFreeForm);
  195. protected
  196. procedure RegisterClient(aClient: TGLBVehicle);
  197. procedure DeRegisterClient(aClient: TGLBVehicle);
  198. procedure DeRegisterAllClients;
  199. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  200. public
  201. constructor Create(AOwner: TComponent); override;
  202. destructor Destroy; override;
  203. procedure DoSteering;
  204. property Clients: TList read FClients;
  205. published
  206. property Cadencer: TGLCadencer read GetCadencer write SetCadencer;
  207. property SteerInterval: Double read FSteerInterval write SetSteerInterval;
  208. property WorldCollisionMap: TGLFreeForm read FWorldCollisionMap write SetWorldCollisionMap;
  209. end;
  210. (* Returns or creates the TGLBVehicle within the given behaviours.
  211. This helper function is convenient way to access a TGLBVehicle. *)
  212. function GetOrCreateVehicle(Behaviours: TGLBehaviours): TGLBVehicle; overload;
  213. (* Returns or creates the TGLBVehicle within the given object's behaviours.
  214. This helper function is convenient way to access a TGLBVehicle. *)
  215. function GetOrCreateVehicle(obj: TGLBaseSceneObject): TGLBVehicle; overload;
  216. implementation //=============================================================
  217. //----------------------------------------------------------------------------
  218. // GetOrCreateVehicle (TGLBehaviours)
  219. //----------------------------------------------------------------------------
  220. function GetOrCreateVehicle(Behaviours: TGLBehaviours): TGLBVehicle;
  221. var
  222. i: Integer;
  223. begin
  224. i := Behaviours.IndexOfClass(TGLBVehicle);
  225. if i >= 0 then
  226. Result := TGLBVehicle(Behaviours[i])
  227. else
  228. Result := TGLBVehicle.Create(Behaviours);
  229. end;
  230. //----------------------------------------------------------------------------
  231. // GetOrCreateVehicle (TGLBaseSceneObject)
  232. //----------------------------------------------------------------------------
  233. function GetOrCreateVehicle(obj: TGLBaseSceneObject): TGLBVehicle;
  234. begin
  235. Result := GetOrCreateVehicle(obj.Behaviours);
  236. end;
  237. //----------------------------------------------------------------------------
  238. (* TGLVehicleManager *)
  239. // TGLVehicleManager.Create
  240. //----------------------------------------------------------------------------
  241. constructor TGLVehicleManager.Create(AOwner: TComponent);
  242. begin
  243. inherited Create(AOwner);
  244. FClients := TList.Create;
  245. RegisterManager(Self);
  246. FSteerInterval := 0;
  247. end;
  248. //----------------------------------------------------------------------------
  249. // TGLVehicleManager.Destroy
  250. //----------------------------------------------------------------------------
  251. destructor TGLVehicleManager.Destroy;
  252. begin
  253. if Assigned(FCadencer) then
  254. FCadencer.RemoveFreeNotification(Self);
  255. FCadencer := nil;
  256. DeRegisterAllClients;
  257. DeRegisterManager(Self);
  258. FClients.Free;
  259. inherited Destroy;
  260. end;
  261. //----------------------------------------------------------------------------
  262. // TGLVehicleManager.DeRegisterAllClients
  263. //----------------------------------------------------------------------------
  264. procedure TGLVehicleManager.DeRegisterAllClients;
  265. var
  266. i: Integer;
  267. begin
  268. // Fast deregistration
  269. for i := 0 to FClients.Count - 1 do
  270. TGLBVehicle(FClients[i]).FManager := nil;
  271. FClients.Clear;
  272. end;
  273. //----------------------------------------------------------------------------
  274. // TGLVehicleManager.DeRegisterClient
  275. //----------------------------------------------------------------------------
  276. procedure TGLVehicleManager.DeRegisterClient(aClient: TGLBVehicle);
  277. begin
  278. if Assigned(aClient) then
  279. begin
  280. aClient.FManager := nil;
  281. FClients.Remove(aClient);
  282. end;
  283. end;
  284. //----------------------------------------------------------------------------
  285. // TGLVehicleManager.RegisterClient
  286. //----------------------------------------------------------------------------
  287. procedure TGLVehicleManager.RegisterClient(aClient: TGLBVehicle);
  288. begin
  289. if Assigned(aClient) then
  290. if FClients.IndexOf(aClient) < 0 then
  291. begin
  292. FClients.Add(aClient);
  293. aClient.FManager := Self;
  294. end;
  295. end;
  296. //----------------------------------------------------------------------------
  297. // TGLVehicleManager.DoSteering
  298. //----------------------------------------------------------------------------
  299. procedure TGLVehicleManager.DoSteering;
  300. var
  301. i: Integer;
  302. begin
  303. for i := 0 to FClients.Count - 1 do
  304. TGLBVehicle(FClients[i]).DoSteering;
  305. end;
  306. //----------------------------------------------------------------------------
  307. (* TGLBVehicle *)
  308. // TGLBVehicle.Create
  309. //----------------------------------------------------------------------------
  310. constructor TGLBVehicle.Create(AOwner: TXCollection);
  311. begin
  312. inherited Create(AOwner);
  313. FSteerUpdateInterval := 0;
  314. FAccumulatedTime := 0;
  315. FMass := 10;
  316. FSpeed := 1;
  317. FMaxForce := 1;
  318. FMaxSpeed := 1;
  319. FUp := TGLCoordinates.CreateInitialized(Self, VectorMake(0, 1, 0), csVector);
  320. FVelocity := TGLCoordinates.CreateInitialized(Self, VectorMake(1, 0, 1), csVector);
  321. FVelocity.Normalize;
  322. FAccumulator := TGLCoordinates.CreateInitialized(Self, VectorMake(1, 0, 1), csVector);
  323. FSteerBehaviours := TObjectList.Create(True);
  324. FWanderSteer := TGLWanderSteer.Create(nil);
  325. FWanderSteer.Vehicle := Self;
  326. FSteerBehaviours.Add(FWanderSteer);
  327. FSeekSteer := TGLSeekSteer.Create(nil);
  328. FSeekSteer.Vehicle := Self;
  329. FSteerBehaviours.Add(FSeekSteer);
  330. FFleeSteer := TGLFleeSteer.Create(nil);
  331. FFleeSteer.Vehicle := Self;
  332. FSteerBehaviours.Add(FFleeSteer);
  333. FPursueSteer := TGLPursueSteer.Create(nil);
  334. FFleeSteer.Vehicle := Self;
  335. FSteerBehaviours.Add(FPursueSteer);
  336. end;
  337. //----------------------------------------------------------------------------
  338. // TGLBVehicle.Destroy
  339. //----------------------------------------------------------------------------
  340. destructor TGLBVehicle.Destroy;
  341. begin
  342. Manager := nil;
  343. FreeAndNil(FSteerBehaviours);
  344. FWanderSteer := nil;
  345. FSeekSteer := nil;
  346. FPursueSteer := nil;
  347. FWorldCollisionSteer := nil;
  348. FreeAndNil(FAccumulator);
  349. FreeAndNil(FUp);
  350. inherited Destroy;
  351. end;
  352. //----------------------------------------------------------------------------
  353. // TGLBVehicle.SetManager
  354. //----------------------------------------------------------------------------
  355. procedure TGLBVehicle.SetManager(const Value: TGLVehicleManager);
  356. begin
  357. if Value <> FManager then
  358. begin
  359. if Assigned(FManager) then
  360. FManager.DeRegisterClient(Self);
  361. if Assigned(Value) then
  362. begin
  363. Value.RegisterClient(Self);
  364. Self.SteerUpdateInterval := Value.SteerInterval;
  365. FWorldCollisionSteer := TGLWorldCollisionSteer.Create(nil);
  366. FWorldCollisionSteer.Vehicle := Self;
  367. FWorldCollisionSteer.Map := Value.WorldCollisionMap;
  368. FSteerBehaviours.Add(FWorldCollisionSteer);
  369. end;
  370. end;
  371. end;
  372. //----------------------------------------------------------------------------
  373. // TGLBVehicle.SetGroupIndex
  374. //----------------------------------------------------------------------------
  375. procedure TGLBVehicle.SetGroupIndex(const Value: Integer);
  376. begin
  377. FGroupIndex := Value;
  378. end;
  379. //----------------------------------------------------------------------------
  380. // TGLBVehicle.FriendlyName
  381. //----------------------------------------------------------------------------
  382. class function TGLBVehicle.FriendlyName: String;
  383. begin
  384. Result := 'Steering';
  385. end;
  386. //----------------------------------------------------------------------------
  387. class function TGLBVehicle.FriendlyDescription: String;
  388. begin
  389. Result := 'Steering-behaviour registration';
  390. end;
  391. //----------------------------------------------------------------------------
  392. // TGLBVehicle.Assign
  393. //----------------------------------------------------------------------------
  394. procedure TGLBVehicle.Assign(Source: TPersistent);
  395. begin
  396. if Source is TGLBVehicle then
  397. begin
  398. Manager := TGLBVehicle(Source).Manager;
  399. Mass := TGLBVehicle(Source).Mass;
  400. Speed := TGLBVehicle(Source).Speed;
  401. MaxForce := TGLBVehicle(Source).MaxForce;
  402. MaxSpeed := TGLBVehicle(Source).MaxSpeed;
  403. GroupIndex := TGLBVehicle(Source).GroupIndex;
  404. end;
  405. inherited Assign(Source);
  406. end;
  407. //----------------------------------------------------------------------------
  408. // TGLBVehicle.Loaded
  409. //----------------------------------------------------------------------------
  410. procedure TGLBVehicle.Loaded;
  411. var
  412. mng: TComponent;
  413. begin
  414. inherited;
  415. if FManagerName <> '' then
  416. begin
  417. mng := FindManager(TGLVehicleManager, FManagerName);
  418. if Assigned(mng) then
  419. Manager := TGLVehicleManager(mng);
  420. FManagerName := '';
  421. end;
  422. end;
  423. //----------------------------------------------------------------------------
  424. // TGLBVehicle.WriteToFiler
  425. //----------------------------------------------------------------------------
  426. procedure TGLBVehicle.WriteToFiler(writer: TWriter);
  427. begin
  428. with writer do
  429. begin
  430. WriteInteger(1); // ArchiveVersion 1, added FGroupIndex
  431. if Assigned(FManager) then
  432. WriteString(FManager.GetNamePath)
  433. else
  434. WriteString('');
  435. WriteInteger(FGroupIndex);
  436. WriteInteger(FMass);
  437. WriteFloat(FSpeed);
  438. WriteFloat(FMaxForce);
  439. WriteFloat(FMaxSpeed);
  440. FVelocity.WriteToFiler(writer);
  441. end;
  442. end;
  443. //----------------------------------------------------------------------------
  444. // TGLBVehicle.ReadFromFiler
  445. //----------------------------------------------------------------------------
  446. procedure TGLBVehicle.ReadFromFiler(reader: TReader);
  447. var
  448. archiveVersion: Integer;
  449. begin
  450. with reader do
  451. begin
  452. archiveVersion := ReadInteger;
  453. Assert(archiveVersion in [0 .. 1]);
  454. FManagerName := ReadString;
  455. Manager := nil;
  456. if archiveVersion >= 1 then
  457. FGroupIndex := ReadInteger
  458. else
  459. FGroupIndex := 0;
  460. FMass := ReadInteger;
  461. FSpeed := ReadFloat;
  462. FMaxForce := ReadFloat;
  463. FMaxSpeed := ReadFloat;
  464. FVelocity.ReadFromFiler(reader);
  465. end;
  466. end;
  467. //----------------------------------------------------------------------------
  468. // TGLBVehicle.GetVelocity
  469. //----------------------------------------------------------------------------
  470. function TGLBVehicle.GetVelocity: TGLCoordinates;
  471. begin
  472. Result := FVelocity;
  473. end;
  474. //----------------------------------------------------------------------------
  475. // TGLBVehicle.SetVelocity
  476. //
  477. procedure TGLBVehicle.SetVelocity(const Value: TGLCoordinates);
  478. begin
  479. FVelocity := Value;
  480. end;
  481. //----------------------------------------------------------------------------
  482. // TGLBVehicle.GetSpeed
  483. //----------------------------------------------------------------------------
  484. function TGLBVehicle.GetSpeed: Double;
  485. begin
  486. Result := FSpeed;
  487. end;
  488. //----------------------------------------------------------------------------
  489. // TGLBVehicle.SetSpeed
  490. //----------------------------------------------------------------------------
  491. procedure TGLBVehicle.SetSpeed(const Value: Double);
  492. begin
  493. FSpeed := Value;
  494. end;
  495. //----------------------------------------------------------------------------
  496. // TGLBVehicle.DoSteering
  497. //----------------------------------------------------------------------------
  498. procedure TGLBVehicle.DoSteering;
  499. var
  500. acceleration: Double;
  501. newLeft: TGLVector;
  502. begin
  503. if AccumulatedTime < SteerUpdateInterval then
  504. exit;
  505. FAccumulator.SetVector(OwnerBaseSceneObject.Direction.AsVector);
  506. FAccumulator.Normalize;
  507. // FAccumulator.AsVector := NullHmgVector;
  508. // FAccumulator.Scale(Speed * AccumulatedTime);
  509. with OwnerBaseSceneObject do
  510. begin
  511. // Collision
  512. FWorldCollisionSteer.ApplySteerForce;
  513. if not FWorldCollisionSteer.Collided then
  514. begin
  515. FSeekSteer.ApplySteerForce;
  516. FWanderSteer.ApplySteerForce;
  517. FFleeSteer.ApplySteerForce;
  518. end
  519. else
  520. begin
  521. FWanderSteer.WanderModifier := OwnerBaseSceneObject.Direction.AsVector;
  522. end;
  523. Direction.AddScaledVector(AccumulatedTime, FAccumulator.AsVector);
  524. VectorCrossProduct(VectorNormalize(Direction.DirectVector), FUp.DirectVector, newLeft);
  525. Up.AsVector := VectorCrossProduct(VectorNormalize(Direction.DirectVector), newLeft);
  526. acceleration := 1 / Mass;
  527. Speed := Lerp(Speed, MaxSpeed, acceleration);
  528. Move(Speed * AccumulatedTime);
  529. end;
  530. AccumulatedTime := 0;
  531. end;
  532. //----------------------------------------------------------------------------
  533. // TGLVehicleManager.Notification
  534. //----------------------------------------------------------------------------
  535. procedure TGLVehicleManager.Notification(AComponent: TComponent; Operation: TOperation);
  536. begin
  537. if (Operation = opRemove) and (AComponent = Cadencer) then
  538. Cadencer := nil
  539. else if (Operation = opRemove) and (AComponent = FWorldCollisionMap) then
  540. begin
  541. FWorldCollisionMap.RemoveFreeNotification(Self);
  542. FWorldCollisionMap := nil;
  543. end
  544. else
  545. inherited;
  546. end;
  547. //----------------------------------------------------------------------------
  548. procedure TGLVehicleManager.SetCadencer(const Value: TGLCadencer);
  549. begin
  550. if FCadencer = Value then
  551. exit;
  552. if Assigned(FCadencer) then
  553. FCadencer.RemoveFreeNotification(Self);
  554. FCadencer := Value;
  555. if FCadencer <> nil then
  556. FCadencer.FreeNotification(Self);
  557. end;
  558. function TGLVehicleManager.GetCadencer: TGLCadencer;
  559. begin
  560. Result := FCadencer;
  561. end;
  562. //----------------------------------------------------------------------------
  563. (* TGLBaseSteerBehaviour *)
  564. //----------------------------------------------------------------------------
  565. constructor TGLBaseSteerBehaviour.Create(AOwner: TComponent);
  566. begin
  567. inherited Create(AOwner);
  568. FVehicle := nil;
  569. FSteerRatio := 1;
  570. end;
  571. //----------------------------------------------------------------------------
  572. procedure TGLBaseSteerBehaviour.SetVehicle(const AValue: TGLBVehicle);
  573. begin
  574. FVehicle := AValue;
  575. end;
  576. //----------------------------------------------------------------------------
  577. (* TGLWanderSteer *)
  578. //----------------------------------------------------------------------------
  579. procedure TGLWanderSteer.ApplySteerForce;
  580. var
  581. vWander: TGLVector;
  582. vStrength: TGLVector;
  583. vDesiredDirection: TGLVector;
  584. const
  585. c2PI = 2 * pi;
  586. begin
  587. with Vehicle do
  588. begin
  589. MakeVector(vWander, VectorAdd(VectorMake(cos(random * c2PI) * FRate,
  590. ClampValue(cos(random * c2PI) * FRate, -0.01 * FRate, 0.01 * FRate),
  591. cos(random * c2PI) * FRate), FWanderModifier));
  592. NormalizeVector(vWander);
  593. ScaleVector(vWander, 10);
  594. FWanderModifier := vWander;
  595. MakeVector(vStrength, OwnerBaseSceneObject.Direction.AsVector);
  596. NormalizeVector(vStrength);
  597. ScaleVector(vStrength, FStrength);
  598. VectorAdd(vStrength, vWander, vDesiredDirection);
  599. NormalizeVector(vDesiredDirection);
  600. VectorSubtract(vDesiredDirection, OwnerBaseSceneObject.Direction.AsVector, vDesiredDirection);
  601. // NormalizeVector(vDesiredDirection);
  602. FAccumulator.AddScaledVector(Ratio, vDesiredDirection);
  603. end;
  604. end;
  605. //----------------------------------------------------------------------------
  606. // TGLBVehicle.SetGLSteeringBehaviours
  607. //----------------------------------------------------------------------------
  608. procedure TGLBVehicle.SetGLSteeringBehaviours(const Value: TGLSteeringBehaviours);
  609. begin
  610. FGLSteeringBehaviours := Value;
  611. end;
  612. //----------------------------------------------------------------------------
  613. // TGLVehicleManager.SetSteerInterval
  614. //----------------------------------------------------------------------------
  615. procedure TGLVehicleManager.SetSteerInterval(const Value: Double);
  616. var
  617. i: Integer;
  618. begin
  619. FSteerInterval := Value;
  620. for i := 0 to FClients.Count - 1 do
  621. TGLBVehicle(FClients.Items[i]).SteerUpdateInterval := FSteerInterval;
  622. end;
  623. //----------------------------------------------------------------------------
  624. // TGLBVehicle.DoProgress
  625. //----------------------------------------------------------------------------
  626. procedure TGLBVehicle.DoProgress(const progressTime: TGLProgressTimes);
  627. begin
  628. FProgressTime := progressTime;
  629. AccumulatedTime := AccumulatedTime + progressTime.deltaTime;
  630. end;
  631. //----------------------------------------------------------------------------
  632. constructor TGLWanderSteer.Create(AOwner: TComponent);
  633. begin
  634. inherited Create(AOwner);
  635. FRate := 1;
  636. FStrength := 1;
  637. end;
  638. //----------------------------------------------------------------------------
  639. (* TGLSeekSteer *)
  640. // TGLSeekSteer.ApplySteerForce
  641. //----------------------------------------------------------------------------
  642. procedure TGLSeekSteer.ApplySteerForce;
  643. var
  644. vDesiredDirection: TGLVector;
  645. vDistance: TGLVector;
  646. lDistance: Single;
  647. begin
  648. if Assigned(FTarget) then
  649. with FVehicle do
  650. begin
  651. vDesiredDirection := VectorNormalize(VectorSubtract(OwnerBaseSceneObject.Position.AsVector,
  652. FTarget.Position.AsVector));
  653. vDistance := VectorSubtract(OwnerBaseSceneObject.Direction.AsVector, vDesiredDirection);
  654. lDistance := VectorLength(vDistance);
  655. FAccumulator.AddScaledVector(10 * FTurnRate * lDistance * Ratio, VectorNormalize(vDistance));
  656. end;
  657. end;
  658. //----------------------------------------------------------------------------
  659. // TGLSeekSteer.Create
  660. //----------------------------------------------------------------------------
  661. constructor TGLSeekSteer.Create(AOwner: TComponent);
  662. begin
  663. inherited Create(AOwner);
  664. FTurnRate := 0.3;
  665. end;
  666. //----------------------------------------------------------------------------
  667. // TGLSeekSteer.Notification
  668. //----------------------------------------------------------------------------
  669. procedure TGLSeekSteer.Notification(AComponent: TComponent; Operation: TOperation);
  670. begin
  671. if (Operation = opRemove) and (AComponent = FTarget) then
  672. begin
  673. AComponent.RemoveFreeNotification(Self);
  674. FTarget := nil;
  675. end
  676. else
  677. inherited;
  678. end;
  679. //----------------------------------------------------------------------------
  680. // TGLSeekSteer.SetTarget
  681. //----------------------------------------------------------------------------
  682. procedure TGLSeekSteer.SetTarget(const Value: TGLBaseSceneObject);
  683. begin
  684. if Assigned(FTarget) then
  685. FTarget.RemoveFreeNotification(Self);
  686. FTarget := Value;
  687. if Assigned(FTarget) then
  688. FTarget.FreeNotification(Self);
  689. end;
  690. //----------------------------------------------------------------------------
  691. // TGLWanderSteer.SetVehicle
  692. //----------------------------------------------------------------------------
  693. procedure TGLWanderSteer.SetVehicle(const AValue: TGLBVehicle);
  694. begin
  695. inherited SetVehicle(AValue);
  696. SetVector(FWanderModifier, Vehicle.OwnerBaseSceneObject.Direction.AsVector);
  697. end;
  698. //----------------------------------------------------------------------------
  699. (* TGLFleeSteer *)
  700. // TGLFleeSteer.ApplySteerForce
  701. //----------------------------------------------------------------------------
  702. procedure TGLFleeSteer.ApplySteerForce;
  703. var
  704. vDesiredDirection: TGLVector;
  705. begin
  706. if Assigned(FTarget) then
  707. with FVehicle do
  708. begin
  709. vDesiredDirection :=
  710. VectorNegate(VectorNormalize(VectorSubtract(OwnerBaseSceneObject.Position.AsVector,
  711. FTarget.Position.AsVector)));
  712. FAccumulator.AddScaledVector(0.3 * Speed * Ratio *
  713. VectorLength(VectorSubtract(OwnerBaseSceneObject.Direction.AsVector, vDesiredDirection)),
  714. VectorNormalize(VectorSubtract(OwnerBaseSceneObject.Direction.AsVector,
  715. vDesiredDirection)));
  716. end;
  717. end;
  718. //----------------------------------------------------------------------------
  719. // TGLFleeSteer.Create
  720. //----------------------------------------------------------------------------
  721. constructor TGLFleeSteer.Create(AOwner: TComponent);
  722. begin
  723. inherited Create(AOwner);
  724. end;
  725. //----------------------------------------------------------------------------
  726. // TGLFleeSteer.Notification
  727. //----------------------------------------------------------------------------
  728. procedure TGLFleeSteer.Notification(AComponent: TComponent; Operation: TOperation);
  729. begin
  730. if (Operation = opRemove) and (AComponent = FTarget) then
  731. begin
  732. AComponent.RemoveFreeNotification(Self);
  733. FTarget := nil;
  734. end
  735. else
  736. inherited;
  737. end;
  738. //----------------------------------------------------------------------------
  739. // TGLFleeSteer.SetTarget
  740. //----------------------------------------------------------------------------
  741. procedure TGLFleeSteer.SetTarget(const Value: TGLBaseSceneObject);
  742. begin
  743. if Assigned(FTarget) then
  744. FTarget.RemoveFreeNotification(Self);
  745. FTarget := Value;
  746. if Assigned(FTarget) then
  747. FTarget.FreeNotification(Self);
  748. end;
  749. //----------------------------------------------------------------------------
  750. (* TGLPursueSteer *)
  751. // TGLPursueSteer.ApplySteerForce
  752. //----------------------------------------------------------------------------
  753. procedure TGLPursueSteer.ApplySteerForce;
  754. var
  755. vDesiredDirection: TGLVector;
  756. vDistance: TGLVector;
  757. lDistance: Single;
  758. begin
  759. if Assigned(FTarget) then
  760. with FVehicle do
  761. begin
  762. vDesiredDirection := VectorNormalize(VectorSubtract(OwnerBaseSceneObject.Position.AsVector,
  763. FTarget.LocalToAbsolute(FTarget.FindChild('GLDummyCube2', True).Position.AsVector)));
  764. FTarget.FindChild('GLDummyCube2', True).Position.Z :=
  765. 1 - 1 * VectorDotProduct(OwnerBaseSceneObject.Direction.AsVector,
  766. FTarget.Direction.AsVector) / VectorDistance(OwnerBaseSceneObject.Position.AsVector,
  767. FTarget.Position.AsVector);
  768. vDistance := VectorSubtract(OwnerBaseSceneObject.Direction.AsVector, vDesiredDirection);
  769. lDistance := VectorLength(vDistance);
  770. FAccumulator.AddScaledVector(Speed * Ratio * lDistance, VectorNormalize(vDistance));
  771. // Ratio := Ratio - 0.00005;
  772. end;
  773. end;
  774. //----------------------------------------------------------------------------
  775. // TGLPursueSteer.Create
  776. //----------------------------------------------------------------------------
  777. constructor TGLPursueSteer.Create(AOwner: TComponent);
  778. begin
  779. inherited Create(AOwner);
  780. end;
  781. //----------------------------------------------------------------------------
  782. // TGLPursueSteer.Notification
  783. //----------------------------------------------------------------------------
  784. procedure TGLPursueSteer.Notification(AComponent: TComponent; Operation: TOperation);
  785. begin
  786. if (Operation = opRemove) and (AComponent = FTarget) then
  787. begin
  788. AComponent.RemoveFreeNotification(Self);
  789. FTarget := nil;
  790. end
  791. else
  792. inherited;
  793. end;
  794. //----------------------------------------------------------------------------
  795. // TGLPursueSteer.SetTarget
  796. //----------------------------------------------------------------------------
  797. procedure TGLPursueSteer.SetTarget(const Value: TGLBaseSceneObject);
  798. begin
  799. if Assigned(FTarget) then
  800. FTarget.RemoveFreeNotification(Self);
  801. FTarget := Value;
  802. if Assigned(FTarget) then
  803. FTarget.FreeNotification(Self);
  804. end;
  805. //----------------------------------------------------------------------------
  806. // TGLWorldCollisionSteer
  807. //----------------------------------------------------------------------------
  808. function TGLWorldCollisionSteer.SphereSweepAndSlide(freeform: TGLFreeForm; SphereStart: TGLVector;
  809. var velocity, newPosition: TGLVector; sphereRadius: Single): Boolean;
  810. var
  811. oldPosition, ray: TGLVector;
  812. vel, slidedistance: Single;
  813. intPoint, intNormal: TGLVector;
  814. newDirection, newRay, collisionPosition, pointOnSphere, point2OnSphere: TGLVector;
  815. i: Integer;
  816. SphereRadiusRel: Single;
  817. begin
  818. SphereRadiusRel := sphereRadius / freeform.Scale.x;
  819. oldPosition := SphereStart;
  820. Result := True;
  821. ray := VectorSubtract(newPosition, oldPosition);
  822. // ray := Velocity;
  823. // newPosition := VectorAdd(newPosition,ray);
  824. vel := VectorLength(ray);
  825. // loops
  826. if vel > 0 then
  827. for i := 0 to 6 do
  828. begin
  829. if (freeform.OctreeSphereSweepIntersect(oldPosition, ray, vel, SphereRadiusRel, @intPoint,
  830. @intNormal)) then
  831. begin
  832. if VectorDistance2(oldPosition, intPoint) <= sqr(sphereRadius) then
  833. begin
  834. intNormal := VectorScale(VectorSubtract(oldPosition, intPoint), 1.0001);
  835. end
  836. else
  837. begin
  838. // intNormal := VectorSubtract(oldPosition,intPoint); //time steps.
  839. // intNormal := VectorScale(VectorNormalize(intNormal), SphereRadius + 0.0001);
  840. if RayCastSphereInterSect(intPoint, VectorNormalize(VectorNegate(ray)), oldPosition,
  841. sphereRadius, pointOnSphere, point2OnSphere) > 0 then
  842. intNormal := VectorScale(VectorSubtract(oldPosition, pointOnSphere), 1.0001)
  843. // intNormal := VectorScale(VectorNormalize(VectorSubtract(oldPosition, PointOnSphere)), SphereRadius + 0.001) //VectorDistance(oldPosition, PointOnSphere));
  844. else
  845. begin
  846. // Assert(False); //debuging.
  847. intNormal := VectorScale(VectorSubtract(oldPosition, intPoint), 1.0001);
  848. end;
  849. end;
  850. // collision.
  851. collisionPosition := VectorAdd(intPoint, intNormal);
  852. oldPosition := collisionPosition;
  853. newRay := VectorSubtract(newPosition, collisionPosition);
  854. newDirection := VectorCrossProduct(intNormal, VectorCrossProduct(newRay, intNormal));
  855. if VectorNorm(newDirection) > 0 then
  856. NormalizeVector(newDirection);
  857. // collision plane with collision ray)
  858. slidedistance := VectorDotProduct(newRay, newDirection);
  859. // if abs(SlideDistance) < 10 * deltaTime then SlideDistance := 0;
  860. ScaleVector(newDirection, slidedistance);
  861. newPosition := VectorAdd(collisionPosition, newDirection);
  862. ray := newDirection;
  863. vel := VectorLength(ray);
  864. if i = 6 then
  865. begin
  866. newPosition := oldPosition;
  867. break;
  868. end;
  869. if vel < 1E-10 then
  870. begin
  871. newPosition := oldPosition;
  872. break;
  873. end;
  874. end
  875. else
  876. begin
  877. if i = 0 then
  878. Result := false;
  879. break;
  880. end;
  881. end; // loop
  882. velocity := ray;
  883. end;
  884. //----------------------------------------------------------------------------
  885. // TGLWorldCollisionSteer.ApplySteerForce
  886. //----------------------------------------------------------------------------
  887. procedure TGLWorldCollisionSteer.ApplySteerForce;
  888. var
  889. vDesiredDirection, vDistance, newPosition: TGLVector;
  890. lDistance: Single;
  891. begin
  892. FCollided := false;
  893. if not Assigned(FMap) then
  894. exit;
  895. newPosition := FVehicle.OwnerBaseSceneObject.Position.AsVector;
  896. FCollided := SphereSweepAndSlide(FMap, oldPosition, velocity, newPosition,
  897. FVehicle.OwnerBaseSceneObject.boundingSphereRadius + 2.3);
  898. oldPosition := newPosition;
  899. if FCollided then
  900. with FVehicle do
  901. begin
  902. vDesiredDirection := VectorNormalize(VectorSubtract(OwnerBaseSceneObject.Position.AsVector,
  903. newPosition));
  904. vDistance := VectorSubtract(OwnerBaseSceneObject.Direction.AsVector, vDesiredDirection);
  905. lDistance := VectorLength(vDistance);
  906. // collision
  907. Speed := Speed * 0.9;
  908. FAccumulator.AddScaledVector(10 * FTurnRate * VectorLength(VectorSubtract(newPosition,
  909. FVehicle.OwnerBaseSceneObject.Position.AsVector)),
  910. VectorNormalize(VectorSubtract(newPosition,
  911. FVehicle.OwnerBaseSceneObject.Position.AsVector)));
  912. end;
  913. // if FCollided then begin
  914. // FVehicle.FAccumulator.AddScaledVector(4, VectorNormalize(VectorSubtract(newPosition, FVehicle.OwnerBaseSceneObject.Position.AsVector)));
  915. // FVehicle.Speed := FVehicle.Speed * 0.95;
  916. // end;
  917. end;
  918. //----------------------------------------------------------------------------
  919. // TGLWorldCollisionSteer.Create
  920. //----------------------------------------------------------------------------
  921. constructor TGLWorldCollisionSteer.Create(AOwner: TComponent);
  922. begin
  923. inherited Create(AOwner);
  924. FMap := nil;
  925. velocity := NullHmgVector;
  926. FTurnRate := 0.3;
  927. end;
  928. //----------------------------------------------------------------------------
  929. // TGLWorldCollisionSteer.Notification
  930. //----------------------------------------------------------------------------
  931. procedure TGLWorldCollisionSteer.Notification(AComponent: TComponent; Operation: TOperation);
  932. begin
  933. if (Operation = opRemove) and (AComponent = FMap) then
  934. begin
  935. AComponent.RemoveFreeNotification(Self);
  936. FMap := nil;
  937. end
  938. else
  939. inherited;
  940. end;
  941. //----------------------------------------------------------------------------
  942. // TGLWorldCollisionSteer.SetMap
  943. //----------------------------------------------------------------------------
  944. procedure TGLWorldCollisionSteer.SetMap(const Value: TGLFreeForm);
  945. begin
  946. if Assigned(FMap) then
  947. FMap.RemoveFreeNotification(Self);
  948. FMap := Value;
  949. if Assigned(FMap) and (FMap <> nil) then
  950. FMap.FreeNotification(Self);
  951. end;
  952. //----------------------------------------------------------------------------
  953. // TGLVehicleManager.SetWorldCollisionMap
  954. //----------------------------------------------------------------------------
  955. procedure TGLVehicleManager.SetWorldCollisionMap(const Value: TGLFreeForm);
  956. begin
  957. if Assigned(FWorldCollisionMap) then
  958. begin
  959. FWorldCollisionMap.RemoveFreeNotification(Self);
  960. FWorldCollisionMap := nil;
  961. end;
  962. FWorldCollisionMap := Value;
  963. if FWorldCollisionMap <> nil then
  964. FWorldCollisionMap.FreeNotification(Self);
  965. end;
  966. //----------------------------------------------------------------------------
  967. procedure TGLWorldCollisionSteer.SetVehicle(const AValue: TGLBVehicle);
  968. begin
  969. inherited;
  970. oldPosition := FVehicle.OwnerBaseSceneObject.Position.AsVector;
  971. end;
  972. initialization //=============================================================
  973. RegisterXCollectionItemClass(TGLBVehicle);
  974. end.