-
examples/creature_behaviors
-
examples/fps_game
-
Demo at "Delphi Programmers Meeting 2024 (Zlot Programistów Delphi 2024)", see demo application. See demo slides (in Polish).
Don’t see the feature you need? Tell us on the forum or Discord.
If you would like to see some feature implemented sooner, please support the engine development on Patreon!
In progress: We have completely new navigation components in https://github.com/castle-engine/castle-engine/pull/533 . They achieve a few things:
more universal (suitable for 1st person 3D, 3rd person 3D, 2D cases),
more configurable inputs, also from editor (expose new "axis" paradigm),
more flexible (functionality split into a few components, easier to pick a subset of functionality you want, easier to write extensions), and honor the physics engine.
Once above is merged, eventually TCastleWalkNavigation
will be deprecated. Don’t worry, the deprecated TCastleWalkNavigation
will still be available for quite a while — we’re aware that many projects use it, since (as of today, before we merge PR 533) we actually advise using TCastleWalkNavigation
, as it’s very easy to use and flexible enough for many situations.
We want 100% of collision detection (which also means ray-casting) at runtime to be done using physics, and thus determined by the presence of components like TCastleMeshCollider
.
We’re almost there… except there are exceptions, see Old system for collisions and gravity. This means TCastleSceneCore.PreciseCollisions
matters. We want to get rid of it, at least for run-time. The old collision detection using our octrees may remain:
Useful at design-time, in editor.
For frustum culling done by TCastleScene
. This is invisible to the user.
To do this:
Deprecate TCastleXxxNavigation
using older collisions. See above — we have components to replace them.
New Viewport.PointingDeviceHit
instead of Viewport.MouseRayHit
, Viewport.TransformUnderMouse
, that exposes physics ray-casting by default.
This is started, things done:
Past Spatial
property is now both simplified (only ssRendering,ssDynamicCollisions
, does not manage other structures) and private. Only TCastleSceneCore.PreciseCollisions
is public.
At design-time (in editor) we always behave as if TCastleSceneCore.PreciseCollisions
is true
and this is good.
Integration with Steam done and rocks, https://castle-engine.io/steam .
TODO: Put engine on Steam as an app. We already have registered the application with Steam, and we have the app ID. We need to add achievements to CGE editor and submit it to Steam.
In progress.
Initial TCastleMoveAttack
done, used in
examples/creature_behaviors
examples/fps_game
Demo at "Delphi Programmers Meeting 2024 (Zlot Programistów Delphi 2024)", see demo application. See demo slides (in Polish).
Has simple logic of movement, getting close to player (or any other enemy), short-range attack.
We also have simple enemy logic implemented in "3D FPS Game" template and to show our behaviors.
TODO:
Use physics for all movement and gravity
Finish firing missiles, TCastleMissile
finish
Eliminate all TODO in src/scene/castlelivingbehaviors_moveattack.inc
and friends
Restore + modernize our "waypoints / sectors" (known as "navmesh" in other engines), make it possible to set up in editor
Change section title from "Living (Early Preview - Functionality Will Change!)" → "Living"
Phase 2: Use behavior trees
Note
|
Old approach to this was offered by the
We want to express their features in different ways, in ways that are more closely and obviously connected with TCastleScene / TCastleViewport / TCastleNavigation. Basically, we’re very happy with current API of |
We want to have a component list class, that
Maps to a subtree in the "Hierarchy" in CGE editor,
Can be used to express current (this will make some code in editor and CastleInternalInspector
simpler):
TCastleTransform
children of TCastleTransform
,
TCastleBehavior
children of TCastleTransform
,
TCastleUserInterface
children of TCastleUserInterface
,
TCastleComponent
non-visual children of TCastleComponent
, now managed in TCastleComponent.NonVisualComponents
.
Can be used to express future things:
Screen (post-processing) effects list, see Screen effects - expose as nicer components,
Materials, textures, effects, see New material components
Tiled map layers, see New API for Tiled layers
Is generic, so we can be safe at compile-time about what is allowed to be inserted. That’s why we don’t want to just use standard TComponentList
.
Would allow CGE editor to easily hide some lists, while not hiding others. E.g. whether to expand TCastleBehavior
in the hierarchy — can be just UI choice.
Conceptually, when Unity has hierarchy (of GameObject
) on left and list of components (components in Unity sense, i.e. pieces of GameObject
) on right, we instead have a tree of components (components in Pascal and CGE sense, i.e. TComponent
). It is just editor UI decision — which levels are shown in the tree (hierarchy), which are not (e.g. behaviors could be hidden, or shown in some different way, in editor — and it shall be unrelated to the Pascal classes organization).
Idea:
TCastleBaseComponentList = class(TComponent)
Internally uses TComponentList
for storage because we want items to auto-disappear when they are freed wherever.
Do not inherit from TComponentList
, to not expose everything, limit access to our methods/properties. So only use it as a private field.
Non-generic, editor can use it as a base class for all nested lists.
Editor operations like move up/down, remove, add, should use this class.
TCastleComponent.GetComponentLists
method: Query all TCastleBaseComponentList
. Maybe it should just use RTTI to query all TCastleComponentList<T>
on given object, from them extract TCastleBaseComponentList
and return them. This is crucial for editor to show hierarchy. One of the lists should be "default" to show it without intermediate item in hierarchy (e.g. TCastleTransform children are Children: TCastleComponentList<TCastleTransform>
but we don’t display Children
intermediate item in hierarchy).
TCastleComponentList<T> = class(TComponent)
Generic, safe to use from code.
internally uses InternalBaseList: TCastleBaseComponentList
to store items, as private filed. (Do not inherit, to not expose everything non-generic.)
Another phrasing of this (equivalent, mostly):
Unify the processing of both visual children of TCastleTransform, and visual children of TCastleUserInterface, and NonVisualComponents — by new TCastleComponentList<T>
. This will be backward compatible, and will guarantee that all these iterations really use the same mechanism (right now these iterations are ~consistent just because they have been manually made to look similar each time).
So we’ll have
TCastleComponent = class(TComponent)
NonVisualComponents: TCastleComponentList<TCastleComponent>;
end;
TCastleUserInterface = class(TCastleComponent)
Children: TCastleComponentList<TCastleUserInterface>;
end;
TCastleTransform = = class(TCastleComponent)
Children: TCastleComponentList<TCastleTransform>;
Behaviors: TCastleComponentList<TCastleBehavior>;
end;
and iterating with for … in …
will be always equivalent to iterating over Children
.
So
for C in MyTransform do
will be equivalent to
for C in MyTransform.Children do
Same
for C in MyUserInterface do
will be equivalent to
for C in MyUserInterface.Children do
And you can also do
for C in MyTransform.Behaviors do…
for C in MyTransform.NonVisualComponents do…
Right now… it’s already mostly like that, but due to the fact that I declared a few things manually in the same way. The new TCastleComponentList<T>
should force it to be consistent, and also make some code easier for editor.
Note
|
The new class will also be our recommendation to use instead of TCollection. Our
We could achieve some of these advantages with |
We want to allow you to edit materials in the CGE editor,
e.g. to modify (or completely override) materials from TCastleScene (like glTF),
to have full control over primitives (like TCastleSphere
or TCastleImageTransform
look),
to enable you to use cool CGE features like mirrors, shader effects easier.
This also means exposing new set of Pascal components to manage materials easier.
Activating shadow maps has some disadvantages now:
You need to setup special X3D nodes and fields. At least put shadows TRUE
on some light source in X3D, most likely you also want to specify defaultShadowMap
on this light source.
The X3D field name is inconsistent. In X3D light nodes, shadows
activates shadow maps, while shadowVolumesMain
activates shadow volumes. This is inconsistent with TCastlePunctualLight.Shadows
, which activates shadow volumes. As part of this work, we should make TCastlePunctualLight
API and X3D nodes more consistent (we can, as shadow map stuff is our extension over X3D).
We should also account for X3D 4.0 shadows additions and report to the X3D working group our experience, ev. suggestions for X3D improvements.
The lights cast shadow maps only within the same scene. (Work is under way to remove this limitation, this refactor is the important step and it is already pushed to the master branch.)
This is in contrast to shadow volumes that are trivial to activate (you literally toggle one checkbox, Shadows
, on our light components TCastleXxxLight
) and work across scenes, thus are very natural to set up using CGE editor.
We want to upgrade our shadow maps support to address above issues:
TCastlePunctualLight
should just have a property ShadowsMethod
(enum smVolumes, smMaps
) that will allow to easily switch between shadow volumes and shadow maps.
Note
|
Alternative, rejected, API idea was to turn Shadows into an enum with a possible "none" value, like Shadows: (None, Volumes, Maps) . Separate Boolean to choose whether shadows are enabled at all, separate from choosing shadows algorithm, seems more natural. It is, conceptually, a different decision "do I want shadows" vs "what shadows algorithm do I want". It also means we (at the engine) have to choose one default shadow algorithm, instead of leaving the decision on users --- which is actually better for users.
|
More API:
Shadows distance?
Instead of current projectionFar, which has auto-calculation but it can reach too far.
What is Unity default, just hard code instead ot detecting?
Shadows distance falloff? Smooth transition to no shadows at all.
This matches the existing logic in shadow(
in GLSL that says "where the shadow map doesn’t reach, assume no shadow". So we just introduce a smooth falloff to this.
Take a look at what Godot, Unity, Ogre3d (last one has both shadow maps and volumes) expose in API, and what are their defaults.
This is already in-progress, see web for all docs.
We want a system to define "packages" in Castle Game Engine.
Package creators can define a "package" that contains code and/or data.
The data can be naturally referred to by the code, e.g. a "car behavior (Pascal code)" can use a "default car crash sound (data, .wav file)".
We can have mostly-data packages (like "collection of medieval weapons") or mostly-code packages (like "support for scripting in LUA", "easy TCP/IP client/server") or a combination of both (like "logic and basic data for Arcade Car Racing game type").
Package can also define platform-specific code (e.g. Java on Android), thus new packages would also allow user-created Android services, iOS services.
Users (developers of games/applications) can define that their project uses given packages.
They can also "lock" versions of the packages (like NPM packages) (so co-developers can checkout the project and associated packages with exactly equal versions). They can also upgrade the packages easily (by command-line build tool and GUI editor).
And of course they can search for packages, both from editor GUI and WWW browser. Packages include typical metadata like title, description, license, screenshot(s), version control repository (GIT for start), website, donation link. Website can feature things like ratings, comments (design of the website is not part of this roadmap item).
We want to have active ecosystem of packages. Packages are created / updated / used without making CGE developers (like Michalis) a bottleneck. CGE becomes the "core" around which we have this ecosystem. This is also our answer to "Unity Asset Store" etc.
Note
|
We have a few specific requirements (which are also a reason why we cannot use existing Lazarus packages / OPM, or FpMake / FpPkg, or GetIt) and a design how to satisfy them. Read on :) |
Basics how it works:
Use lock file like NPM, boss.
Command to install, upgrade:
castle-engine packages install
:
Installs all packages listed in the CastleProject.json
Creates for them a new entry in CastlePackageLock.json
, creating also CastlePackageLock.json
, if it does not exist already; if CastlePackageLock.json
exists and already mentions the package → use version of package specified ("locked").
Creates castle-packages
subdirectory
castle-engine packages upgrade
Updates to latest versions all packages from server.
Default server of each package is "CGE main packages" registry, which is just a repo with JSON pointing to other repos with packages. Package creators submit PR to link to their new package; updating package requires no PR. The server of each package can be customized.
Updates CastlePackageLock.json
(bumps versions)
Updates castle-packages
subdirectory contents.
Files are JSONs serializable with CastleComponentSerialize
:
Upgrade project definition, following existing project roadmap item. So CastleProject.json
with matching Pascal class. Add there declaration of "used packages". This makes project definition readable/editable as easy JSON, and readable/editable using GUI editor at the same time, and consistent with everything else we read/write using CastleComponentSerialize
, like our designs.
For package, create CastlePackageLock.json
, serialized component TCastlePackagesLock
. This is where package metadata lives.
Both CastleProject.json
and CastlePackageLock.json
need a place for comments at top, using JSON field "comment": "…"
CGE editor "Packages" dialog:
Lists currently installed packages
Allow to upgrade them (all, or specific ones)
Allow to install new one from "CGE main packages" registry
Prerequisites:
Packages in CastleProject.json
must allow to override location from which they are to be downloaded:
for development (when package is not submitted to "CGE main packages registry" yet).
for package examples.
Because examples must be able to refer to package data. There has be a way to say "I use a package that is in relative path from me, like CastleLines2D path=".."`
". And then castle-engine packages upgrade
does nothing, and the lock file just copies this relative path, and the package is not downloaded from anywhere.
for organization-specific package repositories. You don’t need to use "CGE main packages registry", though we will of course have one and use it by default.
For each installed package:
Clone repo using GIT
Must contain CastlePackage.json
.
(make error if also CastleProject.json present? or ignore?)
We define TCastlePackage
component, with
CodeSearchPaths: TCastleStringList
// Auto added to compiler paths for this project
// Also auto added to LSP paths for this project
If package contains data/
subdir, make it available with this URL:
castle-package-data:/package-name/<path-inside-package-data>
castle-package-data
protocol is resolved:
when castle-packages
exists (running when in development, from project source repo) then look there in castle-packages/package-name/data/<path-inside-package-data>
.
This is similar to how we resolve caste-data:/
by looking in subdirectory data
.
when castle-packages
does not exist (running from packaged game): look in castle-data:/_castle-packages/package-name/<path-inside-package-data>
. To make it work, castle-engine package
will copy all package data (but not other package stuff, like metadata or code) into _castle-packages
before packing.
High-level goals:
Packages allow users to get extra functionality (beyond what is in main CGE repo). Of course.
Packages allow developers to easily share extra functionality with others.
Packages are easy to install using CGE editor or command-line build tool.
Packages used follow the spec in CastleProject.json
, which is just upgraded CastleEngineManifest.xml
Follow the "packages lock" known from NPM, boss etc.: Allow developer to commit a file that describes each package version, exactly, using GIT hash. This file can be committed to version control, and means that all developers use the same package versions. The "upgrade" of packages must be explicit!
Packages can be upgraded, all or specific ones, using CGE editor or build tool
Packages can contain Pascal code. No extra action should be necessary after installing the package — that is, extra package Pascal paths will be automatically derived from package metadata and passed to compiler.
Packages can contain services — Android-specific, iOS-specific services subdirectories that define any integration with Android or iOS. This is useful for e.g. integrating ad networks, analytics, etc.
Similarly, packages can contain CGE data. And no extra action should be necessary to use this data — both for components included in the package (e.g. internal data for some package functionality) or for project (which may use e.g. some designs).
Packages can contain example projects one can run. This makes sense in CGE (unlike Unity or other engines where you can "run a scene", in CGE you run a project).
Review process: Unlike PRs to CGE repo, new/updated packages don’t require any big review process from CGE devs — we want to be permissive in what packages we allow to be published with "CGE main packages registry".
We reserve the right to make some review, but mostly with goal "doesn’t this contain anything malicious" (e.g. we don’t want package called "easy MMO RPG" that does something malicious on the developer and/or application user machine). But this PR is not "make a decision if this is the right approach, or if CGE devs judge this as good quality or whatever". Of course we will try to review everything and post helpful comments, but CGE core devs cannot be a bottleneck in this process. So:
New package submissions are accepted "by default", the only allowed blocker is "we see something malicious".
Everyone understands that by downloading a package, they download a piece of code/data written by the package’s author. CGE core devs are not responsible for the quality of it.
Ratings, comments, PRs to package, are a way to give feedback / judge the package before you use. We only remove packages (from "CGE main packages registry") packages that are malicious (try to do something obviously unexpected abusing developer/user machine). Packages that are "low quality" just receive the corresponding feedback (ratings, comments). Of course, comments on the CGE website follow our forum and Discord guidelines. Let’s be helpful and constructive and together strive to create something cool.
To repeat: Everyone, including CGE core devs, is of course welcome to make more thorough review of the package, post comments whether something could be done differently etc. But this is just optional, not a blocker. A blocker is only if we see (or someone reports) something malicious.
Releasing new version of package doesn’t require any review. You can just tag your GitHub repo, and the new release is there, CGE repo will find the new tag soon.
New packages, and notices of upgrades, go to internal queue for "quick review": with the main goal to check if the package contains anything malicious.
VR: Michalis has access to Oculus Quest since the beginning of 2022. Port most likely using OpenXR (to include the widest possible range of devices using a single cross-platform API).
AR: most likely using Android / iOS built-in frameworks, as these make AR widely available on modern phones.
See about existing Delphi compatibility - we support Windows and Linux now. We plan to support more platforms with Delphi: Android, iOS…
We should read meshes from glTF to GPU in a way that keeps binary layout of data in glTF, so that it is ultra-fast to load, and it is loaded almost straight from glTF to GPU.
Some modifications to CGE may be required here (CastleGeometryArrays will have to be made more flexible for this). New X3D nodes should be introduced, like BufferGeometry
(same as X3DOM?). See Binary meshes in X3D - my plan and reasons to add binary meshes to X3D spec.
We want to perform skinning fully on GPU, avoiding the drawbacks of current way of importing glTF animations.
To explain, right now we "precalculate" skinned animation imported from glTF to CoordinateInterpolator
nodes, so loading is slower and consumes memory, although playback is fast. We also have an independent skinned animation support in H-Anim, which is slow at runtime (CPU-based). The plan below is to reconcile these two approaches, and make skinned animation in CGE perfect, for both glTF and X3D (H-Anim) users.
We plan to introduce new X3D node for this called SkinnedAnimation
:
This new node would match exactly the glTF skinned animation design.
In particular, it would allow to give explicitly the skin’s "Inverse Bind Matrices", a powerful concept in glTF that allows to perform the skinned animation super-efficiently on GPU. See glTF 2.0 Reference Guide for an overview of glTF specification — the skinned animation is explained there on 2 pages, along with sketch of implementation on GPU.
Also, as the name implies, the new node only deals with skinned animation (where mesh vertexes are affected by joints through weights). You don’t need it at all to make "regular" animation when rigid shapes move/rotate around (e.g. like Spine skeletal animation).
The new node would also enable making skinned animation in X3D using just Transform
nodes for joints. No need for HAnimJoint
.
The new node deliberately avoids any naming connotation with "humanoids". Skinned animation is a standard 2D and 3D animation technique, not specific to humanoids at all. (though of course it can be used for humanoids, as a specific case.)
We could reimplement H-Anim support (currently using CPU implementation, that calculates skin at runtime on CPU each frame — this is slow) by internally using SkinnedAnimation
node.
This new node will make our "skinned animation" have all performance advantages and no disadvantages:
It will react at runtime to changes of joints, so it will be suitable also for inverse kinematics or other usage where joints change at runtime. See https://forum.castle-engine.io/t/joint-bone-controlled-mesh-animation/546 . See https://github.com/castle-engine/castle-engine/tree/master/examples/animations/animate_bones_by_code .
It will be fast at run-time, due to animating on GPU.
It will be fast at loading, and not eat excessive amounts of memory, due to just loading the skin data to GPU.
See:
Thanks to Holger Seelig and X_ITE project, the path how to express this functionality in X3D is already known and tested:
X_ITE introduces new X3D nodes like SheenMaterialExtension, ClearcoatMaterialExtension that express additional material functionality and are straightforward equivalents to glTF extensions above.
X_ITE adds new field to PhysicalMaterial called extensions
(MFNode
, allows X3DMaterialExtensionNode
) to add this functionality to a PhysicalMaterial
.
Older physics based on octrees should be phased out.
In progress: We’re slowly already doing it. If you want to get ahead, you can already use physical colliders (see physics manual) and use queries like PhysicsRayCast
instead of WorldRay
.
TCastleSceneCore.ExposeTransforms
should work both ways, to allow to attach bodies and colliders to parts of the scene. This will enable e.g. ragdolls.
More physics backends, not only Kraft.
We’re looking to add another physics engine that relies on some big, well-known and open-source engine. Our current considerations are either PhysX or Bullet.
As as result of this, more physics engines can also be added more easily in the future.
See more in manual about physics, subsection "TODO".
With a designer. Example usage: blood, snow, rain, fire, smoke… 2D, 3D.
This is already in-progress by Trung Le (Kagamma). Use cge-3d-particle-emitter or Effekseer Integration. See CGE components.
What we have now: The engine includes TCastleTerrain
component and examples/terrain that shows how to generate terrains in various ways (from smoothed random noise, from a ready image) and render it. We also have the "Wyrd Forest" game that also uses CastleTerrain
, and also includes a simple editor of terrain settings. See also news about terrains.
What we need: Visual, interactive editor for terrains, matching e.g. Unity feature set.
Enable editing heightmaps easily:
Edit the terrain heights within CGE editor, using something like a brush to lower/raise clicked points. To make hills, valleys in a comfortable way.
The edited heights just land in TCastleTerrainImage
with internal contents.
Use splatmap and enable editing it, to edit the terrain textures mixture within CGE editor. To effectively paint the terrain with different textures like grass, dirt, rock, snow.
The splatmap is an internal (not directly visible) RGBA texture that determines the weights of the visible textures. E.g. imagine you have 4 visible texture types: grass, dirt, rock, snow. Then
splatmap red channel determines "how much to add grass at this point",
splatmap green channel determines "how much to add dirt at this point",
splatmap blue channel determines "how much to add rock at this point",
splatmap alpha channel determines "how much to add snow at this point".
The editing code can watch over to make sure the weights are normalized, i.e. always sum to 1.0.
More about splatmaps: https://en.wikipedia.org/wiki/Texture_splatting , https://help.world-machine.com/topic/device-splatmap/ .
The existing terrain implementation, in TCastleTerrain
and examples/terrain is a starting point — shows how we can randomize / generate a reasonable terrain with texture weights. But above additions are critical to make it really useful: in practice, for real games, people want to have control over the terrains. So the existing generation will remain part of the workflow, but only as an optional starting point.
Note
|
The fact that you can connect a few terrains together, and our generation can generate "neighbors" effectively, is super-useful and will be preserved. |
Tools to plant big things (3D TCastleScene
) in the terrain, like trees, rocks. You can do it now, though it’s manual: Use behavior TCastleStickToSurface
and put multiple instances of the thing you want. Use TCastleTransformReference
to make it optimal for memory when you can, so that multiple instances share the same resources.
Optional LODs could be nice (but maybe this is outside of scope of terrains; LODs should be just on TCastleScene
. Currently we have LODs on TCastleScene
using TLODNode
- works nice, though complicated to set up, we want to move away from exposing X3D nodes for this.)
Tools to plant many small things, like grass. This is a big different than "big things", and here automatic LODs that e.g. decrease density of grass with distance make sense.
More specialized and efficient rendering algorithm. Right now terrain in the end is just a simple big mesh of triangles. It’s actually quite fast to render (because modern GPUs can handle big shapes) but it’s not a sustainable way to render huge terrains.
Improve shaders for terrain to show it, like this BareGame example.
More than 4 layers. Each new set of 4 layers mean a new splatmap.
Add a Vulkan renderer.
API:
Almost all public CGE API will remain unchanged. For a long time now, we design our API to be independent from OpenGL, and all rendering (e.g. done by TCastleScene
, TCastleViewport
, TCastleUserInterface
, TDrawableImage
) is driven by a renderer-neutral API.
Shaders will continue to be available using GLSL. There will be possibility to precompile them to SPIR-V before usage (for both Vulkan and new OpenGL, as new OpenGL also supports SPIR-V).
Underneath, we will create a "pluggable" architecture for renderers. In theory we could implement a lot of renderers (e.g. also Metal or Direct3D) but given the limited resources, realistically we will focus on 2 renderers: Vulkan and OpenGL ("OpenGL" here meaning really a family OpenGL + OpenGLES + WebGL).
Approach:
We have a simple example code that shows how you can start a new renderer: see new_renderer_skeleton example. This is great for testing initial implementation, before we have a "pluggable" architecture.
Header:
I was playing with PasVulkan from which we could use a Vulkan API header. See news about PasVulkan.
We could also get Vulkan header from GLAD 2 if only we port it to Pascal (we plan this already).
Platforms:
Not all platforms support Vulkan, in particular it’s uncertain whether Apple with ever support it (they want to push Apple-specific Metal API). CGE will most likely use MoltenVK to render using Vulkan on Apple, see plans regarding macOS / iOS and OpenGL, Vulkan.
Pascal bindings: https://github.com/Akira13641/PasBGFX/ . Though reported as having issues: https://discord.com/channels/389676745957310465/468902667003887646/1173371248596762674 , we shall investigate.
Look great:
open-source,
packed with features,
actively developed,
open for bindings from any language, any game engine (it is explicitly made as renderer useful for various game engines),
properly documented,
very good platform and renderer support.
This may be even better than direct Vulkan port. We shall see. On one hand, this provides more possibilities than just Vulkan (e.g. direct Metal renderer). And it may be easier to use than Vulkan. OTOH, it will not allow to squeeze "every last bit of performance from Vulkan" (though we really don’t need that in CGE in the first place; there are lots of optimizations on the table in CGE before it’s worth even thinking about low-level Vulkan optimizations).
Since glPolygonMode
is not available at all on OpenGLES, we need to be able to generate wireframe geometry arrays on CPU, adding a "wireframe" option to CastleArraysGenerator
that will generate a different (line) primitive for TGeometryArrays. Then the renderer can use such TGeometryArrays for OpenGLES.
This is started now, by having Shape.shading = "WIREFRAME"
option, see Shape.shading field. We need to
make it available for all geometry shapes
make this feature more flexible, so that the renderer can switch between wireframe/non-wireframe rendering without any cost.
And then we can implement Attribute.WireframeEffect on OpenGLES correctly,
and allow to set Wireframe on specific viewports (so that some viewports may view wireframe, independent of others) on OpenGLES.
You can subscribe tp https://github.com/castle-engine/castle-engine/issues/554 .
TGLImage.GetContents
is not available on OpenGLES, as it doesn’t support glGetTexImage
. Fixing it is a matter of implementing alternative way that draws texture to FBO and grabs using SaveScreenGL (using glReadPixels internally).
One has to use TGLRenderToTexture to render quad with a texture (making sure the framebuffer size, quad size, and texture size match, and without filtering) and then use glReadPixels to get the pixels from FBO. This will work on mobile (and also on desktops, although it will be less optimal alternative to glGetTexImage).
This will:
be simpler to users, as the engine will be "one single application" for macOS users.
avoid troubles resulting from Apple translocation. It right now prevents the CGE editor from detecting CGE path.
avoid current duplication of castle-editor/data
in distributed package, thus making it smaller by ~60 MB.
See macOS.
This will allow to run CGE editor on macOS by just double-clicking it, out-of-the-box.
See macOS.
We should also enable developers to easily sign their own applications packaged with CGE build tool.
We can make 3D modeling of realistically-looking stuff much easier by reusing libraries of realistic materials.
Explore possibility to support USD – Universal Scene Description format as a first-class citizen, alongside glTF and X3D, in CGE.
Integration with Nakama:
Nakama is an open-source server and client library/API that provide networking capabilities typically needed in games.
The server is written in Go (see source code) and can be extended using Lua, JS, or Go modules. See server framework.
It supports out-of-the-box stuff like user accounts, matchmaking (connect people into rooms where the game happens), leaderboards, chat, etc. There’s infrastructure to synchronize data between players in a multi-player game.
Client library can be used from various game engines and languages so we’re confident it can be used from CGE too.
You can host the server yourself or pay to get ready hosting.
As you can see in above links, it seems really well documented, and actively maintained. These are naturally critical qualities for our dependencies.
I think Nakama may give CGE networking capabilities comparable with some popular solutions known from other game engines :)
Allowing to trivially get multi-player functionality in your games.
We will expose both current CastleEngineManifest.xml
and data/CastleSettings.xml
as something you can edit yourself with GUI.
But we don’t want to create and maintain a custom GUI for them, instead the plan is to:
Create Pascal components with published properties representing their data.
Make the project settings files just "JSON design files" for the editor.
So you’ll have a file like project.castle-project
and using editor menu item like "Project Build Settings" will really just open a design project.castle-project
(JSON) in the editor, and it will be just a serialized TCastleProject
component. Same for "Project Runtime Settings" which edits data/settings.castle-project-settings
.
Bonus: we’ll associate *.castle-project
with the system, to open when you double-click it e.g. from Windows installer.
Bonus: you can add non-visual components to data/settings.castle-project-settings
and load them using Container.DesignedComponent('xxx')
. This is great e.g. to add sounds or fonts or other data that you want to later load in CGE, from any view.
There are a few details that have to be ironed out here:
how should the new equivalent of CastleEngineManifest.xml
and data/CastleSettings.xml
interact. We will likely keep 2 files, project.castle-project
and data/settings.castle-project-settings
, as
Some information doesn’t need to be packed into data, part of it could even be considered "somewhat secret" (e.g. SDK IDs for Android analytics should not be present anywhere in the non-Android builds).
Some information should be packed into data automatically, by default, everything. To enable that Bonus: you can add non-visual components feature.
most intuitive names for all the things above (menu item names, component names, extensions etc.) :)
Moreover:
Expose CastleDataIgnoreCase
in data/settings.castle-project-settings
. This makes sense to be read also by editor when editing the project, to ignore case also at design-time.
Allow designing and testing animations in CGE editor.
The features cover animating typical UI/transform things that you see in CGE editor directly: e.g. UI stuff (like TCastleUserInterface.Translation
, TCastleImageControl.Color
), 3D stuff (TCastleTransform.Translation
, TCastleTransform.Rotation
etc.).
Note
|
Animating everything in CGE is already possible right now using code. You can update any values you want in Update method of your view and change any value you need (like MyControl.Translation ) using routines like Lerp or SmoothStep .
|
The point of this feature is to allow to design and see simple animations from editor. Code will then be able to just play them (e.g. using simple method MyAnimation.Play
) whenever needed.
Features:
Make it possible to animate (at least!) any property of TCastleUserInterface
and TCastleTransform
. Access the property using RTTI, and at design-time in editor allow to choose TargetObject
and TargetProperty
with suitable type.
Bonus: allow to animate any property of any TComponent
.
It should allow to animate at least any Single/Double
, TVector2/3/4
properties (this includes also colors, as TCastleColor[RGB]
is just alias for TVector3/4
; this includes also rotations, that is just TVector4
but can use slerp for interpolation).
Bonus: allow to animate other property types. E.g. animating discrete (like boolean) actually makes sense — to hide stuff by animation, by changing Exists
at specific point in time.
It should use TCastleBehaviorBase
that will allow to attach it to any TCastleUserInterface
and TCastleTransform
. See talk about it in https://github.com/castle-engine/castle-engine/issues/473 .
Each such animation should define:
key-frames
key-values
configurable target component (TComponent)
configurable target property (string? and get/set property using RTTI)
easing (e.g. to make "bouncing" effect at the end of animation), https://easings.net/ https://developer.mozilla.org/en-US/docs/Web/CSS/easing-function . Bonus: easing code and enums could be also used to acceleration/deceleration of TCastleInputAxis
.
Bonus: Group animations, so that from code you can fire like MyUserInterfaceAppear.Play
and it runs a number of animations at once — e.g. something "slides in" (translation changes), something appears (Exists changes), something fades in (Color.alpha changes)
See also:
PR https://github.com/castle-engine/castle-engine/issues/473 and animation-player branch in this fork https://github.com/Freedomax/castle-engine/tree/animation-player
Nice lean tweening code, independent from engine: https://github.com/glhrmfrts/wetween
Address a few shortcomings of our (see examples/screen_effects_demo/
, screen effects):
Change terminology. "Screen effect" is non-standard, "post-processing effects" are better.
Expose as components some standard effects, like blur, changing colors in HSV, grayscale. They should have easy Pascal properties, serializable to JSON, and wrap the related X3D nodes underneath.
Expose as component a customizable shader effect allowing you to provide GLSL code in a text box (TStringList editor) in CGE editor.
This depends on making a more generic TCastleComponentList to expose TCastleScreenEffects.ScreenEffects
list nicely.
Currently we can export (save) nodes graph (from one TCastleScene
or, using TCastleTransform.InternalBuildNode
, from whole TCastleViewport
contents) to X3D or STL.
We want to enable also saving to glTF. This means that everywhere where we allow saving, glTF will also be an output option:
castle-model-viewer, castle-model-converter should be able to save to glTF (from any input model, like X3D, STL, or another glTF).
The editor menu item "Data → Export Viewport to X3D, STL" (see news) will be able to save to glTF.
API: TCastleSceneCore.Save
, SaveNode
will be able to save to glTF.
Our online converter will be able to save to glTF.
GitHub issue: https://github.com/castle-engine/castle-engine/issues/595 .
Right now our X3D graph usage is similar to HTML DOM usage from typical web applications: we modify the graph at runtime, everything that changes stuff (like animations) just changes the graph. This is simple to use, it nicely allows to animate everything in X3D and gives developers an easy way to modify everything at runtime.
The downside is that we waste significant memory, and loading time, in some cases. If you want to play different animations on each TCastleScene
, then they need to have a different graph even though they are loaded from the same URL
. Hence using e.g. TCastleScene.Clone
or TCastleSceneCore.Cache
really internally makes multiple copies of the graph. This could be more optimal in the future. E.g. assuming your model only uses glTF skinned animation or animates simple transformation position/rotation/scale, we could make the graph read-only, and only maintain small "diff" information at each instance.
Right now our FMOD backend uses only "FMOD Core API".
We want to enable using higher-level FMOD events that drive the sound banks exported from "FMOD Studio".
Allow using AudioKinetic’s Wwise as sound backend, and as a middleware to design sounds.
As described in threads, we want to allow loading assets asynchronously. This means that you use CGE API from one thread, but some operations are not "blocking" and CGE can internally use threads to finish their work, while your code continues to calculate, CGE events like Update
continue to be processed etc.
For example:
TCastleScene.LoadAsync(const Url: String; const OnFinish: TNotifyEvent);
TCastleScene.PrepareResourcesAsynchronously;
TCastleTerrain.UpdateDataAsync(const NewData: TCastleTerrainData; const OnFinish: TNotifyEvent);
We already use such approach e.g. with TCastleDownload
. Internally it can download in a thread, but you don’t need to worry about inherent "hard" issues with threads (synchronizing communication between threads, being careful who/when touches the shared variables). This approach results in:
Really comfortable API. You handle everything from one thread, you get simple callbacks when things are done, you can simply watch (e.g. in some Update
) status of something, display progress bars, interrupt the operation etc.
Flexible implementation underneath. It can use Pascal threads underneath, or it can delegate work to another asynchronous API (e.g. to download using Java classes on Android), it can even fallback to synchronous if threads are not possible on some platform.
And it is possible to load OpenGL things in a thread: by having separate OpenGL context for the background thread, that shares resources (like VBO).
The ultimate demo is to implement exploring a huge city and loading neighboring pieces of the city asynchronously.
I mentioned this in the bottom part of Slides, movies and thoughts from my GIC 2022 presentation .
One less image class (we have too many image classes, see https://castle-engine.io/using_images ).
And it will avoid current counter-intuitive fact:
ImageControl.DrawableImage.CustomShader := Xxx;
The above is ignored, because ImageControl.CustomShader
(equal to ImageControl.Content.CustomShader
) overrides TDrawableImage.CustomShader
. Similarly a few other drawable image properties, as TCastleImagePersistent.Draw
does now:
{ All the DrawableImage properties must be set here,
in case multiple TCastleImagePersistent refer to the same
DrawableImage instance through the cache.
Fortunately, almost all TDrawableImage properties have zero cost
of change. }
DrawableImage.SmoothScaling := FSmoothScaling;
DrawableImage.Clip := FClip;
DrawableImage.ClipLine := FClipLine;
DrawableImage.Rotation := FRotation;
DrawableImage.RotationCenter := FRotationCenter;
DrawableImage.Alpha := FAlphaChannel;
DrawableImage.Color := FColor;
DrawableImage.CustomShader := FCustomShader;
Goal: Support modern gamepads (joysticks) with a nice API.
Note: We have support for gamepads (joysticks) already, see CastleJoysticks
and examples/joysticks/
. But it is not easy to use — I’d like to improve the API, and improve it to handle various gamepad types in a more "seamless" fashion.
Features:
It should support at least the most popular controller, which X-box compatible controller, out-of-the-box.
It seems we can easily support much more, using joysticks database: https://trello.com/c/483EsTNX/12-use-database-of-joysticks-to-better-understand-their-buttons-axis . But I make it explicit: the critical feature is support for the most common X-box compatible controller. Support for, potentially, every gamepad that exists in the world is secondary :)
Should support at least Windows, Linux, and Nintendo Switch. Switch support in this case is justified — because we already support Switch gamepads, but we’ll want to upgrade it to new API.
Of course support for more platforms is desired. macOS, and maybe even mobile (it does seem one can connect gamepad to Android through at least Bluetooth, it actually works). But these are secondary. The platforms mentioned above are primary for this feature.
Should support multiple gamepads.
API should be nice. Current CastleJoysticks
is complicated. This means:
TInputPressRelease
structure, as send to TCastleUserInterface.Press
(so in particular, TCastleView.Press
) should have a type like GamePadButton
(alternative to key on keyboard, or mouse button) that occurs when user presses / releases the button. It should say which gamepad was used to press it (to support multiple joysticks connected to system). And it should report a button.
Buttons should have agnostic names, like North, East etc. Avoid using names like A
B
X
Y
that are in different places on different gamepad models (Xbox, PS, Nintendo…). Maybe we can also have names like Accept, Cancel to follow conventions (e.g. on Xbox controller, A corresponds to "Accept" by convention, B corresponds to "Cancel").
TCastleInputAxis
(that is also already in progress) should allow to observe chosen gamepad axis (based on gamepad index, and choice horizontal/vertical, also choice of gamepad axis — typical gamepads now have 2 axis). This is already a nice API to observe input that we want to have.
examples/joystick/
should look better. Show a sketch of a gamepad — and highlight the current axis used, button pressed.
Allow to define tasks that should occur regularly, but do not have to be done every frame. The engine should then automatically execute the tasks based on their need and current workload.
E.g. animation task may say "I want to update the model every frame, but actually I don’t have to — if under heavy workload it’s enough to only update 30 times per second or such". This would be a better (more general, smarter — activated automatically) way of optimizing it than current TCastleScene.AnimationSkipTicks
.
Note
|
The API (terminology) and implementation have to play nicely with Delphi existing concept of "tasks" from Delphi Parallel Programming Library. Delphi already has a "task" meaning "a unit of work that can be executed in auto-created thread (using pool of threads underneath)", see So:
|
A great format, by Khronos. Enables managing compressed textures much better. (than our existing solution: https://castle-engine.io/creating_data_auto_generated_textures.php )
Right now to access a component set up in the design, you have to manually add it to the published
section of the design, adding a declaration like MyViewport: TCastleViewport
.
The goal is to make it more automated. A bit like Lazarus or Delphi IDE when exposing components to code — but with some twist.
It would be easy to just expose all named components from the design in the published
section of the view (this would be experience quite like when Delphi/Lazarus do) but, since typical game designs (we’ve seen it in Unity games in CAG) can contain thousands of components easily, and most of them are not supposed to be accessed from code, we want to go one step further:
Add a button "Expose To Code" (available on single component, or selection of components).
Once used, the component will be added to the published
section of the view (name: type
), and will be updated there (on rename/delete of this component, or change of it’s class).
This is also means we’ll edit the uses
clause of unit to make sure all used component classes are registered, and declared, so that declarations in published
section work. This is also something Delphi/Lazarus do. We know the unit of each component, so it should be easy.
It is possible we’ll add markers {$region 'Castle …'}
to help organize this. See the current markers in gameinitialize.pas
.
Allow to customize the hierarchy instantiated through TCastleDesign
or TCastleTransformDesign
.
In Unity, this is called "prefab overrides". In Delphi/Lazarus, frames also offer this functionality.
The idea is that, in the "outer" design, we can save only the differences from your original design to the customized version.
See Custom components documentation, and the section "Using designs to visually set up default state of your component".
New class TCastleTiledMap.TLayer = class(TCastleComponent)
TODO: Make sure it can be serialized OK. Fallback on TCastleTiledMapLayer
if necessary. But we prefer TCastleTiledMap.TLayer
.
New published property Layers:TCastleComponentList<TLayer>
inside TCastleTiledMap
.
Depends on TCastleComponentList plans. We want to serialize the properties of layers this way.
Remove existing Layers
set from TCastleTiledMap
.
Write code in TCastleTiledMap.CustomSerialization(const SerializationProcess: TSerializationProcess);
to upgrade existing designs to new API.
Pascal code using old Layers
will just be broken and have to be upgraded, acceptable.
Exists
should be in TCastleTiledMap.TLayer
, and not in TCastleTiledMapData.TLayer
.
Should toggling it toggle also TCastleTiledMapData.TLayer.Visible
? Or let TCastleTiledMapData.TLayer.Visible
stay as "initial value"? Undecided, not really very important.
The long-term goal is to have nice components for layers and maybe more (tiles), inside TCastleTiledMap
, with published properties, that can be designed in CGE editor, and that are serialized using existing system to JSON.
It should be possible to design layers (and maybe more, like tiles) in CGE editor.
This way we can go, step by step, to having own Tiled-like editor in CGE, like Godot or Unity.
At the same time, we want to support Tiled (as external application for map editing) and support it fully, because Tiled is great! and it may take us long time to actually have fully useful tile editor in CGE editor. The road should be that Data
stuff, and everything in TCastleTiledMapData
, becomes less and less useful. It’s an internal detail whether our public TCastleTiledMap.TLayer
has a reference like Data:TCastleTiledMapData.TLayer
or not.
Built-in Tiled-like editing features in CGE would be great.
With ability to initialize them from Tiled data, and using similar API as we have for Tiled, see also plans for improving Tiled API.
With ability to design stuff in 3D. See:
This is admittedly a long-term goal. A whole system for this, esp. with 3D, would be cool but also a significant new work.
What will likely be done sooner: "snapping" for 3D operations, that fils some subset of this functionality, e.g. allows to put 3D buildings on a grid.
See docs and TCastleSceneCore.ExposeTransforms
. It already contains TODOs showing how it should work like.
Moreover fix problem with names:
cannot duplicate model with ExposeTransforms now
cannot add another model with same bone names, before customizing bone name prefixes
solution: remove ExposeTransformsPrefix, rather add new property BoneName
that doesn’t have to be unique and can be used for synchronization
document this on docs
Moreover, maybe:
? Should expose the parent bones too (otherwise editing from code is hard, and applying edits back is hard — as you see a combined transformation only)
? Rename to just Expose
? ExposeTransforms
sounds convoluted.
Moving cursor freely in text (clicking, arrow keys, ctrl+arrow keys to move by words)
Free selection of any text subset (clicking, shift+arrows)
Multiline display (thus TCastleMemo, which should internally share code and be essentially TCastleEdit with > 1 line)
Right click with contextual menu - copy, paste, cut, select all, use platform-specific input method
Manual focus. Clicking on edit should keep it focused, no matter where the mouse moves. Tab or clicking elsewhere switches focus. Right now you can workaround it / do it manually by setting Container.ForceCaptureInput
to the edit control.
All above will have to be synchronized with on-screen keyboard behavior on Android.
Moreover we want to support on-screen keyboard behavior on iOS as well, see https://github.com/castle-engine/castle-engine/issues/554 .
I can’t count how many times I’ve been asked "when is the Dark Mode coming to CGE editor" :)
One answer: It is already possible and easy on non-Windows.
We use LCL and our editor just follows your OS (Windows, GTK, …) theme. If you switch your system theme to something dark, then all your applications (including CGE) will become dark. This already works great e.g. on Linux or FreeBSD with GNOME, just switch your theme using GNOME settings and enjoy dark mode for everything.
Unfortunately, on Windows, there’s no setting to change the WinAPI controls to use the dark theme.
On Windows you can use MetaDarkStyle Lazarus package.
We have a PR with this, not merged yet. You can easily do this yourself:
Get Castle Game Engine sources and learn how to build editor yourself.
Get MetaDarkStyle package.
Add it to the CGE editor application, and apply the trivial code changes to editor source from this PR.
Big Plan: The ultimate solution, that will allow to switch dark mode on/off on all platforms with exactly the same results, will come from reimplementing CGE editor using CGE user interface components. We made a decision some time ago, and it will definitely happen — but it’s still a big task, and it will take some time. The major benefits of it will be:
We will be able to use the editor on all platforms there are CGE targets. In particular, on the upcoming web target, which means you will be able to create and edit your games in your browser! Or even on mobile (but don’t hold your breath for making games on mobile — the form factors of mobile devices will likely make UX of CGE editor on mobile not very good).
It will necessitate CGE UI improvements, from which all CGE applications will benefit. For example, ready tree view, object inspector and list components.
It will allow to turn our "inspector at run-time" into full-featured "editor at run-time".
It will allow to avoid some LCL limitations, sometimes widgetset-specific. E.g. LCL GTK 2 widgetset uses deprecated GTK 2 and has known crashing issues, Qt5 widgetset needs libqt5pas library that most people don’t have (or don’t have in relevant version for latest LCL), macOS widgetset does not have a functional frames list and thus sprite sheet editor sucks… We will be able to ignore all of this, as they will be replaced by a cross-platform implementation.
And, last but not least: the dark mode, on all platforms, will be trivial to implement :)
Finish EnvironmentLight X3D node
On top of that CGE component TCastleEnvironmentLight
It will work for all models, it is a great and modern way to do lighting.
As this post discusses, we have a few options to speed up animation processing.
Not all, but some of them should be "on" by default and have no possible adverse effects:
InternalFastTransformUpdate
enable by default and make it work regardless of what is animated.
OptimizeExtensiveTransformations
we should generalize it by remembering the top-most transform that needs to be processed.
In Castle Game Engine, we can auto-reload data files (images (in TCastleImageControl, TCastleImageTransform), scenes, Tiled maps) when they changed on disk. This is great when quickly prototyping the game, you can just save the file in external program (like Blender, GIMP, Tiled), Alt+Tab to the editor (or even your running game), and see how the new data "fits in".
Auto-reloading in editor (we call it "at design-time") is done automatically. Auto-reloading during the running game ("at run-time") must be explicitly enabled, by running the game in debug mode, then entering the inspector (using F8 key) and checking the "Monitor and Auto-Reload Data" checkbox.
The above describes what already works :)
Below are some missing things related to this:
Changing textures used in a scene doesn’t cause reload of the scene.
For example, when TCastleScene
has xxx.gltf
loaded, and xxx.gltf
refers to texture my_texture.png
, then changing xxx.gltf correctly reloads the scene, but changing my_texture.png
does not.
In general, TCastleScene
doesn’t keep a centralized knowledge "all the files that are my dependencies".
Implementing this knowledge is a TODO, it would be good to have it. For auto-reloading, also for possible auto-detection of unused files in data. To expand on the latter idea: While we will probably always pack whole data
to package (so it’s like Unity Assets/Resources
), it would be nice to have a button to allow to clean it manually ("list files in data that seem unused") or have a subdirectory in data (like data/managed/
) where only used data is packaged.
Caching right now sometimes "defeats" reloading. If something is in the cache and is referenced at least 2 times (e.g. there are 2 TCastleImageTransform
components referring to the same image or you use TCastleSceneCore.Cache
and the same scene URL is loaded 2 times), then reloading doesn’t work.
The underlying reason is that cache never "lets go" of the loaded resource, because always someone refers to it, even as TCastleImageTransform
is in the middle of TCastleImageTransform.ReloadUrl
.
Fixing this means reimplementing our ReloadUrl
routines to reload the resource in the cache. Likely a way to notify all users of this resource "this is changing" will be necessary.
We depend on LCL TApplicationProperties.OnActivate
mechanism to detect the file changes when you switch back to CGE editor application. Unfortunately, it is not reliable with LCL GTK2 backend.
Details: Sometimes the TApplicationProperties.OnActivate
event fires when it should, sometimes it doesn’t… You can Alt+Tab between CGE editor and some other application, and see that sometimes TApplicationProperties.OnActivate
just doesn’t happen. This was reproduced also with a trivial application (unrelated to CGE editor). It also happens with Lazarus IDE itself — Lazarus IDE seems to use similar mechanism to detect when Pascal file, opened in Lazarus, changed on disk (e.g. because you also edit it in VS Code). And sometimes, when you Alt+Tab between Lazarus and VS Code, Lazarus doesn’t notice the file change.
The GTK2 can correctly send the relevant event (focus_in_event
), which is used both by CGE TCastleWindow
implementation on GTK, and Lazarus LCL GTK backend. So it doesn’t seem to be GTK2 fault. A similar mechanism just works reliably for TCastleWindow
.
We haven’t found any useful workaround, no other LCL event seems to receive any event that could be useful to workaround it. We have to submit a bugreport for LCL GTK2 (if you want to handle this, please let us know, we can use a help!). And possibly switch to something else (but Qt5 backend also has problems, using libraries that most people don’t have; and it will take some time before we can implement editor without LCL).
The end result: CGE editor on Linux sometimes does not reload the data that changed. However, CGE applications, with "Monitor and Auto-Reload Data" selected, do reload the data reliably at run-time.
We can read float-based images, into these 4 image formats:
We can read from KTX, PNG, TIFF.
However, we cannot save them now.
It doesn’t seem Vampyre supports saving TIFF, it always crashes.
We didn’t test can Vampyre save 16-bit PNG images.
We miss code to save 16-bit PNG images using LibPng.
We miss code to save float images to KTX.
Note
|
This will require bumping required FPC version, but it’s worth it, as it will simplify a lot of code in CGE (and for users that define custom components). And before we get to this in CGE, possibly new FPC release(s) will happen, and most users will have the required FPC version anyway :) |
While records (like TVector3
) cannot be published
in FPC, the information about public
records is available using RTTI. We should add
{$RTTI EXPLICIT
PROPERTIES([vcPublic])
FIELDS([vcPublic])
METHODS([vcPublic])}
(or only PROPERTIES([vcPublic]))
, seems enough?) to castleconf.inc
and recommend it in Custom components documentation.
Then for public
records, like this:
TCastleTransform = class
public
property Translation: TVector3 read ... write ...;
property Scale: TVector3 read ... write ...;
end;
we should be able to read/write them using RTTT, hopefully with code mostly compatible with both FPC and Delphi.
On high level, this means:
We can enhance CastleComponentSerialize
to serialize/deserialize records. Do it, at least for our important records (TVector2
, TVector3
, TVector4
…) or (if no big obstacles) for all records in general.
We can enhance the object inspector, used in CGE editor, to show records. See lazarus/components/jitclasses/.
We shall be able to remove then:
All wrapper classes TCastleVector3Persistent
etc.
All fields using them, like TranslationPersistent: TCastleVector3Persistent
etc.
Generator in tools/internal/generate-persistent-vectors/
Complicated explanation about it in Custom components documentation.
There are a few useful options we could offer for saving, from all cases (from "Data → Export to X3D, STL…" in editor, from https://castle-engine.io/castle-model-viewer , from https://castle-engine.io/castle-model-converter ):
embed all resources using data URI (then the resulting big X3D is "self-contained", you can e.g. use it with https://castle-engine.io/castle-model-viewer-mobile ).
or copy all resources to the target directory (this could be similar to an option offered by Blender → glTF exporter, it can also copy textures on save).
The term "resources" means here everything — other files referred to be Inline
nodes, textures, audio files, shader files etc.
We want to allow using Python to develop Castle Game Engine games.
Two use-cases are important:
Use Python just for adding some behaviors.
This means implementing a class like TCastlePythonBehavior
with PythonCode: TStringList
that descends from TCastleBehavior and allows to write Python code that can be executed at both design-time and run-time. This code should have access to all CGE API.
The main advantage here is that, in contrast to implementing TCastleBehavior in Pascal, Python code can run at design-time. The practical advantages of it:
You don’t need to rebuild the editor to change the published
properties of the Python behavior in the editor’s object inspector, so the workflow is a bit faster than using custom Pascal components in editor. (Python doesn’t have published
but we’ll invent equivalent mechanism).
You can test the execution in editor’s "Play Simulation" mode (now only used to test physics). You can quickly iterate on some code, by just using "Play Simulation" from editor, and editing the Python code in the editor.
Overall, this approach should be useful for everyone, including Pascal developers. You don’t resign from coding in Pascal, you just move some logic to Python. For some behaviors you lose some advantages of Pascal (type-safety checked at compile-time) but you gain some advantages of Python as a scripting language (you can iterate on some ideas faster, test them in editor).
Write the whole game in Python.
This means you write the whole game code in Python. In particular, view’s code is in Python, so e.g. you have a design gameviewmain.castle-user-interface
and a corresponding Python code in gameviewmain.py
. The Python code defines ViewMain
class.
This makes our engine available for Python developers. We get an additional crowd of people interested in our engine. To be clear, you can still mix Python with Pascal code, but the main use-case is here for people who want to write the whole game in Python.
Why?
Choosing Python is enticing. It’s very popular. It does not have a game engine like CGE, from what we can tell (comfortable editor, powerful 3D and 2D, open-source). What we offer may be very attractive to Python developers.
We have https://github.com/pyscripter/python4delphi . Very active, tested by both Delphi and FPC users.
This idea was somewhat validated at 2023 conference in Salamanca. Namely, Embarcadero tries to do similar with FMX - offer it as library for Python devs.
To be clear, this doesn’t preclude integration with other scripting languages. Other reasonable choices exist and we welcome work on integrating them:
Lua is a popular choice in gamedev. One can implement something like TCastleLuaBehavior
that allows to paste LUA scripts that interact with CGE.
Pascal Script is a natural choice for us. And it would bring us the benefits of "it can run at design-time" while staying within the same (well, similar) programming language.
To improve this documentation just edit this page and create a pull request to cge-www repository.