Development: engine 4.0.0 - still almost there: a lot of creatures, items and player improvements
Sorry, still no new release... But, as usual, we have many new features to announce for the upcoming Castle Game Engine 4.0.0 :) For starters, a little movie with explosions fun:
New features:
Creatures/items (commonly called "resources" in many places) improvements:
New example program: resource_animations
. Demonstrates how to define creature/item animations in resource.xml
files, from KAnim and/or X3D animations. Can be also used to preview animations from any resource.xml
files, e.g. you can try it on castle1 creatures and items. See DRAFT.modeling_tutorial.txt (will be moved to nicer HTML page later) for notes about how to design your creatures/items.
Defining short-range creature attack and/or firing a missile are trivial now. See TWalkAttackCreatureKind.AttackXxx
and TWalkAttackCreatureKind.FireMissileXxx
properties, and <fire_missile>
and <attack>
elements in resource.xml
.
What actually happens is configurable by overriding methods TWalkAttackCreature.Attack
and TWalkAttackCreature.FireMissile
. So, while you can think that <attack> is "short-range attack" and <fire_missile> is "firing a missile", in reality it's more like <attack> is "1st configurable attack-like action" and <fire_missile> is "2nd configurable attack-like action".
You still can use extra states for special purposes in TWalkAttackCreature (csMax+1
, csMax+2
etc.), so it's possible to add even more kinds of attack (or really anything else) by overriding appropriate methods.
RemoveDead
property and remove_dead
in resource.xml
.
resource.xml
file), no need for a single line of code.Die animations, and configurable RemoveDead, are also available for Still and Missile creatures. Die animation allows e.g. to make exploding animations for missiles and immobile objects (like barrel in the movie above).
RemoveDead allows to keep the corpse on the level, with special twists for missiles. Your missiles, like arrows, can be left "stuck" in the wall. (This mechanism should be better and more intelligent in the future, as part of the "decal" system. For now, at least it basically works for some cases.)
CastShadowVolumes
and ReceiveShadowVolumes
, default true, configurable for every item and creature (cast_shadow_volumes
and receive_shadow_volumes
in resource.xml
). TItemOnWorld.AutoPick
property, to control automatic picking of items by player, and TItemOnWorld.ExtractItem
method to implement picking yourself.TItemOnWorld.RotationSpeed
property, to control the speed of rotation of items (set to 0 to disable rotating).TInventoryItem.Stack
method to override, to affect how items stacking works.T3D.Middle
, T3DCustomTransform.MiddlePoint
, T3DCustomTransform.PreferredHeight
). Unified gravity on items and creatures, with new comfortable properties (see T3DCustomTransform.Gravity
, T3DCustomTransform.FallSpeed
, T3DCustomTransform.GrowSpeed
). More configurable from resource.xml
file (middle_height
, fall_speed
, grow_speed
, direction_fall_speed
— see creating_data_resources).
T3D.PointingDeviceActivate
, like before.
Our Blender X3D exporter updated for Blender 2.64a.
New KAnim exporter for Blender 2.64a added. For the same reason as a couple of years ago (Blender standard X3D exporter still cannot export animations) we still need it.
Levels improvements:
Placeholders are nicer. You can indicate in level.xml
how to detect placeholder names in 3D level file, for example use placeholders="blender"
to use object names set in Blender. You configure it now nicely to support any other modeler. Also, we now make clear that this detection dependent on modeler is only for TGameSceneManager.LoadLevel
placeholders, nothing else. See level.xml and resource.xml files documentation.
You can register own callbacks, see PlaceholdersNames
and docs of TPlaceholderName
.
TGameSceneManager.LoadLevel
for developer docs.placeholder_default_direction
in creating_data_levels docs.
TCastleSceneManager.OnMoveAllowed
callback, to control how the algorithm described at TCastleSceneManager.MoveLimit
works — allows to limit the working of gravity and/or movement to some 3D space.
Player improvements:
TPlayer.RenderOnTop
feature.T3DOrient
instance has automatically a synchronized T3DOrient.Camera
instance inside. This makes Player<->Camera synchronization work without any fuss. It also allows to switch your view into a computer-controlled creature, which is quite fun. In network games, other players will also be creatures (with data synchronized from network), so this will also allow observing other players when in "spectator" mode — I saw this feature in Tremulous, it's quite cool.TPlayer.Flying
and TPlayer.FlyingTimeOut
, a simpler and more flexible properties to control player flying (replace previous TPlayer.FlyingMode
and friends).
Image API improvements:
AlphaChannel
detection, code simplified (and much shortened). Our alphaChannel extension is now available for all X3DTextureNode.TGLImage
class in GLImages
unit, for drawing images on 2D screen. This encapsulates a display list, and in the future will be seamlessly changed to PBO for modern OpenGL versions.ForbiddenConvs
parameter to LoadImage
removed, along with TImageLoadConversions
and friends. They were complicated, and not really useful in practice. (If you're really paranoid about conversions, you can use LoadImage
to any class and make conversions yourself, honoring any order/limits as you desire.)Other changes:
CastleGameCache
removed. We automatically use the global GLContextCache
now, this makes things trivial to use and automatically optimal. If you really, really want to use a separate cache for some stuff, you can still do it by TCastleScene.CreateCustomCache
and TCastlePrecalculatedAnimation.CreateCustomCache
— but, aside from debugging, it's hard to imagine why you would need it now :)TCastleControl
controls. Also Idle
fixes for multiple TCastleControl
in a single application.Shape
renamed to CastleShapes
, Images
to CastleImages
, Triangle
to X3DTriangles
. New unit CastleTriangles
extracted from VectorMath
(to make a huge VectorMath
unit at least a little slimmer).Large press / release callbacks and virtual methods rearrangement: all presses (KeyDown
, MouseDown
, MouseWheel
) now go to a single Press
method (with TInputPressRelease
param). Likewise, all releases (KeyUp
, MouseUp
(we didn't implement mouse wheel releases yet)) go to Release
. Same goes for callbacks, now you have OnPress
and OnRelease
.
This allows a huge code cleanup (and shortening) in a lot of places. Since our engine concentrates input processing on TInputShortcut
, where you can customize whether it's key and/or mouse button and/or mouse wheel, it makes sense to store "press" and "release" as a single TInputPressRelease
value. Previously, a lot of code was complicated because of this, and also some methods had a lot of parameters to pass all key/mouse information in separate variables.
If you want to add some key/mouse shortcut to your game, you can now do it easily:
Create it, like this:
Input_UseLifePotion := TInputShortcut.Create(nil, 'Use life potion', 'life_potion_use', igItems); Input_UseLifePotion.Assign(K_L, K_None, #0, false, mbLeft);
Then use it in TCastleWindow.OnPress
or TCastleControl.OnPress
callback, or in an overridden TInputListener.Press
method (TInputListener
is an ancestor for many things, like TCamera
, TUIControl
, TCastleSceneManager
) like
procedure Press(Window: TCastleWindow; const Event: TInputPressRelease); begin if Input.IsEvent(Event) then ... end;
The keymap management in CastleInputs
unit cooperates with it nicely. For example you can check which shortcut matches by InputsAll.SeekMatchingShortcut
. You can get an input from user by CastleMessages.MessageKeyMouse
. This is great for games where you want to allow user to customize inputs. See GameControlsMenu
in castle1 source for a working example of it, with TCastleOnScreenMenu integration
.
You can of course still hardcode the particular keys/mouse buttons etc., if you want. It's still simple as the TInputPressRelease
is a pretty trivial structure, it has EventType
field, and even helpers like IsKey
. So you can do
procedure Press(Window: TCastleWindow; const Event: TInputPressRelease); begin if Input.IsKey(CharEscape) then ... if Input.IsMouseButton(mbLeft) then ... end;