这是我为了应聘一个游戏公司写的小游戏,以前不怎么接触java,还是第一次正式写java程序,有错误的地方,还望见谅!
下面是对游戏的一个简介:因为公司要求用英文,我就不翻译了,嘿嘿!
Guide and Improvements of Puyo Game
Author: handwolf 2005-4-30
Email: handwolf@tom.com
---------------
Rules of Game:
---------------
(1) Spheres come down from the top of the game board in pairs. A player can rotate and move them on their way down as following :
Press Key Sphere action
left move left by 1 step
right move right by 1 step
down move down by 1 step
blank space deasil turn by 1 step
(2) Spheres come in 4 different colors: red, blue, green, and yellow. New sphere's color is generated randomly.
(3) Removes spheres from screen when more than four same_color spheres links(horizontally, vertically or both(as in tetris)). Allowing any sphere remaining to drop and fill the vacated space. This may lead to several possible "chain combos" if additional colors match.
(4) If one sphere is blocked because there is something underneath, the other one will continue falling (with no player control over it) until it reaches something.
(5) About the score:
4 same-color spheres link in one line: +4
5 same-color spheres link in one line: +8
6 same-color spheres link in one line: +12
------------------------
The function of Buttons:
------------------------
(1) "Play" Button : Push this button to start a puyo game. while the game is playing, pushing this button will restart the puyo game.
(2) "Pause" Button: When text on this button is "Pause", pushing this button will pause the playing game, and the text on this button will changed to "Continue".
When text on this button is "Continue", pushing this button will continue the paused game, and the text on this button will changed to "Pause".
(3) "Level Up" Button: Push this button to add the game level, the highter level, the more difficult. And the highest level is 10.
(4) 'Level Down" Button: Push this button to reduce the game level, the lower level, the less difficult. And the lowest level is 1.
(5) 'Quit" Button: Once push this button, the application will be closed.
--------------------
Improvements
--------------------
I think once generate 2 spheres is a bit simple to players.
If once generate 3 or 4 new spheres, and make the game board larger, the game will be more challenging.
下面是java源代码,直接拷贝出来了.
import java.awt.*;
import java.awt.event.*;
import java.net.URLClassLoader;
import java.util.*;
//
//CLASS : Puyo
//ABSTRACT : the board of Puyo game
//NOTE :
//CREATE : handwolf 2005-4-29
//
public class Puyo extends Frame{
public static boolean m_bIsPlay=false;
public static int m_iScore = 0;
public static TextField m_fieldScore,m_fieldLevel;
public static MyTimer m_timer;
GameCanvas m_gameScr; //game screen
//added by handwolf 2005-4-30 (start)
public static Button play_b;
public static Button pause_b;
public static Button level_up_b;
public static Button level_down_b;
//added by handwolf 2005-4-30 (end)
public static int m_iLevel=1; //init game level
public static void main(String[] argus){
Puyo w_puyo = new Puyo("Puyo V1.0 Author:Handwolf");
WindowListener w_winListener = new WinListener();
w_puyo.addWindowListener(w_winListener);
}
//construct of Puyo, init the frame
Puyo(String title){
super(title);
setSize(400,420);
setResizable(false); //unresizable
setLayout(new GridLayout(1,2));
//left side of frame, contains the spheres
m_gameScr = new GameCanvas();
m_gameScr.addKeyListener(m_gameScr);
add(m_gameScr);
//right side of frame
Panel rightScr = new Panel();
rightScr.setLayout(new GridLayout(2,1,0,30));
rightScr.setSize(120,420);
add(rightScr);
//Game info, in the rightUp side
MyPanel infoScr = new MyPanel();
infoScr.setLayout(new GridLayout(8,1,0,1));
infoScr.setSize(120,300);
rightScr.add(infoScr);
//info of how to play this game
Label labelLeft = new Label("Left : left",Label.LEFT);
Label labelRight = new Label("Right: right",Label.LEFT);
Label labelDown = new Label("Down : down",Label.LEFT);
Label labelTurn = new Label("Turn : space",Label.LEFT);
infoScr.add(labelLeft);
infoScr.add(labelRight);
infoScr.add(labelDown);
infoScr.add(labelTurn);
labelLeft.setSize(new Dimension(20,60));
labelRight.setSize(new Dimension(20,60));
labelDown.setSize(new Dimension(20,60));
labelTurn.setSize(new Dimension(20,60));
//score of the player, and level of game
Label scorep = new Label("Score:",Label.LEFT);
Label levelp = new Label("Level:",Label.LEFT);
m_fieldScore = new TextField(8);
m_fieldLevel = new TextField(8);
m_fieldScore.setEditable(false);
m_fieldLevel.setEditable(false);
infoScr.add(scorep);
infoScr.add(m_fieldScore);
infoScr.add(levelp);
infoScr.add(m_fieldLevel);
scorep.setSize(new Dimension(20,60));
m_fieldScore.setSize(new Dimension(20,60));
levelp.setSize(new Dimension(20,60));
m_fieldLevel.setSize(new Dimension(20,60));
m_fieldScore.setText("0");
m_fieldLevel.setText("1");
//buttons,in the rightDown side
MyPanel controlScr = new MyPanel();
controlScr.setLayout(new GridLayout(5,1,0,5));
rightScr.add(controlScr);
//play
play_b = new Button("Play");
play_b.setSize(new Dimension(50,200));
play_b.addActionListener(new Command(Command.button_play,m_gameScr));
//Pause
pause_b =new Button("Pause");
pause_b.setSize(new Dimension(50,200));
pause_b.addActionListener(new Command(Command.button_pause,m_gameScr));
//Level Up
level_up_b = new Button("Level Up");
level_up_b.setSize(new Dimension(50,200));
level_up_b.addActionListener(new Command(Command.button_levelup,m_gameScr));
//Level Down
level_down_b =new Button("Level Down");
level_down_b.setSize(new Dimension(50,200));
level_down_b.addActionListener(new Command(Command.button_leveldown,m_gameScr));
//Quit
Button quit_b = new Button("Quit");
quit_b.setSize(new Dimension(50,200));
quit_b.addActionListener(new Command(Command.button_quit,m_gameScr));
controlScr.add(play_b);
controlScr.add(pause_b);
controlScr.add(level_up_b);
controlScr.add(level_down_b);
controlScr.add(quit_b);
setVisible(true);
m_gameScr.requestFocus();
//init the timer
m_timer = new MyTimer(m_gameScr);
m_timer.setDaemon(true);
m_timer.start();
m_timer.suspend();
}
}
//MyPanel, set the gap around
class MyPanel extends Panel{
public Insets getInsets(){
return new Insets(0,20,0,20);
}
}
//*************end of class Puyo******************//
//
//CLASS : GameCanvas
//ABSTRACT : the display screen of Puyo game, display the spheres
//NOTE :
//CREATE : handwolf 2005-4-29
//
class GameCanvas extends Canvas implements KeyListener{
Image m_images[]; //the images of sphere
int m_iUnitHeight; //the height of one unit,(the highest image's height)
int m_iUnitWidth; //the height of one unit,(the widest image's width)
TwoSphere m_twoSphere; //the active two sphere,which come down from the top of the game board.
int m_iRowNum; //row number of unit
int m_iColumnNum; //column number of unit
int m_iMaxAllowRowNum; //the max row that can contain sphere that can not fall down
int m_iSphereInitRow; //the init row of new sphere
int m_iSphereInitCol; //the init col of new sphere
int [][] m_iArrScr; //units of screen
//construte,init the data of screen
GameCanvas(){
m_images = new Image[4];
m_iUnitHeight = 0;
m_iUnitWidth = 0;
for(int i = 1; i < 5; ++i){
String strFileName = "sphere" + i + ".png";
m_images[i-1] = getImage(strFileName);
if(m_iUnitHeight < m_images[i-1].getHeight(this))
m_iUnitHeight = m_images[i-1].getHeight(this);
if(m_iUnitWidth < m_images[i-1].getWidth(this))
m_iUnitWidth = m_images[i-1].getWidth(this);
}
m_iRowNum = 12;
m_iColumnNum = 6;
m_iMaxAllowRowNum = m_iRowNum-1;
m_twoSphere = new TwoSphere(this);
m_iSphereInitRow = m_iRowNum - 1;
m_iSphereInitCol = m_iColumnNum/2;
m_iArrScr = new int [24][12];
}
//init the units of screen , init the sphere
void initScr(){
for(int i=0;i<24;i++)
for (int j=0; j<12;j++)
m_iArrScr[i][j]=0;
m_twoSphere.reset();
repaint();
}
//paint the screen
public void paint(Graphics g){
for(int i = 0; i < m_iRowNum; i++)
for(int j = 0; j < m_iColumnNum; j++)
drawUnit(i,j,m_iArrScr[i][j]);
}
//get the image specified by the filename
Image getImage(String filename)
{
URLClassLoader urlLoader = (URLClassLoader)getClass().getClassLoader();
java.net.URL url = null;
Image image = null;
url = urlLoader.findResource(filename);
image = Toolkit.getDefaultToolkit().getImage(url);
MediaTracker mediatracker = new MediaTracker(this);
try
{
mediatracker.addImage(image, 0);
mediatracker.waitForID(0);
}
catch(InterruptedException _ex)
{
image = null;
}
if(mediatracker.isErrorID(0))
image = null;
return image;
}
/
//MODULE : GameCanvas.drawUnit
//ABSTRACT : draw one unit of screen
//RETURN : void
//ARGUMENTS:
// I/O TYPE NAME EXPLANATION
// I int row,col the row ann col of unit in the screen
// I int type the image of unit,1--yellow sphere,2--blue sphere,3--green sphere,4--red sphere
//CREATE : handwolf 2005-4-29
/
public void drawUnit(int row,int col,int type){
m_iArrScr[row][col] = type;
Graphics g = getGraphics();
g.setColor(Color.black);//back color of screen is black
g.fill3DRect(col*m_iUnitWidth,getSize().height-(row+1)*m_iUnitHeight,m_iUnitHeight,m_iUnitWidth,true);
switch(type){
case 1: //1--yellow sphere
case 2: //2--blue sphere
case 3: //3--green sphere
case 4: //4--red sphere
g.setColor(Color.black);//back color of screen is black
g.fill3DRect(col*m_iUnitWidth,getSize().height-(row+1)*m_iUnitHeight,m_iUnitHeight,m_iUnitWidth,true);
g.drawImage (m_images[type-1], col*m_iUnitWidth,getSize().height-(row+1)*m_iUnitHeight, this);
break;
}
g.dispose();
}
public TwoSphere getTwoSphere(){
return m_twoSphere;
}
//get value of the specified unit in the screen
public int getScrUnit(int row,int col){
if (row < 0 || row >= m_iRowNum || col < 0 || col >= m_iColumnNum)
return(-1);
else
return(m_iArrScr[row][col]);
}
public int getInitRow(){
return(m_iSphereInitRow);
}
public int getInitCol(){
return(m_iSphereInitCol);
}
/
//MODULE : GameCanvas.deleteSameColorLink
//ABSTRACT : removes spheres from screen when more than four same_color spheres links(horizontally, vertically or both(as in tetris))
//RETURN : void
//CREATE : handwolf 2005-4-29
/
void deleteSameColorLink(){
class UnitXY{//save the unit that should be removed
public int col;
public int row;
UnitXY(){
col = 0;
row = 0;
}
UnitXY(int x, int y){
col = x;
row = y;
}
}
java.util.List lst_UnitDel = new ArrayList();//save the unit that should be removed
//search spheres horizontally
for(int iRow = 0; iRow < m_iRowNum; ++iRow){
int iLinkNum = 1;//the number of same_color spheres that link in line
for(int iCol = 0; iCol < m_iColumnNum - 3;){
//same sphere
if(iCol + iLinkNum < m_iColumnNum && m_iArrScr[iRow][iCol] != 0 && m_iArrScr[iRow][iCol] == m_iArrScr[iRow][iCol + iLinkNum]){
++iLinkNum;
}else if(iLinkNum >= 4){//find one line
Puyo.m_iScore += (iLinkNum-3)*4; //add the score
for(int iCol2 = iCol; iCol2 < iCol+iLinkNum; ++iCol2){
UnitXY w_unit = new UnitXY();
w_unit.col = iCol2;
w_unit.row = iRow;
lst_UnitDel.add(w_unit);//add to list, delete later
}
iCol = iCol + iLinkNum;//next col
iLinkNum = 1;
}else{
iCol = iCol + iLinkNum;//next col
iLinkNum = 1;
}
}
}
//search spheres vertically
for(int iCol = 0; iCol < m_iColumnNum; ++iCol){
int iLinkNum = 1;//the number of same_color spheres that link in line
for(int iRow = 0; iRow < m_iRowNum - 3;){
//same sphere
if(iRow + iLinkNum < m_iRowNum && m_iArrScr[iRow][iCol] != 0 && m_iArrScr[iRow][iCol] == m_iArrScr[iRow + iLinkNum][iCol]){
++iLinkNum;
}else if(iLinkNum >= 4){//find one line
Puyo.m_iScore += (iLinkNum-3)*4;
for(int iRow2 = iRow; iRow2 < iRow+iLinkNum; ++iRow2){
UnitXY w_unit = new UnitXY();
w_unit.col = iCol;
w_unit.row = iRow2;
lst_UnitDel.add(w_unit);//add to list, delete later
}
iRow = iRow + iLinkNum;//next row
iLinkNum = 1;
}else{
iRow = iRow + iLinkNum;//next row
iLinkNum = 1;
}
}
}
boolean bNeedDelAgain = false;//This function may lead to several possible "chain combos" if additional colors match
for(int i = 0; i<lst_UnitDel.size(); ++i ){
UnitXY w_unit=(UnitXY)lst_UnitDel.get(i);
drawUnit(w_unit.row,w_unit.col,0);
m_iArrScr[w_unit.row][w_unit.col]=0;
bNeedDelAgain = true;
}
//spheres remaining drop and fill the vacated space
for(int iCol = 0; iCol < m_iColumnNum; ++iCol){
boolean bIsColOver = true;
while(bIsColOver){
boolean bFlagModified = false;
for(int iRow = 0; iRow < m_iRowNum - 1; ++iRow){
if(m_iArrScr[iRow][iCol] == 0 && m_iArrScr[iRow+1][iCol] != 0){
m_iArrScr[iRow][iCol] = m_iArrScr[iRow+1][iCol];
m_iArrScr[iRow+1][iCol] = 0;
drawUnit(iRow+1,iCol,0);
drawUnit(iRow,iCol,m_iArrScr[iRow][iCol]);
bFlagModified = true;
}
}//end of for iRow
bIsColOver = bFlagModified;
}//end of while
}//end of for iCol
Puyo.m_fieldScore.setText(""+Puyo.m_iScore);
if(bNeedDelAgain)
deleteSameColorLink();
}
//check whether the game is over
boolean isGameEnd(){
for (int iCol = 0 ; iCol <m_iColumnNum; ++iCol){
if(m_iArrScr[m_iMaxAllowRowNum][iCol] != 0)
return true;
}
return false;
}
public void keyTyped(KeyEvent e){
}
public void keyReleased(KeyEvent e){
}
//conduct the message of key press
public void keyPressed(KeyEvent e){
if(!Puyo.m_bIsPlay)
return;
switch(e.getKeyCode()){
case KeyEvent.VK_DOWN:m_twoSphere.fallDown();break;
case KeyEvent.VK_LEFT:m_twoSphere.leftMove();break;
case KeyEvent.VK_RIGHT:m_twoSphere.rightMove();break;
case KeyEvent.VK_SPACE:m_twoSphere.deasilTurn();break;
}
}
}
//*************end of class GameCanvas******************//
//
//CLASS : Command
//ABSTRACT : conduct the Buttons' message
//NOTE :
//CREATE : handwolf 2005-4-29
//
class Command implements ActionListener{
static final int button_play = 1; //distribute id to buttons
static final int button_levelup = 2;
static final int button_leveldown = 3;
static final int button_quit = 4;
static final int button_pause = 5;
static boolean pause_resume = true;
int curButton; //current button
GameCanvas scr; //the screen
Command(int button,GameCanvas scr){
curButton = button;
this.scr=scr;
}
//conduct the Buttons' message
public void actionPerformed (ActionEvent e){
switch(curButton){
case button_play:if(Puyo.m_bIsPlay){
Puyo.m_bIsPlay = false;
Graphics g = scr.getGraphics();
g.clearRect(0,0,200,500);
}
Puyo.m_timer.suspend();
scr.initScr();
Puyo.m_bIsPlay = true;
Puyo.m_iScore = 0;
Puyo.m_fieldScore.setText("0");
Puyo.m_timer.resume();
scr.requestFocus();
break;
case button_levelup:if(Puyo.m_iLevel < 10){
Puyo.m_iLevel++;
Puyo.m_fieldLevel.setText(""+Puyo.m_iLevel);
Puyo.m_iScore = 0;
Puyo.m_fieldScore.setText(""+Puyo.m_iScore);
Puyo.level_down_b.enable(true);
} else{
Puyo.level_up_b.enable(false);
}
scr.requestFocus();
break;
case button_leveldown:if(Puyo.m_iLevel > 1){
Puyo.m_iLevel--;
Puyo.m_fieldLevel.setText(""+Puyo.m_iLevel);
Puyo.m_iScore = 0;
Puyo.m_fieldScore.setText(""+Puyo.m_iScore);
Puyo.level_up_b.enable(true);
}else{
Puyo.level_down_b.enable(false);
}
scr.requestFocus();
break;
case button_pause:if(pause_resume){
Puyo.m_timer.suspend();
pause_resume = false;
Puyo.pause_b.setLabel("Continue");
}else{
Puyo.m_timer.resume();
pause_resume = true;
Puyo.pause_b.setLabel("Pause");
}
scr.requestFocus();
break;
case button_quit:System.exit(0);
}
}
}
//*************end of class Command******************//
//
//CLASS : TwoSphere
//ABSTRACT : two spheres, which come down from the top of the game board.
//NOTE :
//CREATE : handwolf 2005-4-29
//
class TwoSphere{
Sphere sphere1,sphere2;//contains to sphere
GameCanvas scr; //the screen
TwoSphere(GameCanvas scr){
this.scr = scr;
sphere1 = new Sphere(scr);
sphere2 = new Sphere(scr);
sphere2.col = sphere1.col + 1;//2 is on right of 1
}
//reinit two sphere, and display them
public void reset(){
sphere1.reset();
sphere2.reset();
sphere2.col = sphere1.col + 1;
dispSphere();
}
/
//MODULE : TwoSphere.deasilTurn
//ABSTRACT : turn the two spheres deasil, 2 turn around 1 deasil.
//RETURN : void
//CREATE : handwolf 2005-4-29
/
public void deasilTurn(){
if(sphere1.sphereState == 2 || sphere2.sphereState == 2)//only one sphere can move
return ;
Puyo.m_timer.suspend();
if(sphere1.col < sphere2.col && sphere2.assertValid(-1,0) && sphere2.assertValid(-1,-1)){//2 is on the right side of 1
sphere2.Move(-1,-1);//2 move to leftdown side of 2
}else if(sphere1.row > sphere2.row && sphere1.col > 0 && sphere2.assertValid(0,-1) && sphere2.assertValid(1,-1)){//2 is on the down side of 1
sphere2.Move(1,-1);//2 move to leftup side of 2
}else if(sphere1.col > sphere2.col && sphere2.assertValid(1,0) && sphere2.assertValid(1,1)){//2 is on the left side of 1
sphere2.Move(1,1);//2 move to rightup side of 2
}else if(sphere1.row < sphere2.row && sphere1.col < scr.m_iColumnNum-1 && sphere2.assertValid(0,1) && sphere2.assertValid(-1,1)){//2 is on the up side of 1
sphere2.Move(-1,1);//2 move to rightdown side of 2
}
Puyo.m_timer.resume();
}
//move two sphere left by step 1
public void leftMove(){
if(sphere1.sphereState == 2 || sphere2.sphereState == 2)//only one sphere can move
return ;
if( sphere1.col < sphere2.col && sphere1.assertValid(0,-1)){//1 is on the left side of 2
sphere1.leftMove();
sphere2.leftMove();
}else if( sphere1.col > sphere2.col && sphere2.assertValid(0,-1)){//1 is on the right side of 2
sphere2.leftMove();
sphere1.leftMove();
}else{
if(sphere1.assertValid(0,-1) && sphere2.assertValid(0,-1)){
sphere1.leftMove();
sphere2.leftMove();
}
}
}
//move two sphere right by step 1
public void rightMove(){
if(sphere1.sphereState == 2 || sphere2.sphereState == 2)//only one sphere can move
return ;
if(sphere1.col < sphere2.col && sphere2.assertValid(0,1)){//1 is on the left side of 2
sphere2.rightMove();
sphere1.rightMove();
}else if(sphere1.col > sphere2.col && sphere1.assertValid(0,1)){//1 is on the right side of 2
sphere1.rightMove();
sphere2.rightMove();
}else{
if(sphere1.assertValid(0,1) && sphere2.assertValid(0,1)){
sphere1.rightMove();
sphere2.rightMove();
}
}
}
//move two sphere down by step 1
public boolean fallDown(){
boolean b1, b2;
if(sphere1.row > sphere2.row){//1 is on up side of 2, then move 2 first
b2 = sphere2.fallDown();
b1 = sphere1.fallDown();
}else{
b1 = sphere1.fallDown();
b2 = sphere2.fallDown();
}
return (b1 || b2);
}
//display two spheres
public synchronized void dispSphere(){
sphere1.dispSphere();
sphere2.dispSphere();
}
}
//*************end of class TwoSphere******************//
//
//CLASS : Sphere
//ABSTRACT : display in one unit of screen
//NOTE : used by class TwoSphere
//CREATE : handwolf 2005-4-29
//
class Sphere {
int sphereType; //the type of sphere ,1--yellow sphere,2--blue sphere,3--green sphere,4--red sphere
int sphereState; //sphere's state, 1--enabled, 2--disabled
int row,col; //sphere's position in the screen
GameCanvas scr; //screen
Sphere(GameCanvas scr){
this.scr = scr;
//generate a random sphere type
Random random2=new Random();
Random random1 = new Random(random2.nextInt());
sphereType =(Math.abs(random1.nextInt()+1) % 4) + 1;
sphereState = 1;
row = scr.getInitRow();
col = scr.getInitCol();
}
public void reset(){
//generate a random sphere type
Random random2=new Random();
Random random1 = new Random(random2.nextInt());
sphereType =(Math.abs(random1.nextInt()+1) % 4) + 1;
sphereState = 1;
row = scr.getInitRow();
col = scr.getInitCol();
}
//move the sphere by step iDiscY in row and iDiscX in col
public void Move(int iDiscY, int iDiscX){
dispSphere(0);
row = row + iDiscY;
col = col + iDiscX;
dispSphere(sphereType);
}
//move the sphere left by step 1
public void leftMove(){
Move(0,-1);
}
//move the sphere right by step 1
public void rightMove(){
Move(0,1);
}
//move the sphere down by step 1
public boolean fallDown(){
if(sphereState == 2)
return(false);
if(assertValid(-1,0)){
Move(-1,0);
return(true);
}else{
sphereState = 2;
dispSphere(sphereType);
return(false);
}
}
//Whether the unit spcified by (row + iStepY, col +iStepX) is empty, true--empty, false--not empty or out of screen
boolean assertValid(int iStepY,int iStepX){
int iDownUnitFlag = scr.getScrUnit(row + iStepY, col +iStepX);
if(iDownUnitFlag != 0){
return false;
}
return true;
}
//display the sphere in the screen
public synchronized void dispSphere(){
scr.drawUnit(row,col,sphereType);
}
//display the sphere in the screen, sphere type is s
public synchronized void dispSphere(int s){
scr.drawUnit(row,col,s);
}
}
//*************end of class Sphere******************//
//timer class
class MyTimer extends Thread{
GameCanvas scr; //screen
public MyTimer(GameCanvas scr){
this.scr = scr;
}
public void run(){
while(true){
try{
sleep((10-Puyo.m_iLevel + 1)*100);
}
catch(InterruptedException e){}
if(!scr.getTwoSphere().fallDown()){
scr.deleteSameColorLink();
if(scr.isGameEnd()){
Puyo.m_bIsPlay = false;
Graphics g = scr.getGraphics();
g.clearRect(0,0,200,500);
g.drawString("Game Over!",100,100);
suspend();
}else
scr.getTwoSphere().reset();
}
}
}
}
//*************end of class MyTimer******************//
class WinListener extends WindowAdapter{
public void windowClosing (WindowEvent l){
System.exit(0);
}
}
//*************end of class WinListener******************//
//end of file
如果您发现程序有什么问题,能联系我的话,十分感谢!
下面是四个图片资源(球)
下面是程序运行效果!