Class T3DMoving

Unit

Declaration

type T3DMoving = class(T3DCustomTransform)

Description

3D object moving and potentially pushing other 3D objects. Good for elevators, doors and such.

Other 3D objects may be pushed, if Pushes. There are two methods of pushing available, see PushesEverythingInside. Only the 3D objects with T3D.CollidesWithMoving are ever pushed by this object (the rest of 3D world is treated as static, does not interact with elevators / doors or such).

You can also stop/reverse the move to prevent some collisions from occuring at all. This way you can e.g. prevent the door from automatically closing, if someone/something blocks the way. You do this by overriding BeforeTimeIncrease. See TDoomLevelDoor.BeforeTimeIncrease in "The Castle" for example how to do this.

Hierarchy

Overview

Methods

Protected function GetTranslation: TVector3Single; override;
Protected function OnlyTranslation: boolean; override;
Protected function GetTranslationFromTime(const AnAnimationTime: TFloatTime): TVector3Single; virtual; abstract;
Protected procedure BeforeTimeIncrease(const NewAnimationTime: TFloatTime); virtual;
Public constructor Create(AOwner: TComponent); override;
Public procedure Update(const SecondsPassed: Single; var RemoveMe: TRemoveType); override;
Public procedure Translate(const T: TVector3Single); override;

Properties

Protected property AnimationTime: TFloatTime read FAnimationTime;
Published property Pushes: boolean read FPushes write FPushes default true;
Published property PushesEverythingInside: boolean read FPushesEverythingInside write FPushesEverythingInside default true;

Description

Methods

Protected function GetTranslation: TVector3Single; override;

Implements T3D.GetTranslation by always calling GetTranslationFromTime(AnimationTime). Descendants should only override GetTranslationFromTime.

Protected function OnlyTranslation: boolean; override;
 
Protected function GetTranslationFromTime(const AnAnimationTime: TFloatTime): TVector3Single; virtual; abstract;
 
Protected procedure BeforeTimeIncrease(const NewAnimationTime: TFloatTime); virtual;

Do something right before animation progresses. Called at the beginning of our Update, right before AnimationTime changes to NewAnimationTime.

Useful for taking care of collision detection issues, as our assumption always is that "nothing collides". Which means that if you don't want your T3DMoving to collide with e.g. player or creatures or items, then you should prevent the collision before it happens. This is the place to do it.

Public constructor Create(AOwner: TComponent); override;
 
Public procedure Update(const SecondsPassed: Single; var RemoveMe: TRemoveType); override;
 
Public procedure Translate(const T: TVector3Single); override;
 

Properties

Protected property AnimationTime: TFloatTime read FAnimationTime;

Local object time, always increasing, used to track animations.

Published property Pushes: boolean read FPushes write FPushes default true;

Are other 3D objects pushed when this object moves. Only the 3D objects with T3D.CollidesWithMoving are ever pushed by this object (the rest of 3D world is treated as static, does not interact with elevators / doors or such).

Only relevant if GetCollides. Non-colliding objects never push others.

Published property PushesEverythingInside: boolean read FPushesEverythingInside write FPushesEverythingInside default true;

If Pushes is True, this determines how pushing actually works. There two methods:

  1. PushesEverythingInside = True: We move every 3D object that is inside our bounding box and has CollidesWithMoving=True. This is sensible if we can reasonably assume that things inside our box are standing. For example if this is a (vertical or horizontal) elevator, then creatures/items are usually standing/lying inside, and naturally move with the same speed (and direction) as the elevator.

  2. When PushesEverythingInside = False: We check precise collision between 3D objects with CollidesWithMoving=True and our triangle mesh. Actually, we use T3DList.BoxCollision / T3DList.SphereCollsion, that will use children's T3D.BoxCollision / T3D.SphereCollsion; they check collisions with triangle mesh in case of TCastleScene with Spatial containing e.g. ssDynamicCollisions.

Neither method is really perfect.

PushesEverythingInside = False seems like a more precise check, as it actually compares the triangle mesh, taking into account the interior of (this) moving 3D object. PushesEverythingInside = True just approximates the moving 3D object by it's bounding box.

On the other hand, PushesEverythingInside = True makes the elevator more "sticky". With PushesEverythingInside = False, when player hits the floor, it takes them some time to raise up. This creates a "bouncing camera" effect when the elevator goes up quickly: player constantly falls to the ground, tries to get up, but elevator moves up and player falls to it's ground again. When the elevator goes down, the player/creature constantly falls down on it because of gravity, which again causes artifacts as gravity may work significantly slower/faster than elavator moving speed. When the elevator is a horizontal moving platform, it will "slip" from under the player/creature, leaving the poor fella suddenly hanging in the air, and falling down because of gravity in the next second.

In practice: PushesEverythingInside should be True for small containers, when you can reasonably assume that things (creatures, player, items) stand inside, and when you intend to use it for transport of 3D stuff. For very large moving stuff, that possibly interacts with flying players/creatures in some creative way, PushesEverythingInside may be False.


Generated by PasDoc 0.14.0.