In this section the basic ideas and details behind CEL are described and explained.
What are Entities?
Every object in the game is represented by an entity. The entity system allows the game programmer (using CEL) to speak to game objects in a consistant manner. Examples of entities are: the player, the world itself, creatures, a candle, objects in general, items, ... It is important to note that entities don't have to represent visual objects. An entity can be a part of a story line (i.e. a quest) that the player has to solve.
One of the most important concepts in CEL is the notion of a Property Class. Attached to every entity we have a list of property classes. A property class describes a specific kind of behaviour or attribute set for an entity. All the property classes together define what the entity really is and can do. In addition to the property classes predefined by CEL you can also write your own property classes (in C++ or Python).
To clarify what you can use property classes for we give a list of the current implemented property classes:
Essentially it is a piece of code (like a C++ class) that you can attach to an entity. They can send out messages.
- pcworld.region: A region represents an area in the engine. It usually contains some sectors with geometry although it is also possible to make regions containing only mesh factories or materials.
- pcworld.zonemanager: The zone manager is a more powerful version of pcregion. It supports dynamic loading for big worlds.
- pccamera.standard: A camera represents what the player sees on screen. A camera is usually in first-person or third-person mode.
- pcinput.standard: This property class represents input from the keyboard, mouse, or joystick. An entity that has this property class attached to it will get messages when input is generated.
- pctools.inventory: The inventory property class contains a set of other entities. An entity which has this property class is capable of containing other entities. This property class can have several attributes that put some limit on what the inventory can contain. The pctools.inventory.characteristics property class is used to define limits for entities (see below). Common limits are weight, size, number of inventory slots, ... but the system is not limited to those. The system is hierarchical. For example, a box entity can have an inventory so that you can put objects in that box. If the player picks up the box then the box including the contents will be in the player inventory. All objects in the world (except for the world itself) belong to some inventory. This is to avoid dangling references. The inventory system goes to great lengths to insure that the maximum capacity of entities inside is not exceeded. This even works for nested inventories. i.e. if the player holds a box and the weight of the box plus contents is near the limit of what the player can hold then you will not be able to add another item to the box.
- pctools.inventory.characteristics: This property class defines the characteristics that some object has in relation to the inventory system. For example, with this property class you can say that the weight of an entity is 10.
- pcobject.mesh: This property class represents a mesh from the engine. Use this if you want a visual representation for an entity.
- pcobject.mesh.select: If you want this entity to receive messages when other meshes (or this mesh) are selected you can use this property class. It is very configurable and even allows you to drag objects along a 3D plane.
- pcmove.solid: If your mesh has a solid representation that needs to be used for collision detection or physics than it must have this property class.
- pcmove.linear: This is the movement system. If you want an entity to move around, have proper collision detection and gravity then you should use this class.
- pcmove.actor.analog and pcmove.actor.standard: These property classes can be used for the main actor. They help synchronise camera, movement system, and animation on the model. The first does multi-directional movement like in platform and action games, whereas the second does turn and move forward movement which is useful for certain cases.
- pc2d.tooltip: This is a convenient property class that allows you to have tooltips. In some games this can be useful for showing information about the actor on which the cursor is resting.
- pctools.timer: Use this property class to get messages when a specific time has passed. Can also repeat.
- pctools.properties: This is a general property class to store properties with an entity. These properties are otherwise not used. It is simply a way to associate data with an entity.
- pclogic.spawn: A property class that represents a spawn point where creatures or other entities can be created.
- pclogic.trigger: A property class that sends messages to the behaviour as soon as some other entity enters a trigger area. Can be useful for doors that open when a player arrives or something.
- pc2d.billboard: This can be used for 2D images on top of 3D world or even for making full 2D games.
- pclogic.quest: This is a powerful and general quest system using a state machine. This is not only useful for RPG games but also for FPS games where a quest can be as simple as 'player presses button' -> 'light goes on'.
- pcmove.pathfinder: The path finder can be used by creatures that are interested in finding out how to move to some location through the level. This property class works together with pcmove.steer in order to actually move the entity around until it reaches the correct destination. This property class also generates events when the destination is reached or the destination cannot be reached for some reason.
- pctools.bag: A bag of strings.
- pclogic.wire: A message conduit. This property class can listen for a certain message on a channel (or entity) and then redirect them as other messages to other channels. It also supports parameter transformation and expressions on those parameters. This is a very useful property class that can be used to connect other property classes so that they act in a coherent manner (for example, listening to a message from the input property class so that you can send out a message to a timer to do something else).
- and more...
Several more property classes are planned like:
- pclocator: The locator is used to keep track of the position of another entity. There can be multiple instances of locator attached to one entity if that entity is interested in more than one entity. When a locator is attached to an entity the entity will receive events when the other entity moves, becomes visible, becomes invisible, or is destroyed. Only the last event is immediate. The others are only calculated every second (default: this is configurable for any locator). The locator is very useful in combination with the pcpathfinder above.
This is only the beginning. More property classes will follow as the game system is further refined. The property class system is a very dynamic and flexible system which allows us to dynamically change properties of entities on the fly. It is possible to add/remove any of the above property classes at any time. This is something that is very hard to do if we were to use the traditional inheritance based entity system.
Property classes are created by getting their property class factory. These are usually implemented in a plugin. You load the plugin at startup of your game and you then create property classes for your entities from that plugin when you need them.
The Physical Layer (PL)
The PL is actually what CEL is all about. It describes the constraints on interactions between entities and also constraints about what an entity can do. The idea is that you attach property classes to an entity. Every property class defines some specific physical attribute or constraint for an entity. The collection of all property classes attached to some entity define what the entity really is. Property classes can be dynamically added or removed from a given entity. Usually the BL will do that.
One important note with this entity system is that one usually doesn't subclass entities. There is only one type of entity and that is provided by the PL. To control behaviour of entities one adds the appropriate property classes instead. The core of CEL doesn't have property class implementations but only provides interfaces which allows a game to create property class implementations. But CEL will come with a set of pre-made property classes which are potentially useful for all/most games.
The PL itself is split into several sub-layers:
- Entity Manager: The entity manager is responsible for creating and managing bare-bones entities.
- Message System: This will allow property classes to send messages to each other.
- Property Class System: Here property classes are managed.
- Persistence Layer: To save/load entities the persistence layer is defined.
A very important part of CEL is the message system. Each entity acts as a message channel on which interested parties can subscribe or broadcast messages. Every message has a message id by which it can be recognized. These id's are hierarchical so that you can easily listen to a collection of messages at once.
Property classes are one of the main generators of messages and can also react to them.
The following table lists a few current messages grouped by the property class by which they are generated (from the list of example property classes above):
- cel.entity.add: An entity was added to the inventory contained within this entity.
- cel.entity.remove: An entity was removed.
- cel.entity.add.this: This entity was added to another inventory.
- cel.entity.remove.this: This entity was removed from another inventory.
- cel.mesh.select.down: Mouse down on a mesh (selection).
- cel.mesh.select.up: Mouse up on a mesh.
- cel.mesh.select.move: Mouse move for a mesh.
- cel.timer.wakeup: Timer wake-up event.
- cel.properties.set: Property has been set.
- cel.properties.clear: Property will be cleared.
- cel.input.<key>.down: Specified command has been activated (i.e. the key associated with the command is pressed).
- cel.input.<key>.up: Specified command has been de-activated (i.e. the key associated with the command is released).
- and more...
More messages will of course follow. This is only the beginning.
The persistence layer in CEL allows games to save and load entity state. In a single player game this can be used for saving the current game state so that the player can later load the game again. In a multiplayer game this can be used in more controlled scenarios to persists parts of the world in a cache or on the network. There are currently two persistence layer: classic (using binary output) or XML.