Castle Game Engine For Unity Developers

1. Introduction

If you come with a knowledge of another game engine, like Unity, this page will try to explain how some concepts map to Castle Game Engine. If you have any questions, remember to ask on forum, Discord chat or other places.

2. What is the equivalent of Unity GameObject?

GameObject in Unity is (simplifying) something that exists in your world, and may be visible, and may have children that are affected by a transformation.

For game objects (not user-interface), the closest equivalent of GameObject in Castle Game Engine is the TCastleTransform class. Instances of TCastleTransform can be arranged in a hierarchy, where each element transforms (moves, rotates, scales) the children. The most important class of CGE is the TCastleScene, which is a descendant of TCastleTransform that can actually render/animate/collide a model. Simply set TCastleScene.Url to load your model (like a glTF file) there.

Our manual documents TCastleScene and TCastleTransform features in chapter Viewport with scenes, camera, navigation. Basically you can do stuff like

MyScene.Url := 'castle-data:/my_model.gltf';
MyScene.Translation := Vector3(1, 2, 3);
MyScene.PlayAnimation('run', true);

The TCastleTransform hierarchy is placed in a TCastleViewport, which is a 2D user-interface element (descendant of TCastleUserInterface).

For objects that are user-interface elements, the most important base class is TCastleUserInterface. It has many descendants, like

  • obvious user interface controls: TCastleButton, TCastleLabel, TCastleRectangleControl, TCastleImageControl…​

  • layouts: TCastleVerticalGroup, TCastleHorizontalGroup,

  • and finally a critical UI component TCastleViewport which is a "gateway" to actually render a hierarchy of TCastleTransform.

See user interface documentation.

3. How to design a level composed from multiple assets, creatures etc.?

In the simplest case, for each 3D model, you create a TCastleScene instance. You can do this visually, using the CGE editor, or from code.

To group (and transform as a group) a number of TCastleScene instances you can use additional TCastleTransform instances. The TCastleScene is also a TCastleTransform descendant, so it can have children too.

Follow the template "3D FPS Game" (create it by running our editor, choose "New Project" and then choose "3D FPS Game" as a starting point). In the resulting project, open the design data/gamestateplay.castle-user-interface in the editor, to actually see what I mean (in this and previous answer).

Our goal with CGE editor is to provide an experience similar to Unity and other game engine editors. So you can drop 3D models on your design, and drag them to design a level.

4. Where to place code for specific actors (like creatures, items)? What is the equivalent of "adding a MonoBehaviour to a GameObject" in Unity?

There are multiple ways how you can control CGE stuff:

  1. The equivalent of MonoBehaviour is TCastleBehavior class. So you can define a class descending from TCastleBehavior, and add an instance of it to TCastleTransform. Like

      type
        TMyBehaviorClass = class(TCastleBehavior)
        public
          procedure Update(const SecondsPassed: Single; var RemoveMe: TRemoveType); override;
        end;

    Then add such behavior instance from code:

      var
        MyBehavior: TMyBehaviorClass;
      begin
        MyBehavior := TMyBehaviorClass.Create(SomOwner);
        MyBehavior.Xxx := ...; // configure necessary parameters
        MyTransform.AddBehavior(MyBehavior);
      end;

    See our template "3D FPS Game" (create it by running our editor, choose "New Project" and then choose "3D FPS Game" as a starting point) that shows exactly this approach. It defines a trivial TEnemy class that defines the logic of an enemy, and is a TCastleBehavior descendant. It controls the enemy movement. It also allows to check (e.g. when shooting ray) "did I hit an enemy" by checking SomeTransform.FindBehavior(TEnemy) <> nil.

    While the above examples show attaching a behavior using code, you could also add TEnemy in editor. See editor and custom components docs for information how to register TEnemy class in editor. This requires to restart editor within the project with menu option "Project -> Restart Editor (With Custom Components)". It is an extra step, but it makes sense for complicated behaviors, which can be configured in the editor easier.

    The engine comes with a few standard behaviors too (like TCastleBillboard, TCastleSoundSource) and these are comfortable to add and configure from the editor.

  2. Another way to control things in CGE is to create class descendants from existing classes. In CGE you can create descendants from almost all classes (including important TCastleTransform and TCastleUserInterface), and override virtual methods there. E.g. you can override TCastleTransform.Update to perform something every frame.

    So you could define a class like TMyCreature that descends from TCastleTransform or TCastleScene. This class would control it’s own transformation (e.g. it would change it’s own Translation to move the creature) and it would possibly load some children (more TCastleTransform and TCastleScene instances) to show and animate the creature.

    This is a classic OOP approach. This is like Unreal Engine that allows you to define your own actor classes that override the base class.

  3. You can also assign events, like OnPress. Most UI controls expose obvious events, like TCastleButton.OnClick. You are free to handle these events at one central place (like an LCL TForm descendant (only if you use TCastleControl), or CGE TUIState descendant) or decentralized (e.g. create a different instance of your own class to handle events of each different creature, different item).

    The approach to use events is similar to using UI in Lazarus LCL or Delphi VCL.

  4. You can also control things from outside, e.g. control all creatures from the state instance. The state like TStatePlay (see above mentioned template "3D FPS Game") has its own methods to Update and handle input. The state can keep references to everything you have in your world, and it can control them.

