User Tools

Site Tools


This is an old revision of the document!


Adding new Entities to the DeathMatch MOD

FIXME This is still work in progress. The speaker entity is not yet included in any official Ca3DE release and this guide and the entity itself will go trough changes in the next days.

Introduction

This guide will show you how to create new entities for the DeathMatch MOD. To make this guide more demonstrative every step to create a new entity is illustrated on the example of a speaker entity class. This speaker entity is a non-visible source of a sound effect. The effect is played depending on configuration either as the entity is created or when it is triggered. It is possible to let the entity to play the sound one time or in a loop.
Use cases for such an entity would be ambient bird chipper or shocking sound effects that are triggered when the player moves to a specific location.

What are entities?

Generally an entity is an dynamic object in the game world. Dynamic means that the object is interactive and can change in its state or even change other entities in their state. This is opposed to the level geometry which is static and doesn't change during game play. Entities may move around a level or change their appearance over time (e.g. a player model that moves around and is animated). But entities don't need to me movable or visible they can also be at a fixed location but interact in some other way with the world. Take for example a trigger entity that reacts on players moving into it by opening a door (that is an entity itself).
So basically entities make an otherwise static world interactive and most importantly introduce the “game” aspect into a game. Without entities you would be running trough a static level with no means of interaction.

Entities in the DeathMatch MOD

Entities in the DeathMatch MOD fulfill the above description. Since the DeathMatch MOD is a multi player game entities exist not only in one game instance (as it would be with single player games). Each entity exists on the game server as well as on every client that is participating in the game.
The server is responsible for all interaction of the entities and sends the results of this to each client. This is necessary so each client will see the same results (e.g. the position of a player will be calculated on the server side and sent to each client so this player will be visible at the exact same location on all clients).
But there are also things that are performed on the client side. These include visual and acoustic events, like the explosion of a grenade together with an explosion sound. There is no need for these things to be calculated on the server and the clients only need to know when and where to show this explosion, but how it is seen or heard is up to the client code.

Insert new entity class in EntityClassDefs.lua

Entities are instances of entity classes. An entity class contains a name and different properties of an entity. Furthermore it contains a reference to the entities source code file (entity functionality is implemented in C++, see next section).
So to implement a new entity you first need to declare a new entity class in the entity class definitions script. This lua script is located in the DeathMatch root directory and has the filename EntityClassDefs.lua.
This script contains all entity classes usable in the DeathMatch MOD and poses as a good example of what entity class scripts can look like.
To define a new entity class for our speaker entity we first need to add the class to the global entity class table:

EntityClassDefs["speaker"]=newEntClassDef(Common,

This line adds a new entry named “speaker” into the entity class definitions table (too learn more about Lua and tables refer to the Lua documentation on http://www.lua.org). The new entry is created using the function newEntClassDef() that can also be found in the script file.
The first parameter Common is a table of common entity properties that are used for most entities (it contains for example a name property used by each entity). Followed by this Common table comes the table of our own entity class. Here we define each property ourselves.

{
    isPoint    =true;
    CppClass   ="EntSpeakerT";
    description="A simple invisible speaker that can playback a sound shader.";

The first three properties are default properties that are part of each entity. Defining them give the engine the ability to use properties of this class.
isPoint Determines if the entity is a point entity. Point entities aren't related to any map brush and therefore invisible to the player. If an entity should be part of a brush and therefore have a volume (e.g. trigger entities) you would have to set this property to false and the isSolid property to true. Both properties are false per default so we don't net to explicitly set isSolid to false.
:!: You always have to define either isPoint or isSolid as true otherwise an entity of this class cannot be created. :!:
The next property CppClass points to cpp class that implements the functionality of this entity. In the next section we will create this class, for now we just declare the classname EntSpeakerT here.
description is a short description of this entity class used by CaWE.

    soundshader=
    {
        type       ="string";
        description="Name of the sound shader used by this speaker for playback.";
        value      ="";
    };

Now comes the first custom property. Properties are defined by a name following type, description and default value of this property. In this case each speaker entity needs a sound shader name to correspond to. This sound shader will be played when playback is triggered by the entity. Since the name of a sound shader is a character string its type is defined as “string”.

    autoplay=
    {
        type       ="flags";
        description="Whether the sound plays automatically once the entity is created and doesn't need to be triggered first.";
        flags      ={ "autoplay", true };
    };

The next property is a boolean property. autoplay determines if the sound starts playing as soon as an instance of this entity class is created or if playback has to be triggered first.
The property type is flags. Flags can contain one or more flags that can be set/unset. Each flag is set in the flags table at the bottom of each property along with a default value.

    interval=
    {
        type       ="float";
        description="Time in seconds between two sound playbacks. [...]";
        value      =0;
    };
})

The last property is an integer value that defines the time interval between two sound playbacks. A small value means that the sound is played more often whereas a big value means that there are longer pauses between two playbacks. The default value of zero means that the sound is only played one time on each trigger.

This concludes the class definition of the new speaker entity class. The defined properties can be set to custom values inside CaWE where will will create instances of this entity and define for example a specific shader name that is used with this entity instance.

Implementing the C++ class of the entity

To give the entity life you need to implement its functionality in a C++ class. To do this you have to create a source and header file inside the DeathMatch/Code directory. For the speaker entity these files are Speaker.hpp and Speaker.cpp.
We start with the Speaker.hpp file.

#ifndef _SPEAKER_HPP_
#define _SPEAKER_HPP_

#include "../../BaseEntity.hpp"


class SoundI;


class EntSpeakerT : public BaseEntityT
{

The class name needs to be exactly the same name as declared in the entity class definition: EntSpeakerT. This class must be derived from BaseEntityT the basic class that is used for all entities.

    public:

    // Constructor
    EntSpeakerT(const EntityCreateParamsT& Params);

    // Destructor
    ~EntSpeakerT();

You need to implement a constructor that accepts const EntityCreateParamsT& as parameter since these parameters are always passed to a newly created entity. The destructor is optional and needed here for release of the sound object used by the speaker entity.

    // TypeInfo stuff.
    const cf::TypeSys::TypeInfoT* GetType() const;
    static void* CreateInstance(const cf::TypeSys::CreateParamsT& Params);
    static const cf::TypeSys::TypeInfoT TypeInfo;    

FIXME

    virtual void Think(float FrameTime, unsigned long ServerFrameNr);
    virtual void ProcessEvent(char EventID) const;

FIXME

    private:

    enum EventIDs
    {
        EventID_PlaySound                // Sound playback event send by the server.
    };

    bool    Play;                        // If the sound should be played. Can be triggered during runtime.
    float   Interval;                    // Interval between two sound playbacks. 0 means the sound is only played one time if triggered.
    float   TimeUntilNextSound;          // Time left until the sound is played another time.
    SoundI* Sound;                       // The sound object to play.
};

#endif

FIXME

Conclusion

FIXME

modding/addingnewdmentities.1210348906.txt.gz · Last modified: 2013-01-07 12:07 (external edit)