2. Entities

For a more in-depth descriptions of specific entities, refer to

2.1. Basic properties

2.2. Camera

Not all entities can see, but for those that do, the eyes are the windows to the soul. In the Half-Life universe, an entity is called the camera or the view. The camera is located at a fixed position relative to the entity’s origin, at least at server side. At client side, the player’s camera position is slightly complicated by view bobbing if enabled.

2.3. Movement

All entities in Half-Life has an associated movement type, or movetype. These are all the possible movetypes in Half-Life:

MOVETYPE_NONE
The entity never moves and not subjected to gravity. Examples of entities using this movetype are triggers, RPG laser spots, env_explosion, etc. In the engine code, SV_Physics_None handles the physics of this movetype. This function simply calls the Think function associated with the entity and returns.
MOVETYPE_WALK
This movetype is only used by the player and gives rise to the familiar air and ground movement physics of the player (see Player movement basics).
MOVETYPE_STEP
This is the primary movetype used by monsters, analogous to MOVETYPE_WALK for the player. SV_Physics_Step handles this movetype, and it computes water buoyancy physics, gravity by Euler’s method (see Gravity), friction, position update, and also runs the entity’s Think function.
MOVETYPE_FLY
This movetype is used by entities that do not experience gravity, but has collision. For example, the Nihilanth (Nihilanth) uses this movetype, so does the tripmine (Tripmine), crossbow bolt, and many others. Notably, this movetype is also used by the player on a ladder (Ladders). The SV_Physics_Toss is responsible of this movetype. It runs the Think function, perform other checks, and compute position update and collisions.
MOVETYPE_TOSS
This movetype is used by gibs, dead monsters, and certain pickup items such as the battery and suit. Similar to MOVETYPE_FLY, the SV_Physics_Toss function handles this movetype, though with gravity.
MOVETYPE_PUSH
This movetype is used by entities that can push and crush other entities, but does not clip to worldspawn. These are buttons, doors, func_breakable (func_breakable, but not func_pushable), func_rotating, func_wall, func_pendulum, etc. SV_Physics_Pusher runs the physics for this movetype, which calls either SV_PushRotate or SV_PushMove at some point, and calls the Think function of the entity.
MOVETYPE_NOCLIP
Entities with this movetype does not experience gravity, and does not clip with any other entity. SV_Physics_Noclip is responsible of the physics, which consists of running the Think function, computing position and angle update, and SV_LinkEdict.
MOVETYPE_FLYMISSILE
This movetype is not found to be used by any entity in vanilla Half-Life. The SV_Physics_Toss function is responsible of its physics.
MOVETYPE_BOUNCE
This movetype is used by entities that can bounce off other entities. A prominent example is the hand grenade (Hand grenade), but satchel charges (Satchel charge), MP5 greandes, and others use this movetype as well. Similar to MOVETYPE_TOSS, SV_Physics_Toss is called for this movetype, but with the bounce coefficient (see Collision) computed by .
MOVETYPE_BOUNCEMISSILE
Just like MOVETYPE_FLYMISSILE, this movetype does not seem to be used by any entity in the unmodded Half-Life. SV_Physics_Toss is also called for this movetype, and the bounce coefficient (see Collision) is set to be , independent of entity gravity.
MOVETYPE_FOLLOW
Entities of this movetype tracks the movement of the entity given by pev->aiment. For example, the CBasePlayerItem class, subclassed by all player weapons, follows the player and is set to this movetype. Entities of this movetype does not experience gravity or collision. SV_Physics_Follow runs its physics code, and consists of calling Think and copying the aiment origin and angles, along with SV_LinkEdict.
MOVETYPE_PUSHSTEP

This entity seems to only be used by func_pushable. The physics of this movetype is very similar to that of MOVETYPE_PUSH, except that MOVETYPE_PUSHSTEP uses a slightly different way to collide with other entities.

TODO

MOVETYPE_COMPOUND
This movetype does not seem to be used.

2.4. Gravity

2.5. Friction

2.6. Hitboxes

2.7. Collision

