1

How does one go about dynamically updating a GUI created with MyCanvas in java? I'm trying to program a board game called Lotus.

This is a description of the game: Players attempt to maneuver their playing pieces (10 in the two-player version, six in the three- or four-player game) from the start area along the game track to the finish area. Pieces move a number of spaces equal to the number of other pieces they are stacked on. Only the piece on the top of a stack may move. There are two entrances onto the game track, but only one route leading to the finish area. The track contains a "trampoline" space which allows a player to double the distance of a move when landing on this spot. The first player to remove all of his pieces wins.

Basically, I have two classes so far. A GameEngine class and a GUI class.

GameEngine.java

package GameEngine;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Stack;
import java.util.Timer;

import javax.swing.JFrame;

import GUI.MyCanvas;

/**
 * Lotus Game Engine 
 * 
 * Functionality:
 * 1) Generates a GUI and modifies it in real-time based on player input through the Finch.
 * 2) Tracks whose current turn it is.
 * 3) Manages all game pieces on the Lotus game board.
 * 4) Determines when a player has won the game.
 * 
 *
 */
public class GameEngine extends Canvas {


    // Instantiate a few variables
    boolean isRunning = true; // Game is currently active
    private java.util.Timer timer;

    /* Create 25 stacks that correspond to each position on the game board
    ArrayList<Stack<Integer>>[] positions = new ArrayList<Stack<Integer>>[25]; 

    public GameEngine() {
        for (int i=0; i<positions.length; i++) {
            positions[i] = new Stack<?>();
        }
    } 
    */


    //The following 8 Stacks are named using the following conventions:
    //posS## - The 'S' indicated that this is one of the starting Stacks.
    //       - The first number indicates the player (1 or 0)
    //       - The second number indicates the size of the starting stack (1, 2, 3, or 4)

    StackByCompositionWithArrayList<Integer> posS01 = new StackByCompositionWithArrayList<Integer>();
    StackByCompositionWithArrayList<Integer> posS02 = new StackByCompositionWithArrayList<Integer>();
    StackByCompositionWithArrayList<Integer> posS03 = new StackByCompositionWithArrayList<Integer>();
    StackByCompositionWithArrayList<Integer> posS04 = new StackByCompositionWithArrayList<Integer>();

    StackByCompositionWithArrayList<Integer> posS11 = new StackByCompositionWithArrayList<Integer>();
    StackByCompositionWithArrayList<Integer> posS12 = new StackByCompositionWithArrayList<Integer>();
    StackByCompositionWithArrayList<Integer> posS13 = new StackByCompositionWithArrayList<Integer>();
    StackByCompositionWithArrayList<Integer> posS14 = new StackByCompositionWithArrayList<Integer>();


    // Launch GUI

    public static void main(String[] args){
        MyCanvas c = new MyCanvas();
        JFrame frame = new JFrame();
        frame.setSize(420, 420);
        frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
        frame.getContentPane().add(c);
        frame.setVisible(true);
    }

    //Loads proper number of game pieces (0's and 1's) into starting stack positions.

    public void setUpStacks(){
        //Single Stacks
        posS01.push(0);
        posS11.push(1);
        //Double Stacks
        for (int x = 0; x < 2; x++){
            posS02.push(0);
            posS12.push(1);
        }
        //Triple Stacks
        for (int x = 0; x < 3; x++){
            posS03.push(0);
            posS13.push(1);
        }
        //Quad Stacks
        for (int x = 0; x < 4; x++){
            posS04.push(0);
            posS14.push(1);
        }


    }

    //@author rshannon

    public void gameLoop()
    {
        timer = new Timer();
        timer.schedule(new GameLoop(), 0, 1000 / 60); //new timer at 60 fps, the timing mechanism
    }

