1

Background:

For the past few months, I've been working on a turn-based RPG in my free time in Java. I have only been programming for around a year, so my expertise is mostly limited to command line applications and object-oriented programming principles that I learned in elementary CS classes.

Development was going swimmingly up until I started to adapt the game from taking input from the command line to using a custom-made UI that I started building using Swing. This is largely because command line-based input lets me stop everything that I'm doing and wait for input from a scanner or something in that vein, but judging from threads that I've read on here (Waiting for multiple button inputs in Java Swing, Waiting till button is pressed), Swing's event-driven nature doesn't really allow you to wait for anything without interrupting the EDT and freezing the GUI, which is a bad thing for my purposes.

The Problem:

While Swing is quite novel to me, I've got it working on the main menu and see how it could readily be applied to games where data is relatively centralized between a few objects that utilize simple commands from the user to move or attack or what have you. My problem is that my RPG has anywhere between 2 and 16 active characters in a battle scenario, which can be user-controlled or AI controlled, can use any number of different commands (including something like 16 different skills) and player characters have to be able to access an inventory common between all of them. Suffice to say, my game is heavily menu-driven. For example, I'll post a method called from the loop that I run during a battle:

//initializes a turn; written as a function to cut down on duplicate code
public battleData initializeTurn(battleData toInitialize){
    if(toInitialize.initializeSkill()) {
        if(toInitialize.initializeTarget(playerParty, playerMinions, 1) == 0)
            return initializeTurn(toInitialize); //recursive call if the user cancelled
    }                                            //the skill they selected.
    else {
        if(toInitialize.initializeTarget(enemyParty, enemyMinions, -1) == 0)
            return initializeTurn(toInitialize); //see above
    }
    return toInitialize;
}

This method calls two functions written in the gameCharacter class, initializeTarget and initializeSkill to choose a target from two arrays of passed targets and one skill out of the character's two skill lists. Derived from the gameCharacter class are the playerCharacter and Monster classes, which calculate the return values of the methods from user input and a rudimentary AI, respectively. Since I have a lot of data about skills and items stored across different classes and user input behaves differently depending on which character is getting input, whether they're choosing a target or selecting a skill at the moment and where they are in the scope of the skill selection menu, I'm finding it very difficult to formulate an algorithm that lets me make the entire thing event-driven, since events can mean so many different things depending on what part of the menu is being looked at presently.

Solutions:

I've read about things like swingworkers being used to handle background tasks, states being used to feed input to different places and timers being used to regularly update graphical components, but I'm not familiar enough with Swing to really know what the best route is to take at this point. I'm more looking for a general algorithm to implement than a magical solution that will let me solve my problem without changing much of my code. I'm more than willing to reshape quite a bit of what I've written so far, so don't be afraid to tell me that I'll have to redo quite a bit if you think that it will make the program better.

Thanks for bearing with me; if you need more context, I'd be happy to explain or post more code. I would have posted more to start with, but most of the menus that I mentioned are 1-200 lines and are more easily explained than actually copied.

Community
  • 1
  • 1
  • Possible [duplicate](http://stackoverflow.com/q/24725420/230513). – trashgod Jun 02 '15 at 21:01
  • To sum up, you select the character, then select skill / order, then select target and you do that for 2-16 characters. Finally the battle frame (single turn) goes through and then you are ready for next turn? Correct me if I've misunderstood something – AlmasB Jun 02 '15 at 21:07
  • @AlmasB That's presently how the game works, but I'm not sure how to implement that algorithm in an event-driven context or generally get it to work with Swing, given that selection of characters, skills and targets hinges on waiting for user input, but you can't really do that without interrupting the EDT and freezing the GUI. At least as far as I know, but that's really why I'm asking. – Miles Sanguinetti Jun 02 '15 at 21:55

1 Answers1

1

First of all, you can make the problem slightly easier by thinking of GUI as something that does nothing constantly while updating the screen, as opposed to command line not doing anything while waiting for input. Since it's a turn based game, there must be requirements to when the turn is considered ready for computation. Typically this happens when the user has completed his input. In your case, from what I've gathered, the input is essentially orders to different game characters. Hence, every time user orders to do something (clicks an order button for a game character) there must be a check similar to isReadyToCompute(). When the method returns true you can call computeTurn(). Below is somewhat rough representation in code. There's a few gameplay related checks you will need to add but it should give an idea of where to start

skillButton1.addActionListener(e -> {
    // change cursor to "select" type cursor
    skill1 = true;
});

public class Mouse implements MouseListener {
    public void mouseClicked(MouseEvent e) {
         // get mouse x y
         // find target game character at x y or if none then return
         // remember the character as target
         // of skill1 of selected character
         // and count this as order complete for selected character
         skill1 = false;
         // change cursor to normal

         if (isReadyToCompute()) computeTurn();
    }
}

The overall idea is that you don't need a loop because the GUI already has its own internal one and it runs on EDT. The EDT captures and dispatches events which are handled by action and mouse listeners. When using command line you wait for the scanner which listens for input event, similarly in GUI you wait for the aforementioned listeners which in turn listen for button press or mouse events. For more information on how to write listeners please refer to the official Oracle tutorials:

https://docs.oracle.com/javase/tutorial/uiswing/events/actionlistener.html

https://docs.oracle.com/javase/tutorial/uiswing/events/mouselistener.html

If it is all the same to you, I'd recommend you switch to JavaFX, which is a more rich graphics framework, better option for games and sort of a successor of Swing. http://docs.oracle.com/javase/8/javafx/get-started-tutorial/jfx-overview.htm#JFXST784

AlmasB
  • 3,377
  • 2
  • 15
  • 17
  • I had played around with action listeners a bit while implementing a main menu a bit earlier, but just running checks for the current status of input seems like an efficient solution. I'll definitely consider giving JavaFX a look, as Swing did seem a bit wonky for designing something as complex as a game with many states, menus and submenus. Does the JavaFX scenebuilder work well for stuff like what I'm working on? Any tutorials on that that you would recommend? – Miles Sanguinetti Jun 02 '15 at 22:27
  • I actually run JavaFX tutorials myself: https://www.youtube.com/channel/UCmjXvUa36DjqCJ1zktXVbUA/videos If you prefer official tutorials: http://docs.oracle.com/javase/8/javafx/get-started-tutorial/jfx-overview.htm#BABHCIBA . Feel free to contact me if you require more help – AlmasB Jun 02 '15 at 22:40
  • After looking at some of your tutorials and playing around with JavaFX, I can't begin to express how much better of a system it feels like for designing flashier UI stuff. Your tutorials are super thorough and helpful too, thanks a bunch. – Miles Sanguinetti Jun 03 '15 at 02:03