Java-Gaming.org Hi !
Featured games (91)
games approved by the League of Dukes
Games in Showcase (798)
Games in Android Showcase (234)
games submitted by our members
Games in WIP (865)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Entity Component Manager  (Read 6030 times)
0 Members and 1 Guest are viewing this topic.
Offline kabbotta

Senior Newbie





« Posted 2014-09-09 20:56:38 »

I was prototyping a game in Ruby using Chris Powell's example of an entity/component setup. I've started writing up the game in Java, and after doing a rough translation of the system, I've noticed it is a little awkward in Java. Here is the Manager.java https://gist.github.com/kabbotta/a12ed6d08cd491aaec60 that I've got. It works, but I was hoping to get some ideas on how it might be done better in Java. A lot of Chris's system revolves around the dynamic nature of Ruby and the fact that all collections are pretty much the same.

In particular, one of the things I'm missing from Ruby is that I was able to use a direct reference to a class instead of a String in methods like comp(entity, comp_class). In Ruby, the method looked like this:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
  def comp(entity, component_class)
    store = @component_stores[component_class]
   
    return nil if store.nil?

    components = store[entity]
    return nil if components.nil? || components.empty?

    components.first
  end


And it could be used in this way:

1  
manager.comp(player, Position)


Where Position is an actual class name and can be recovered by calling component.class. As opposed to how in Java I'm taking in a String and then pulling the class name out of what getClass() returns:

1  
manager.comp(player, "Position");


Thanks for any suggestions you can offer!
Offline cylab

JGO Kernel


Medals: 195



« Reply #1 - Posted 2014-09-10 06:42:27 »

You can do exactly the same in java. component_class would be of type Class and then you can pass in Position.class.

Mathias - I Know What [you] Did Last Summer!
Offline KevinWorkman

« JGO Plugged Duke »


Medals: 288
Projects: 12
Exp: 12 years


HappyCoding.io - Coding Tutorials!


« Reply #2 - Posted 2014-09-10 13:21:51 »

I'm really not sure what you're asking. Maybe you'd be better off posting the Java code (as an MCVE) instead of the Ruby code?

If you're just asking how to add Class instances to a collection, then here is an MCVE of my own:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
import java.util.ArrayList;
import java.util.List;

public class Test {

   public static void main(String... args) {
      List<Class<?>> classes = new ArrayList<Class<?>>();
      classes.add(List.class);
      classes.add(ArrayList.class);
      classes.add(Test.class);
   }
}

HappyCoding.io - Coding Tutorials!
Happy Coding forum - Come say hello!
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Catharsis

JGO Ninja


Medals: 76
Projects: 1
Exp: 21 years


TyphonRT rocks!


« Reply #3 - Posted 2014-09-10 22:11:14 »

You also should use generic methods. Following you manager -> comp method example:

1  
public final <T extends IComponent> T comp(IEntity entity, Class<T> compType) {}


IComponent being whatever your base component interface type may be. I suppose you could just leave it T and be able to stuff any objects into it. I've found in my ES efforts that there is a benefit to having a base component interface with a few extra utility methods useful for a component architecture defined over just Object.

IEntity can be your base entity interface. You could also pass in any other ID (integers have been popular in various blog posts on ES). In my ES efforts I actually store the components internally to an entity or "component manager" and don't have a separate entity object really.

The nice thing about the above is that it provides for a generic, but explicit return type based on the Class provided when calling the method.

Postion p = manager.comp(entity, Position.class);

Another nice thing is that you can have wildcard / generic collections backing the internal implementation of "manager" such that if you only have typed getters / setters like the above "comp" method then you can do generic type casts safely in the "comp" method

You can also use the compType as an key into any backing collection (HashMap, etc.)

ES / component architectures are definitely possible in Java.

Check out the TyphonRT Video Suite:
http://www.typhonvideo.com/

Founder & Principal Architect; TyphonRT, Inc.
http://www.typhonrt.org/
http://www.egrsoftware.com/
https://plus.google.com/u/0/+MichaelLeahy/
Offline kabbotta

Senior Newbie





« Reply #4 - Posted 2014-09-11 23:57:57 »

Thanks guys! This was all really helpful, especially your suggestions, Catharsis. Everything seems to be a bit smoother now, and the generics helped get rid of a bunch of unnecessary casting. The only thing is that I now have an "unchecked cast" warning in the comp method that I have to suppress. Is there any way around that?

