• entries
22
11
• views
25679

# Toasty Update #1

1192 views

The first update is here, and it has a few things in it that I would like to show off. This might be very long.

So first thing's first, to start using the game engine you can create a GameSystem object like so:Toasty::GameSystem* system = new Toasty::GameSystem();
Now you don't have to use a GameSystem but it is useful in doing these things:

Automatic Unique ID Assignment

This makes use of the template class UniqueIDHandler, which allows any type with a ++ operator to be used. You just call GetNextID and RemoveID(T id) to use it. Anything dealing with this should use the same type, or be able to implicitly convert from it. I use unsigned 32-bit ints in the GameSystem at the moment, so the technical maximum number of entities are 4, 294, 967, 295 (Should be enough). I am still toying around with whether or not the GameSystem should allow selection of the type to use, maybe your game only needs 256 entities in it at any one time?

Automatic Assignment of a Valid MessageSystem* to Entities

Entities are basically a simple container of an ID (of type T, which should match the UniqueIDHandler type that you are using) and position, scale, rotation and a possibly non-unique name. They require a MessageSystem* so it can notify any listeners of position, scale, rotation and name changes.

MessageSystem Creation and Passing to Systems

The way systems and components communicate is via the message system, to facilitate an easy way to make sure systems match the same MessageSystem the GameSystem creates it's own and passes it to a system when it is added, if a System wants it, it can keep it and listen for messages it wants. Now keep in mind performance is not currently the goal, features are so at the moment the MessageSystem will immediately deliver the message to all listeners which thrashes the cache. I would like to perform this for a maximum amount of time at the end of a frame (Before scene unloading \ loading or entity destruction) instead.

Automatic Timing

Using the default timer (std::chrono aka Toasty::ChronoTimer) the GameSystem is able to easily time each frame and calculate Dt and FPS. You are able to extend from BaseTimer and create your own timer for use within the GameSystem. Also making use of the timer, you can get an average fps or the exact last fps!

System Updating

If you call this function:system->Run();
All systems added to the GameSystem will be updated in reverse order that you added them as well as timing them (This is an infinite loop). If a system returns false in it's update, that means it wants the whole GameSystem to shutdown. Run doesn't have to be used, Tick can be used to perform a single frame. I plan on doing research into multi-threading because I would like to be able to mark systems as multi-threaded and have the GameSystem perform their updates on other threads. Being able to change order of systems is something I might add as well.

Entity Lookup

The gamesystem obviously provides an easy way to get either a group of entities by name (Names aren't unique remember!) or a single entity by ID out of all entities added to it.

Attached component lookup

Being able to find other components in the GameSystem is a must, so you can easily get a vector of all components added to an Entity pointer or ID. On top of that you can also get a specific system by name and get any components attached to your entity that way (some systems may allow multiple components attached to it). If you get it via a vector you will have to dynamic_cast it until you find the one you want.

the point of Toasty is to be ultra modular. No graphics, physics or anything is included with it but are done in other modules which you can either link to statically, dynamically or at load them at runtime (Which this handles). Actually loading a plugin at run time instead of linking to it makes it kind of difficult to actually use the things it loads in, but at the moment you could write a Serialiser and then in some text editor write out a file that would load the plugin and use components from it and attach them to entities, if you then wanted to do something in game logic you might need some kind of scripting language or other way to glue it together.

You could do that all yourself manually if you liked though, as the GameSystem class is just a wrapper around a whole bunch of useful classes in Toasty.

Continuing on you would call:system->Run();
Which would perform the main game loop, although seeing as there isn't any scenes, entities or any other systems nothing will happen. Lets fix that:Toasty::GameSystem* system = new Toasty::GameSystem();Toasty::BehaviourSystem* behaviourSystem = new Toasty::BehaviourSystem(system);system->AddSystem(behaviourSystem, true);
So, the behaviour system just allows one to add a behaviour to a Entity similar to Unity, but we need a behaviour so let's make one!#include "BehaviourComponent.h"#include "ConsoleLogger.h"#include class Test: public Toasty::BehaviourComponent{public: Test(Toasty::GameSystem* system, Toasty::Entity* ent) : BehaviourComponent(system, ent) { } virtual ~Test() { } virtual void Initialise() { Toasty::LogInfoPositive(entityAttachedTo->GetName()); } virtual void Shutdown() { } virtual void Update() { Toasty::LogInfo("FPS: " + std::to_string(gameSystem->GetFPS())); }};
and this just logs out the FPS every update of the 'script' and the name of the entity it is attached to, but to actually use it we have to do this: // Create game system and set it up with a timer. // It automatically gets set with the default ChronoTimer. Toasty::GameSystem* system = new Toasty::GameSystem(); //Create the systems we are going to use. Then add them to the gamesystem we are using. Toasty::BehaviourSystem* behaviourSystem = new Toasty::BehaviourSystem(system); system->AddSystem(behaviourSystem, true); // Create an entity to attach a behaviour component to Toasty::Entity* myFirstEntity = new Toasty::Entity(); // Give the Entity the message system and a UniqueID. gameSystem->AddEntity(myFirstEntity); // Add the test 'script' to the Entity. Test* test = new Test(system, myFirstEntity); behaviourSystem->AddEntity(myFirstEntity, test); // Run the system! system->Run(); // Cleanup delete system; delete test; delete myFirstEntity; delete behaviourSystem;
Notice the cleanup requires you to delete all memory you created? That's by design, at least for the moment I am still contemplating whether or not to use smart pointers to handle memory.

What follows are images of a Windows, Linux and Mac OSX machine (Thankyou cmake!) running this test with an image of their specs and interesting data about the compiled forms on each one.

Windows

Followed by this on the Nth frame:

ToastyGameSystem DLL filesize: 68 Kilobytes

ToastyGameSystem Lib filesize: 72 Kilobytes

ToastySystemTest.exe filesize: 42 Kilobytes

Linux

libToastyGameSystem.so filesize: 103 Kilobytes

ToastySystemTest binary: 19 Kilobytes

Mac OSX

libToastyGameSystem.dylib filesize: 114 kilobytes

ToastySystemTest binary filesize: 25 kilobytes

What's interesting is the performance of the windows computer seems the worst (It doesn't even hit 1k fps!!) even though it has the better specs! Maybe you guys can guess as to why that is...I'll probably give you the answer in the comments later on. On the next post I'll be talking about the coolness of scenes, how they can be used, the simple math side of things, extending the system and things I still need to do before ToastyGameSystem is done!

