2

I'm creating a game with hundreds of abilities, so trying to leverage abstracts and generics as much as possible.

Each ability extends an abstract Ability class with universal methods like getCooldown(player), which gets a specific ability's cooldown for a player. Inheritance saves me from having to duplicate that code in every ability class.

public abstract class Ability {

public static String getCooldown() {
    int cooldown;
    //logic to get cooldown in milliseconds
    return cooldown;
    }
}

But the logic and metadata for each ability are unique and coded like such:

public class Parry extends Ability {
    public static String getDescription() {
        ...
    }
    public static void castAbility() {
        ...
    }
}

Here's my enum. I'm using an enum because abilities and their metadata are constants that are ideally available at compile time. I also don't want to store the metadata separate from the classes which have the rest of the ability logic.

public enum AbilityEnum {
    BORN_READY(BornReady.class),
    JUGGLER(Juggler.class),
    ...
    PARRY(Parry.class);

    public final Class<? extends Ability> cls;
    AbilityEnum(Class<? extends Ability> cls) {
        this.cls = cls;
    }
}

In other parts of the codebase, I want to use the Enum to generically get basic info on an ability, cast a spell, etc. I want to avoid hard-coding for any specific ability because there are 200+ of them. For example, when a player opens their skill menu, I need to grab the descriptions for every ability. I'd rather not type [ability_name].getDescription() 200+ times.

for (AbilityEnum ability : AbilityEnum.values()) {
        String tooltip = ability.cls.getDescription();
        ...
        // load descriptions into menu system so players
        // can hover abilities for a tooltip description
    }

If I try to run this I get the error:

Cannot resolve method 'getDescription' in 'Class'

This confuses me because I bounded the generic, so why does it think it has a Class instead of an Ability? I think I'm either misusing generics or have the wrong syntax for calling methods this way. Perhaps I should be using a list or something else instead of an enum?

42ultra
  • 21
  • 2
  • 1
    This has nothing to do with the enum. This doesn't work for the same reason that `BornReady.class.getDescription()` doesn't work. – Federico klez Culloca Sep 11 '22 at 20:45
  • 1
    [This answer](https://stackoverflow.com/a/18778915/133203) contains the solution (using reflection), but it's not an exact duplicate so I won't mark it as such. – Federico klez Culloca Sep 11 '22 at 20:47
  • @FedericoklezCulloca Good to know--I guess I don't know how .class works. Obviously, `BornReady.getDescription()` works, but I need to pass these classes to the enum constructor. I will look into reflection. Thanks! – 42ultra Sep 11 '22 at 21:05
  • 1
    Do you really need 200 or more classes? If the classes all have the same or similar methods, they could just be enum values. You can add methods and fields to an enum, and that might be what you want to do with the `description` field. – Dawood ibn Kareem Sep 11 '22 at 21:15
  • @DawoodibnKareem Perhaps. There's a lot of logic, listeners, and such for each ability so I've been organizing a class file for each one. The listeners might actually require me to use a class. I could potentially store all of the metadata in the enum and leave the logic in the classes. – 42ultra Sep 11 '22 at 21:27
  • If you can express the logic in lambdas, you may be able to put it in the enums too. – Dawood ibn Kareem Sep 11 '22 at 21:38
  • Does this answer your question? [Why shouldn't Java enum literals be able to have generic type parameters?](https://stackoverflow.com/questions/4290878/why-shouldnt-java-enum-literals-be-able-to-have-generic-type-parameters) – Dmitry Khamitov Sep 11 '22 at 23:31
  • @DmitryKhamitov This is a good article. I believe it explains why what I want to do isn't exactly supported. – 42ultra Sep 12 '22 at 04:21

0 Answers0