Sign in to follow this  
DonaldHays

Unity Component-based entities, looking for feedback (playable Asteroids clone!)

Recommended Posts

I love using javascript for prototyping. Its dynamic nature and relative simplicity helps me solve problems without worrying about memory management and such. I've been reading about component-based entities, and decided to try implementing a component-based entity system in a small game before attempting to develop one in a larger project. When trying to find hidden walls in a space that you don't understand well, it's often effective to just blindly run into them head first! Naturally, it's better to do this in a small, safe environment than a large one with much at stake. I chose to make a simple Asteroids clone. Please feel free to play it, download it, poke its code with a stick, etc. Edit: Oh, and BTW, the game depends on the canvas and audio tags. It'll run best in recent versions of Safari, Firefox, and Opera. There's a small audio issue in Chrome, and I don't think it'll work at all in IE. http://donaldhays.com/projects/spaceRockShooter/ I have a few thoughts and things I would like feedback on. The details of my approach. There is a core "class" called Entity. It is little more than a set of components, as well as some metadata like ids and types. I have some logic for dynamic retrieval of entities based on type and id. A component is an object encapsulating some data and logic. It has a reference to its associated entity. There aren't really any surprises here. The game has an event system. Anything can register to listen to events. Registration involves passing an entity to listen to, the name of the event, and the function to invoke when the event occurs. Anything can trigger an event. Triggering involves passing an entity to trigger the event on, the name of the event, and any miscellaneous data associated with the event. What is the virtue of a pure-aggregation approach? A commonly-cited article recommends a pure-aggregation model, where there is no explicit Entity type, and entities only exist in the sense that a set of different components share the same entity id. The article seemed light on reasons for doing this over the approach I took (my approach including an explicit Entity type). I'm not intuitively arriving at any real advantages to a pure-aggregation approach, so I'm just wondering if anybody could enlighten me. Sudden disappearing entity/component problem. When a bullet hits an asteroid, the asteroid reacts to the collision event by destroying itself and the bullet. This happens in the middle of a loop in the physics engine that iterates over all physics components. This results in a scenario where a list (the list of physics components) changes while it is being iterated over (the asteroid deletes itself and a bullet). This is an opportunity for error, and I indeed had some issues until I added some extra case-specific code. I didn't like the solution, though, and I'm wondering if anybody has a generic approach to these kinds of scenarios that doesn't involve sprinkling sanity checks everywhere. I think component-based entities were, on net, a pretty big win for me. This project only has about 1,000 lines of code, so it isn't very big, but it had a real vibe of coming together much more nicely than other projects of similar scope have. Methods are small and straightforward, modules aren't coupled all that tightly, things don't really feel like they're doing more jobs than they should, etc. I felt like I was able to just keep moving forward with feature adds or mutations to existing features without breaking things. It was nice.

Share this post


Link to post
Share on other sites
Firstly, that's a nicely structured game with very clean code.