5. What is the equivalent of Unity Assets subdirectory?

You should place your game data in the data subdirectory of the project. See manual about the "data" directory. It will be automatically packaged and available in your games.

Everything inside your data subdirectory is loadable at runtime. In this sense, it is actually similar to Assets/Resources/ subdirectory of Unity, if you care about details.

Things that are not your game data (like your source code) should not be placed in the data subdirectory. The source code should live outside of data. Only the compiler must be able to find it (you can specify your sources locations using standard Lazarus Project Options and/or (for building cross-platform projects) using <compiler_options> in CastleEngineManifest.xml). By convention, most CGE examples place Pascal source code in the code subdirectory (or in top-level project directory), but this is really only a convention.

The layout of a larger CGE project may be like this:

my_project/
  CastleEngineManifest.xml     <- the project root; manifest XML file is used by CGE build tool and CGE editor
  data/                        <- game data lives here; up to you how to organize this
    CastleSettings.xml         <- defines UI scaling, default font
    example_image.png
    example_model.gltf
    state_main_menu.castle-user-interface
    ...
  code/                        <- Pascal game code lives here; up to you how to organize this
    gameinitialize.pas
    gamestatemainmenu.pas
    ...
  ...                          <- any other subdirectories and files? Up to you. Consider docs/ and README.md.

6. What model formats are supported?

See supported model formats. In short: glTF is the best :) This documentation page also links to instructions for various authoring tools "how to export your data".

Test your models with view3dscene to see what is supported. If you double-click on a model from CGE editor, it will automatically launch view3dscene.

7. Do you support FBX model format?

No, and we will probably never do (unless indirectly through some universal conversion library). FBX is a proprietary model format by Autodesk. Please don’t use FBX, it’s proprietary (the Autodesk specification of FBX is "secret" deliberately, and Autodesk only sanctions using FBX through it’s paid SDK), and also not that good. Use glTF.

If you have existing models in FBX format you can convert them to glTF. If you have the source versions of your models, possibly you can just reexport them from your authoring software to glTF. You can also use Blender or a number of other tools to convert between model formats.

8. Why does editor template "3D FPS Game" show a different approach than examples/fps_game?

TODO: We work on removing the inconsistency documented below, by introducing new, editor-friendly API for creature behaviors.

The examples/fps_game example shows how to use our Utilities for typical 3D games that are included in CastleCreatures, CastleItems and friend units. It is an older example, not using CGE editor.