Many entities in Half-Life collide with one another. The velocity of the colliding entity usually changes as a result, while the position and velocity of the entity receiving the collision usually stay constant, countering real world Newtonian physics. The process of changing the velocity is usually referred to as velocity clipping. Collision is one of the most common events in Half-Life, so it is worthwhile to study its physics.

Collision is detected by determining the planes that run into the way of a line traced from the moving entity’s position to the future position. The future position depends on the frame rate, the velocity and the base velocity associated with the colliding entity. Let be the plane normal and let be the velocity at the instant of collision. Let be the bounce coefficient which, under certain conditions, depends on sv_bounce (denoted as ) and (see Friction). The bounce coefficient controls how the velocity is reflected akin to a light ray. If is the velocity resulting from the collision, then the general collision equation (GCE) can be written as

Before we proceed, we must point out that this equation may be applied multiple times per frame. The functions responsible of actually displacing entities are SV_FlyMove for non-players and PM_FlyMove for players. These functions perform at most four aforementioned line tracing, each time potentially calling the velocity clipping function.

_images/collision-overbounce.svg

Fig. 2.1. Depiction of a general case of collision, where the player collides with plane at .

Collision in the general case is depicted in Fig. 2.1.. The point at which collision occurs is , and let the arrow the velocity vector . Then, the length of represents the dot product , and is a projection of onto the line , which is parallel to the plane normal. In general, this dot product is scaled by , causing the final velocity vector to point out of the plane, shown by . If instead, then would be the final vector.

In most cases, players have because and so is . In general, for players is computed by . The case of is more common for other entities. For example, snarks have and . In general, if the movement type of an entity is designated as MOVETYPE_BOUNCE, then .

Care must be taken when . To understand why, we first observe that , because otherwise there would not be any collision events. With

we see that if then the angle between the resultant velocity and the plane normal is obtuse. As a result, collisions will occur indefinitely with an increasing . To prevent this, the game utilises a safeguard immediately after the line tracing process in the respective FlyMove functions to set .

Hence, assuming we employ the following trick to quickly find : write and expanding each in the RHS to give

where is the smallest angle between and confined to . Observe that the resulting speed is strictly increasing with respect to in . In fact, the curve of resultant speed against is hyperbolic provided and . When does equal zero, the resultant speed will be linear in like so:

Again, this result assumes . On the other hand, for the very common case of we have

Observe that the resultant velocity is always parallel to the plane, as one can verify that is indeed true.

2.7.1. Speed preserving circular walls

In Half-Life, we can sometimes find concave walls made out of multiple planes that approximate a circular arc. Examples can be found in some Office Complex maps such as the wall shown in Fig. 2.2.. Circular walls can be a blessing for speedrunners because they allow making sharp turns without losing too much speed. In fact, if the number of planes increases, the approximation will improve, and so the speed will be better preserved.

_images/speed-preserving-c1a2.jpg

Fig. 2.2. An example of a “speed preserving” wall in the Office Complex map of c1a2, which is made up of multiple planes to approximate an arc.

_images/circular-wall.svg

Let be the number of walls and let be the angle subtended by the arc joining the midpoints of every wall. For example, with the first and the last walls will be perpendicular, and with they will be opposite and parallel instead. Let be the velocity immediately after colliding with the -th wall, and assuming is parallel to and coincident with the first wall. Assume also that , which means that the angle between adjacent planes cannot be acute. If the velocity does not change due to other external factors throughout the collisions, then

The general equation at frame is simply

It can be verified that

This demonstrates the speed preserving property of circular walls. Observe also that the final speed is completely independent of the radius of the arc. Perfectly circular walls are impossible in Half-Life due to the inherent limitations in the map format, so some amount of speed loss is unavoidable. Nevertheless, even with and we can still preserve half of the original speed.

This is somewhat analogous to uniform circular motion in the real world. In the real world, an object rotating around a point in a circular path experiences centripetal acceleration with constant angular speed . The velocity of the rotating body changes its direction continuously to keep up with the circular arc, but crucially, the magnitude or speed remains constant throughout. In theory, there is no restriction on how small the radius of curvature can be.