Hi there.  Good to see another Entity/Component framework in the pipeline!  I have a few comments I thought of while reading I wanted to share that might provide some improvements.

It might be a little name confusion that you have your whole Framework being called a system (GameSystem in this case) while a "system" is a defined and integral part of your framework already.  It's a pretty minor thing, but just something I thought about.

It seems you could reduce some redundancy when creating systems (not GameSystem) considering, currently, you have to pass the GameSystem to the system's constructor, but you also have to call AddSystem().  I would think AddSystem() could pass the GameSystem being used to the system (lots of "systems" heh).

Similar thing with Components, you pass the entity and system to the Component's Constructor, then call GameSystem::AddEntity() and pass both the entity and component. I think you should be able to emove so many references to systems and entity.

BTW, when adding multiple components, do you continually call AddEntity() with the entity and Component?  I would think you should call AddComponent() to the entity (or, the reverse, AddEntity() to the Component), and only once call the GameSystem::AddEntity() with the give entity.

You might want to provide a GameSystem::Update() as well as a ::Run() if some user would want to do things outside the Toasty Game Engine.

Also, you might want to provide built in methods of creating objects in your system instead of relying on new and delete (ex: GameSystem::CreateEntity(), which returns a entity, and GameSystem::DeleteEntity().  It may even use smart pointer under the cover).

Just a few thoughts I had while reading this.  I'd love to see how you create your systems as well.  Good luck, and keep it up!

Hey BeerNutts!

Yeah that is a good point, It's technically an entitycontainer, systemcontainer with helpful functionality and I'm not quite sure what to call it, any ideas? I am not so sure about calling it Framework or Engine...

I actually want to remove any dependency on GameSystem, it's more of a helper class (similar to Root in Ogre) which you don't have to use but makes things a lot easier on you. Not all systems will have to be the same, that's why I keep dependency injection in the constructor, if that's what the system needs then it needs it!

Same as above with this, each component should have it's dependencies in the constructor, if that happens to be a GameSystem then so be it (Although I think if it requires a GameSystem something is wrong).

So you would only add an entity once to the GameSystem then you would add it to any other system you want, like:

// Create an entity to attach a behaviour component to, 0 for the first param means
// that we don't want to use the message system.
Toasty::Entity* myFirstEntity = new Toasty::Entity();

// Create a new behaviour that we made (print entity name and FPS).
DebugInfoTest* test = new DebugInfoTest(system, myFirstEntity);

// Add the behaviour to the entity.

// Create a render component
2DRenderComponent* renderTest = new 2DRenderComponent("image.png");

// Add render component to the entity.


Because each system is (or should be) independant you must call AddEntity with the entity and component you want on each system you want it in. Entities do not know anything about the components that are 'attached' to it, although adding the entity to a component is a decent idea, I have it that way for fast component lookup if you have the entity pointer.

I may do this, not sure at the moment as the GameSystem should be something you can use easily, if you need more control you can just use the same classes that GameSystem uses (EntityContainer, SystemContainer, SceneContainer, UniqueIDHandler, MessageSystem) and customise the way it all works as much as you need.

I already have a DestroyEntity (It doesn't destroy the memory, but it removes all the components from all the systems in the GameSystem at the end of the current frame) and I'm thinking of overriding AddEntity to have no arguments and just return an Entity pointer.

Your thoughts were intriguing and have given me much to think about! I'm in the middle of writing the next update now so you can see that soon!

## Create an account

Register a new account