On one hand, the examples/fps_game approach gives you more things "out of the box" now. E.g. using this approach, you can trivially get a creature that knows how to travel in 3D space, how to approach an enemy to have a good position to shoot a missile or do a close-range attack. On the other hand, examples/fps_game approach doesn’t map nicely to CGE editor, and is not absolulety flexible (although it may be quite enough for a typical first-person shooter, and there are many ways to customize it — see subpages of https://castle-engine.io/manual_high_level_3d_classes.php , and see TMedKitResource and TMedKit classes in fps_game).

So examples/fps_game and our template "3D FPS Game" present indeed a different approach to creating an FPS game. We know about it, and it is a TODO, of course we want to remove this discrepancy. The plan to do this is mentioned at the bottom of https://castle-engine.io/manual_3d_utlities_overview.php and roadmap . Basically our API from CastleCreatures will be adjusted to easily create a "ready" TEnemy with more intelligence out of the box. IOW, we will make the approach from template "3D FPS Game" more powerful, it will be trivial to create your own TEnemy that has advanced intelligence.

What to do right now:

  • If you want to have flexibility, I would advice following "3D FPS Game" template idea, and create your own creature AI. This is the better approach long-term, and it is the approach which we will focus on (extending it in the future).

  • Only if you want to have something close to what examples/fps_game presents, i.e. a typical first-person shooter, then follow examples/fps_game approach.

9. Should I use TCastleWindow or TCastleControl?

A short summary of the answer: Use TCastleWindow. If all you want is a cross-platform game, where everything is rendered using Castle Game Engine. If you come here and want to "just make a game using CGE", use TCastleWindow.

Details: The difference is outlined on https://castle-engine.io/manual_lazarus_control.php :

  • TCastleControl means that engine rendering is inside Lazarus form. That is, TCastleControl is a regular Lazarus control that can be placed on a larger form. You can use Lazarus designer to place LCL controls, and you can use CGE editor to design CGE controls (within TCastleControl).

  • TCastleWindow means that engine rendering is a separate window, and we’re not using LCL. You can use CGE editor to design controls. So you lose access to LCL controls, but in exchange you get perfect cross-platform code (Android, iOS, Switch only with with TCastleWindow).

In both cases, you can use Lazarus as an IDE — to write code, debug etc. In both cases, you can use CGE editor to design CGE controls (that go inside TCastleControl or TCastleWindow).

10. Where is Time.timeScale?

An equivalent is to set MyViewport.Items.TimeScale.

It is specific to the given world, which is an instance of TCastleAbstractRootTransform available in MyViewport.Items. Simple games will just have one viewport, a TCastleViewport instance. Multiple instances of TCastleViewport are possible, and then can share the same world, or show a different world (just assign Items between).

There in an additional time scaling possible by TCastleScene.TimePlayingSpeed. This is local in given TCastleScene instance.

11. Where is Time.deltaTime?

In Container.Fps.SecondsPassed. See the https://castle-engine.io/manual_state_events.php for the most trivial usage example.

In you override the TCastleUserInterface.Update (including TUIState.Update) or TCastleTransform.Update method, then you also have an explicit parameter SecondsPassed that contains this value. In TCastleTransform.Update the time is already scaled (if you used MyViewport.Items.TimeScale mentioned above).

12. Making components inactive

Both TCastleTransform and TCastleUserInterface have a Boolean Exists property: TCastleTransform.Exists, TCastleUserInterface.Exists. By default this is true. Simply set it to false to make everything behave as if this component was not part of the hierarchy. Non-existing components are not visible, do not collide, do not handle any input, do not cause any events etc. So Unity GameObject.SetActive(xxx) translates to CGE MyTransform.Exists := xxx.

You can also control the TCastleTransform.Collides, TCastleTransform.Pickable and TCastleTransform.Visible properties of TCastleTransform. These are useful to make something e.g. visible but non-collidable, or collidable but invisible. Note that when Exists is false, it "overrides" them, and non-existing object never collides and is never visible.

13. User interface scaling

We have UI scaling, to adjust to any screen size smartly, and it works similar to Unity canvas scaling. It allows to design assuming a specific window size, and as long as you set sensible anchors, the design will look reasonable at various screen resolutions (even with different aspect ratio). It merely scales the coordinates — the actual rendering is done for the final resolution, so it looks "sharp" always.

The scaling is configured using CastleSettings.xml file. The default CGE editor "New Project" templates set UI scaling to adjust with a reference window size of 1600x900.

14. Unity Services

Mobile services like ads, analytics, in-app purchases and more are available as Android services or iOS services. You declare them in CastleEngineManifest.xml and then build the project using our build tool. These allow to integrate your code with various 3rd-party services (from Google, Apple and others) or use mobile APIs that require special permissions (like vibrations).

The "service" means "a part of the project, in binary or source code, added during the build stage".

  • Android services may contain Java code, precompiled libraries for Android, Gragle configuration and more.

  • iOS services may contain Objective-C code, precompiled libraries for iOS, CocoaPods configuration and more.

  • On other platforms, so far we didn’t need a similar concept. E.g. integration of CGE with 3rd-party services on desktops is always possible by normal Pascal units that expose e.g. FMOD or Steam API. That said, it is possible that we will add "services" for other platforms some day.

15. Shaders

You can of course replace or enhance the shaders used by our engine.

We have compositing shaders which is like Unity3d "surface shaders" but on steroids :) I’m quite proud of this, it really allows to easily write a piece of shader code and add it to some shapes, and (compared to Unity3d "surface shaders") it has some cool new features, like the ability to combine many effects (so you can write one shader effect, maybe add another shader effect), or changing shading of lights or textures or making proceduraly generated (on GPU) textures.

