7. Adding a simple moving object

In next chapters you will learn how to add player, creatures and items following our API. But not every game needs to use these high-level concepts, a lot of times your requirements are just I want to add an object to the scene, and be able to move it. You can do it easily in our engine because you can add to your scene manager any 3D object (descendant of T3D), in particular you can add:

  • TCastleScene: a full-featured 3D or 2D object, you can load it's data from a 3D/2D file (or build it at runtime by building a simple graph of X3D nodes — see examples). It can contain inside animations, interactions, scripting and a lot of other stuff that you can express using VRML / X3D nodes.

  • T2DScene: descendant of TCastleScene especially suitable for 2D, for example a Spine animation.

  • T3DTransform, T3DOrient: two simple containers for a list of 3D objects that can transform (translate, rotate, scale) them.

Note that it's Ok to add the same instance of TCastleScene (for example, a tree) many times to your scene manager hierarchy. This allows to reuse it's data completely, which is the best for performance/memory!

As a simple example, let's add an animated dragon to our scene. At the beginnig (right after you initialized your 3D world, usually by SceneManager.LoadLevel) you add your 3D objects to the world:

// add to global variables:
var
  DragonTransform: T3DTransform;
  Dragon: TCastleScene;
 
// ... somewhere after SceneManager.LoadLevel do:
 
DragonTransform := T3DTransform.Create(Application);
DragonTransform.Translation := Vector3Single(1, 2, 3); // initial translation
SceneManager.Items.Add(DragonTransform);
 
Dragon := TCastleScene.Create(Application);
DragonTransform.Add(Dragon);
Dragon.Load(ApplicationData('dragon.x3dv'));
Dragon.ProcessEvents := true; // enable animations and interactions within dragon.x3dv

Now you can change DragonTransform.Translation at any time you want. To change it continously, use the OnUpdate event (see TCastleWindowCustom.OnUpdate, TCastleControlCustom.OnUpdate). Like this:

procedure WindowUpdate(Container: TUIContainer);
// or (in case of Lazarus control): procedure TForm1.CastleControl1Update(Sender: TObject);
var
  SecondsPassed: Single;
begin
  // Note: use CastleControl1.Container.Fps.UpdateSecondsPassed in case of Lazarus control
  SecondsPassed := Container.Fps.UpdateSecondsPassed;
  // Move the dragon to the right.
  // Thanks to multiplying by SecondsPassed, it is a time-based operations,
  // and will always move 10 units / per second.
  DragonTransform.Translation := DragonTransform.Translation +
    Vector3Single(10, 0, 0) * SecondsPassed;
end;

That's it, you have a moving 3D object in your world, and the movement in 100% controlled by your code!

For more advanced usage, note that:

  • You can add many of such objects to your world, and use T3DTransform or T3DOrient to build any transformation hierarchy that is comfortable.

    You can remove and add these objects during your game freely. To keep performance, just avoid loading from 3D model files (TCastleScene.Load) during the game, so you may need to keep some scenes precreated. Our mechanism of creature/items resources exposes a flexible approach based on this, but for simple cases you can just do it yourself.

  • You can override these classes to define your own stuff. These objects can collide and perform AI if you want. Note that every T3D object knows it's World so it knows how to move and collide within the 3D world. That's how AI is implemented. See T3D.Move, T3D.MoveAllowed, T3D.Height and T3D.LineOfSight methods.