2
\$\begingroup\$

What are the recommended approaches for an event system of a turn-based RPG's battle engine?

The system I'm currently working on has a runEvent method that sorts the actions queue based on their priorities. This method should also call the object's (item, player, condition) method according to an eventid, which currently is a String ("TurnStart", "TurnEnd", etc). The different objects may or may not have the same parameters for the same eventid.

In JavaScript, it would be something like the following:

retval = action['on' + eventid].apply(this, args);

I've read about using Java's Reflection to call a method through a String stored in a variable, but some people advise against it because of its security flaws.

I also thought about having a switch (eventid) inside a handler method that would call the appropriate method, but I think that would become impractical, given the substantial amount of different parameters combinations.

So, what is the recommended approach for this kind of situation in Java?

Note: It doesn't need to be based on String passing.

\$\endgroup\$
  • \$\begingroup\$ No 100% inline with your question, but if you're already comfortable with JavaScript you could look into offloading your event logic there using the Rhino JavaScript Engine built into Java 7 \$\endgroup\$ – Matt Sams Sep 3 '14 at 0:12
3
\$\begingroup\$

I'm not too sure if I understand the question correctly so forgive me if my answer if off, but this is how I would go about a turn-based event system.

Firstly, the actions that are represented by strings and ids can be converted into something more object-oriented which would be something like:

public abstract class Action {
    public abstract void execute();
}

That way you don't have to use switch or if-else statements; you would have to extend the action class.

To sort these actions out I would probably use an enumeration as each instance implements Comparable:

public enum Priority {
    PRE_TURN, PHASE, POST_TURN
}

And implement it into the action class like so:

private Priority priority;

public Action(Priority priority) {
    this.priority = priority;
}

public Priority getPriority() {
    return priority;
}

Action is an abstract class because there are no arguments in the execute method. This means you will have to specify the necessary fields in the constructor of the extending class which acts as a work-around to the many different parameters. It also enforces you to specify its priority. An example would be:

public class BattlePhase extends Action {
    private Entity e, Entity target;
    private Attack attack;

    public BattlePhase(Entity e) {
        this(e, e.inLineTarget(), e.getCurrentAttack());
    }

    public BattlePhase(Entity e, Entity target, Attack attack) {
         super(Priority.MEDIUM);
         this.e = e;
         this.target = target;
         this.attack = attack;
    }

    @Override
    public void execute() {
        attack.perform(e, target);
    }
}

Character c = scene.currentCharacter();
scene.queueAction(new BattleAction(c, selectedTarget, c.getMove(selectedMove)));

In the class that manages event you could use a priority queue that will sort actions added to the queue if you specify a 'Comparator'.

Queue<Action> actions = new PriorityQueue<>(10, new Comparator<Action>() {
    public int compare(Action a1, Action a2) {
        return a1.getPriority().compareTo(a2.getPriority());
    }
});

(the first argument, 10, is the initial capacity)

Or you could use a List and sort it when you add actions by calling the Collection#sort

Then your runEvent method would be something like:

public void runEvent() {
    Action a;
    if ((a = actions.poll) != null) {
        a.execute();
    }
}

That's just the outline of it, you might want to add a procedure to sequence the actions so that they don't all run at once.

\$\endgroup\$
0
\$\begingroup\$

ouch ! ... eventing is normally pub sub ... I say "this happened" and you as a handler go "ok now i need to do ..." this presumably is like some sort of action list system in which case I would implement it as such.

Does java have lambdas yet? I would have somehting like this in c# ...

class EventManager 
{
    List<Action> actions;

    void AddAction(Action action)
    {
        actions.Add(action);
        actions.Sort(...);
    }

    void ExecuteNextAction()
        var nextAction = actions.FirstOrDefault();
        if(nextAction != null)
           nextAction();
    }
}

then you can do something like ...

var actionManager = GetTheGlobalactionManagerFromSomewhere();

actionManager.AddAction(() => 
{ 
   DoStuff(); 
   DoMoreStuff();
});

You could also make ActionManager static if its a global thing. This is sort of how tasks work in .Net but with added clever threading abstraction.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.