See examples/viewport_and_scenes/shader_effects for simple demo in Pascal that attaches an effect, coded in GLSL, to a scene loaded from glTF. The shader uniform variable can be set at runtime from Pascal of course, and thus you can configure the shader at runtime with zero cost.

See https://github.com/castle-engine/demo-models, subdirectory compositing_shaders for demos of Effect nodes in pure X3D (you can load them all from CGE; it’s just that these demos create Effect node by X3D code, not by Pascal code).

The compositing shaders documentation, in particular this document, describe how these shader effects work.

16. Viewports

In Unity, your typical world is a hierarchy of 3D GameObjects.

  • Somewhere in this world, you have a Camera component, that determines the camera parameters (like projection) and viewport sizes. The transformation of the associated GameObject determines the camera position and rotation.

  • You can have multiple Camera components on different GameObjects to have multiple viewports.

  • Somewhere in this world, you have a canvas that acts as a place for 2D controls like buttons and images.

In CGE, it is a bit different. Viewport (TCastleViewport) is a 2D control, and it can render 3D world inside.

  • You design a hierarchy of TCastleUserInterface components. They all have the same properties to control position and size, using anchors, using FullSize (fill the parent etc.).

  • There are numerous TCastleUserInterface descendants, like buttons, images, and viewports.

  • Within a viewport (TCastleViewport) instance, you place your 3D world (in Viewport.Items).

  • A viewport is always connected with exactly one camera in Viewport.Camera. This camera determines projection settings and position, rotation of the viewer.

The above describes the typical design as seen in editor templates. To see it in action, create a "New Project" in the editor, using the template like "3D FPS Game", and open the design data/gamestateplay.castle-user-interface in the editor.

In short, in Unity "viewport" and "camera" and "UI" are just things inside your 3D world. In CGE, "viewport" (and the corresponding "camera") contains your 3D world, and "viewport" is part of your UI.

In effect,

  • In CGE the "viewport" can be positioned/sized just like any other 2D control. See examples/viewport_and_scenes/multiple_viewports for an example that shows 4 viewports.

  • The Z-order (what is in front/behind) of the viewport in CGE is straightforward, it works just like all other 2D controls. You can easily place other 2D controls in front or behind a viewport (the latter is useful if the viewport has Transparent background).

  • In CGE each "viewport" may show a completely different, unrelated, 3D world. The viewports can also share the world (show the same world from different cameras), simply set them the same Viewport.Items value.

17. Prefabs

Prefabs are a way to store GameObject hierarchy, with Unity components attached, in a file.

The usual equivalent in CGE is to create a xxx.castle-transform file where you create a design with a root being TCastleTransform or TCastleScene. This allows you to compose a transformation hierarchy of TCastleTransform / TCastleScene instances. You can then load this xxx.castle-transform multiple times, as a single thing. See the examples/advanced_editor, the file data/soldier_with_cape.castle-transform there is a simplest example of this approach.

The equivalent of prefabs for Unity UI elements is a UI design file, xxx.castle-user-interface, already mentioned above.

18. Playing sounds

The equivalent of Unity AudioSource is our TCastleSoundSource. It is a behavior, you attach it to a parent TCastleTransform and it can play spatialized sound. Note that for non-spatial sounds, you can also just call TSoundEngine.Play, this is simpler and there’s no need for a TCastleSoundSource instances.

The equivalent of Unity AudioClip is our TCastleSound.

See manual chapter about sound for information how to use sound in CGE.

19. What is the difference between Owner and Parent in CGE?

So Parent and Owner are separate concepts, even declared in different classes.

Sometimes both Parent and Owner may be set to the same instance, if it is suitable in the particular situation, but in general these 2 things just perform 2 separate functions. For example, in CGE editor, owner of everything in the design is always one central DesignOwner component. When you load the design yourself, you provide the Owner instance explicitly (as a parameter to UserInterfaceLoad, TransformLoad, ComponentLoad) and then you specify parent yourself but adding the design to the hierarchy (e.g. MyParentUi.InsertFront(MyLoadedUi)).


To improve this documentation just edit the source of this page in AsciiDoctor (simple wiki-like syntax) and create a pull request to Castle Game Engine WWW (cge-www) repository.