    private class GameLoop extends java.util.TimerTask
    {
        public void run() { // this becomes the loop

            /*
            if(pos24counter==10 || pos25counter==10){
                isRunning = false;
            }
            */

            if (!isRunning){
                timer.cancel(); // Stop timer
                //declareWinner(); // Declare winner
            }
        }
    }


public void Updater (StackByCompositionWithArrayList<Integer> stack, int position, boolean player, Graphics g){

        int distance = stack.size();

        //PLAYER 1 == TRUE == BLUE == 1
        //PLAYER 2 == FALSE == RED == 0

        int finalPosition;

        if (position == 15){
            position = position - 3;
        }
        if ((position == 16) && (distance > 1)){
            position = position - 3;
        }
        if ((position == 17) && (distance > 2)){
            position = position - 3;
        }

        finalPosition = position + distance;

        if (finalPosition == 1){
            pos1.push(stack.pop());
        }
        if (finalPosition == 2){
            pos2.push(stack.pop());
        }
        if (finalPosition == 3){
            pos3.push(stack.pop());
        }
        if (finalPosition == 4){
            pos4.push(stack.pop());
        }
        if (finalPosition == 5){
            pos5.push(stack.pop());
        }
        if (finalPosition == 6){
            pos6.push(stack.pop());
        }
        if (finalPosition == 7){
            pos7.push(stack.pop());
        }
        if (finalPosition == 8){
            pos8.push(stack.pop());
        }
        if (finalPosition == 9){
            pos9.push(stack.pop());
        }
        if (finalPosition == 10){
            pos10.push(stack.pop());
        }
        if (finalPosition == 11){
            pos11.push(stack.pop());
        }
        if (finalPosition == 12){
            pos12.push(stack.pop());
        }
        if (finalPosition == 13){
            pos13.push(stack.pop());
        }
        if (finalPosition == 14){
            pos14.push(stack.pop());
        }
        if (finalPosition == 15){
            pos15.push(stack.pop());
        }
        if (finalPosition == 16){
            pos16.push(stack.pop());
        }
        if (finalPosition == 17){
            pos17.push(stack.pop());
        }


//*************************************************************************************************************\\
//*************************************************************************************************************\\
//*************************************************************************************************************\\
//*************************************************************************************************************\\
//*************************************************************************************************************\\


        //Could make it so the GUI Updater method continuously peeks at each stack, it it
        //returns 1 then the circle should be blue, if it returns 0 then the circle should
        //be red, and else, it sets the circle to black (empty.)

        //OR

        //Could make it so the Updater Class executes only when a Finch interaction is made
        //In this case, the parameters would include the stack where the position is, (we will
        //need to know the size of the stack, so I think we should implement a size method in
        //the StackByCompositionWithArrayList Class definition.) Also, we will need to a boolean
        //value to determine which player's turn it is. This method will need access to all of the
        //position stacks (pos1-pos25.) I think that this class should be written in the GameEngine
        //class.


        if(distance > 1){
            if (player == true){

            }
            else{

            }
        }












    }


}

GUI.java

package GUI;

import java.awt.GridLayout;
import javax.swing.JFrame;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.*;

import GameEngine.StackByCompositionWithArrayList;


public class MyCanvas extends Canvas{

    public MyCanvas(){

    }

    public void paint(Graphics g){
        g.setColor(Color.black);
        g.drawLine(30, 100, 100, 30);
        g.drawLine(300, 30, 100, 30);
        g.drawLine(300, 30, 370, 100);
        g.drawLine(370, 350, 370, 100);
        g.drawLine(370, 350, 320, 350);
        g.drawLine(320, 120, 320, 350);
        g.drawLine(320, 120, 280, 80);
        g.drawLine(120, 80, 280, 80);
        g.drawLine(120, 80, 80, 120);
        g.drawLine(80, 120, 80, 250);
        g.drawLine(80, 250, 100, 270);
        g.drawLine(170, 270, 100, 270);
        //Breaking pattern, moving to Left most line.
        g.drawLine(30, 100, 30, 270);
        g.drawLine(30, 270, 80, 320);
        g.drawLine(230, 320, 80, 320);
        g.drawLine(230, 320, 230, 250);
        g.drawLine(300, 250, 230, 250);
        g.drawLine(300, 250, 300, 130);
        g.drawLine(250, 130, 300, 130);
        g.drawLine(250, 130, 250, 200);
        g.drawLine(150, 200, 250, 200);
        //Breaking pattern, moving to smallest vertical line.
        g.drawLine(170, 270, 170, 250);
        g.drawLine(100, 250, 170, 250);
        g.drawLine(100, 250, 100, 130);
        g.drawLine(150, 130, 100, 130);
        g.drawLine(150, 130, 150, 200);
        g.fillOval(110,140,30,30);  //14
        g.fillOval(110,180,30,30);  //13
        g.fillOval(140,210,30,30);  //12
        g.fillOval(185,210,30,30);  //11
        g.fillOval(260,140,30,30);  //17
        g.fillOval(260,180,30,30);  //16
        g.fillOval(230,210,30,30);  //15
        g.fillOval(185,280,30,30);  //10
        g.fillOval(80,280,30,30);   //9
        g.fillOval(40,210,30,30);   //8
        g.fillOval(40,130,30,30);   //7
        g.fillOval(80,55,30,30);    //6
        g.fillOval(185,40,30,30);   //5
        g.fillOval(290,55,30,30);   //4
        g.fillOval(330,130,30,30);  //3
        g.fillOval(330,210,30,30);  //2
        g.fillOval(330,290,30,30);  //1 

    }


