Saturday, January 16, 2016

BobEngine has been Updated to an Entity-Component System

Enhanced Logo

It may have seemed like I just dropped off the face of the Earth for the past month or more but there are a few reasons for that. First, it was the end of the semester so I was very busy studying for final exams! Then it was Christmas break and I had just bought GTA V and gotten A Link Between Worlds as gift so I put some hours into those... :) But I wasn't totally slacking on my Android work! In the time since the last tutorial video I made I've been working on a massive over-haul of BobEngine.

Updates can always be found at https://github.com/Bobbyloujo/BobEngine

The update, which I just pushed to GitHub before writing this, introduces a new Entity-Component design system to BobEngine that is still mostly compatible with all the old features and uses of BobEngine. I should note: some things from the old version have been removed and package names and hierarchy has changed. Most of the things that were removed were poorly implemented features that I think most people did not use anyway. Among the features removed was the collision system, however it was replaced with a better system which I will go into later in this post. Many projects will be able to move over to the new version will little trouble, however imports will need to be fixed.

Let me talk about what an Entity-Component design system is and how I decided to implement it into BobEngine. The simplest definition I give is this: in an Entity-Component system every object in the game is defined as entity (player, enemies, coins, etc) which are composed of components which can hold data or add functionality to the entity (health variables, movement logic, input handling, etc).

BobEngine has been revamped to be centered around an Entity class and Component interface. The Component interface is empty and used as a marker interface. You can create any component you want just by implementing (or extending!) the Component interface. It can then be added to entities and has the benefit of being retrievable from the entity by component type.

Why did I choose to make Component an interface? I wanted to be able to make components that are a combination of different functionality. Let me explain:

There are some special component types in BobEngine that extend the Component interface. These include Updatable, TouchInputHandler, and others that help add functionality to components. For example, Updatable adds the method update(double deltaTime). ANY component that implements the Updatable interface and belongs to an entity in the current room will be updated via its update(double deltaTime) event each frame. TouchInputHandler works similarly but includes events for handling input from the touch screen. So, you want to make a component that updates every frame AND can handle touch input? Simple. This way you can just implement both interfaces!

An Entity in BobEngine is also a component. One effect that this has is that an entity can be a collection of other entities. This could be helpful for something like a large boss that consists of multiple parts.

Also, because of the way I implemented components it is possible to give entities functionality like updating and input handling. This allowed me to convert GameObject to an entity while keeping the usage of GameObject almost the same. The only major difference to the use of GameObject is the removal of the Quad inner class, but good riddance to that. The same functionality that Quad provided can be obtained more simply with the Entity-Component system.

Also worth mentioning: Rooms are also now entities and can be given components.

For those of you who have invested time in working through the video tutorial series, you'll be happy to know that everything learned in that series is still usable. More tutorials will be made to teach you how to use the new functionality.

So, other than the switch to an Entity-Component system, what else is new?

The New Collision System

I mentioned earlier that the old collision system had been entirely removed and replaced with a new one. So what is the new system like? You'll find that there is a new class called CollisionSystem accompanied by CollisionBox and CollisionHandler. A CollisionBox is a component that can be added to an entity and as you might have guessed it defines the bounds of a box used for the detection of collisions. A CollisionHandler can be assigned to a CollisionBox so that when that box collides with another the collision event can be handled. Entities with CollisionBox components can be added to a CollisionSystem which will check for collisions between the boxes and dispatch collision events to the CollisionHandlers! A new example is included in the Android Studio project which demonstrates a few different uses of the collision system.

Parent Transformations and other fun tricks

In the new BobEngine transformations (position, rotation, dimensions) are handled with Transformation components. This allowed me to implement a new feature: parent transformations! Have a player entity and you need to his cape to stay on his back as he moves around? No problem! Just set the cape's tranformation's parent to the player's transformation! The cape's new "origin" will be the position of the player, so the cape can now be easily positioned relative to the player! This also effects scale (which is also a new feature!) and rotation! You can see how I played around with this in the example bobEngineTest with the entity BobEngineMothership.

This is also fantastic for large, multi-part entities.

The "BobEngine mother ship" composed of 7 separate entities

Room Grid

Rooms now use a grid to place objects on the screen. By default, the size of one grid unit is one pixel so it will behave just like before. However, you can now set the size of the grid units manually and independently for the X and Y axes. The size of a grid unit can be set as a number of pixels or such that a specific number of units will fit in width or height of the screen. I recommend the latter and here's why: the getRatioX() and getRatioY() methods have been deprecated. Any sizing or positioning of objects on the screen will use grid unit rather than pixels. So if you set your grid to be 20 units wide, an object with a width of 10 will always be half the width of the screen no matter the actual size of the screen. Also, if the object starts at an X position of 0 and moves 1 unit per frame, it will always take 20 frames for the object to move across the whole screen regardless of actual screen dimensions.

Jumpy Bug has been updated in many ways to demonstrate usage of all the new features including the new grid feature.

Closing Thoughts

There are some other fun things in store for you when you check out the new version of BobEngine. The numbers and characters graphics have been updated, the out-of-place utility functions in Room (getAngleBetween(), etc) have been moved to a Util class, and some other things have just been reorganized in ways that make more sense then before.

I really feel like this update opens the door for many new use cases for BobEngine and will help make BobEngine one of the best open-source engines for Android. This update also creates a lot of room for expansion, such as the possibility of OpenGL ES 2.0 support and other great features. I will be changing up my workflow a little bit after this update. You may start to see more frequent but smaller updates from here on out. This new version will not be given a new version name and will just be referred to as BobEngine.

If you find any bugs or have some suggestions or insights, please do let me know. The decision to make this change was made after some discussion on Reddit and it really helped me improve my engine. I'm all ears!

As always, if you have any questions feel free to ask. You can contact me on social media or via email:


Email: bobbyloujo@gmail.com

Happy developing,
Benjamin Blaszczak

No comments:

Post a Comment