1

I am writing an Entity Component System for a game engine in Java (using LibGDX).

I have an entity with an arraylist of various components. Each component inherits from a base Component class.

I want to have a method on my entity that can give me a reference to a component of a specific type (e.g., a RenderComponent, a PhysicsComponent, etc.). I have tried the following, but it doesn't seem to work.

public class Entity
{
   private ArrayList<Component> _components;

   ...

    public void AddComponent(Component c)
    {
            _components.add(c);
            c.Enable();
    }

    public Component GetComponent(String componentType)
    {
        Component s = null;

        for (int i = 0; i < _components.size(); i++)
        {           
            if (_components.get(i).getClass().getSimpleName() == componentType)
                    s = _components.get(i);
        }

        return s;
    }
}

The returned object is null.

How should I do this? Is there a more clever way to make the parameters specify a type (instead of a simple string)?

Also, what if I want ALL components of a specific type? How should I deal with that?

I read a bit about reflection, but I have never used it. I am still quite new to Java programming.

Thanks in advance.

4
  • 1
    have you tried instanceOf Commented Nov 2, 2015 at 19:07
  • 1
    Don't use == with String, that's probably the issue here Commented Nov 2, 2015 at 19:09
  • when you search for, say, RenderComponent, do you want to get also subclasses of that type? Commented Nov 2, 2015 at 19:49
  • No, right now I only want the specific type and not any parent or sub classes. Commented Nov 2, 2015 at 19:56

5 Answers 5

3

Try this

public class Entity
{
    private ArrayList<Component> _components;

    ...

    public void addComponent(Component c)
    {
        _components.add(c);
        c.Enable();
    }

    public Component getComponent(Class componentClass)
    {
        for (Component c : _components)
        {           
            if (c.getClass() == componentClass)
                return c;
        }

        return null;
    }
}

you call the method like this:

getComponent(PhysicsComponent.class)

and for getting a list:

    public List<Component> getAllComponents(Class componentClass)
    {
        List<Component> components = new ArrayList<Component>();
        for (Component c : _components)
        {           
            if (c.getClass() == componentClass)
                components.add(c);
        }

        return components;
    }
Sign up to request clarification or add additional context in comments.

Comments

2

Fortunately, this can be done without resorting to this hideous thing called reflection. You can simply use the instanceof operator. E.g.:

for (Component c : components)
    if (c instanceof PhysicsComponent)
        return c;

Comments

1

Can you add a public final static String or Enum field in each of the Component class to indicate the type and then use that for type checking in stead of reflection? Then you can put all these types in an enum. Reflection is simply too slow and expensive.

7 Comments

I guess I could do that, but is there really no way to specify the type in the parameters, like the following: Component GetComponent(TypeOfClassIWant className)
public class Component { public static ComponentName TYPE = ComponentName.Component; } public class ChildA extends Component { public static ComponentName TYPE = ComponentName.ChildA; } public class ChildB extends Component { public static ComponentName TYPE = ComponentName.ChildB; } public enum ComponentName { Component, ChildA, ChildB; } Then you can pass in an enum as a param.
Actually the above approach will not work by itself because if you create a component this way Component b = new ChildA(); the component name will end up being "Component" instead of "ChildA". What you can do is add a getName() method in each class and return the correct ComponentName in there.
Is it possible to make a static method that returns the name of THIS class? I don't think the this keyword works with static methods, so ...
code public class Component { public ComponentName getName() { return ComponentName.Component; } } public class ChildA extends Component { @Override public ComponentName getName() { return ComponentName.ChildA; } } code
|
1

You can pass in a class type instead.

public Component GetComponent(Class componentType){

    Component s = null;

    for (int i = 0; i < _components.size(); i++)
    {           
        if (_components.get(i).getClass() == componentType)
                s = _components.get(i);
    }

    return s;
}

2 Comments

How would I call the method? I don't want to create a new class for the parameter (using the new keyword). It seems like I can't do the following... Component c_temp = e.GetComponent(PhysicsComponent);
Oh, I just appended .class and now it seems to work. Thanks!
1

Replace == with .equals

if (_components.get(i).getClass().getSimpleName().equalsIgnoreCase(componentType))

Note: Why don't you use Map instread of List? It will be faster.

Edit: Its easy. Below is Map way of doing it.

private Map<String, Component> _components = new HashMap<String, Component>();

public void addComponent(Component c) {
    _components.put(c.getClass().getSimpleName(), c);
    c.Enable();
}

public Component getComponent(String componentType) {
    return _components.get(componentType);
}

3 Comments

I know, but I am new to maps and dictionaries, so I want to start with the arraylist and then later implement it with a map.
Thanks, it works with maps now. Would you say this approach is better than the one proposed (among others) by bughi? Both works right now, but one uses the string as the lookup and the other uses the class type.
@Wikzo It depends what you need. But in plain context, yes, this approach is much better then looping arraylist.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.