This is the comp method I'm using now along with the declaration of component_stores for reference:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
private HashMap<Class<?>, HashMap<String, Component>> component_stores = new HashMap<Class<?>, HashMap<String, Component>>();

public final <T extends Component> T comp(String entity, Class<T> comp_type) {
    HashMap<String, Component> store = component_stores.get(comp_type);

    if (store != null) {
        @SuppressWarnings("unchecked")
        T comp = (T)store.get(entity);

        if (comp != null) return comp;
    }

    return null;
}


And this is the add_comp method I use to add a component to an entity:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
public Component add_comp(String entity, Component comp) {
    HashMap<String, Component> store = component_stores.get(comp.getClass());

    if (store == null) {
        store = new HashMap<String, Component>();
        component_stores.put(comp.getClass(), store);
    }

    if (store.containsKey(entity)) {
        return null;
    } else {
        store.put(entity, comp);
        return comp;
    }
}


Thanks for the tip about producing a MCVE to get the best results as well!
Offline Catharsis

JGO Ninja


Medals: 76
Projects: 1
Exp: 21 years


TyphonRT rocks!


« Reply #5 - Posted 2014-09-12 02:00:10 »

Handling the unchecked cast how you are doing currently is fine as long as the "store" Map is encapsulated such that components of a different type can't be added to it surreptitiously. An example of that could be a child class of the "manager" class having access to the collections. In the code you listed below you didn't mark add_comp final for instance, so a child class could change the behavior if access to the collections were possible.

If add_comp and comp methods are the only way to access those internal implementation collections then you are guaranteeing type safety by the method definition / class type for external use of your API.

Check out the TyphonRT Video Suite:
http://www.typhonvideo.com/

Founder & Principal Architect; TyphonRT, Inc.
http://www.typhonrt.org/
http://www.egrsoftware.com/
https://plus.google.com/u/0/+MichaelLeahy/
Offline kabbotta

Senior Newbie





« Reply #6 - Posted 2014-09-12 04:12:15 »

Thanks for all your help. I didn't mark add_comp final, because I was under the impression final meant the method would not modify any of the class members. I think I was mixing it up with C++ const.
Offline Catharsis

JGO Ninja


Medals: 76
Projects: 1
Exp: 21 years


TyphonRT rocks!


« Reply #7 - Posted 2014-09-12 09:06:46 »

final does mean "const" when applied to variables, but is even stricter than C++.

final on a method or class prevents further modification by subclasses which is important for consistency of a component architecture.

I noticed you are probably new to Java with naming "add_comp" method as typical Java style is "addComp"..

Welcome!  Grin

Check out the TyphonRT Video Suite:
http://www.typhonvideo.com/

Founder & Principal Architect; TyphonRT, Inc.
http://www.typhonrt.org/
http://www.egrsoftware.com/
https://plus.google.com/u/0/+MichaelLeahy/
Pages: [1]
  ignore  |  Print  
 
 

 
Riven (87 views)
2019-09-04 15:33:17

hadezbladez (4365 views)
2018-11-16 13:46:03

hadezbladez (1558 views)
2018-11-16 13:41:33

hadezbladez (4503 views)
2018-11-16 13:35:35

hadezbladez (876 views)
2018-11-16 13:32:03

EgonOlsen (4165 views)
2018-06-10 19:43:48

EgonOlsen (4870 views)
2018-06-10 19:43:44

EgonOlsen (2809 views)
2018-06-10 19:43:20

DesertCoockie (3715 views)
2018-05-13 18:23:11

nelsongames (4015 views)
2018-04-24 18:15:36
Java Gaming Resources
by philfrei
2019-05-14 16:15:13

Deployment and Packaging
by philfrei
2019-05-08 15:15:36

Deployment and Packaging
by philfrei
2019-05-08 15:13:34

Deployment and Packaging
by philfrei
2019-02-17 20:25:53

Deployment and Packaging
by mudlee
2018-08-22 18:09:50

Java Gaming Resources
by gouessej
2018-08-22 08:19:41

Deployment and Packaging
by gouessej
2018-08-22 08:04:08

Deployment and Packaging
by gouessej
2018-08-22 08:03:45
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!