Array Of Sub-Classes

I have defined a top-level abstract “item” type in my game, like this:

public abstract class GameItem {
   ...
}

And then I have a few concrete implementations, like this:

public class Hammer extends GameItem {
  ...
}

public class Nail extends GameItem {
  ...
}

I then built an “encyclopedia” class that contains a list of all the game assets that are available:

public class Encyclopedia {
  public final GameItem[] items = new GameItem[] {
    new Hammer(),
    new Nail()
  };
}

However, that means that Java is creating an instance of each game item when construction the encyclopedia. What I really want is an array of class references, rather than of class instances, like this:

public class Encyclopedia {
  public final Class<GameItem>[] items = new Class<GameItem>[] {
    Hammer.class,
    Nail.class
  };
}

But that code is not valid.

How can I store an array of subclasses like this?

If this isn’t a good idea, then what is a “good” way to store references to all your game assets? I know I can do it via XML or JSON or something like that, but I’m trying to encapsulate all me game assets in code rather than in data files so that I can take advantage of type checking in my IDE, and also avoid the overhead of parsing and processing XML or JSON data. Plus, there will be code associated with each game item, which makes storing the game assets as data less than ideal.

You could instantiate all your items, keep it in a singleton class, and just reuse the same objects over and over again. This way you don’t have to instantiate more and more (reflection is slower than normal new Object()ing) item objects. The same can be applied to tiles, if they exist in your game.

This post is a really good example of how Blocks would be used over and over again.

I thought about that, but ultimately I will need to instantiate multiple instances of various entities and they’ll have instance-specific properties (like “quality” or “remainingCharge” or whatever), so a singleton won’t really work for that.

I’m thinking about alternate ways to instantiate my encyclopedia…I’ll work something up and then post it here.

I cannot test it right now but the only thing I found at first glance that needs to be changed is this:


public class Encyclopedia {
  public final Class<? extends GameItem>[] items = new Class<? extends GameItem>[] {
    Hammer.class,
    Nail.class
  };
}

because otherwise you would get an Class cannot be converted to Class

This way the Class generics typing would be correct afair (I use something similar)

Edit:
Actually, the above code does not work, but it works this way:


public final Class<? extends GameItem>[] items = (Class<? extends GameItem>[])new Object[] {
    Hammer.class,
    Nail.class
  };

Note: this will get you some unchecked warnings

Or more general approach (without unchecked warnings):

  public final Class<?>[] items = new Class<?>[] {
    Hammer.class,
    Nail.class
  };

The question is actually for what purpose you’ll need the Encyclopedia at all…

I can’t talk for TimmerCA but I got something comparable to that: my “Encyclopedia” class is an enum class where each enum consists of an ID and class object. On runtime I build a map so I can easily get the class objects from its unique ID and create objects with it afterwards. I know this might not be the nicest way to implement this, but it works and is dynamic enough for my approaches (adding a new sub element to this enum class is all thats needed for it to work with my system)

Protip: you can cheat Java into letting you create generic arrays without any ugly, unnecessary (from the pov of the programmer) casts or annoying warnings by using a generic, varags method.


public static <T> T[] genericArray(T... arr) {
    return arr;
}

use like this:


public static final Class<? extends GameItem>[] items = genericArray(
    Hammer.class,
    Nail.class
);

Java even infers the generic type when used like this so it’s a very clean method. You can even create empty arrays of programmable lengths by using the Array.copyOf method as well:


public static <T> T[] genericArrayEmpty(int n, T... foo) {
    return Arrays.copyOf(foo, n);
}

Where “foo” is a dummy parameter. You can use it like this:


public static final Class<? extends GameItem>[] items2 = genericArrayEmpty(5);

Helps if you’re a fan of pretty code.

As an aside…doing anything like this is only manageable if if the number of distinct things is small.

Neat :slight_smile:

I think you should only have the GameItem class, and hamners, nails etc are just instances of GameItem, and probably defined in a text file somewhere.

The most straightforward approach would be to create an enum (with a name such as “ItemTypes”) where you manually create an entry representing each item type. You can pass a reference to the corresponding class object into each enum entry’s constructor. You can then use reflection with that class object to instantiate item objects. If that is too slow, you can provide a factory lambda to each enum as well.

This may be a tedious process. The only real alternative is to use a library such as https://code.google.com/archive/p/reflections/ to scan your classes at runtime and find every class within a particular package or marked with a particular annotation. You could then store the results in a HashMap allowing access by item name.

In my little Terraria-like game ProjectMP items and blocks are stored in the singleton class but entities (due to being totally separate objects for each one) must be instantiated via reflection. All the entity types are stored in an EntityRegistry which is just a singleton for the string ID and entity class. Enums don’t work in my case simply because it has to be modular, and I should be able to instantiate any type of entity I need to without having to refer to an enum (modding and the like as well).

How about a hashmap with class as key and GameItem as value

I keep a single instance of each game item, with ID as key. This way in an inventory system all I have to do is store an ID/quantity/etc…
Items are extended into weapons and contain ‘use’, ‘primary fire’, ‘secondary fire’, etc as methods, which take the entity using them as a parameter.