In reply to your question "Sudden disappearing entity/component problem", what you have there is a synchronization issue (edit, actually it isn't, since it happens in a single thread, but the following still applies). There are a couple of ways you could fix it.

1. Make a copy of the physicsComponents array in physicsTick function. That way it won't change while you're using it, only on the next iteration.

2. Instead of remove entities directly from it, add all the entities to be removed to a separate list, and process that list after you've iterated through them all.

One odd thing I noticed was your worldWrapper component. Shouldn't this function be handled in the physics component? So rather than doing:
        position.x += velocityX;
position.y += velocityY;


do this instead:
        position.x = (position.x + velocityX) % width;
position.y = (position.y + velocityY) % height;



Another suggestion would be to split out the level logic into it's own entity/component, and have the gameRules component listen for a levelCompleted or playerDied events from it.

Regards
elFarto

[Edited by - elFarto on May 26, 2010 3:10:14 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by DonaldHays
What is the virtue of a pure-aggregation approach?

I haven't found it. I also have an explicit Entity class. It stores positional data, a list of components, and some metadata. I don't see any reason to move this data into components, since almost every other component needs it. It doesn't make sense to eliminate Entity just for the sake of a "pure" approach.

Quote:
Sudden disappearing entity/component problem. When a bullet hits an asteroid, the asteroid reacts to the collision event by destroying itself and the bullet. This happens in the middle of a loop in the physics engine that iterates over all physics components. This results in a scenario where a list (the list of physics components) changes while it is being iterated over (the asteroid deletes itself and a bullet). This is an opportunity for error, and I indeed had some issues until I added some extra case-specific code. I didn't like the solution, though, and I'm wondering if anybody has a generic approach to these kinds of scenarios that doesn't involve sprinkling sanity checks everywhere.

There's a bunch of ways to handle this. The simplest is to create a list of iterators referencing to-be-destroyed objects, and then erase each one in turn after the update.

Another way is to send out an EntityDestroyed message to every subsystem (including the one responsible for sending the message), and only remove components in response to this message. This way, the actual removal of the Entity from the list occurs whenever you do your message processing, not during the physics update. This will only work, of course, if your message processing doesn't occur instantaneously.

Quote:
I think component-based entities were, on net, a pretty big win for me. This project only has about 1,000 lines of code, so it isn't very big, but it had a real vibe of coming together much more nicely than other projects of similar scope have. Methods are small and straightforward, modules aren't coupled all that tightly, things don't really feel like they're doing more jobs than they should, etc. I felt like I was able to just keep moving forward with feature adds or mutations to existing features without breaking things. It was nice.

I've found the same. The system is easy to use and infinitely extensible. It's a definite winner for me.

Share this post


Link to post
Share on other sites
Quote:
Original post by elFarto
Firstly, that's a nicely structured game with very clean code.


Thank you kindly!

Quote:
Original post by elFarto
In reply to your question "Sudden disappearing entity/component problem", what you have there is a synchronization issue (edit, actually it isn't, since it happens in a single thread, but the following still applies).


A thought that went through my head when I was addressing the issue: "this would suck even more in a multithreaded world."

Quote:
Original post by elFarto
1. Make a copy of the physicsComponents array in physicsTick function. That way it won't change while you're using it, only on the next iteration.

2. Instead of remove entities directly from it, add all the entities to be removed to a separate list, and process that list after you've iterated through them all.

Quote:
Original post by Ariste
There's a bunch of ways to handle this. The simplest is to create a list of iterators referencing to-be-destroyed objects, and then erase each one in turn after the update.

Another way is to send out an EntityDestroyed message to every subsystem (including the one responsible for sending the message), and only remove components in response to this message. This way, the actual removal of the Entity from the list occurs whenever you do your message processing, not during the physics update. This will only work, of course, if your message processing doesn't occur instantaneously.


I tried a deferred deletion approach at first and ran into a somewhat different issue. If a bullet intersects multiple asteroids when it runs a physics step, it would destroy all intersecting asteroids before going away. While the player might be tickled happy with that, it's not what I wanted. To solve that issue the bullet would need to mark itself as spent in some way, and subsequent physics tests would need to check against that.

I like the deferred messaging, though. It reminds me a little of Cocoa's Event Loop architecture. I could queue up events, execute them in turn, and take any events out of the queue if their associated entities are destroyed. Seems a promising direction.

Quote:
Original post by elFarto
One odd thing I noticed was your worldWrapper component. Shouldn't this function be handled in the physics component? So rather than doing:
*** Source Snippet Removed ***
do this instead:
*** Source Snippet Removed ***


For whatever reason, I felt compelled to have the player's bullets not wrap around the world. To accomplish the same behavior in the physics component would require exposing a worldWrap flag in the physics component, which would not be unreasonable, but I wanted to try components in many many places :D. I seem to recall hearing of physics engines that get fussy if you let something other than the physics engine itself move an object around, so that probably gives more weight to allowing world wrapping only inside the physics component.

Quote:
Original post by elFarto
Another suggestion would be to split out the level logic into it's own entity/component, and have the gameRules component listen for a levelCompleted or playerDied events from it.


That's reasonable, particularly on the levelCompleted event. As-is the game rules determine when a level is complete based off the number of remaining asteroids, which is a piece of logic that could also appropriately be determined by a level entity.

Quote:
Original post by Ariste
I haven't found it. I also have an explicit Entity class. It stores positional data, a list of components, and some metadata. I don't see any reason to move this data into components, since almost every other component needs it. It doesn't make sense to eliminate Entity just for the sake of a "pure" approach.


That's what it seems like to me, it just appears to be a popular thing to do, and I'm wondering if there's a particular advantage to it versus just being trendy.

Share this post


Link to post
Share on other sites
If you can do away with Entities entirely, then it seems like a very clean approach. Just update each subsystem and each one updates the components it knows about. Why have it iterate over entities which typically have a one-to-one relationship with the components of interest? Couldn't all this per-entity data just become another type of component?

Share this post


Link to post
Share on other sites
Did not get a chance to look through code yet but I wanted to leave you a quick comment: I used it on Chrome and I didn't notice any bugs or audio bugs. I'm using the latest beta version of Chrome so I don't know if that is why I didn't notice them though.

Share this post


Link to post
Share on other sites
Quote:
Original post by Kylotan
If you can do away with Entities entirely, then it seems like a very clean approach. Just update each subsystem and each one updates the components it knows about. Why have it iterate over entities which typically have a one-to-one relationship with the components of interest? Couldn't all this per-entity data just become another type of component?

The thing is, some properties need to be visible to nearly every component. What's the point of sticking them in their own component? What do you gain?

Note that Entity doesn't even need to be updated. In my implementation, it's not. It's essentially a container for positional and rotational data with some metadata attached. Entities don't act; they're acted upon by their components. Moving Entity's data into its own subsystem would only complicate this process.

I also find it convenient to use Entity as an interface for component retrieval. If one component needs access to another component, it queries its Entity. This makes sense conceptually, and it's really easy to implement. You don't need to pass around pointers to every subsystem or some other such mechanism.

Share this post


Link to post
Share on other sites
Quote:
Original post by Ariste
Quote:
Original post by Kylotan
If you can do away with Entities entirely, then it seems like a very clean approach. Just update each subsystem and each one updates the components it knows about. Why have it iterate over entities which typically have a one-to-one relationship with the components of interest? Couldn't all this per-entity data just become another type of component?

The thing is, some properties need to be visible to nearly every component. What's the point of sticking them in their own component? What do you gain?

Note that Entity doesn't even need to be updated. In my implementation, it's not. It's essentially a container for positional and rotational data with some metadata attached. Entities don't act; they're acted upon by their components. Moving Entity's data into its own subsystem would only complicate this process.

I also find it convenient to use Entity as an interface for component retrieval. If one component needs access to another component, it queries its Entity. This makes sense conceptually, and it's really easy to implement. You don't need to pass around pointers to every subsystem or some other such mechanism.


In your engine, you've made an assumption that every entity has a position.

Consider for a moment that you have an entity that simply plays music. It's not environmental - it just plays music at an adjustable volume. It has no spatial location, so why suggest that it does by including position in the Entity class? If you have an Entity class, I believe it should be as light weight as possible, presenting the bare minimum required for finding components and identifying them.

Share this post


Link to post
Share on other sites
In thinking about how I would go about implementing a component-based entity system in plain-old-c (which has been, shall we say, an interesting exercise), I've been finding that there would likely be little difference for me between a system with a dedicated Entity type and a pure-aggregation system. While in my current javascript code all components hold references to their associated entity, in a pure-aggregation approach they would simply have an entity id.

For a component to get another component on the same entity, the interface in plain-old-c would be nearly the same for either system. It would involve calling a getComponentForEntity function, passing either the pointer to the entity in the entity-type system, or the entity id in the pure-aggregation system. The most significant difference would be in performance. Holding a reference to the entity directly grants o(1) access to the entity's collection of components. Needing to lookup the entity given its id involves a likely hashtable search. Both approaches would obviously then need a search of the component collection. Now, would that performance difference actually be problematic? Probably not in the kinds of games I wish to make, no.

I think, at this point, the biggest thing tripping me up is just the weird vibe I get from the pure-aggregation approach. To not have any actual objects that exist that I can point to and say, "that right thar is the entity!" is weird. It's not like the vibe I got when I learned how absolutely everything is an object in Smalltalk (even the classes!), which was like an eye-opening enlightening experience.

My plan has been to try writing the asteroids game several times. I think there's a decent chance that only one rewrite will suffice for my learning purposes. The rewrite was planned from the beginning to try to mimic a pure-c approach (structs and functions, not objects), but now I think I'll also try the pure-aggregation approach, just to see how it goes.

Also, just to comment on one other thing, the entities in my asteroids code do not have position or orientation data, for precisely the reason pointed to by Sphet: not all entities have position or orientation. In particular, my GameRules entity is just such an entity. My entities have a collection of components, a uid used by the system for bookkeeping purposes, a user-settable string id that can be used to get the entity from a global context (getEntityById("gameRules"), getEntityById("player")), and a user-settable type string ("asteroid", "playerShot", "playerShip", etc). That seems a reasonable set of information for an entity to have to me.

Share this post


Link to post
Share on other sites
My approach to entity deletion is slightly different.
First off, all logic is solely handled via Components.
Entity is just a container for Components and has no logic besides updating its chil entities and components recursively.

Hence inside the component.OnUpdate call, you cannot remove the Entity and/or Component due to the iterator being changed.

What i did to solve this is pretty simple.
A Component exposes a Destroy(Entity entity) method and stores the reference in a static list.
The main game loop then scans the list at the end of the frame, removes the entities in question from the hierarchy and calls their virtual OnDestroy method for finalization.

Works like a charm and even works very well if you use multiple entity hierarchies in parallel.

Share this post


Link to post
Share on other sites
I know this thread is a year old now but I'm so glad to find it :).
It is kinda hard to find info on component based game design in javascript.

Are you still coding js-games? [b]Should we code something together?[/b]

I made this "game" using a component based approach: [b][url="http://game.sylt.nu/example"]http://game.sylt.nu/example[/url][/b]
Use arrow-keys or wasd. Change zoom using scroll-wheel.

My component based approach is quiet different from the one in your asteroids game.
[b]I wrote an article on it: [url="http://jsteam.org/component-based-entities/"]http://jsteam.org/co...based-entities/[/url][/b]
[b]
Is my approach even component based?[/b] I have no logic in the components. Only state.
What I find being awesome about this is that there are much fewer references between components and entities (none at all actually).
The subsystems contains all the logic and works on an entity (as opposed to a component) and thus the problem of communication
between components disappears.

What do you think about my approach [b]I could really use some feedback[/b] :mellow:

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Forum Statistics

    • Total Topics
      627784
    • Total Posts
      2979036
  • Similar Content

    • By KARTHI
      Now I am making 2d Game. I want to sell the game in playstore as a paid game but I didn't know how to reach the player so please someone tell me how to make them to download quickly
    • By Ahrakeen
      Hello our team aare making the game Neo arcana a logical crisis. and w are presently searching for some graphics people to help with the models for the game.
      we are using the setting of urban arcana and the game will be a strategic roleplaying game. in so we are in need of help with the graphics.
      if you interested to aiding us with your skills let us know. we are presently working on the prologue with the aim of finishing the story of some of the things that happened back then.
      to set up the story for the main game itself where tim is now trying to regainw hat he has lost back then. And manuever in the strange world that is hidden beneath the surface of the city.
       
      We aim with the prologue done turning it into a demo to get funding . so i hope to get more help with this.
    • By Hacktion Architects
      Hey guys me and my team have made our first game! Would be awesome if you guys could download, play it and let us know what you think!

      3. 2. 1. GO! Fly through the local school grounds with three other drones vying for the fastest time. Racing past the football fields, weaving in between pillars and squeezing through tight corridors, in Drozone speed is everything.
      Race through checkpoints while keeping your eyes out for power ups that give you a big short burst of speed, but be careful not to lose control!
      And if you're having problems completing the course you will want to grab the shield power up to double your health.
      Pick your drone and start racing, will you be able to beat our fastest lap time?
      Trailer here:
      https://www.youtube.com/watch?v=tekETULy2Qk&feature=youtu.be
      Link to download:
      https://gamejolt.com/games/drozone/292176
      A game developed by a group of seven young indie devs, from Brisbane Australia, Drozone is focused on delivering the exhilaration of flying a drone in first person.
      The experience is built up around competition between players and seeing who can get the fastest time. Let us know what you’re fastest time is!
    • By Polycanic Studios

      Everybody's favorite hard hitting reality blood sport is back and is better than ever. Join your host Miss Midnight and enter the Graviators arena for a new and thrilling style of combat.
      Graviators is a 3rd person arena based brawler in which you can play online multiplayer and LAN multiplayer with up to 4 friends or test your skills in our single player mode. Choose your fighter, control your gravity and fight using each characters unique ranged and melee attacks. 

      Download now at: www.graviators.com or watch the Trailer
      Graviators is currently released but will be receiving updates to make improvements and fix any issues so please bear with us! If you want to know more about what we are up to, follow us here for regular devlogs or check out our Facebook or Twitter for updates. 
      If you want to get in contact with us, please feel free to comment here, polycanicstudios@gmail.com or send us a message on Facebook!
    • By INTwindwolf
      COMPANY AND THE PROJECT

      We are an indie game studio consisted of professional and friendly people. Additionally, we are a team of skilled artists and dedicated indie enthusiasts. Our current project is INT, developed on Unity Engine 5 for platforms Windows, Linux, and Mac.

      INT is a 3D Sci-fi RPG with a strong emphasis on story, role playing, and innovative RPG features such as randomized companions. The focus is on the journey through a war-torn world with fast-paced combat against hordes of enemies. The player must accomplish quests like a traditional RPG, complete objectives, and meet lively crew members who will aid in the player's survival. Throughout the game you can side and complete missions through criminal cartels, and the two major combatants, the UCE and ACP, of the Interstellar Civil War.
      Please note that all of our current positions are remote work. You will not be required to travel.
      For more information about us, follow the links listed below.
      INT Official website
      Steam Greenlight
      IndieDB page
      Also follow social media platforms for the latest news regarding our projects.
      Facebook
      Twitter
       
      TALENT NEEDED
      We are looking for an Animator to join the Art team to create and polish animations for the game. You will be collaborating with fellow members of the team, and follow instructions from the Project Lead and the Animation team Lead in crafting smooth, flowing animations.
      As an Animator for this project, your duties would include:
      Create rigs to be used for animations. Skin 3D models to rigs. Contribute to constructive team discussions. Attend regular team meetings.  
      REQUIREMENTS
      To be successful in this position, following requirements apply:
       
      Have working knowledge of 3D animation suites. Understand import/export requirements for Unity Engine integration. Excellent self-management skills. Excellent attention to detail. Excellent communication skills. Preferred requirement:
      Knowledge of the Unity Engine UMA character creation system would be an advantage.  
      REVENUE - SHARE
      This is the perfect opportunity to get into the game development industry. Being an Indie team we do not have the creative restrictions often imposed by publishers or other third parties. We are extremely conscientious of our work and continuously uphold a high level of quality throughout our project.
      We are unable to offer wages or per-item payments at this time. However revenue-sharing from crowd-funding is offered to team members who contribute 15-20 hours per week to company projects, as well as maintain constant communication and adhere to deadlines. Currently the crowd-funding campaign is scheduled for the year 2018. Your understanding is dearly appreciated.
       
      TO APPLY
      Please send your Cover Letter, CV, Portfolio (if applicable), and other relevant documents/information to this email: JohnHR@int-game.net
      Thank you for your time! We look forward to hearing from you!
      John Shen
      HR Lead
      Starboard Games LLC
  • Popular Now