• Content count

  • Joined

  • Last visited

Community Reputation

730 Good

About dave19067

  • Rank

Personal Information

  1.   Thanks for the ideas.  I will probably go with the traditional "Floor" design with portals to move between them since it would be easier to develop, and have each floor be a large map so the player gets the open-ended feeling from being in outer-space.  The game will probably feature a large boss, but the player can keep playing in the current world as long as they want after they beat it, e.g. maybe by having infinite procedurally generated quests.         I've been trying to find the name of this game since working on this idea.  I played Transcendence a lot around 3 years ago and it will have a big influence on my game, especially the portal system and how shops work.         I've never heard of this game before, but I'll have to play it.  From looking at the overview, it has a lot of similar features to what I would want to implement in my game such as the crew skill system.  My game won't be anywhere near the scope of Approaching Infinity, since I'll probably forego the planet exploration gameplay and focus on space exploration.
  2. Hey guys,   I was thinking of a game idea I would like to design on, a roguelike set in outerspace in which you control a spaceship and you can move freely throughout the map.  It would have most traditional roguelike elements, e.g. permadeath, but unlike a traditional roguelike, would not have confined spaces/mazes due to the outerspace theme.   What do you think would be the best map/gamespace design for this type of game and why?   I was thinking of two possibilities:   1. Floors: Have each level be limited in width/height.  You can still move freely within the level, but there would be an invisible boundary preventing you from going outside the level.  The player can get to new levels by going through wormholes, analogous to stairs or portals in traditional roguelikes.  Similarily, you could have special levels, e.g. one with a puzzle where you move asteroids around to get to a special item.   2. Open-ended: The world is just one huge map, e.g. GTA or Elder Scrolls.  You would have different areas, e.g. an area with allies and shops, an area with asteroids and environmental dangers, an area with an enemy faction, a puzzle area.   Thanks, David
  3. Entities-Parts I: Game Objects

    Sorry for the late response.  I haven't dealt with a situation like that where I would need parts to be updated in a certain order.  In that case, you can probably modify the Entity class to use SortedMap instead of HashMap.  Another solution is to add another method to your physics part called preUpdate(), which can be called before the main update stage.
  4. Background Download RPG Battle Example and Java version of Entities-Parts Framework Download C++ version of Entities-Parts Framework I. Game Objects II. Interactions III. Serialization (current) The previous articles focused on entity structure and interaction. In the previous version of the RPG Battle Example, all of the code that defined the entity attributes was in the CharacterFactory. For example, it contained code to set the health of the meleer character to 200 and add spells to the support mage. We now want to move entity data out of the code and into data files. By storing the entity data in files, we can conveniently modify them without compiling the code. In addition, the data files could be reused if the code was ported to another language. This will be the last article in the series and covers serialization. For the purposes of this article, I chose XML and JAXB. If you aren't familiar with these technologies, I recommend googling about them as the article revolves heavily around them. Note that JAXB library refers to conversion between objects and data as marshalling, but this article will use the term serialization. The advantages of XML are that it is a popular way to store data and is human-readable. JAXB is a powerful XML serialization framework packaged with Java EE 6 that uses annotations to mark serializable classes and fields. Using the annotations as hints, JAXB automatically de/serializes class instances and does much of the grunt work for us. The main drawback of JAXB is that it is slower to serialize/deserialize data compared to binary serialization frameworks such as Kryo and Java Serialization. In 1,000,000 runs of a serialization perfomance test, JAXB unmarshalling (a.k.a deserialization) took 249972ms, while Kryo took only 2557ms (Performance Comparison). There are many viable ways to serialize/deserialize entities so I decoupled serialization code from general-purpose classes such as Entity and Part. This makes the code easy to modify if you want to switch to another serialization framework. Even if you decide to use another serialization framework, I hope this article gives you an idea of what issues or general approaches are associated with data serialization. RPG Battle Example (continued) The top of the article contains the download link for the RPG Battle Example. The RPG Battle Example has been updated to use JAXB serialization to load entities from files. The serialized files of the character entities are stored in the relative project path "data/characters/". Through the help of a program I created called EntityMaker.java, I used the old character factory, now renamed to CharacterFactory_Old, to serialize the entities to XML files. The following is the "meleer.xml" file: 0.0 0.0 0.01 0.03 200.0 Sword 25.0 50.0 CLOSE MONSTERS OFFENSIVE The XML contains elements that represent the entity and the individual parts. Notice that not all variables are stored. For example, the Entity class has variables isInitialized and isActive that don't appear in the file above. The values for these variables can be determined at runtime so they don't need to be stored. The attributes xmlns:xsi and xsi:type are needed by JAXB to deserialize the data to the necessary type. As you might imagine, it is very convenient to edit entities on the fly without compiling the whole program again. The human-readable XML format allows us to easily change entity behavior by updating existing part elements or add new part elements, e.g. a FlyingPart element to the "meleer.xml" file. The CharacterFactory from part II has been refactored to contain only one method instead of several methods to create each character. The path to the XML file containing the serialized Entity is passed into the createCharacter method which converts the file to an Entity. XmlUtils is a helper class I created that serializes/deserializes between XML and Java objects. I will describe what the arguments to the read method represent later on in the article. public class CharacterFactory { /** * Creates an character entity from a file path. * @param path path to the serialized character definition * @param name * @param alliance * @return new character */ public static Entity createCharacter(String path, String name, Alliance alliance) { Entity character = XmlUtils.read(Paths.CHARACTERS + path, new EntityAdapter(), Bindings.BOUND_CLASSES, "bindings.xml"); character.get(DescriptionPart.class).setName(name); character.get(AlliancePart.class).setAlliance(alliance); return character; } } In order to make a class recognized by JAXB for serialization, we add annotations such as @XmlRootElement and @XmlElement to the class. For example, the following classes EquipmentPart and SummonSpell contain annotations: @XmlRootElement public class EquipmentPart extends Part { @XmlElement private Weapon weapon; @XmlElementWrapper @XmlElement(name = "spell") private List spells; ... @XmlRootElement public class SummonSpell extends Spell { @XmlJavaTypeAdapter(EntityAdapter.class) @XmlElement private Entity summon; ... In case you don't know already, here are what the annotations mean: @XmlRootElement - Creates a root element for this class. @XmlAccessorType(XmlAccessType.NONE) - Defines whether properties, fields, or neither should be automatically serialized. The XmlAccessType.NONE argument means that by default, variables and properties will not be serialized unless they have the @XmlElement annotation. @XmlElement(name = "spell") - This annotation defines fields or properties that should be serialized. The argument name = "spell" says that each Spell object in the list of spells should be wrapped in the tags. @XmlElementWrapper - This wraps all of the individual elements in a tags. @XmlJavaTypeAdapter(EntityAdapter.class) - The Entity field will be serialized and deserialized using the specified XML adapter passed in as the argument. Obstacles Ideally, it'd be nice to add annotations to our classes and just let our serialization framework do the rest of the work without any more effort from us. But often there are obstacles with serialization, such as classes that we don't want to or can't add annotations to. The following sections describe solutions for these issues and may be a little confusing because it goes into more advanced usage of JAXB: XML Adapters and Bindings. XML Adapters Since the classes Entity and Part can be reused in multiple games, we want to avoid adding JAXB annotations to these classes or modifying them to fit a specific purpose such as serialization. However, de/serializing unmodifiable classes requires some workarounds which I'll describe. The first step to making Entity serializable is creating an XmlAdapter to convert Entity to a serializable class. We add two new classes, the serializable class EntityAdapted and the adapter EntityAdapter which is derived from the JAXB class XmlAdapter. The EntityAdapted class contains the fields from Entity that need to be serialized such as parts and contains JAXB annotations. The EntityAdapter class converts between the unserializable form, Entity, and the serializable form, EntityAdapted. EntityAdapter is referenced in SummonSpell because SummonSpell contains a reference to an Entity and is also used in the CharacterFactory.createCharacter method. @XmlRootElement(name = "entity") public class EntityAdapted { @XmlElementWrapper @XmlElement(name = "part") private List parts; public EntityAdapted() { } public EntityAdapted(List parts) { this.parts = parts; } public List getParts() { return new ArrayList(parts); } } public class EntityAdapter extends XmlAdapter { @Override public EntityAdapted marshal(Entity entity) throws Exception { EntityAdapted entityAdapted = new EntityAdapted(entity.getAll()); return entityAdapted; } @Override public Entity unmarshal(EntityAdapted entityAdapted) throws Exception { Entity entity = new Entity(); for (Part part : entityAdapted.getParts()) { entity.attach(part); } return entity; } } Bindings We would like to add the @XmlTransient annotation to Part because we don't want to store any fields in that class. There is a way to add JAXB annotations to a class without modifying the class. If you noticed, "eclipselink.jar" was added to the project. This is a 3rd party library that allows JAXB annotations to be added to unmodifiable classes by defining the annotations in an XML file. This is what the bindings.xml file looks like and you'll notice that it contains an element to make Part xml-transient. When serializing a list of an abstract type, e.g. the parts in the EntityAdapted class, the serializer needs to know what subtypes of Part could exist in the list. As you saw in the createCharacter method of the CharacterFactory, you'll see that Bindings.BOUND_CLASSES is passed in as an argument to XmlUtils.read. This static list contains the classes that JAXB needs to know in order to serialize the list of parts with the data in the subclasses of Part. public class Bindings { /** * Required for serializing list of base types to derived types, e.g. when a list of parts is serialized, binding * the health part class to the serialization will allow health parts in the list to be serialized correctly. */ public static Class[] BOUND_CLASSES = new Class[] { HealSpell.class, SummonSpell.class, AlliancePart.class, DescriptionPart.class, EquipmentPart.class, FlyingPart.class, HealthPart.class, ManaPart.class, MentalityPart.class, RestorePart.class, TimedDeathPart.class }; } In the entityparts.parts package, there is a file called "jaxb.properties". This file must be added to a package of any class included in BOUND_CLASSES above. See JAXBContext for more information. Final Notes The article described the basics of using JAXB to serialize entities and parts. Also, some of the more advanced features of JAXB such as XMLAdapter were used to overcome obstacles such as unmodifiable classes. In addition to JAXB, I recommend taking a look at these serialization frameworks: SimpleXML (Java) - An easy-to-use, lightweight alternative to JAXB. If you're developing an Android app, I recommend this over JAXB. Otherwise, you need to include the 9 megabyte JAXB .jar with your app (see JAXB and Android Issue). The SimpleXML .jar file is much smaller, weighing in at less than 400kb. I haven't used any of these libraries, but they are the most recommended from what I've researched: JSONP (Java) - JSON is a human-readable format that also holds some advantages over XML such as having leaner syntax. There is currently no native JSON support in Java EE 6, but this library will be included in Java EE 7. Kryo (Java) - According to the performance comparison (Performance Comparison), it is much faster than JAXB. I'll probably use it in a future project. The downside is it doesn't produce human-readable files, so you can't edit them in a text editor. Protobuffer (C++) - A highly recommended serialization framework for C++ developed by Google. Article Update Log 25 May 2014: Initial draft.
  5. Entities-Parts III: Serialization

    Hi DeVisscha,   I was actually considering JSON for this article.  JSON syntax is leaner and would fit this case well.  The only reasons I didn't go with JSON is because I have little experience with it and would require importing another 3rd party library because there isn't any support for it in Java EE 6.
  6. Entities-Parts II: Interactions

    Good question.  I don't have experience working on a large-scale game, but I think you can combine both approaches in a game/engine:   In the Entities-Parts implementation, components have access to other components if they're from the same entity.  Put update logic in a component if it only needs to reference it's member variables or components of it's parent entity, e.g. the RestorePart in the example.   If you have logic that requires references to components from multiple entities or knowledge of the outside world, probably best to put the logic in a high-level class such as a system.  In the example, the BattleSystem is used to handle A.I. and targeting logic because they require access to a list of entities.
  7. Background I. Game Objects II. Interactions (current) III. Serialization The previous article in the series, Game Objects, gave a broad overview of entities and parts, an implementation for the Entity and Part class, and a simple example showing a lopsided fight between a monster Entity and a helpless villager Entity. It was basic enough to demonstrate how to use the Entity and Part classes but it didn't address entity management or interaction in detail. In addition to addressing these topics, the example will be expanded so that the villager's friends will join the battle against a mob of monsters. The previous article focused more on how entities and parts were structured. In this article, I will focus on ways to handle interactions between high-level classes, entities, and parts. Some examples of interactions are A.I. to target enemies or support allies, spell effects such as healing and summoning, and dealing damage to another character. I will also introduce a new class to the Entity-Parts framework: EntityManager, and an event system. The implementation of the framework will be provided in Java and C++ w/boost. Handling Interactions Interactions between Parts of the same Entity Putting logic in parts is a good idea when you want to model interactions between parts of the same entity. For example, a part for health regeneration could simply get the health part of its parent entity and increase the health every update step. In the Entities-Parts framework you add logic to parts by overriding the initialize, update, or cleanup methods. Interactions between Multiple Entities Putting logic in high-level classes such as systems and managers is a good idea when you want to model interactions between entities. For example, an Entity such as a warrior will need a list of enemy entities to attack. Implementing all of this logic in parts is difficult because the parts would be responsible for finding references of enemy entities to damage. As seen in the previous article's MonsterControllerPart, it is difficult to pass in references to other entities to parts without issues appearing. A better approach is to have a high-level class, e.g. a BattleSystem, become responsible for finding enemy entities because they inherently keep references to all entities. Events Events are commonly used in programming and are not restricted to games. They allow objects to immediately perform actions when something interesting happens. For example, when a missle receives a collision event, its collision event handler method makes it explode. In this fashion, the missle doesn't have to check each frame if it collided with anything, only when the collision happened. Events can sometimes simplify interactions between multiple objects. Event managers allow an object to wait on a certain event to happen and then act upon it while being decoupled from objects publishing the event. An event manager is a centralized hub of event publication/subscription that allows entities or other systems to simply subscribe to the event manager instead of the individual objects who are publishing the events. Likewise, the publishers can just publish an event to the event manager and let the event manager do the work of notifying the subscribers of the event. For example, the entity manager listens for an event where a new entity is created. If a new entity is spawned, say by a summon spell, the entity manager receives the event from the event manager and adds the new entity. It doesn't have to contain a reference to the summon spell. RPG Battle Example (continued) Now that we've discussed a high-level overview of handling interactions between high-level classes, entities, and parts, let's continue the example from the previous article. The RPG Battle Example has been completely refactored to support a larger battle between two teams of characters: Monsters vs. Villagers. Each side will have a Meleer, Ranger, Flying Ranger, Support Mage, and Summoner. Monster names start with M. and villager names start with V. Here is output of a round of combat in the updated example. Each character's information is displayed as well as the action it took during the current simulation time: SIMULATION TIME: 3.0 M.Meleer1 is dead! M.Ranger1 - Health: 89.25 - Mana: 0.0 Attacking with Bow. 34.0 damage dealt to V.Ranger1 M.FlyingRanger1 - Health: 100.0 - Mana: 0.0 Attacking with Bow. 23.0 damage dealt to V.Ranger1 M.SupportMage1 - Health: 100.0 - Mana: 56.0 Casting Light Heal. Healed 30.0 health on M.Ranger1 M.Summoner1 - Health: 100.0 - Mana: 39.0 Attacking with Staff. 14.0 damage dealt to V.Ranger1 V.Ranger1 - Health: 28.25 - Mana: 0.0 Attacking with Bow. 29.0 damage dealt to M.Ranger1 V.FlyingRanger1 - Health: 100.0 - Mana: 0.0 Attacking with Bow. 21.0 damage dealt to M.Ranger1 V.SupportMage1 - Health: 100.0 - Mana: 34.0 Casting Light Heal. Healed 30.0 health on V.Ranger1 V.Summoner1 - Health: 100.0 - Mana: 39.0 Attacking with Staff. 12.0 damage dealt to M.Ranger1 Demon - Health: 100.0 - Mana: 0.0 Attacking with Claw. 28.0 damage dealt to V.Ranger1 Demon - Health: 100.0 - Mana: 0.0 Attacking with Claw. 21.0 damage dealt to M.Ranger1 Now, let's walk through key sections of the example code. Character Creation In the updated example, characters of differing roles are created using a CharacterFactory. The following is a helper method to create a base/classless character. Note the parts that are added. They provide an empty entity with attributes that all characters should have such as name, health, mana, stat restoration, alliance (Monster or Villager), and mentality (how the AI reacts to certain situations). private static Entity createBaseCharacter(String name, float health, float mana, Alliance alliance, Mentality mentality) { // create a character entity that has parts all characters should have Entity character = new Entity(); character.attach(new DescriptionPart(name)); character.attach(new HealthPart(health)); character.attach(new ManaPart(mana)); character.attach(new RestorePart(0.01f, 0.03f)); character.attach(new AlliancePart(alliance)); character.attach(new MentalityPart(mentality)); return character; } Then, there are methods for creating specific characters such as the flying ranger. The method to create the flying ranger calls createBaseCharacter method to create a base character with 100 health, 0 mana, and an Offensive Mentality that tells it to attack with its weapon and ignore defense or support. We add the equipment part with a bow weapon that does 15-35 damage and the flying part to make a base character a flying ranger. Note that weapons with an AttackRange of FAR can hit flying entities. public static Entity createFlyingRanger(String name, Alliance alliance) { Entity ranger = createBaseCharacter(name, 100, 0, alliance, Mentality.OFFENSIVE); Weapon bow = new Weapon("Bow", 15, 35, AttackRange.FAR); ranger.attach(new EquipmentPart(bow)); ranger.attach(new FlyingPart()); return ranger; } As you can see, it is relatively easy to create numerous character roles or change existing character roles through reuse of parts. Take a look at the other CharacterFactory methods to see how other RPG classes are created. Entity Management The EntityManager is a centralized class for entity retrieval, addition, and removal from the game world. In the example, the EntityManager keeps track of the characters battling eachother. The list of characters is encapsulated in the Entity Manager to prevent it from being accidentally altered or replaced. The game loop uses the entity manager to retrieve all the entities and update them. Then, update is called on the entityManager so that it updates its entity list according to recently created or removed entities. Main.java: for (Entity entity : entityManager.getAll()) { entity.update(delta); } entityManager.update(); Events To create a summoner with a summon spell, we need to find a way to notify the EntityManager that a new entity has been summoned so the EntityManager can add it to the battle. This can be accomplished with events. The EventManager is passed to the summon spell's use method and it calls the notify method on the EventManager to notify the EntitySystem to add the summoned Entity. In the entity manager's constructor, it called a method to listen for the EntityCreate event. The classes that make up the event are the EntityCreateEvent and the EntityCreateListener. I didn't create the original event manager class so I can't take credit for it. See Event Manager for the original implementation and details on creating event listener and event classes. Note: The C++ version of the EventManager works differently using function bindings instead of event listeners. The comments in the file 'EventManager.h' will show you how to use it. Summon spell: public class SummonSpell extends Spell { private Entity summon; public SummonSpell(String name, float cost, Entity summon) { super(name, cost); this.summon = summon; } public void use(EventManager eventManager) { HealthPart healthPart = summon.get(HealthPart.class); healthPart.setHealth(healthPart.getMaxHealth()); eventManager.notify(new EntityCreatedEvent(summon)); System.out.println("\tCasting " + name); } } Event for entity create: public class EntityCreateEvent implements Event { private Entity entity; public EntityCreateEvent(Entity entity) { this.entity = entity; } @Override public void notify(EntityCreateListener listener) { listener.create(entity); } } EventListener for entity created: public interface EntityCreateListener { public void create(final Entity entity); } Stat Restoration In the example, characters regenerate health each timestep. The RestorePart increases the health and mana of its parent Entity every time its update method is called. It interacts with the HealthPart and ManaPart and updates their state. public class RestorePart extends Part { private float healthRestoreRate; private float manaRestoreRate; public RestorePart(float healthRestoreRate, float manaRestoreRate) { this.healthRestoreRate = healthRestoreRate; this.manaRestoreRate = manaRestoreRate; } @Override public void update(float dt) { HealthPart healthPart = getEntity().get(HealthPart.class); float newHealth = calculateRestoredValue(healthPart.getMaxHealth(), healthPart.getHealth(), healthRestoreRate * dt); healthPart.setHealth(newHealth); ManaPart manaPart = getEntity().get(ManaPart.class); float newMana = calculateRestoredValue(manaPart.getMaxMana(), manaPart.getMana(), manaRestoreRate * dt); manaPart.setMana(newMana); } private float calculateRestoredValue(float maxValue, float currentValue, float restoreRate) { float manaRestoreAmount = maxValue * restoreRate; float maxManaRestoreAmount = Math.min(maxValue - currentValue, manaRestoreAmount); float newMana = currentValue + maxManaRestoreAmount; return newMana; } } Battle System The BattleSystem is where high-level interactions between entities are implemented, e.g. targeting and intelligence. It also contains rules of the game such as when an entity is considered dead. In the future, we might want to create an AI System to handle targeting and just have the Battle System control the rules of the game. But, for a simple example it's fine as it is. In the following code snippet of the BattleSystem, note that it is using each character's Mentality part to specify how it will act in the current turn. The BattleSystem also resolves the issue from the last example of providing potential targets for attacking and supporting. public void act(Entity actingCharacter, List characters) { Mentality mentality = actingCharacter.get(MentalityPart.class).getMentality(); if (mentality == Mentality.OFFENSIVE) { attemptAttack(actingCharacter, characters); } else if (mentality == Mentality.SUPPORT) { boolean healed = attemptHeal(actingCharacter, characters); if (!healed) { attemptAttack(actingCharacter, characters); } } else if (mentality == Mentality.SUMMON) { boolean summoned = attemptSummon(actingCharacter); if (!summoned) { attemptAttack(actingCharacter, characters); } } } In addition to managing AI, it contains the game rules, such as when a character should be removed from the game using the helper method isAlive and the EntityManager remove method. for (Entity character : characters) { if (!isAlive(character)) { entityManager.remove(character); System.out.println(character.get(DescriptionPart.class).getName() + " is dead!"); } Conclusion Handling interactions between entities can become complex in large-scale games. I hope this article was helpful in providing several approaches to interactions by using high-level classes, adding logic to parts, and using events. The first and second articles addressed the core of creating and using entities and parts. If you want, take a closer look at of the example code or change it to get a feel of how it manages interactions between entities. Though the CharacterFactory is fine for small and medium-sized games, it doesn't scale well for large games where potentially thousands of game object types exist. The next article, Serialization, will describe several approaches to mass creation of game object types using data files and serialization. Article Update Log 16 April 2014: Initial release
  8. Entities-Parts I: Game Objects

    SpiderJack - Thanks SpiderJack!  Like I said, I don't have a fixed timeframe for the next article because I'm carefully planning out what I want to talk about next.  I did make a lot of progress on the example code today so things are moving along smoothly.  I'm shooting to complete it by the end of the month.
  9. Entities-Parts I: Game Objects

    Sanka - Glad you like the article .  I can't say for sure when it will be out because I'm busy with work and school, but I hope by the end of this month.  If not, I'll add more content to the example.
  10. Background I. Game Objects (current) II. Interactions III. Serialization This article is the first in a series of articles about the practical application of the entity-component pattern to game programming. This article, in particular, describes what an entity and a component are, how they interact with eachother, and what the advantages of the entity-component pattern are over some traditional methods of creating gameobjects. Also, it will describe the Entities-Parts framework which is simply a collection of reusable classes and concepts for entity-component interaction. Since I started implementing the entity-component model several years ago, it has evolved based off of experience using it in my games and studying various articles and other implementations. It has not been tested in large scale games such as RPGs, so by no means is it perfect. The implementation and the articles will keep evolving as my knowledge increases and I develop more games. As part of the framework, I will also provide an implementation of the entity and component and an example rpg-battle system showing interactions between entities and components. The example will be built on in the next articles. The implementation is provided in Java and C++ w/boost. It is generic enough that you can reuse your components in multiple games and decouple your game objects, i.e. entities, from high-level game logic and systems. I prefer to use the word 'part' instead of 'component' because it is shorter. The Problem Some approaches to creating game objects require you to cram all functionality into one GameObject class, or create several game object classes that have duplicate code. With the entity-component pattern, you can reuse code and make your game objects dynamic by thinking of them as a bunch of interconnected parts. Deep Inheritance Hierarchy Approach: Let's say you have a Monster class. The class contains a few variables, such as those for health, damage, and position. If you want a new type of Monster that flies, you derive a FlyingMonster class from the Monster class. If you want a spellcasting Monster, you derive a SpellMonster class from the Monster class. The problem arises when you want a spellcasting flying monster. You now need to decide whether you want to derive SpellFlyingMonster from FlyingMonster or SpellMonster. Furthermore, you will need to copy and paste code from the FlyingMonster or SpellMonster class to provide the functionality that the SpellFlyingMonster is missing from its parent class. Monolithic Class Approach: Another approach is creating a single class that represents and contains all the functionality of your game objects, i.e. the GameObject. While this solves the issue of having duplicate code that exists in deep inheritance hierarchies, this class can quickly get out of hand as it becomes responsible for flying, spells, health, position, etc. Maintaining it will be near impossible and gameobjects will be required to hold data for functionality they don't need. For example, a monster that only flies will still need to keep a collection of spells. Solution - Entity-Component Approach: With the entity-component pattern, you think of a monster as an entity made up of several parts. You do not need separate classes for Monster, FlyingMonster, SpellMonster, and SpellFlyingMonster. For example, to create a FlyingMonster, you create an entity and add a health part, a damage part, and a flying part. If later on, you want it to cast spells, you add the spell part with one line of code. You can create dozens of monster types by mixing and matching parts. Explaining the Concept Note: The approach I present is fundamentally different to ECS (Entity Component Systems). In ECS, components only store the data, but do not provide the functionality. Instead, the functionality is provided by external systems. See http://en.wikipedia.org/wiki/Entity_component_system. It is natural to categorize gameobjects into monsters, items, and walls. Notice that these objects have similar attributes and functionality. They all need to be drawn, hold a physical space in the world, and collide with the player in some way. The line between different categories of gameobjects tend to blur as the gameobjects become more complex. For example, adding movement and damaging spikes to a wall, basically turns it into an enemy, e.g. Thwomp in Mario. In the entity-component pattern, game objects are described as entities that contain several attributes and functionality. The components/parts provide an abstraction for the attributes and functionality. Parts can be functional, e.g. control the behavior the entity, or just hold attributes that other systems and parts can reference, e.g. a health stat. The entity is responsible for managing parts as well as their lifetimes, i.e. initializing, updating, and cleaning up parts. There are many benefits of this approach: code reusability, addition/removal of attributes in a game object during runtime, and ease in generating new game object types in complex games such as MMORPGs. Example: Roleplaying Game (RPG) Battle It's best to illustrate how the entity-part framework works using the following example game/simulation. The example project is attached to this article. The example is in Java, but the C++ code for the Entity and Part classes is also attached. The Main class contains the logic to initialize and run our game. It creates a monster and a helpless villager. It then uses a basic game loop and updates the entities. While running the application, the state of the game will be printed to the console by the monster entity such as the monster's health, villager's health, and monster's height as the result from flying. As you can see, it is very easy to create new types of monsters once you write the code for the parts. For example, we can create a nonflying monster by removing the line of code that attaches the flying part. The MonsterControllerPart is the AI for the monster entity and the target passed into its constructor is the entity that will be attacked. We can make a friendly monster by passing in an enemy Entity into the MonsterControllerPart constructor instead of the helpless villager. public class Main { // main entry to the game application public static void main(String[] args) throws InterruptedException { Entity villager = createVillager(); Entity monster = createMonster(villager); // very basic game loop while (true) { villager.update(1); monster.update(1); Thread.sleep(1000); } } // factory method for creating a monster public static Entity createMonster(Entity target) { Entity monster = new Entity(); monster.attach(new StatsPart(100, 2)); // If we don't want our monster to fly, simply uncomment this line. monster.attach(new FlyingPart(20)); // If we don't want our monster to cast spells, simply uncomment this line. monster.attach(new SpellsPart(5)); monster.attach(new MonsterControllerPart(target)); monster.initialize(); return monster; } // factor method for creating an innocent villager public static Entity createVillager() { Entity villager = new Entity(); villager.attach(new StatsPart(50, 0)); villager.initialize(); return villager; } } MonsterControllerPart code, which serves as the AI and behavior for the monster, includes attacking its target, saying stuff, and attempting to use spells. All of your parts must derive from the Part class. Optionally, parts such as the MonsterControllerPart can override the initialize, cleanup, and update methods to provide additional functionality. These methods are called when its parent entity gets respectively initialized, cleaned up, or updated. Notice that parts can access other parts of its parent entity, e.g., entity.get(StatsPart.class). public class MonsterControllerPart extends Part { private Entity target; public MonsterControllerPart(Entity target) { this.target = target; } @Override public void initialize() { System.out.println("I am alive!"); } @Override public void cleanup() { System.out.println("Nooo I am dead!"); } @Override public void update(float delta) { StatsPart myStatsPart = entity.get(StatsPart.class); // if target has stats part, damage him if (target.has(StatsPart.class)) { StatsPart targetStatsPart = target.get(StatsPart.class); target.get(StatsPart.class).setHealth(targetStatsPart.getHealth() - myStatsPart.getDamage()); System.out.println("Whomp! Target's health is " + targetStatsPart.getHealth()); } // if i have spells, heal myself using my spells if (entity.has(SpellsPart.class)) { entity.get(SpellsPart.class).castHeal(); System.out.println("Healed myself! Now my health is " + myStatsPart.getHealth()); } } } General-purpose StatsPart keeps track of important RPG stats such as health and damage. This is used by both the Monster and the Villager entity. public class StatsPart extends Part { private float health; private float damage; public StatsPart(float health, float damage) { this.health = health; this.damage = damage; } public float getHealth() { return health; } public void setHealth(float health) { this.health = health; } public float getDamage() { return damage; } } SpellsPart class gives the Monster a healing spell to cast. public class SpellsPart extends Part { private float healRate; public SpellsPart(float healAmount) { this.healRate = healAmount; } public void castHeal() { StatsPart statsPart = entity.get(StatsPart.class); statsPart.setHealth(statsPart.getHealth() + healRate); } } FlyingPart code allows the Monster to fly to new heights. public class FlyingPart extends Part { private float speed; // in more sophisticated games, the height could be used to tell if an entity can be attacked by a grounded opponent. private float height = 0; public FlyingPart(float speed) { this.speed = speed; } @Override public void update(float delta) { height += speed * delta; System.out.println("Goin up! Current height is " + height); } } The Entity-Part Code The following code blocks are for the Entity class and the Part class. These two classes are the base classes you need for the entity-part framework. Entity class: /** * Made up of parts that provide functionality and state for the entity. * There can only be one of each part type attached. * @author David Chen * */ public class Entity { private boolean isInitialized = false; private boolean isActive = false; private Map
  11. Entities-Parts I: Game Objects

    Good feedback...   This is a part of a series of articles.  This first article describes the implementation of the entity and component class I use which I tried to make as simple and flexible as possible, and serves as a practical introduction to anyone who is new to the entity-component pattern.   I also moved the sidenote about the more datadriven ECS approach in the "Example" section.   Josh -  I fleshed out the conclusion some more and made it more clear this is a part of an article series.  I agree the example is very basic, but I think it describes the base functionality of the entity and part class.  I will elaborate on the example in the next article when I talk about entity management and interaction, which would be too much to put in this article.   Buckeye - You're right.  The comparison shouldn't be in the "Explaining the Concept" section and should be more about the entity-component pattern.  I created a new section called "The Problem" which talks about traditional approaches to gameobject creation and renamed some things so it wouldn't seem like an attack on OO which I didn't intend it to be.  I added some things in "Explaining the Concept" that detail the entity-component pattern specifically.
  12. Entities-Parts I: Game Objects

    Thanks for the feedback guys,   I have added the C++ version in the 'article resource'.  I took the C++ code from one of my games and modified it to remove any game specific code and uses of the boost library.  Let me know if there are any bugs with it since I haven't had a chance to test it.   Madhed - Yes, the entities own and manage components.  I'll add a couple sentences about the relational database inspired model in the Usage Notes.  I'm not completely sure what the alternate implementation is, but I assume that it's getting entities and parts by integer IDs instead of pointers.