first commit
This commit is contained in:
116
CS1322/p6/MyWay/CCoord.java
Normal file
116
CS1322/p6/MyWay/CCoord.java
Normal file
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
* <PRE>
|
||||
* Coord.java
|
||||
*
|
||||
* Revisions: 1.0 Nov. 12, 2002
|
||||
* Created the Coord class
|
||||
* 1.1 Nov. 12, 2002
|
||||
* Compiled, Commented, Finished
|
||||
*
|
||||
* </PRE>
|
||||
*
|
||||
* @author <A HREF="mailto:gtg184g@mail.gatech.edu">Jose Manuel Caban</A>
|
||||
* @version Version 1.1, Nov. 12, 2002
|
||||
*/
|
||||
|
||||
/*
|
||||
*Everything from the Model and Control are extenstions of Coord for the
|
||||
*simple reason that everything in the 2D world will be a coordinate on a Grid
|
||||
*handled by a separate class
|
||||
*/
|
||||
public class CCoord {
|
||||
|
||||
/**
|
||||
*Points
|
||||
*/
|
||||
private int x;
|
||||
private int y;
|
||||
private int h;
|
||||
|
||||
///////////////
|
||||
//Constructor//
|
||||
///////////////
|
||||
|
||||
/**
|
||||
*Default Constructor
|
||||
*sets all values to 0
|
||||
*/
|
||||
public CCoord(){
|
||||
x = 0;
|
||||
y = 0;
|
||||
h = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*Takes in params for all values
|
||||
*@param x, the x coordinate
|
||||
*@param y, the y coordinate
|
||||
*@param h, the height value
|
||||
*/
|
||||
public CCoord(int x, int y, int h){
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.h = h;
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
//Accessors/Modifiers//
|
||||
///////////////////////
|
||||
|
||||
/**
|
||||
*@return value of x
|
||||
*/
|
||||
public int getX(){
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
*@param x, the new x coordinate
|
||||
*/
|
||||
public void setX(int x){
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
/**
|
||||
*@return value of y
|
||||
*/
|
||||
public int getY(){
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
*@param y, the new y value
|
||||
*/
|
||||
public void setY(int y){
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
*@return the height
|
||||
*/
|
||||
public int getH(){
|
||||
return h;
|
||||
}
|
||||
|
||||
/**
|
||||
*@param h, the new height
|
||||
*/
|
||||
public void setH(int h){
|
||||
this.h = h;
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
|
||||
/**
|
||||
* Debugging main for class Coord.
|
||||
* This method will rigorously test my code.
|
||||
*
|
||||
* <br><br>
|
||||
* @param args a String array of command line arguments.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
|
||||
|
||||
}// end of main(String[] args)
|
||||
|
||||
}// end of class Coord
|
||||
77
CS1322/p6/MyWay/CEngine.java
Normal file
77
CS1322/p6/MyWay/CEngine.java
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* <PRE>
|
||||
* CEngine.java
|
||||
*
|
||||
* Revisions: 1.0 Nov. 17, 2002
|
||||
* Created the CEngine class
|
||||
*
|
||||
* </PRE>
|
||||
*
|
||||
* @author <A HREF="mailto:gtg184g@mail.gatech.edu">Jose Manuel Caban</A>
|
||||
* @version Version 1.0, Nov. 17, 2002
|
||||
*/
|
||||
|
||||
public class CEngine {
|
||||
|
||||
|
||||
/**
|
||||
*Scan the input file and assign game map to the grid
|
||||
*/
|
||||
public void scanMap(String inFile){
|
||||
try{
|
||||
BufferedReader br = new BufferedReader(new FileReader(inFile));
|
||||
}
|
||||
catch(FileNotFoundException fnfe){
|
||||
System.err.println("File not found - CNode.scanMap()" + fnfe);
|
||||
}
|
||||
|
||||
//skip first 5 lines
|
||||
try{
|
||||
for(int i=0;i<5;br.readLine());
|
||||
}
|
||||
catch(Exception e){
|
||||
System.err.println(e+" when attempting to skip 5 lines of file"+
|
||||
" - CNode.scanMap()");
|
||||
}
|
||||
|
||||
for(int x=0; x<15; x++){
|
||||
String strTemp = br.readLine();
|
||||
for(int y=0; y<15; y++){
|
||||
switch(strTemp.charAt(z)){
|
||||
case s:
|
||||
grid[x][y] = new CTile(x,y,1,false);
|
||||
grid[x][y].setSpecial(true);
|
||||
grid[x][y].setNibble(false);
|
||||
break;
|
||||
case f:
|
||||
grid[x][y] = new CTile(x,y,1,false);
|
||||
grid[x][y].setParam(false);
|
||||
break;
|
||||
case n:
|
||||
grid[x][y] = new CTile(x,y,1,false);
|
||||
grid[x][y].setNibble(true);
|
||||
grid[x][y].setSpecial(false);
|
||||
break;
|
||||
//create a wall by default
|
||||
default:
|
||||
case w:
|
||||
grid[x][y] = new CTile(x,y,2,false);
|
||||
break;
|
||||
}//end switch
|
||||
}//end for(y)
|
||||
}//end for(x)
|
||||
}
|
||||
|
||||
/**
|
||||
* Debugging main for class CEngine.
|
||||
* This method will rigorously test my code.
|
||||
*
|
||||
* <br><br>
|
||||
* @param args a String array of command line arguments.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
|
||||
|
||||
}// end of main(String[] args)
|
||||
|
||||
}// end of class CEngine
|
||||
69
CS1322/p6/MyWay/CGrid.java
Normal file
69
CS1322/p6/MyWay/CGrid.java
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* <PRE>
|
||||
* CGrid.java
|
||||
*
|
||||
* Revisions: 1.0 Nov. 17, 2002
|
||||
* Created the CGrid class
|
||||
*
|
||||
* </PRE>
|
||||
*
|
||||
* @author <A HREF="mailto:gtg184g@mail.gatech.edu">Jose Manuel Caban</A>
|
||||
* @version Version 1.0, Nov. 17, 2002
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class CGrid {
|
||||
|
||||
/**
|
||||
*2D array to store the game data
|
||||
*/
|
||||
private CCoord[][] grid;
|
||||
|
||||
////////////////
|
||||
//Constructors//
|
||||
////////////////
|
||||
|
||||
public CGrid(){
|
||||
//create default size
|
||||
this(15,15);
|
||||
}
|
||||
|
||||
public CGrid(int iLength, int iHeight){
|
||||
grid = new CCord[iLength][iHeight];
|
||||
}
|
||||
|
||||
public CGrid(String inFile){
|
||||
this(15,15);
|
||||
this.scanMap();
|
||||
}
|
||||
|
||||
public CGrid(String inFile, boolean varGrid){
|
||||
if(varGrid){
|
||||
scanMap(inFile);
|
||||
}
|
||||
else{
|
||||
this(15,15);
|
||||
scanMap(inFile);
|
||||
}
|
||||
}
|
||||
|
||||
///////////
|
||||
//Methods//
|
||||
///////////
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Debugging main for class CGrid.
|
||||
* This method will rigorously test my code.
|
||||
*
|
||||
* <br><br>
|
||||
* @param args a String array of command line arguments.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
|
||||
|
||||
}// end of main(String[] args)
|
||||
|
||||
}// end of class CGrid
|
||||
57
CS1322/p6/MyWay/CIntelligence.java
Normal file
57
CS1322/p6/MyWay/CIntelligence.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* <PRE>
|
||||
* CIntelligence.java
|
||||
*
|
||||
* Revisions: 1.0 Nov. 13, 2002
|
||||
* Created the CIntelligence class
|
||||
*
|
||||
* </PRE>
|
||||
*
|
||||
* @author <A HREF="mailto:gtg184g@mail.gatech.edu">Jose Manuel Caban</A>
|
||||
* @version Version 1.0, Nov. 13, 2002
|
||||
*/
|
||||
|
||||
public class CIntelligence implements Constants{
|
||||
|
||||
public CGrid createNodeGrid(CGrid cGrid, int iFloorLevel){
|
||||
CGrid cToSend = new CGrid(cGrid.getX(),cGrid.getY());
|
||||
|
||||
for(int x=0; x<cGrid.length; x++){
|
||||
for(int y=0; y<cGrid[].length;y++){
|
||||
if(cGrid[x][y].getH() == iFloorLevel){
|
||||
cToSend[x][y] = new Coord(x,y,iFloorLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int x=0; x<cGrid.length;x++){
|
||||
for(int y=0; y<cGrid[].length;y++){
|
||||
if(cToSend[x][y] != null){
|
||||
createNode(cToSend,new Coord(x,y,iFloorLevel));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createNode(CGrid cToAdd, Coord cAt){
|
||||
int x = cAt.getX();
|
||||
int y = cAt.getY();
|
||||
int h = cAt.getH();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Debugging main for class CIntelligence.
|
||||
* This method will rigorously test my code.
|
||||
*
|
||||
* <br><br>
|
||||
* @param args a String array of command line arguments.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
|
||||
|
||||
}// end of main(String[] args)
|
||||
|
||||
}// end of class CIntelligence
|
||||
59
CS1322/p6/MyWay/CMonster.java
Normal file
59
CS1322/p6/MyWay/CMonster.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* <PRE>
|
||||
* Monster.java
|
||||
*
|
||||
* Revisions: 1.0 Nov. 13, 2002
|
||||
* Created the Monster class
|
||||
*
|
||||
* </PRE>
|
||||
*
|
||||
* @author <A HREF="mailto:gtg184g@mail.gatech.edu">Jose Manuel Caban</A>
|
||||
* @version Version 1.0, Nov. 13, 2002
|
||||
*/
|
||||
|
||||
public class CMonster extends CCoord implements Constants{
|
||||
|
||||
/**
|
||||
*Defines the Intelligence of the monster
|
||||
*whether player controlled or CPU controlled
|
||||
*/
|
||||
private CIntelligence oIntel;
|
||||
|
||||
/**
|
||||
*Define image for monster
|
||||
*Icons should be named as follows:
|
||||
*Iconname000.jpg, with the 000 incrementing up with each animation number
|
||||
*When used with the constructor, just give the iconname without 000 and the
|
||||
*constructor will search for the correct icon (so for a single icon lacking
|
||||
*any animation, it would be iconname000.jpg and be sent to the constructor
|
||||
*as iconname. Similarly, an icon with animations would have files
|
||||
*icon000.x, icon001.x, and icon002.x and have the name "icon" send to the
|
||||
*constructor.
|
||||
*/
|
||||
ImageIcon[] imgSprite;
|
||||
|
||||
////////////////
|
||||
//Constructors//
|
||||
////////////////
|
||||
|
||||
public CMonster(int x, int y, int h, String iconFile, CIntelligence oIntel){
|
||||
super(x,y,h);
|
||||
}
|
||||
|
||||
///////////
|
||||
//Methods//
|
||||
///////////
|
||||
|
||||
/**
|
||||
* Debugging main for class Monster.
|
||||
* This method will rigorously test my code.
|
||||
*
|
||||
* <br><br>
|
||||
* @param args a String array of command line arguments.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
|
||||
|
||||
}// end of main(String[] args)
|
||||
|
||||
}// end of class Monster
|
||||
106
CS1322/p6/MyWay/CNode.java
Normal file
106
CS1322/p6/MyWay/CNode.java
Normal file
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* <PRE>
|
||||
* CNode.java
|
||||
*
|
||||
* Revisions: 1.0 Nov. 17, 2002
|
||||
* Created the CNode class
|
||||
* 1.1 Nov. 17, 2002
|
||||
* Added Primary code, Commented, Finished
|
||||
*
|
||||
* </PRE>
|
||||
*
|
||||
* @author <A HREF="mailto:gtg184g@mail.gatech.edu">Jose Manuel Caban</A>
|
||||
* @version Version 1.1, Nov. 17, 2002
|
||||
*/
|
||||
|
||||
/**
|
||||
*The Engine class (CEngine) can take in a board and turn it into a game map.
|
||||
*The Engine class then creates another grid which will below the game map
|
||||
* that holds the nodes for the Intelligence class (CIntelligence).
|
||||
*The Node classes hold the data for where a ghost can move and are used to
|
||||
* send ghosts after the player. If pacman is between Node A and Node B and
|
||||
* a ghost finds itself in Node A, it will turn and head in the direction of
|
||||
* Node B. These Intelligence specifics are handled in the
|
||||
* CIntelligence->CIntelGhost class
|
||||
*/
|
||||
public class CNode extends CCoord{
|
||||
|
||||
/**
|
||||
*Define where the ghost can move when at this node
|
||||
*/
|
||||
private boolean MV_LEFT;
|
||||
private boolean MV_RIGHT;
|
||||
private boolean MV_UP;
|
||||
private boolean MV_DN;
|
||||
private boolean INC_HEIGHT;
|
||||
|
||||
///////////////
|
||||
//Constructor//
|
||||
///////////////
|
||||
|
||||
/**
|
||||
*@param up, can move up?
|
||||
*@param down, can move down?
|
||||
*@param left, can move left?
|
||||
*@param right, can move right?
|
||||
*@param incH, can increase height by using node?
|
||||
*@param x, x-coord
|
||||
*@param y, y-coord
|
||||
*@param h, h-coord
|
||||
*/
|
||||
public CNode(boolean up, boolean down, boolean left, boolean right,
|
||||
boolean incH, int x, int y, int h){
|
||||
super(x,y,h);
|
||||
MV_UP = up;
|
||||
MV_DN = down;
|
||||
MV_LEFT = left;
|
||||
MV_RIGHT = right;
|
||||
INC_HEIGHT = incH;
|
||||
}
|
||||
|
||||
///////////
|
||||
//Methods//
|
||||
///////////
|
||||
|
||||
/**
|
||||
*@return true if can go up from node
|
||||
*/
|
||||
public boolean canMV_UP(){
|
||||
return MV_UP;
|
||||
}
|
||||
|
||||
/**
|
||||
*@return true if can go down from node
|
||||
*/
|
||||
public boolean canMV_DN(){
|
||||
return MV_DN;
|
||||
}
|
||||
|
||||
/**
|
||||
*@return true if can move left from node
|
||||
*/
|
||||
public boolean canMV_LEFT(){
|
||||
return MV_LEFT;
|
||||
}
|
||||
|
||||
/**
|
||||
*@return true if can move right
|
||||
*/
|
||||
public boolean canMV_RIGHT(){
|
||||
return MV_RIGHT;
|
||||
}
|
||||
|
||||
/**
|
||||
*@return true if can increase height at this node
|
||||
*/
|
||||
public boolean canINC_HEIGHT(){
|
||||
return INC_HEIGHT;
|
||||
}
|
||||
|
||||
/**
|
||||
*@return Coordinates of the Node
|
||||
*/
|
||||
public CCoord getNodeCoord(){
|
||||
return (new CCoord(this.getX(), this.getY(), this.getH()));
|
||||
}
|
||||
}// end of class CNode
|
||||
80
CS1322/p6/MyWay/CTile.java
Normal file
80
CS1322/p6/MyWay/CTile.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* <PRE>
|
||||
* Tile.java
|
||||
*
|
||||
* Revisions: 1.0 Nov. 12, 2002
|
||||
* Created the Tile class
|
||||
*
|
||||
* </PRE>
|
||||
*
|
||||
* @author <A HREF="mailto:gtg184g@mail.gatech.edu">Jose Manuel Caban</A>
|
||||
* @version Version 1.0, Nov. 12, 2002
|
||||
*/
|
||||
|
||||
public class CTile extends CCoord{
|
||||
|
||||
/**
|
||||
*Defines whether the object is coming from the ground up to a given level
|
||||
*or whether it is a floating object (i.e. a bridge)
|
||||
*/
|
||||
private boolean bIsFloating;
|
||||
|
||||
/**
|
||||
*Define whether block has a special nibble
|
||||
*/
|
||||
private boolean bHasSpecial;
|
||||
|
||||
/**
|
||||
*Define whether block has a nibble
|
||||
*/
|
||||
private boolean bHasNibble;
|
||||
|
||||
////////////////
|
||||
//Constructors//
|
||||
////////////////
|
||||
|
||||
/**
|
||||
*@param x, the x-coord
|
||||
*@param y, the y-coord
|
||||
*@param h, the height
|
||||
*/
|
||||
public CTile(int x, int y, int h){
|
||||
this(x,y,h,false);
|
||||
}
|
||||
|
||||
/**
|
||||
*Same as other constructor but adds
|
||||
*@param bIsFloating, defines whether the object is floating or not
|
||||
*/
|
||||
public CTile(int x, int y, int h, boolean bFloating){
|
||||
super(x,y,h);
|
||||
bIsFloating = bFloating;
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
//Accessors/Modifiers//
|
||||
///////////////////////
|
||||
|
||||
/**
|
||||
*@return true if object can be passed over
|
||||
*/
|
||||
public boolean isPassable(Coord op){
|
||||
if(op.getH() == this.h){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Debugging main for class Tile.
|
||||
* This method will rigorously test my code.
|
||||
*
|
||||
* <br><br>
|
||||
* @param args a String array of command line arguments.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
|
||||
|
||||
}// end of main(String[] args)
|
||||
|
||||
}// end of class Tile
|
||||
27
CS1322/p6/MyWay/Constants.java
Normal file
27
CS1322/p6/MyWay/Constants.java
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* <PRE>
|
||||
* Constants.java
|
||||
*
|
||||
* Revisions: 1.0 Nov. 13, 2002
|
||||
* Created the Constants class
|
||||
*
|
||||
* </PRE>
|
||||
*
|
||||
* @author <A HREF="mailto:gtg184g@mail.gatech.edu">Jose Manuel Caban</A>
|
||||
* @version Version 1.0, Nov. 13, 2002
|
||||
*/
|
||||
|
||||
public interface Constants {
|
||||
|
||||
/*Directions*/
|
||||
/**
|
||||
*Define 4 movement constants: MV_UP, MV_DN, MV_LFT, MV_RGHT
|
||||
*/
|
||||
public static final int MV_UP = 0;
|
||||
public static final int MV_DN = 1;
|
||||
public static final int MV_LFT = 2;
|
||||
public static final int MV_RGHT = 3;
|
||||
|
||||
|
||||
|
||||
}// end of class Constants
|
||||
20
CS1322/p6/MyWay/board_1.txt
Normal file
20
CS1322/p6/MyWay/board_1.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
0 7
|
||||
1 1
|
||||
13 1
|
||||
13 13
|
||||
1 13
|
||||
w w w w w w w w w w w w w w w
|
||||
w s f n n n n w n n n n f s w
|
||||
w f w w w w n w n w w w w f w
|
||||
w n w n n n n w n n n n w n w
|
||||
w n w n w w w w w w w n w n w
|
||||
w n w n n n n n n n n n w n w
|
||||
w n w n n n w w w n n n w n w
|
||||
f n n n n n w f w n n n n n w
|
||||
w n w n n n w w w n n n w n w
|
||||
w n w n n n n n n n n n w n w
|
||||
w n w n w w w w w w w n w n w
|
||||
w n w n n n n w n n n n w n w
|
||||
w f w w w w n w n w w w w f w
|
||||
w s f n n n n w n n n n f s w
|
||||
w w w w w w w w w w w w w w w
|
||||
20
CS1322/p6/MyWay/board_2.txt
Normal file
20
CS1322/p6/MyWay/board_2.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
0 7
|
||||
1 1
|
||||
13 1
|
||||
13 13
|
||||
1 13
|
||||
w w w w w w w w w w w w w w w
|
||||
w s f n n n n n n n n n f s w
|
||||
w f w w w w w n w w w w w f w
|
||||
w n w f f f w n w f f f w n w
|
||||
w n w w w w w n w w w w w n w
|
||||
w n w n n n n n n n n n w n w
|
||||
w n w n w n w w w n w n w n w
|
||||
f n n n n n w f w n n n n n f
|
||||
w n w n w n w w w n w n w n w
|
||||
w n w n n n n n n n n n w n w
|
||||
w n w w w w w n w w w w w n w
|
||||
w n w f f f w n w f f f w n w
|
||||
w f w w w w w n w w w w w f w
|
||||
w s f n n n n n n n n n f s w
|
||||
w w w w w w w w w w w w w w w
|
||||
800
CS1322/p6/MyWay/p6.nfo.txt
Normal file
800
CS1322/p6/MyWay/p6.nfo.txt
Normal file
@@ -0,0 +1,800 @@
|
||||
CS1322: Programming Assignment #6 - Fall 2002.
|
||||
Assigned: November 11, 2002
|
||||
Phase I Instant Feedback Due Date: November 21, 2002 11:59:59
|
||||
Phase II Instant Feedback Due Date: November 25, 2002 11:59:59
|
||||
DUE Date: November 25, 2002 11:59:59 PM
|
||||
|
||||
|
||||
Program Title: Pacman
|
||||
|
||||
|
||||
Files Provided
|
||||
====================================================================
|
||||
|
||||
o P6.nfo.txt - this file
|
||||
o board_1.txt - an input file that specifies board #1
|
||||
o board_2.txt - an input file that specifies board #2
|
||||
o GhostAI.class - a class that makes decisions on Ghost movement
|
||||
o P6Constants.java - Interface needed for P6
|
||||
(You must use these constants when appropriate)
|
||||
o various image files
|
||||
|
||||
Learning Objectives
|
||||
====================================================================
|
||||
|
||||
o Advanced DataStructures
|
||||
o Advanced GUIs
|
||||
|
||||
|
||||
Other Resources
|
||||
====================================================================
|
||||
|
||||
Website containing screenshots and nfo file with pictures at
|
||||
|
||||
http://128.61.63.158/cs1322/P6
|
||||
|
||||
|
||||
PROGRAM OVERVIEW
|
||||
====================================================================
|
||||
Welcome to the 6th and final programming assignemnt! A word of
|
||||
caution: This project will be the most difficult one in this course.
|
||||
You will be required to utilize all that you have learned in order to
|
||||
complete this assignment. START EARLY!
|
||||
|
||||
This assignment will be very similar to the arcade classic - Pacman.
|
||||
For those of you who aren't familiar with the game, Pacman is a little
|
||||
yellow smiley face controlled by you, the user. The goal is to have
|
||||
Pacman eat all the nibbles (dots on the board). If Pacman completes
|
||||
this objective, you win the game. However, there are 4 ghosts
|
||||
pursuing Pacman. If one of the ghosts catches him, the game is over.
|
||||
Pacman has one defense however: the special nibbles placed on the
|
||||
board. If Pacman eats a special nibble, the ghosts can be eaten by
|
||||
Pacman for a time. During this period, the ghosts run away from
|
||||
Pacman. If a ghost is eaten, it returns to its start location on the
|
||||
board and resumes it's role of pursing and attempting to catch Pacman
|
||||
even if the others are still running from Pacman. After a time, all
|
||||
the ghosts return to the original state of pursuing Pacman.
|
||||
|
||||
HEY! guess what! START EARLY!
|
||||
|
||||
|
||||
A Word About Imlementation and Grading
|
||||
====================================================================
|
||||
|
||||
In the past five assignments, the TAs and nfo files have largely
|
||||
specified exactly which methods, parameters, classes and fields you
|
||||
would need to complete the assignment. This assignment will be
|
||||
different. While we will supply a recommended design, the exact means
|
||||
of implementation in terms of which methods or fields you use is left
|
||||
ambiguous. With the exception of the Instant Feedback phases, you
|
||||
will be largely responsible for figuring out which methods you wish to
|
||||
create to solve a given problem. This assignment will be graded more
|
||||
in terms of functionality i.e. "does this feature function correctly?"
|
||||
rather than "is this method present with these exact parameters".
|
||||
With this in mind, you can feel free to create whatever methods you
|
||||
wish to solve the problem. In addition, those of you looking for a
|
||||
challenge or wanting to fight "the man" can feel free to deviate as
|
||||
much or as little as you want from the design below. (Again, with the
|
||||
exception of the Instant Feedback phases. You must do what we tell
|
||||
you there.) Keep in mind, however, that as you deviate from the
|
||||
recommended design, it becomes difficult to give partial credit if
|
||||
things don't work correctly. So if you do choose to go your own way,
|
||||
do so at your own risk. If you are not yet comfortable leaving the
|
||||
nest, the design below is provided.
|
||||
|
||||
<cough>Start Early!
|
||||
|
||||
|
||||
Overall Design
|
||||
====================================================================
|
||||
|
||||
In the MVC (Model, View, Controller) paradigm of GUI programming, we
|
||||
separate parts of the program into three pieces:
|
||||
|
||||
The Model - This class or group of classes stores the state of the
|
||||
data in the program. It is often a data structure such as a BST or
|
||||
Heap. The model typically is independent of any GUI widgets. This
|
||||
allows our program to be more portable. If we wanted to use our
|
||||
data in some interface other than a GUI, say a text console
|
||||
interface, there would be little to no recoding of the model.
|
||||
|
||||
The View - This gruop of classes is responsible for displaying the
|
||||
GUI. Often they extend or hold GUI widget instances. We don't
|
||||
want the view to hold the state of any data. This is the role of
|
||||
the model.
|
||||
|
||||
The Controller - This class or group of classes is responsible for
|
||||
manipulating the model according to the needs of the program.
|
||||
Often is the listener of events from GUI widgets (as EventHandler
|
||||
was in P5)
|
||||
|
||||
The UIDelegate paradigm of GUI programming is very similar to MVC.
|
||||
The only difference is that in UIDelegate we combine the roles of View
|
||||
and Controller into one class or group of classes.
|
||||
|
||||
|
||||
Now an overview of the classes of Pacman:
|
||||
|
||||
Model - GamePiece, WallPiece, FloorPiece, MoveablePiece, Ghost, Pacman
|
||||
View - GameBoard, PacmanFrame
|
||||
Controller - PacmanFileReader, PacmanEngine, PacmanFrame
|
||||
|
||||
Notice PacmanFrame is both a View and a Controller. This means it
|
||||
will be a UIDelegate class.
|
||||
|
||||
|
||||
|
||||
PHASE I - The Pieces - Instant Feedback
|
||||
====================================================================
|
||||
|
||||
The classes in this phase will be model classes that represent the
|
||||
tiles and pieces on the board. They will be independent of any GUI
|
||||
widgets. They merely will hold information about the piece such as
|
||||
where it is on the board.
|
||||
|
||||
Create a class called GamePiece. This class will be an abstract super
|
||||
class to all pieces of the game board. GamePiece should include the
|
||||
following:
|
||||
|
||||
o a protected int called "x". This variable will represent which
|
||||
column the piece is in. i.e., it's location along the x-axis.
|
||||
o a protected int called "y". This variable will represent which
|
||||
row the piece is in. i.e., it's location along the y-axis.
|
||||
|
||||
Together these two variables represent the exact location of the
|
||||
board this particular piece is in. The location 0,0 will be the
|
||||
upper left hand corner of the game board.
|
||||
|
||||
o public accessors for both of the above variables.
|
||||
|
||||
o a public method called setPostition that takes in two
|
||||
parameters: x followed by y and sets the location variables to
|
||||
these parameters.
|
||||
o a constructor that takes in two parameters: x followed by y and
|
||||
sets the location variables to these parameters.
|
||||
|
||||
|
||||
Create a class called FloorPiece. This class will extend GamePiece.
|
||||
It will also add the functionality of nibbles (The dots that Pacman
|
||||
eats) Each FloorPiece can have a regular nibble, a special nibble
|
||||
(one that allows Pacman to chase the ghosts), or neither (but not
|
||||
both). FloorPiece should have the following:
|
||||
|
||||
o a private boolean variable called "hasNibble". This variable
|
||||
will represent whether or not this FloorPiece has a nibble that
|
||||
Pacman eats (the regular ones, not the ones that lets Pacman
|
||||
chase Ghosts)
|
||||
o a private boolean variable called "hasSpecial". This variable
|
||||
will represent whether or not this FloorPiece has a special
|
||||
nibble that allows Pacman to chase Ghosts.
|
||||
o accessors and modifiers for both of the above
|
||||
o a constructor that takes in four parameters: the x and y
|
||||
location and two booleans representing whether or not this FloorPiece
|
||||
should have a nibble or a special. This constructor should chain
|
||||
to the super constructor and set hasNibble and hasSpecial
|
||||
according to the parameters.
|
||||
|
||||
|
||||
Create a class called WallPiece. This class will extend GamePiece.
|
||||
It will also add the functionality of a wall on the game board.
|
||||
Neither ghosts nor Pacman can travel on or through walls. They can
|
||||
only travel on FloorPieces. Your WallPiece class should have the
|
||||
following:
|
||||
|
||||
o a constructor that takes in two parameters: the x and y
|
||||
locations of this piece. This constructor should chain to the
|
||||
super constructor.
|
||||
|
||||
|
||||
Create a class called MoveablePiece. This class will be abstract and
|
||||
extend GamePiece. This class will be the super class of both Ghost
|
||||
and Pacman. MoveablePiece should have the following:
|
||||
|
||||
o a constructor that takes in two ints: the x and y location of
|
||||
this piece. This constructor should chain to the
|
||||
super constructor.
|
||||
o a public method named "move" that returns void and takes in an
|
||||
int representing a direction. This parameter will be either
|
||||
NORTH, EAST, SOUTH, or WEST from P6Constants. This constants
|
||||
will represent up, right, down and left respectively. In this
|
||||
method you should "move" the piece. This means modify the
|
||||
piece's x or y location accordingly. Don't forget that (0,0) is
|
||||
the top left corner of the board.
|
||||
|
||||
|
||||
|
||||
PHASE II - Ghosts and Pacman - Instant Feedback
|
||||
====================================================================
|
||||
|
||||
These two classes will be model classes for Pacman and an individual ghost.
|
||||
|
||||
Create a class called Pacman which extends MoveablePiece. This class
|
||||
will model the Pacman piece which the user will control. Pacman
|
||||
should include the following:
|
||||
|
||||
o a private int variable named "direction". This variable will
|
||||
contain one of the four constants from P6Constants: NORTH, EAST,
|
||||
SOUTH, WEST. This variable will represent the direction Pacman
|
||||
is currently heading on the board. This variable will be
|
||||
initialized to EAST.
|
||||
o a constructor that takes in two ints: the x and y location of
|
||||
this piece. This constructor should chain to the
|
||||
super constructor.
|
||||
|
||||
Now the Ghosts...
|
||||
|
||||
Before we get into the details of implementing Ghost, let's talk
|
||||
about how the Ghost will chase (or run from) Pacman.
|
||||
|
||||
Provided to you is a class called GhostAI. This class has a single
|
||||
static method:
|
||||
|
||||
public static int[] getGhostMove(int ghostX, int ghostY,
|
||||
int pacmanX, int pacmanY)
|
||||
|
||||
Here's what the parameters do
|
||||
o ghostX: the x location of a ghost
|
||||
o ghostY: the y location of a ghost
|
||||
o pacmanX: the x location of Pacman
|
||||
o pacmanY: the y location of Pacman
|
||||
|
||||
The return value will always be an int array of size four. The array
|
||||
contains each of the four directions from P6Constants in the order of
|
||||
priority. So:
|
||||
|
||||
o index 0: the ghost's first choice of directions to move
|
||||
o index 1: the ghost's second choice of directions to move
|
||||
o index 2: the ghost's third choice of directions to move
|
||||
o index 3: the ghost's fourth (last) choice of directions to
|
||||
move
|
||||
|
||||
So why bother with all this priority stuff? Why not just return the
|
||||
direction the ghost wants to move. Well what if we have a case like
|
||||
the following:
|
||||
|
||||
Ghost
|
||||
Wall Wall Wall Wall Wall
|
||||
Pacman
|
||||
|
||||
The ghost's first choice of movement will be SOUTH toward Pacman. But
|
||||
that's not an option because of the wall. We don't want our Ghosts to
|
||||
just sit if they can't go somewhere. So we would try our second
|
||||
choice, which in this case would be either EAST or WEST. The last
|
||||
choice, in index 3, would be NORTH away from Pacman. Consider the
|
||||
following case:
|
||||
|
||||
Wall Wall
|
||||
Wall Wall
|
||||
Wall Ghost Wall
|
||||
Wall Wall Wall
|
||||
Pacman
|
||||
|
||||
In this case, none of the first three choices will contain viable
|
||||
moves. So the ghost's only choice is to go up. If this happens,
|
||||
there will be a gap between the Ghost and the bottom wall. On the
|
||||
next turn the Ghost can indeed use its first choice and move SOUTH
|
||||
(Given that Pacman isn't going anywhere for some reason) If Pacman
|
||||
were to stay put, the Ghost would end up oscillating back and forth
|
||||
against the bottom wall. What happens if the Ghost is running from
|
||||
Pacman after Pacman ate a special nibble. The priorities are just
|
||||
reversed. Logically this makes sense. If a ghost's first priority
|
||||
was to move SOUTH towards Pacman while chasing Pacman, SOUTH will be
|
||||
the last priority when Pacman is chasing the ghost. Unfortunately,
|
||||
the Ghost artificial intelligence algorithm we provide is somewhat
|
||||
primitive. Consider the following case:
|
||||
|
||||
Wall Wall Wall Wall Wall Wall
|
||||
Wall
|
||||
Pacman Wall Ghost
|
||||
Wall Wall Wall
|
||||
|
||||
|
||||
If Pacman were to never move, the Ghost would simply run up against
|
||||
the West wall over and over. If the Ghost were smart, it would go
|
||||
around the South wall to get to Pacman but it doesn't. You must use
|
||||
the Ghost movement algorithm we provide for instant feedback.
|
||||
However, for the final turn in, you can develop your own, better
|
||||
movement algorithm if you wish. (Just make sure it works) This would
|
||||
be worth some juicy extra credit.
|
||||
|
||||
Create a class called Ghost that extends MoveablePiece. This class
|
||||
will represent a Ghost. There will be four instances in your program,
|
||||
one for each of the four ghosts. Ghost should have the following:
|
||||
|
||||
o a private int variable called "ghostNum". This will be the
|
||||
number of the ghost.
|
||||
o a private boolean variable called "runAwayFlag". This will be
|
||||
true if this Ghost is running from Pacman and false if chasing
|
||||
Pacman.
|
||||
o a private int variable called "runAwayCount". This will
|
||||
contain the number of returns remaining for this ghost to run
|
||||
from Pacman. (Remember that a ghost will run from Pacman for a
|
||||
fixed number of moves if Pacman eats a special nibble)
|
||||
o a private int variable called "startX". This will contain the
|
||||
starting x coordinate for this ghost.
|
||||
o a private int variable called "startY". This will contain the
|
||||
starting y coordinate for this ghost.
|
||||
|
||||
The startX and startY variables together represent the start
|
||||
coordinates for the Ghost. The ghost will begin the game at this
|
||||
location. The ghost will also return to this location if eaten
|
||||
by pacman when running from him.
|
||||
o accessors for ghostNum, runAwayFlag, startX and startY
|
||||
o a public void method named "runAway" which takes in no parameters.
|
||||
This sets runAwayFlag to true and initializes runAwayCount to
|
||||
RUN_AWAY_DURATION from P6Constants
|
||||
o a public void method called "resetGhost" which takes in no
|
||||
parameters. This method will be invoked if this ghost is eaten
|
||||
by Pacman. It should turn runAwayFlag to false and return the
|
||||
ghost to it's start coordinates.
|
||||
o a public method named "getMove" that returns an int[] and takes
|
||||
in two parameters: pacman's x and y location. This method will
|
||||
calculate the array of size four containing this ghost's choices
|
||||
of movement as described above. Feel free to use the GhostAI
|
||||
class. Keep in mind however that the getGhostMove method
|
||||
provided assumes the ghost is chasing pacman. You will need to
|
||||
modify the array to have the ghost run away from Pacman if this
|
||||
is the case. If the Ghost is indeed running from Pacman, be sure
|
||||
to deduct a turn from runAwayCount and check to see if
|
||||
runAwayCount is zero, in which case you should have the ghost no
|
||||
longer run from Pacman. This method will not actually set the
|
||||
location of the ghost based on the GhostAI method. It simply
|
||||
returns the array of choices. We do this because this ghost has
|
||||
no clue whether any of its choices will take it into a wall. A
|
||||
class later in the project will process the choices and decide
|
||||
which moves are legal for this ghost. The ghost will then be
|
||||
told which way to move.
|
||||
o a public constructor that takes in three parameters: an x and y
|
||||
start location and a ghostNum representing this ghost's number.
|
||||
You should set the instance variable accordingly.
|
||||
|
||||
|
||||
PHASE III - PacmanFileReader
|
||||
====================================================================
|
||||
|
||||
From this point, you can feel free to ignore the design and do your
|
||||
own thing if you wish provided you supply all the functionality of the
|
||||
design we recommend. Remember the warning about grading though.
|
||||
Even if you choose to use your own design, your program must still
|
||||
present equivalent capabilities. And if your program doesn't work and
|
||||
you used a different design, there is less chance of getting partial
|
||||
credit.
|
||||
|
||||
Also realize that from this point there will be less explicit
|
||||
information on what methods you need or how to implement them. There
|
||||
are a variety of implementations that fit the suggested design. You
|
||||
can choose one that suits you. You do not need to ask if you can
|
||||
create a particular method or field. If it seems like you need method
|
||||
x to perform some task, by all means, do it.
|
||||
|
||||
Onward...
|
||||
|
||||
Create a class called PacmanFileReader. This class will be
|
||||
responsible for reading in a board file like one of the two we
|
||||
provided you and translating it into an array of GamePiece instances.
|
||||
If you open up one of the board files, you'll notice several rows of
|
||||
seemingly random characters. Let's discuss the tokens found in
|
||||
board_1.txt:
|
||||
|
||||
w <==> P6Constants.WALL <==> an instance of WallPiece
|
||||
f <==> P6Constants.FLOOR <==> an instance of FloorPiece w/out either
|
||||
kind of nibbles
|
||||
n <==> P6Constants.NIBBLE <==> an instance of FloorPiece with a
|
||||
regular nibble
|
||||
s <==> P6Constants.SPECIAL <==> an instance of FloorPiece with a
|
||||
special nibble
|
||||
|
||||
The first five rows specify the starting locations of Pacman and the
|
||||
ghosts.
|
||||
|
||||
0 7 <-- Pacman's x,y start coordinates
|
||||
1 1 <-- Ghost #1's startX and startY instance variable values.
|
||||
13 1 <-- Ghost #2's startX and startY instance variable values.
|
||||
13 13 <-- Ghost #3's startX and startY instance variable values.
|
||||
1 13 <-- Ghost #4's startX and startY instance variable values.
|
||||
|
||||
The next rows will contain the four tokens discussed above. There
|
||||
will always be 15x15 tokens. Look at the picture on the project
|
||||
website under "using board_1.txt". Can you see the relationship
|
||||
between the text file and the appearance of the board?
|
||||
|
||||
In this class, the goal is to translate these tokens into an array of
|
||||
GamePieces. We recommend your PacmanFileReader have the following:
|
||||
|
||||
o a private GamePiece[][] variable named "pieceArray". This
|
||||
array will model the board seen in the GUI.
|
||||
o a BufferedReader to read the board file
|
||||
o instance variables for pacman and four ghosts
|
||||
o a constructor that takes in the name of a file to read.
|
||||
o a helper method or series of helper methods called by the
|
||||
consturctor that does the following:
|
||||
- instantiates a BufferedReader to read the board file
|
||||
passed into the constructor
|
||||
- Reads each of the first five lines of the board file, uses
|
||||
a StringTokenizer to get the x and y start coordinates and
|
||||
instantiates Pacman or each of the four Ghosts (depending on
|
||||
which line you're on)
|
||||
- for the rest of the fifteen lines: Keep two counters, one
|
||||
for the x index of the board and one for the y index.
|
||||
Read in a line and use a StringTokenizer to get each
|
||||
token. Instantiate each cell of pieceArray to the
|
||||
appropriate GamePiece subclass passing in the x and y
|
||||
index as the GamePiece coordinates. After each token
|
||||
increment the x counter. After each line increment y and
|
||||
reset x.
|
||||
|
||||
|
||||
PHASE IV - The GUI
|
||||
====================================================================
|
||||
|
||||
In this phase we will code the View portion of our MVC design. There
|
||||
are two classes: PacmanFrame and GameBoard which will extend JFrame
|
||||
and JPanel, respectively. The GameBoard will be responsible for
|
||||
drawing or painting the board according to the GamePiece array you
|
||||
created in PacmanFileReader. Now it's time for our segway into
|
||||
painting.
|
||||
|
||||
Let's talk a moment about paintComponent:
|
||||
|
||||
Every GUI component has a protected method called paintComponent that
|
||||
is reponsible for making the GUI component look the way it does. The
|
||||
unoverrided form draws the default appearance for the widget. For a
|
||||
JPanel this is just huge blank gray area. For JButtons there is some
|
||||
slight shadowing on the edges of the button. However, you can
|
||||
override this method in a subclass of a GUI widget. In this overriden
|
||||
method you can make the widget appear almost anyway you want. You can
|
||||
draw lines, pictures, shapes, change the widget's color, etc.
|
||||
|
||||
The paintComponent() function receives a Graphics object that is
|
||||
used to draw on the component which owns it (In this case a GameBoard).
|
||||
It is important to know that you will NEVER call paintComponent directly;
|
||||
if you would like to update your component, call repaint(). The swing
|
||||
windowing environment will send the proper Graphics context to
|
||||
paintComponent(). Familiarize yourself with all of the methods in the
|
||||
Graphics component from the API so you can draw using your Graphics
|
||||
object. The Graphics parameter can sort of be thought of as your
|
||||
brush and the widget where paintComponent is overriden as your canvas.
|
||||
|
||||
An example of an overridden paintComponent function:
|
||||
|
||||
protected void paintComponent( Graphics g ) {
|
||||
|
||||
// I call the super paintComponent to draw the component the regular
|
||||
//way first
|
||||
super.paintComponent( g );
|
||||
|
||||
//set the Graphics object's current color to blue. This is sort of
|
||||
like dipping your brush into blue paint
|
||||
g.setColor(java.awt.Color.blue);
|
||||
|
||||
//draw a circle (actually an oval with equal width and height)
|
||||
//100 pixels in diameter. The result will be an unfilled
|
||||
//blue circle
|
||||
g.drawOval( 0, 0, 100, 100 );
|
||||
|
||||
}// end of paintComponent( Graphics )
|
||||
|
||||
|
||||
Let's talk a moment about images. Images in java are represented by a
|
||||
variety of classes. The easiest way to use images is to use the
|
||||
ImageIcon class. The constructor of this class takes in a String that
|
||||
is the file name of a jpg, gif, etc. In order to draw images on a GUI
|
||||
widget, we need to draw an instance of Image not ImageIcon. ImageIcon
|
||||
provides a method called .getImage which returns an Image instance
|
||||
representation of the image at the file name you passed in. The
|
||||
Graphics instance also requires you have an ImageObserver as a
|
||||
parameter to the drawImage method. ImageIcons come with another
|
||||
method called .getImageObserver() which will fill this requirement.
|
||||
|
||||
Create a class called GameBoard that extends JPanel. This class should have the
|
||||
following:
|
||||
|
||||
o a private GamePiece[][] variable named "pieceArray". This
|
||||
array will model the board seen in the GUI.
|
||||
o a constructor that takes in a file name of a board file. This
|
||||
file name will be passed off to a PacmanFileReader.
|
||||
o a method called from the constructor that initializes the
|
||||
provided images of the four ghosts, the image of a ghost in run
|
||||
away mode, and of pacman.
|
||||
o a protected method called paintComponent that takes in a
|
||||
Graphics instance and returns void. This method is fairly
|
||||
complicated since it has to draw the entire Pacman board
|
||||
including the Pacman image and the ghost images.
|
||||
|
||||
We will be drawing a series of rectangles on the widget. Each
|
||||
rectangle will represent one value of pieceArray. WallPiece
|
||||
instances will be drawn blue. FloorPiece instances black.
|
||||
FloorPiece instances with regular nibbles will have small yellow
|
||||
rectangles or circles in the center of the black rectangle and
|
||||
instances with special nibbles will have larger orange
|
||||
rectangles or circles in the center of the black rectangle.
|
||||
Pacman and the ghosts will be drawn last over the top of the
|
||||
board. So how exactly are we supposed to draw one blue or black
|
||||
or orange rectangle at an exact location on the board. For this
|
||||
we'll have to do a little arithmetic.
|
||||
|
||||
The number of rectangles drawn per row will be the same number of
|
||||
elements in one dimension of piecesArray and the number of rows
|
||||
drawn will be the same number in the other dimension of
|
||||
piecesArray.
|
||||
|
||||
The width of one board rectangle will be the width of the whole
|
||||
board divided by the number of elements in the X dimension of
|
||||
pieceArray. The height of one board rectangle will be the
|
||||
height of the whole board divided by the number of elements in
|
||||
the Y dimension of pieceArray.
|
||||
|
||||
The method .fillRect(int, int, int, int) inside Graphics takes in
|
||||
four parameters: xStart, yStart, width, height. the "pen" starts
|
||||
at pixel xStart and yStart as the top left corner in the
|
||||
rectangle and draws a rectangle width wide and height high. So
|
||||
how do we get to the correct x and y start locations. Since each
|
||||
board rectangle represents an array of GamePieces, we can draw
|
||||
the correct GamePiece rectangle in the correct spot by setting
|
||||
our x start pixel to be the x index of the array multiplied by
|
||||
the width of one rectangle. Respectivley we can set our y start
|
||||
pixel to be the y index of the array multiplied by the height of
|
||||
one rectangle. See the figure on the P6 website under "Drawing a
|
||||
Rectangle on GameBoard". Now we'll discuss what to do in
|
||||
paintComponent:
|
||||
|
||||
- call super.paintComponent to draw the default widget
|
||||
first.
|
||||
- get the width and height of one rectangle
|
||||
- iterate through pieceArray. If the piece we're at is a
|
||||
WallPiece instance, draw a blue rectangle. If it's
|
||||
a FloorPiece with no nibble, draw a black rectangle. If
|
||||
it has a nibble, draw the nibble accordingly. You may
|
||||
have to experiment with a centering the nibble in the
|
||||
middle of the black rectangle. Here's a hint though:
|
||||
you'll be dividing by two a lot.
|
||||
- after drawing the GamePieces, draw the pacman image at his
|
||||
current location.
|
||||
- draw each of the ghosts at their current location. Don't
|
||||
forget to draw the ghosts with the correct image. If they
|
||||
are being chased you need to draw them appropriately.
|
||||
|
||||
NOTE: The x and y instance variables in Pacman and Ghost are
|
||||
the index the GamePiece they reside on. In other words
|
||||
thore values will always be between 0 and 14. The x and y
|
||||
values when dealing with the Graphics object are pixels.
|
||||
Keep this in mind.
|
||||
|
||||
Create a class called PacmanFrame which extends JFrame. This class
|
||||
will contain a GameBoard and a menu. PacmanFrame should have the
|
||||
following:
|
||||
|
||||
o an instance of GameBoard
|
||||
o a JMenu with two JMenuItems:
|
||||
- one that activates a new game: This should restart the
|
||||
game no matter what the state of the current game.
|
||||
- one that exits the program. This should stop the JVM just
|
||||
as if we clicked on the X in the top right corner of the
|
||||
frame.
|
||||
o a default constructor which sets up the frame with a
|
||||
BorderLayout, instantiates a new GameBoard and adds it to the
|
||||
center. There is a constant in P6Constants called BOARD_FILE
|
||||
containing the name of the file to tokenize into a GamePiece
|
||||
array.
|
||||
o We recommend you set the size of the frame to be about 520x520
|
||||
o helper methods that set up the menus.
|
||||
o We recommend you have this class be a listener for its own
|
||||
JMenuItems. You will need to then have this class implement
|
||||
ActionListener.
|
||||
o The program should exit gracefully if either the quit menu is
|
||||
chosen or the X in the top right is clicked.
|
||||
|
||||
|
||||
|
||||
PHASE V - PacmanEngine
|
||||
====================================================================
|
||||
|
||||
The PacmanEngine class will be our controller in the MVC paradigm for
|
||||
this project. It will likely be your single biggest class. For lack
|
||||
of a better description, PacmanEngine will be the arbiter for the
|
||||
game. It will process user control inputs, decide which movements by
|
||||
pacman and the ghosts are legal, regulate the rate at which pacman and
|
||||
the ghosts, move and determine whether a win or loss condition exists.
|
||||
|
||||
First let's talk about Swing Timers. The class javax.swing.Timer is a
|
||||
class that can be set to fire ActionEvents at a specific
|
||||
interval. (yes the same Events fired by JButtons and JMenuItems) We
|
||||
will be using two Timers in PacmanEngine. One will regulate Ghost
|
||||
movement. Every time the Ghost Timer fires, we want all the ghosts to
|
||||
move one square. Where they move will be determined by the four
|
||||
element array returned from Ghost's getMove method. A second timer
|
||||
will regulate Pacman's movement. This timer will fire at a slightly
|
||||
faster rate because we want Pacman to be able to outrun the ghosts.
|
||||
Every time the Pacman Timer fires, we want Pacman to move one square
|
||||
in the direction specified in Pacman's direction variable. You will
|
||||
need to look at the API for specific methods to use.
|
||||
|
||||
Next let's talk about Key Listening. We've worked with ActionEvents
|
||||
and ChangeEvents. Now you will use a third event/listener group that
|
||||
listens for events from the keyboard. The game will be controlled by
|
||||
six different keyboard keys. The four arrow keys will control
|
||||
Pacman's direction. The 's' key will start the game (start Pacman and
|
||||
the Ghosts moving) at the beginning of a game. The 'p' key will pause
|
||||
and unpause the game. It's important to understand how Pacman will be
|
||||
controlled. Pacman does not move only when a key is pressed. He
|
||||
progresses in the direction specified by his direction variable at all
|
||||
times. The arrow key pressed merely changes this direction variable.
|
||||
There are exceptions to this. If pacman's direction takes him into a
|
||||
wall, Pacman will halt and wait until an arrow key is pressed to give
|
||||
him a new direction.
|
||||
|
||||
Now let's talk about JOptionPanes. The JOptionPane class provides
|
||||
simple pre-packaged diaglog boxes. All you need is a JFrame instance
|
||||
and the message you want to show the user. Here's how we will use one
|
||||
for this project:
|
||||
|
||||
JOptionPane.showMessageDialog(<instance of JFrame>,
|
||||
<String instance containing message
|
||||
you want to show to the user>,
|
||||
<String instance containing message
|
||||
to be displayed in Dialog Box title bar>,
|
||||
<int constant representing icon to be displayed in
|
||||
dialog box along with message>);
|
||||
|
||||
This method call will pop up a small dialog box on top of your PacmanFrame.
|
||||
Your instance of JFrame will be your PacmanFrame instance. Your message
|
||||
and title should be something meaningful and relevant. You can use any icon
|
||||
you want. Check out the API for a listing of icons and how to use them.
|
||||
Included in your dialog box will be an "OK" JButton which will close the box
|
||||
if pressed. This button is added and handled automatically by the method.
|
||||
No effort on your part is needed to add or handle the event from the button.
|
||||
|
||||
Create a class called PacmanEngine that implements both ActionListener
|
||||
and KeyListener. PacmanEngine should have the following:
|
||||
|
||||
o a javax.swing.Timer called GhostTimer. This variable will fire
|
||||
an ActionEvent every P6Constants.GHOST_INTERVAL milliseonds
|
||||
causing all the Ghosts to move one square
|
||||
o a javax.swing.Timer called PacmanTimer. This variable will fire
|
||||
an ActionEvent every P6Constants.PACMAN_INTERVAL milliseonds
|
||||
causing Pacman to move one square.
|
||||
o a GameBoard instance called board. This will be the GameBoard
|
||||
instance used to draw the state of the board
|
||||
o a PacmanFrame instance.
|
||||
o a Ghost[] variable called ghosts. This array will hold the
|
||||
four Ghosts in play.
|
||||
o a Pacman variable called pacman. This will be the Pacman
|
||||
instance in play.
|
||||
|
||||
o a constructor which takes in a PacmanFrame and a GameBoard and
|
||||
sets the appropriate variables to these parameters. You will
|
||||
also need to initialize both Timers. (but don't start them yet.)
|
||||
Also set the Ghost array and the Pacman variable to those
|
||||
variables initialized by PacmanFileReader.
|
||||
|
||||
o a method public void actionPerformed which takes in an
|
||||
ActionEvent. This method will be called by both Timers at the
|
||||
appropriate interval.
|
||||
|
||||
If this method was called by the PacmanTimer, it is Pacman's turn
|
||||
to move. You do not need to worry about any keys pressed in this
|
||||
method. Remember Pacman always moves in the direction specified
|
||||
by his direction variable every time the Timer fires. Before
|
||||
moving Pacman to the next square though, you need to first
|
||||
determine that the move is legal (i.e., Pacman won't be moving on
|
||||
top of a WallPiece or off the board) You have the GameBoard,
|
||||
pacman's current x and y locations and his current direction.
|
||||
From this information you can determine whether or not any given
|
||||
move is legal. It is recommended that the functionality for
|
||||
determining whether a given move is legal be abstracted to a
|
||||
helper method since you will be using the same functionality for
|
||||
the ghosts. If a given move is found to be legal, call Pacman's
|
||||
move method (extended from MoveablePiece) passing in the
|
||||
direction. Do not have PacmanEngine directly set the x and y
|
||||
location variables.
|
||||
|
||||
If this method was called by the GhostTimer, you will need to
|
||||
iterate through all four ghosts. At each ghost, call the getMove
|
||||
method to retrieve each ghost's array of move choices. You
|
||||
should then iterate through this array and move the ghost using the
|
||||
first legal move you encounter. (Remember the zeroth index holds
|
||||
the highest choice of movement for a particular ghost)
|
||||
|
||||
No matter which Timer called the method, you will need to
|
||||
determine if the most recent move by either Pacman or the Ghosts
|
||||
resulted in a state that should end the game. If all of the
|
||||
FloorPieces are missing nibbles, the player has won the game.
|
||||
You should display a notificatoin that the player has won using a
|
||||
JOptionPane message dialog. (That's why we have an instance of
|
||||
PacmanFrame which extends JFrame) If one of the Ghosts and
|
||||
Pacman occupies the same square and that Ghost is not running
|
||||
from Pacman, the player loses. Again display an appropriate
|
||||
message dialog to the user. If a Ghost and Pacman occupies the
|
||||
same square but that ghost is in fact running from Pacman, you
|
||||
should reset that ghost. You also need to process any time
|
||||
Pacman eats a nibble. If it's a regular simply remove that
|
||||
nibble from the board by notifying that particular floor piece to
|
||||
turn it's nibble boolean to false. If it's a special nibble, you
|
||||
not only need to have the FloorPiece set it's special boolean to
|
||||
false but you also need to iterate through all four ghosts and
|
||||
have them go into run away mode. The ghosts should run from
|
||||
Pacman and begin counting down their runAwayCount variables.
|
||||
|
||||
After processing all moves, if no end game condition exists, you
|
||||
should call repaint() on the GameBoard instance. This will make
|
||||
the GameBoard display the new locations of the ghosts.
|
||||
|
||||
|
||||
o a method public void keyPressed which takes in a KeyEvent.
|
||||
This method will be automatically called when any keyboard key is
|
||||
pressed. There are only six we care about though. If the 's'
|
||||
key is pressed, you should start both timers if they are not
|
||||
already running. If the 'p' key is pressed, you should stop the
|
||||
timers if they are running and start them if stopped. If one of
|
||||
the four arrow keys is pressed, you should set Pacman's direction
|
||||
variable to reflect the key pressed. You should only set the
|
||||
variable, however, if the Timers are running. But how do we
|
||||
figure out which key was pressed? The KeyEvent class has a
|
||||
method called getKeyCode() which returns an int that represents a
|
||||
key. Look through the KeyEvent API to figure out which constant
|
||||
represents the appropriate keys.
|
||||
|
||||
|
||||
|
||||
PHASE VI - Testing and Turnin
|
||||
====================================================================
|
||||
|
||||
Create a Driver class called "P6". This class should have a main
|
||||
method which instantiates PacmanFrame.
|
||||
|
||||
Swing GUI components can sometimes throw exceptions without the
|
||||
program crashing. i.e. you may see a stack trace on the
|
||||
console but amazingly the program still appears to be
|
||||
functioning. We consider this no different than if the program
|
||||
crashed. You should not have any stack traces from exceptions
|
||||
of any kind. You should catch and handle all exceptions.
|
||||
|
||||
This project, again, will require you to look through the API for many
|
||||
solutions to a given task. Please make an honest effort to figure out
|
||||
things for yourself before you seek outside help. This is the point
|
||||
of the exercise.
|
||||
|
||||
Make sure you turn in the following files:
|
||||
|
||||
o GamePiece.java
|
||||
o WallPiece.java
|
||||
o FloorPiece.java
|
||||
o MoveablePiece.java
|
||||
o Ghost.java
|
||||
o Pacman.java
|
||||
o PacmanFileReader.java
|
||||
o GameBoard.java
|
||||
o PacmanFrame.java
|
||||
o PacmanEngine.java
|
||||
o P6.java
|
||||
|
||||
These may vary if you deviated from the suggested design.
|
||||
|
||||
|
||||
PHASE VII - Extra Credit (Optional)
|
||||
====================================================================
|
||||
|
||||
There will be a modest amount of extra credit given to those students
|
||||
who go above and beyond the call of duty in the project. Make sure
|
||||
you do not attempt any extra credit until you can certify that the
|
||||
core requirements of the project have been satisfied.
|
||||
|
||||
Here are some ideas:
|
||||
|
||||
o In board #2, allow Pacman and/or the ghosts to go through the
|
||||
hole on either the left or right side of the board and appear on
|
||||
the opposite side. (i.e. wrapping around the board)
|
||||
o Make pacman "chew" as he moves along the board. A second
|
||||
pacman image with his mouth closed is provided
|
||||
o Make pacman and the ghosts move smoothly from square to square
|
||||
rather than abruptly appear in the next square.
|
||||
o Create a smarter ghost movement algorithm that allows ghosts to
|
||||
go around walls to get to pacman rather than just run up against
|
||||
the wall.
|
||||
o Develop a scoring system and display it somehow in PacmanFrame
|
||||
o Put fruit on the board like in Ms. Pacman
|
||||
o Use sound!
|
||||
o Two player!
|
||||
|
||||
====================================================================
|
||||
|
||||
Reference in New Issue
Block a user