Development: engine 4.0.0 - still almost there: a lot of creatures, items and player improvements

November 14, 2012
Lights Editor playing with shadow maps
Lazarus form with 2 castle controls sharing textures
resource_animations: Knight default idle animation
resource_animations: Knight attack animation
resource_animations: Spider Queen (castle1 creature)
resource_animations: Sword (an item, with animations Attack and Ready shown with respect to player)
Missile (arrow) stuck in a wall
Missile (arrow) stuck in a wall
Missile (arrow) stuck in a wall
Missile (arrow) stuck in a wall
Missile (arrow) stuck in a wall

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:

  1. Creatures/items (commonly called "resources" in many places) improvements:

    1. 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.

      (The knight animated model comes from opengameart.org.)

    2. 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.

    3. Removing dead creature corpses from level is trivial, see RemoveDead property and remove_dead in resource.xml.
    4. Weapons behavior is trivial to define also:
      1. short-range attack and missile firing (with ammo or not) is configurable fully inside TItemWeaponKind (and related resource.xml file), no need for a single line of code.
      2. A weapon can also immediately shoot (like a pistol).
      3. Ammunition type is configurable both for missile firing (arrows to fire) and immediate shooting or short-range (bullets for a pistol).
    5. 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.)

    6. CastShadowVolumes and ReceiveShadowVolumes, default true, configurable for every item and creature (cast_shadow_volumes and receive_shadow_volumes in resource.xml).
    7. TItemOnWorld.AutoPick property, to control automatic picking of items by player, and TItemOnWorld.ExtractItem method to implement picking yourself.
    8. TItemOnWorld.RotationSpeed property, to control the speed of rotation of items (set to 0 to disable rotating).
    9. TInventoryItem.Stack method to override, to affect how items stacking works.
    10. New nice properties to control middle point used for collisions (see 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).
    11. Removed default TCreature and TItemOnWorld behavior on "activation" (Input_Interact, usually "e" in 3D games like "The Castle" and left mouse click in traditional 3D viewers). Previously they were making a simple description "what you see" on the Notifications, which may not be a desirable default behavior for many games. If needed, you can reimplement this (or many other ideas) by overriding TCastleSceneManager.PointingDeviceActivate3D . You can also make your own T3D descendants and override their T3D.PointingDeviceActivate, like before.
  2. 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.

  3. Levels improvements:

    1. 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.

    2. Magic "margin" parameter around sectors removed. We now just look at waypoint's bounding box. See notes about sectors/waypoints for user, and see TGameSceneManager.LoadLevel for developer docs.
    3. Extracting direction (for initial direction that the creature is facing) from placeholder. See placeholder_default_direction in creating_data_levels docs.
    4. 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.
  4. Player improvements:

    1. TPlayer.RenderOnTop feature.
    2. Every 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.
    3. TPlayer.Flying and TPlayer.FlyingTimeOut, a simpler and more flexible properties to control player flying (replace previous TPlayer.FlyingMode and friends).
  5. Image API improvements:

    1. Cleanups around AlphaChannel detection, code simplified (and much shortened). Our alphaChannel extension is now available for all X3DTextureNode.
    2. Introducing 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.
    3. 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.)
  6. Other changes:

    1. Unit 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 :)
    2. OpenGL resources are automatically shared between two or more TCastleControl controls. Also Idle fixes for multiple TCastleControl in a single application.
    3. Generic unit name 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).
    4. 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;