I'm currently trying to develop a GUI for a "Tower of Hanoi" game. (The "towers" game should be familiar to many out there as a lesson in recursion. I however am using this example to practice developing GUI's and Graphics)
Not sure if my train of thought is on the right track so I'll write a little description of what I am trying to do, followed by my code.
Basically I have a game board divded into 3 cells.
- each cell can hold MAX of 10 disks.
- Class "Disk" handles each instance of a disk.
- Class "GameSheet" has a method "addDisk" that creates a specified number of disks and adds them to an array.
Ideally what I am trying to accomplish (but not sure if it is possible this way), is have each disk and it properties stored in an array...somehow like this:
disks[0] = fillRoundRect(5,5,10,10,15,15);
disks[1] = fillRoundRect(7,7,14,14,15,15);
disks[2] = fillRoundRect(9,9,18,18,15,15);
disks[3] = fillRoundRect(11,11,22,22,15,15);
disks[4] = fillRoundRect(13,13,26,26,15,15);
disks[n] = fillRoundRect(n,n,n,n,n,n);
(the value of the parameters here are irrelavant, just note that they are all different)
So whenever i want a disk that is "fillRoundRect(9,9,18,18,15,15);" all I have to do is (somehow) draw disks[2].
Is this possible? Is there a better way to do this?
I am trying to figure out the best way to write a "moveDisk" method, that will get a starting row, and a destination row. Then draw the selected "disk" in the destiniation row, while deleting the original in the starting row.(using click events)
Below is what I have so far:
Any help/suggestions would be greatly appreciated.
atsea
Not sure if my train of thought is on the right track so I'll write a little description of what I am trying to do, followed by my code.
Basically I have a game board divded into 3 cells.
- each cell can hold MAX of 10 disks.
- Class "Disk" handles each instance of a disk.
- Class "GameSheet" has a method "addDisk" that creates a specified number of disks and adds them to an array.
Ideally what I am trying to accomplish (but not sure if it is possible this way), is have each disk and it properties stored in an array...somehow like this:
disks[0] = fillRoundRect(5,5,10,10,15,15);
disks[1] = fillRoundRect(7,7,14,14,15,15);
disks[2] = fillRoundRect(9,9,18,18,15,15);
disks[3] = fillRoundRect(11,11,22,22,15,15);
disks[4] = fillRoundRect(13,13,26,26,15,15);
disks[n] = fillRoundRect(n,n,n,n,n,n);
(the value of the parameters here are irrelavant, just note that they are all different)
So whenever i want a disk that is "fillRoundRect(9,9,18,18,15,15);" all I have to do is (somehow) draw disks[2].
Is this possible? Is there a better way to do this?
I am trying to figure out the best way to write a "moveDisk" method, that will get a starting row, and a destination row. Then draw the selected "disk" in the destiniation row, while deleting the original in the starting row.(using click events)
Below is what I have so far:
Code:
public class Disk {
//private int row;
//private int column;
private int startX;
private int startY;
private int diskWidth;
private int diskHeight;
private int arcWidth;
private int arcHeight;
/** Creates a new instance of Disk */
public Disk(Graphics gfx, int x, int y, int width, int height, int arcW, int arcH) {
this.arcHeight = arcH;
this.arcWidth = arcW;
this.diskHeight = height;
this.diskWidth = width;
this.startX = x;
this.startY = y;
gfx.fillRoundRect(startX, startY, diskWidth, diskHeight, arcW, arcH);
}
}
Code:
public class GameSheet {
private static final int GAME_LINE_HEIGHT = 300;
private static final int GAME_POLE_HEIGHT = 240;
private static final int GAME_POLE_WIDTH = 10;
private static final int MAX_DISK = 10;
private static final int ROW_COUNT = 12;
private static final int COL_COUNT = 3;
public static final int GAME_CELL_WIDTH = 200;
public static final int GAME_AREA_START_X = 5;
public static final int GAME_AREA_START_Y = 5;
public static final int DISK_HEIGHT = 25;
private int firstClickRow;
private int firstClickCol;
private int[][] gameCells;
private Disk[] disks;
/** Creates a new instance of GameSheet */
public GameSheet() {
this.gameCells = new int[ROW_COUNT][COL_COUNT];
//later MAX_DISK will be user defined
this.disks = new Disk[MAX_DISK];
//fill each cell with -1 so that it can detemine wether to draw or not
//-1 means the cell is empty...maybe put in a "final" variable later
//THIS MAY NOT BE NECESSARY
int i = 0;
while (i < ROW_COUNT){
int j = 0;
while (j < COL_COUNT){
gameCells[i][j] = -1;
j++;
}
i++;
}
//initialize the first click row and column
this.firstClickRow = -1;
this.firstClickCol = -1;
}
/**
*set the column and row of the FIRST click that is
*inside the playing area
*@param row the row that was clicked
*@param col the column that was clicked
*/
public void setFirstRowColumn(int row, int col) {
if ((row >= 0) &&
(row < 12) &&
(col >= 0) &&
(col < COL_COUNT)) {
}else{
this.firstClickRow = -1;
this.firstClickCol = -1;
}
}
/**
*set the column and row of the SECOND click that is
*inside the playing area
*@param row the row that was clicked
*@param col the column that was clicked
*/
public void setSecondRowColumn(int row, int col) {
if ((row >= 0) &&
(row < 12) &&
(col >= 0) &&
(col < COL_COUNT)) {
//this will draw a disk in the location of the second click
this.firstClickRow = row;
this.firstClickCol = col;
}
}
/**
*Draw the game space in the main window
*1 row 3 col grid and 3 poles
*@param gfx Graphics
*/
public void drawGameSpace(Graphics gfx){
//draws the vertical lines
//set initial loop conditions
int lineCount = 0;
int startX = GAME_AREA_START_X;
int startY = GAME_AREA_START_Y;
//a loop to draw the 4 vertical lines
while (lineCount < 4){
//draw the line
gfx.drawLine(startX, startY, startX, startY + GAME_LINE_HEIGHT);
//move over cell width pixles
startX += GAME_CELL_WIDTH;
//increment lineCount
lineCount++;
}
//re initialize the start point for the horizontal lines
startX = GAME_AREA_START_X;
startY = GAME_AREA_START_Y;
//draw the top and bottom lines
gfx.drawLine(startX, startY, startX + GAME_CELL_WIDTH * 3, startY);
gfx.drawLine(startX, startY + GAME_LINE_HEIGHT, startX + GAME_CELL_WIDTH * 3, startY + GAME_LINE_HEIGHT);
//draw the poles in the middle of each "cell"
gfx.setColor(Color.gray);
gfx.fillRoundRect(102, startY + GAME_LINE_HEIGHT - GAME_POLE_HEIGHT, GAME_POLE_WIDTH, GAME_POLE_HEIGHT, 3, 3);
gfx.fillRoundRect(302, startY + GAME_LINE_HEIGHT - GAME_POLE_HEIGHT, GAME_POLE_WIDTH, GAME_POLE_HEIGHT, 3, 3);
gfx.fillRoundRect(502, startY + GAME_LINE_HEIGHT - GAME_POLE_HEIGHT, GAME_POLE_WIDTH, GAME_POLE_HEIGHT, 3, 3);
// Disk dropper
if ((this.firstClickRow != -1) &&
(this.firstClickCol != -1)) {
//this will eventually place the disk in the proper location
//must put it in the next available row in the column
}
}
/**
*Create a specified number of disks. As the number of disks increases the size
*of the disk descreases, giving a pyramid appearance. Each disk is then placed in an array
*so it may be used later.
*@param numberOfDisks the number of disks to create
*@param gfx graphics area associated with the disk
*@param diskColor color of the disks
*@param startX start x co ordinate of the disk/roundRect
*@param startY start y co ordinate of the disk/roundRect
*/
public void addDisk(int numberOfDisks, Graphics gfx, Color diskColor, int startX, int startY){
//set the color of the Disks
gfx.setColor(diskColor);
int i = 0;
int diskNumber = numberOfDisks;
int startDiskSize = GAME_CELL_WIDTH - 8;
// Calculate the starting position of the cell.
int x = startX + 2; //2 pixles in
//draw as many rectangles as requested
while (i < diskNumber){
int y = startY - i * DISK_HEIGHT;
// Make a new disk
Disk newDisk = new Disk(gfx, x, y + 2, startDiskSize, DISK_HEIGHT - 4, 15, 15);
//add it to an array
this.disks[i] = newDisk;
startDiskSize = startDiskSize - 16;
x = x + 8;
i++;
}
}
}
Code:
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.*;
import java.awt.*;
public class HanoiRedux extends JFrame implements MouseListener {
private int gameState;
private static final int GAME_HEIGHT = 500;
private static final int GAME_WIDTH = 800;
private static final int TITLE_X = 350;
private static final int TITLE_Y = 200;
private static final int TITLE_MSG_X = 326;
private static final int TITLE_MSG_Y = 215;
private static final int GAME_STATE_INTRO = 0;
private static final int GAME_STATE_SETUP = 1;
private static final int GAME_STATE_PLAYING = 2;
private static final int GAME_STATE_OVER = 3;
private boolean bFromClick;
private GameSheet gameSheet;
/** Creates a new instance of HanoiRedux */
public HanoiRedux() {
this.setSize(GAME_WIDTH, GAME_HEIGHT);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.addMouseListener(this);
this.gameState = GAME_STATE_INTRO;
this.setVisible(true);
//initialize the game board
this.gameSheet = new GameSheet();
}
public static void main(String[] args) {
new HanoiRedux();
}
/**
*Draw the title screen
*/
private void drawTitleScreen(){
//grab the area within the borders of the window
Container clientArea = this.getContentPane();
//get the graphics associated with the clientArea
Graphics gfx = clientArea.getGraphics();
//get the dimensions of the client area
int width = clientArea.getWidth();
int height = clientArea.getHeight();
//set the contents of the clientArea to black
gfx.fillRect(0, 0, width, height);
//write the Title in Red
gfx.setColor(Color.red);
gfx.drawString("Towers Of Hanoi", TITLE_X, TITLE_Y );
//write a short title messgae
gfx.setColor(Color.gray);
gfx.drawString("(click screen to continue)", TITLE_MSG_X, TITLE_MSG_Y);
}
/**
*Draws the space the where the game is actually played
*/
private void drawGameSpace(){
//grab the area within the borders of the window
Container clientArea = this.getContentPane();
//get the graphics associated with the clientArea
Graphics gfx = clientArea.getGraphics();
//get the dimensions of the client area
int width = clientArea.getWidth();
int height = clientArea.getHeight();
//set the contents of the clientArea to black
gfx.fillRect(0, 0, width, height);
//code to draw the lines of the board
//set the color of the lines
gfx.setColor(Color.red);
//use the class GameSheet
this.gameSheet.drawGameSpace(gfx);
//this.gameSheet.drawDisks(4, gfx, Color.ORANGE, 7, 275);
this.gameSheet.addDisk(7, gfx, Color.ORANGE, 7, 280);
//this.gameSheet.addDiskTest(7, gfx, Color.ORANGE, 7, 275);
//this.gameSheet.addDiskTest(gfx, 7, 275);
}
/**
*Paint on the game sheet
*Overides the previous paint method
*/
public void paint(Graphics gfx){
//decide exactly what to paint using an if statement
if (this.gameState == GAME_STATE_INTRO){
this.drawTitleScreen();
} else if(this.gameState == GAME_STATE_SETUP){
this.drawGameSpace();
}
}
public void mouseClicked(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
if (this.gameState == GAME_STATE_INTRO){
this.gameState = GAME_STATE_SETUP;
this.repaint();
this.initializeFromClick();
}else if (this.gameState == GAME_STATE_SETUP){
if (this.bFromClick){
//record the mouse row and column
int row = this.convertYtoRow(e.getY());
int col = this.convertXtoCol(e.getX());
gameSheet.setFirstRowColumn(row, col);
this.bFromClick = false;
this.repaint();
}else{
int row = this.convertYtoRow(e.getY());
int col = this.convertXtoCol(e.getX());
gameSheet.setSecondRowColumn(row, col);
this.repaint();
this.bFromClick = true;
}
}else if (this.gameState == GAME_STATE_PLAYING){
this.repaint();
}
}
/**
*Initializes the position of the first click
*i.e. the "from" col
*/
private void initializeFromClick(){
this.bFromClick = true;
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
private int convertXtoCol(int x) {
Container clientArea = this.getContentPane();
int borderSize = (this.getWidth() - clientArea.getWidth());
int col = (x - borderSize - GameSheet.GAME_AREA_START_X) / GameSheet.GAME_CELL_WIDTH;
return col;
}
private int convertYtoRow(int y){
Container clientArea = this.getContentPane();
int borderSize = (this.getWidth() - clientArea.getWidth());
int titleSize = (this.getHeight() - clientArea.getHeight()) - borderSize;
int row = (y - titleSize - GameSheet.GAME_AREA_START_Y) / GameSheet.DISK_HEIGHT;
return row;
}
}
Any help/suggestions would be greatly appreciated.
atsea