Authors:

Targeted audience:

Required reading:

Required knowledge:

Explains:

Pitfalls of Euler Angles

Eulers are good because they are simple, small and easy to represent for user interface.

If you do not intend to have any support for multiple gravities, you can just as well use them in your AI. Usually, you will change just the heading of an object, or adjust pitch when shooting and similar.

If you want to have your entities behave properly in a gravity field other than default gravity, you must never use entity's orientation in euler angles (pl_OrientationAngle part of its placement). You should only refer to its matrix. You will set its desired rotation in relative coordinate system. To get some useful information about orientation use these functions (implemented in CMovableEntity):

  GetRelativeHeading()
GetRelativePitch()
GetReferenceHeadingDirection()
GetHeadingDirection()
GetPitchDirection()

Entity Procedure Overriding

In the EntitySyntax, in the part about procedure declaration, overriding possibility is mentioned. Procedures cannot be overloaded, but they have a system similar to C++ virtual function overriding. Sometimes you have a procedure that you call in a base class and want to be able to replace it for certain derived classes to behave differently. In that case, you can use overriding.

When you override a procedure from a base class, if any other procedure calls it (or jumps to it), the overriding procedure will be called (jumped to) instead.

The syntax is described briefly in Entity Source (ES) Syntax like this:

procedure_implementation :
identifier '(' event_specification ')' (':' identifier '::' identifier)opt
'{' statements '}' (';')opt

The optional part after the input event specification is the override. The first identifier is the class you override from and the second is the procedure name that you want to override. E.g. ": CEnemyBase::StartAttack" means that this procedure overrides the procedure StartAttack from the CEnemyBase class.

Overridden and overriding procedures do not need to have same names, and, on the other hand, giving them same names will not be considered overriding if the overriding specification is not present.

IMPORTANT: When you override some procedure, both procedures get same state numbers, and there is no way to call the base procedure from any entity of this class, or derived classes. So, when you plan to use overriding, you usually make a dummy procedure that just jumps to the one that does the job. Then you override the dummy procedure. This way you can always call (jump to) the one that does the job if you want to.

Demo Consistency and Network Synchronization

NOTE: If you are not deeply familiar with the networking and demo saving/replay systems in games, perhaps you are not aware of the fact that those things are usually just two variants of the same technique. Demo replay is usually just a little extension to the networking system enabling saving the data that would be sent to another computer in a network game to be saved to disk instead, and later loaded and replayed as if connected to a network game. When demo saving is initiated, the network system (which always runs, even in a single player game it runs in a local-loop mode) saves the data identical to that sent to a new client connecting to a server. Then during the game, all packets that would be sent to the client are saved to the disk. Later, that same data can be loaded and played back as if you are connected to that saved game session.

Current built-in networking system in Serious Engine, uses an action-based system, usual for peer-to-peer technologies, as opposed to current frame packets which would be used in a client-server system. This means that each computer keeps an entire copy of the session state and the server relays actions from all players to each computer. Each computer must do exactly same thing when it receives same actions.

Exactly defined, current session state is a value of an integral function maintained at each computer. Each action packet is then a delta applied to that function. If all computers start with a session state and receive same actions, they should maintain same state.

IMPORTANT: Note that for those assumptions to hold, applying same actions to same session state must yield same changes. This means that you have to take care you do not do any random actions in the entity code AI.

The term random actions, however, does not exclude pseudo-random actions. You may use IRnd() and FRnd() functions in from CEntity class. They are safe because they use a custom pseudo-random number generator which relies on a seed stored in the session state.

IMPORTANT: Never use ANSI C rand() function and its companion functions in entity AI, because they can create inconsistencies between session states on different computers and improper demo playback.

You may only use rand() in parts that are not related to maintaning the session state, i.e in rendering only. E.g. you may use rand() in RenderGameView(), RenderParticles(), AdjustShadingParameters(), etc.

One more thing needs to be kept in mind. Rendering is independent of the session state ticks. Tick always run at 20 Hz, while rendering speed (frame rate) can be different. I.e. more than one frame can be rendered between two ticks (using lerping), or more than one tick can be calculated between two frames (if frame rate drops below 20). Therefore, you must not change entity's state in the rendering functions, since it will interfere with session state consistency.

This also implies that you must never use IRnd() and FRnd() in rendering. The engine will assert against doing this, so it is unlikely that you can oversee that problem.