Boa tarde pessoal. Gostaria da opinião de quem possui mais experiência que eu em java e desenvolvimento de jogos. Fiz o seguinte esquema para utilizar uma habilidade (skill) em um jogo simples que estou desenvolvendo.
public class Game {
.
.
.
public void onUpdate() {
SkillManager.getInstance().update();
if (InputManager.getInstance().isPressed(KeyEvent.VK_Z)) {
this.player.atackWithSkill(new Mage("enemy"), Mage.FIRE_BALL);
}
}
public void onRender(Graphics2D grp) {
for (BufferedImage img : SkillManager.getInstance().getFramesToDraw()) {
grp.drawImage(img, null, this.player.getPosition().getX() + 50, this.player.getPosition().getY() + 50);
}
}
}
public class SkillManager {
private static SkillManager instance;
private final HashMap<Integer, AbstractSkill> skills;
private final ArrayList<BufferedImage> frames;
private SkillManager(){
this.skills = new HashMap<>();
this.frames = new ArrayList<>();
}
public static SkillManager getInstance(){
if(instance == null){
instance = new SkillManager();
}
return instance;
}
public void addSkill(AbstractSkill skill, int skillCode) throws IOException{
skill.loadResources();
this.skills.put(skillCode, skill);
}
public AbstractSkill useSkill(int skillCode) throws CoolDownTimeException{
AbstractSkill sk = this.skills.get(skillCode);
sk.enable();
return sk;
}
public void update(){
Iterator it = this.skills.entrySet().iterator();
this.frames.clear();
while (it.hasNext()){
AbstractSkill sk = (AbstractSkill) ((Entry) it.next()).getValue();
if (sk.isEnable()){
sk.update();
this.frames.add(sk.getFrameToDraw());
}
}
}
public ArrayList<BufferedImage> getFramesToDraw(){
return this.frames;
}
public AbstractSkill getSkill(int skillCode){
return this.skills.get(skillCode);
}
}
public abstract class AbstractPlayer{
.
.
.
public void atackWithSkill(AbstractCharacter enemy, int skillCode) {
int newCurrentMp = this.getCurrentMp() - SkillManager.getInstance().getSkill(skillCode).getMpCost();
if (newCurrentMp >= 0) {
try {
AbstractSkill skill = SkillManager.getInstance().useSkill(skillCode);
int newEnemyHp = (this.getAtack() + skill.getAtack()) - enemy.getDefenseBase();
enemy.setCurrentHp(enemy.getCurrentHp() - newEnemyHp);
this.setCurrentMp(newCurrentMp);
} catch (CoolDownTimeException exp) {
//System.out.println("COOL DOWN");
}
}
}
}
public abstract class AbstractSkill extends Entity {
private static final String RESOURCE_PATH = "skills/";
private static final int SPRITE_WIDTH = 192;
private static final int SPRITE_HEIGTH = 192;
private final SpriteAnimation spriteSkill;
private final int atack;
private final int mpCost;
private final int coolDownMillis;
private long lastUsedTime;
private boolean active;
private AudioClip skillUsedAudio;
public AbstractSkill(String name, String spritePath, String audioPath, int atack, int mpCost, int coolDownMillis) {
super(name, (RESOURCE_PATH + spritePath), (RESOURCE_PATH + audioPath), SPRITE_WIDTH, SPRITE_HEIGTH);
this.atack = atack;
this.mpCost = mpCost;
this.lastUsedTime = 0;
this.spriteSkill = new SpriteAnimation();
this.active = false;
this.coolDownMillis = coolDownMillis;
}
public int getAtack() {
return this.atack;
}
public int getMpCost() {
return this.mpCost;
}
@Override
public void loadResources() throws IOException {
for (int i = 0; i < 5; i++) {
BufferedImage img = ImageManager.getInstance().loadImage(this.getSpritePath(), this.getSpriteWidth() * i, 0, this.getSpriteWidth(), this.getSpriteHeigth());
this.spriteSkill.addImage(img);
}
for (int i = 0; i < 3; i++) {
BufferedImage img = ImageManager.getInstance().loadImage(this.getSpritePath(), this.getSpriteWidth() * i, this.getSpriteHeigth(), this.getSpriteWidth(), this.getSpriteHeigth());
this.spriteSkill.addImage(img);
}
this.skillUsedAudio = AudioManager.getInstance().loadAudio(this.getAudioPath());
}
public void update() {
this.spriteSkill.update();
if (this.spriteSkill.isEndOfLoop()) {
this.disable();
}
}
public BufferedImage getFrameToDraw() {
return this.spriteSkill.getCurrentImage();
}
public boolean isEnable() {
return this.active;
}
public void enable() throws CoolDownTimeException {
if ((System.currentTimeMillis() - this.lastUsedTime) >= this.coolDownMillis) {
this.active = true;
this.spriteSkill.enable();
this.skillUsedAudio.play();
this.lastUsedTime = System.currentTimeMillis();
} else {
throw new CoolDownTimeException();
}
}
public void disable() {
this.active = false;
}
}
O que vocês acham? Quais outras formas existem de fazer isso? Esta forma é boa? O que posso melhorar nela? Qualquer ajuda é bem vinda! Muito obrigado a todos que puderem dar uma ajuda 