    public void test(Graphics g){
        g.setColor(Color.red);
        g.fillOval(330,210,30,30);  //2
        g.fillOval(330,290,30,30);  //1 
    }

}

When I call the test method in GUI.java, it doesn't update the GUI?

Any suggestions on this mess that I have here?

mKorbel
  • 109,525
  • 20
  • 134
  • 319
Bob Shannon
  • 638
  • 2
  • 10
  • 19
  • I don't see where you are call `test` – MadProgrammer Apr 03 '13 at 06:32
  • 1
    You're also mixing heavy weight (`Canvas`) and light weight (`JFrame`) components. This is not recommended. Instead, I recommend that you only use light weight components, such as `JPanel` instead – MadProgrammer Apr 03 '13 at 06:33
  • I don't call it in this specific code snippet, but I added it into the main method of the GameEngine and it didn't work. What do you mean by heavy weight and light weight components? – Bob Shannon Apr 03 '13 at 06:38
  • Java has two UI frameworks (actually it has 3, but lets keep it simple). AWT and Swing (Swing is based off AWT). AWT components are considered heavy weight, they have a 1:1 relationship with a native peer. Swing components are considered light weight, they share a native peer. Mixing the two tends to lead to lots of nasty problems, which are just best avoided. My other concern is I don't know where the `Graphics` context for the `test` method is coming from – MadProgrammer Apr 03 '13 at 06:43
  • So I should recode the GUI class using Swing? I'd wish to make it so that the current code can be used. I just don't understand how to update the GUI dynamically. Right now everything is hard coded, and then the paint method is ran. – Bob Shannon Apr 03 '13 at 06:52
  • I'd certainly recommend it. Check out [Performing Custom Painting](http://docs.oracle.com/javase/tutorial/uiswing/painting/) for an overview – MadProgrammer Apr 03 '13 at 06:54
  • There are any number of excellent (and crappy) examples about. For [example](http://stackoverflow.com/questions/15779877/rotate-bufferedimage-inside-jpanel/15780090#15780090) – MadProgrammer Apr 03 '13 at 07:06

1 Answers1

1
  1. use Swing JPanel instead of AWT Canvas

  2. override paintComponent for JPanel instead of paint for Canvas

  3. put all painting in the array, prepare that before paintComponent / paint is executed, inside paintComponent / paint only loop inside this array

  4. answer to your question is add code line super.paint(g);, then old painting is cleared and a new is dispalyed

mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • Do I add super.paint(g); to the test method? Then when I call the test method it will update the GUI? I just tried that and it doesn't seem to work. – Bob Shannon Apr 03 '13 at 06:38
  • @Bob I think what mKorbel is getting at, is all you custom painting should be done within and/or from your `paint` method (or `paintComponent` if you're using Swing components) – MadProgrammer Apr 03 '13 at 06:44
  • But how can I change the GUI while the program is already running? – Bob Shannon Apr 03 '13 at 06:53
  • @Bob Swing uses a passive rendering engine. That is, repaints are schedule by the RepaintManager when it thinks something needs to be updated. You can suggest to the RepaintManager to update the ui by calling `repaint` on the component you want updated – MadProgrammer Apr 03 '13 at 06:55