Time to show some dumb screenshots from my even dumber ioquake3 fork.
Since school started, I decided to start working on a little engine project for next year's Bosnian gamedev competition. It's gonna be a heavily modified Quake 3 engine that shares some of its ideas and philosophy with GoldSRC and CryEngine. What that actually means will be explained some other day.
So... what is this? A blue dynamic light entity? No. It only looks like it. I'll explain what's going on. Simply put, the engine is managing two entity systems at once.
The engine was originally written in C, and as such, the concept of entity classes isn't achieved via classes themselves. It still does it the way Quake and Quake 2 did it, by using structs and function pointers. Nothing wrong with the approach, depending on the scale of the game.
For example:
void func_breakable_pain( gentity_t* self, gentity_t* attacker, int damage )
{
if ( self->health - damage <= 0 )
{
// Gib me
GibEntity( self, 0 );
// Remove entity from world
G_FreeEntity( self );
}
}
void func_breakable_use( gentity_t* self, gentity_t* other, gentity_t* activator )
{
// Damage itself when triggered
func_breakable_pain( self, activator, self->health );
}
void SP_func_breakable( gentity_t* self )
{
G_SpawnInt( "health", "50", &self->health );
G_SpawnString( "model", 0, &self->model );
trap_SetBrushModel( self, self->model );
// Link entity into world
trap_LinkEntity( self );
self->takedamage = 1;
self->pain = func_breakable_pain;
self->use = func_breakable_use;
}
I'm not satisfied with that though. To get what satisfies me, it'd take much more work to modify the existing system, than to make a new one from scratch. So the latter is exactly what I'm doing.
This is how it'd approximately be in the new system:
class FuncBreakable : public BaseQuakeEntity
{
public:
void Spawn() override
{
health = spawnArgs->GetInt( "health", 50 );
takeDamage = DamageTypes::All;
}
void Use( IEntity* activator, IEntity* caller, UseType useType, float value ) override
{
Pain( activator, health );
}
void Pain( IEntity* attacker, int damage ) override
{
if ( health - damage <= 0 )
{
SpawnGibs( GetOrigin(), 20, "models/somegibs.md3" );
MarkForRemoval(); // next tick, this entity is gone
}
}
const int GetEntityFlags() override
{
return EntityFlags::SolidBrushEntity | EntityFlags::Static; // will automatically set up a brush model, movement type and solidity
}
private:
int health{ 0 };
}
This is just there to get you the basic idea. There's a ton of other stuff I've had in mind for this project.
The blue light is there instead of a visible brush entity, because I didn't finish the networking code. The netcode treats the entity from the new system as if it were one from the legacy system, so it ends up writing the data entirely wrongly, and the client, of course, interprets it wrongly. It's a miracle that it didn't crash the game LOL
Other than that, I'm messing with it just so I can get an excuse to use TrenchBroom instead of J.A.C.K. (even though J.A.C.K. also supports Q3)
I'm loving it so far!