📄 ptgame.java
字号:
/***
*** 程序名称: PTGame.java 1.0 04/07/15
*** 程序功能: 设计一个功能如Motorola手机中的号码游戏。将1至8个数字随机
*** 安排在8个空档的位置上,然后通过四个光标键或鼠标将1至8个
*** 数字按顺序排列好即告成功。
*** 设计日期: 2004年07月15日
*** 作 者: Huqiguang
***
*/
import java.awt.*;
import java.applet.*;
import java.awt.event.*;//2
import java.awt.Font;
import java.util.Date;
import java.applet.AudioClip;
public class PTGame extends Applet implements MouseListener,KeyListener,Runnable //2,3,4
{
final int TWidth=120; //定义常量为图块的宽度及高度
final int THeight=120;
Image TArray[]=new Image[8]; //定义具有9个元素的图像数组对象
Image TAll; //用来存放完整的图像
final int InfoWidth=120; //提示信息显示的宽度
int TKNo[][]=new int[3][3]; //图块的位置
final int NoImage=-1; //表示此位置无图块
int StepCount=0; //统计拼图的次数及所用的时间
int CountTime=0; //6 统计你所用的时间(以秒为单位)
final int FXup=1; //定义图块移动的方向
final int FXdown=2;
final int FXleft=3;
final int FXright=4;
final int FXno=-1; //表示图块不移动
boolean EndGame=false; //是否结束拼图游戏
AudioClip Music1,Music2,Music3,Music4; //5 声明四个存放声音文件的对象
Thread TimeThread;
String Message=" ";
private Thread clockThread=null; //4 利用多线程方式让时钟动起来
public void start()
{
if(clockThread==null)
{
clockThread=new Thread(this);
clockThread.start();
}
}
public void run()
{
Thread myThread=Thread.currentThread(); //4
while(clockThread==myThread)
{
repaint();
try
{
Thread.sleep(1000);
}
catch(InterruptedException e) { }
}
while(true) //6
{
try
{
TimeThread.sleep(999);
if(CountTime>300)
Message="加加油,你会赢的!";
if(!EndGame)
CountTime++;
}
catch(Exception e) { }
}
}
public void init()
{
TimeThread=new Thread(this); //6 创建一个时间线程
TimeThread.start();
MediaTracker MedTracker=new MediaTracker(this); //建立一个媒体跟踪器
TAll=getImage(getDocumentBase(),"Picture/T1.jpg"); //装入当前目录下Picture子目录下的T1.jpg图像
MedTracker.addImage(TAll,1); //跟踪装载的完整图像
try
{
MedTracker.waitForAll();
}
catch(Exception e)
{
System.out.println("图像装载不成功!");
}
for(int i=0; i<TArray.length;i++)
{
TArray[i]=createImage(TWidth,THeight); //建立一个相应大小的空白图像
Graphics g=TArray[i].getGraphics();
int PRow=i%3; //计算每个图块应在的位置
int PCol=i/3;
//以下是使用drawImage()方法将TAll总图像中指定区域的号码图块画到(0,0)和(TWidth,THeight)规定的区域上。
//注:虽然目标区域都是(0,0)和(TWidth,THeight),但是每次产生的g对象实际上不同
g.drawImage(TAll,0,0,TWidth,THeight,PRow*TWidth,PCol*THeight,(PRow+1)*TWidth,(PCol+1)*THeight,this);
//即:实质上是从TAll中总图像取指定位置上的号码图块画到不同g对象的(0,0)至(TWidth,THeight)组成的区域上。
}
initImage(); //初始化装入各图块
addMouseListener(this); //把鼠标作为监听器
addKeyListener(this); //把键盘作为监听器
Music1=getAudioClip(getCodeBase(),"Music/9.au"); //装载声音文件存入相应对象中
Music2=getAudioClip(getCodeBase(),"Music/hi.au");
Music3=getAudioClip(getCodeBase(),"Music/yahoo1.au");
Music4=getAudioClip(getCodeBase(),"Music/town.mid");
}
public void initImage()//以随机方式分配图块(每次的游戏初始图块位置都不同)
{
CountTime=0; //6 将计时器归零
int SaveUsed[]=new int[9]; //用来标记每个图块是否使用
int m=0,n=0;
for(int i=0;i<9;i++)
SaveUsed[i]=0; //初始化为0,表示每个图块都未使用
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
int ImageNum=-1;
do
{
ImageNum=(int)(Math.random()*9); //随机产生一个大于等于0,小于9的整数
}
while(SaveUsed[ImageNum]==1); //当第ImageNum个图块标记了1时,表示该图块已使用,重新随机选[0-8]的图块。
if(ImageNum==8) //当为第9个图块时,则记录住该图块被分配的位置。
{ m=j; n=i; }
TKNo[j][i]=ImageNum; //将第 ImageNum 个图块分配到第j行第i列的位置上
SaveUsed[ImageNum]=1; //将第 ImageNum 个图块标记为1,即表示已使用
}
}
TKNo[m][n]=NoImage; //当为第9个图块时,将其位置设为无图块。
StepCount=0; //拼图次数初始化为0
}
public void paint(Graphics g)
{
g.setColor(Color.CYAN);
g.fillRect(0,0,InfoWidth,THeight*3);//绘制一个实心的矩形区域
g.setFont(new Font("黑体",Font.PLAIN,15));
g.setColor(Color.red);
g.drawString("注: 点击开始",10,260);
g.drawString("移动图块次数:",10,40); //显示拼图的次数
g.setColor(Color.black);
g.drawString(" "+StepCount,15,60);
g.setColor(Color.red);
g.drawString("你 已 用 了:",12,100);
g.setColor(Color.black);
g.drawString(""+CountTime+" 秒",35,120);
g.setColor(Color.red);
g.drawString(""+Message,6,140);
// **
g.setColor(Color.CYAN);
g.fillRect(InfoWidth+TWidth*3,0,InfoWidth+30,THeight*3);//绘制一个实心的矩形区域
g.setFont(new Font("幼圆",Font.BOLD,15));
g.setColor(Color.LIGHT_GRAY);
g.fill3DRect(InfoWidth+TWidth*3+15,8,InfoWidth-10,150,true); //立体矩形框
g.setColor(Color.red);
g.drawString("当前的时间",InfoWidth+TWidth*3+25,30);
g.drawString("游戏规则",InfoWidth+TWidth*3+30,190);
g.setColor(Color.black);
g.drawString("1.鼠标双击要移",InfoWidth+TWidth*3+10,220);
g.drawString(" 动的图块即可",InfoWidth+TWidth*3+10,240);
g.drawString(" 移动或用键盘",InfoWidth+TWidth*3+10,260);
g.drawString(" 的四个【←↑",InfoWidth+TWidth*3+10,280);
g.drawString(" ↓→】方向键",InfoWidth+TWidth*3+10,300);
g.drawString("2.按功能键【F2】",InfoWidth+TWidth*3+10,320);
g.drawString(" 重新开局。",InfoWidth+TWidth*3+10,340);
// **
g.setColor(Color.black);
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
int x=i*TWidth+InfoWidth;
int y=j*THeight;
if(TKNo[i][j]==NoImage) //如果该区域无图块
g.fill3DRect(x,y,TWidth,THeight,true);
else
{
g.drawImage(TArray[TKNo[i][j]],x,y,this);
g.drawRect(x,y,TWidth,THeight);
}
}
}
CheckGame(); //检查游戏是否结束
if(EndGame)
{
g.setColor(Color.blue);
g.drawString("再来一局? 请按",5,180);
g.drawString("【F2】开始 ...",5,200);
g.setColor(Color.red);
g.setFont(new Font("黑体",Font.BOLD,30));
g.drawString("恭喜你,你真棒!",180,130);
g.setColor(Color.black); //制作阴影字
g.drawString("恭喜你,你真棒!",182,132);
Music4.play(); //播放胜利音乐
}
Date now=new Date(); // 4
Font FontSize1=new Font("黑体",Font.BOLD,14);
Font FontSize2=new Font("Impact",Font.BOLD,20);
int year=now.getYear()+1900;
int month=now.getMonth()+1;
String day=now.toString().substring(8,10); //now.getDay();
String weekday=now.toString().substring(0,3); //获取英文星期
if(weekday.equals("Mon")) //注:不能用(weekday=="Thu")这种方式进行字符串比较相等,因为..
weekday="星期 一";
else if(weekday.equals("Tue"))
weekday="星期 二";
else if(weekday.equals("Wed"))
weekday="星期 三";
else if(weekday.equals("Thu"))
weekday="星期 四";
else if(weekday.equals("Fri"))
weekday="星期 五";
else if(weekday.equals("Sat"))
weekday="星期 六";
else if(weekday.equals("Sun"))
weekday="星期 日";
int hour=now.getHours();
int minute=now.getMinutes();
int second=now.getSeconds();
g.setFont(FontSize1);
g.setColor(Color.blue);
g.drawString(" "+year+"年"+month+"月",InfoWidth+TWidth*3+25,60);
g.setFont(FontSize2);
g.setColor(Color.red);
g.drawString(" "+day,InfoWidth+TWidth*3+50,90);
g.setFont(FontSize1);
g.setColor(Color.blue);
g.drawString(" "+weekday,InfoWidth+TWidth*3+30,110);
g.setColor(Color.MAGENTA);
g.drawString(" "+hour+"时"+minute+"分"+second+"秒",InfoWidth+TWidth*3+18,130);
this.requestFocus(); //获取焦点
} //4
public void update(Graphics g) //
{
// g.clearRect(InfoWidth+TWidth*3+5,30,InfoWidth+TWidth*3+200,300);
paint(g);
}
public void mouseClicked(MouseEvent e) //以下为鼠标响应事件(事件处理方法)
{
int PX=e.getX()-InfoWidth; //获取被点击图块的位置
int PY=e.getY();
int PRow=PX/TWidth; //计算出被点击图块所在的行列位置
int PCol=PY/THeight;
int FXn=MoveFX(PCol,PRow); //获取图块要移动的方向
if(FXn!=FXno) //如果有方向
{
MoveImage(PCol,PRow,FXn); //则照此方向移动图块
StepCount++; //移动次数增加一次
Music1.play(); //播放正确音乐
repaint();
}
else
{
Music2.play(); //播放错误音乐
}
}
public void mouseEntered(MouseEvent e)
{
}
public void mouseExited(MouseEvent e)
{
}
public void mousePressed(MouseEvent e)
{
}
public void mouseReleased(MouseEvent e)
{
}
public int MoveFX(int PCol,int PRow) //判断图块移动的方向(鼠标)
{
if(PCol-1>=0)
if(TKNo[PRow][PCol-1]==NoImage)
return FXup;
if(PCol+1<=2)
if(TKNo[PRow][PCol+1]==NoImage)
return FXdown;
if(PRow-1>=0)
if(TKNo[PRow-1][PCol]==NoImage)
return FXleft;
if(PRow+1<=2)
if(TKNo[PRow+1][PCol]==NoImage)
return FXright;
return FXno;
}
public void MoveImage(int PCol,int PRow, int FXn) //根据方向来移动图块(鼠标)
{
switch(FXn)
{
case FXup :
TKNo[PRow][PCol-1]=TKNo[PRow][PCol];
TKNo[PRow][PCol]=NoImage;
break;
case FXdown :
TKNo[PRow][PCol+1]=TKNo[PRow][PCol];
TKNo[PRow][PCol]=NoImage;
break;
case FXleft :
TKNo[PRow-1][PCol]=TKNo[PRow][PCol];
TKNo[PRow][PCol]=NoImage;
break;
case FXright :
TKNo[PRow+1][PCol]=TKNo[PRow][PCol];
TKNo[PRow][PCol]=NoImage;
break;
}
}
public void keyPressed(KeyEvent e)
{
if(EndGame) //当游戏结束且按了F2时,重新开始
{
initImage();
EndGame=false;
Music3.play(); // 5 播放胜利音乐
repaint();
return;
}
int FXn=0; //表示无方向
switch(e.getKeyCode())
{
case KeyEvent.VK_DOWN :
FXn=FXdown;
break;
case KeyEvent.VK_UP :
FXn=FXup;
break;
case KeyEvent.VK_LEFT :
FXn=FXleft;
break;
case KeyEvent.VK_RIGHT :
FXn=FXright;
break;
case KeyEvent.VK_F2 : // 当按下F2功能键时,重新开局。
initImage();
Music4.stop(); //结束胜利音乐
Music3.play(); //5 播放重新开局的音乐
repaint();
return;
default : return;
}
boolean MoveFX=MoveImage(FXn); //调用MoveImage()方法实现按指定方向移动图块
if(MoveFX)
{
StepCount++; //移动次数加1
Music1.play(); //播放移动音乐
repaint(); //显示下一帧图像
}
else
{
Music2.play(); //播放错误音乐
}
}
public void keyReleased(KeyEvent e)
{
}
public void keyTyped(KeyEvent e)
{
}
public boolean MoveImage(int FXn) //根据所按键盘的方向键来移动图块
{
int ColNoImage=-1; //表示该列无图块
int RowNoImage=-1;
int i=0,j=0; //i和j分别为行、列标号
while(i<3 && RowNoImage==-1) //两个while()语句是用来判断第i行的哪一列无图块
{
while(j<3 && ColNoImage==-1)
{
if(TKNo[i][j]==NoImage) //如果第i行第j列无图块
{
RowNoImage=i; //则记录它的位置
ColNoImage=j;
}
j++;
}
i++; //下一行
j=0; //从第0列开始
}
switch(FXn)
{
case FXup :
if(ColNoImage==3) return false;
TKNo[RowNoImage][ColNoImage]=TKNo[RowNoImage][ColNoImage+1];
TKNo[RowNoImage][ColNoImage+1]=NoImage; //将此处置为无图块标志
break;
case FXdown :
if(ColNoImage==0) return false; //表明第0行第0列无图块,故无法实现向下移动,只能向左或向上移。
TKNo[RowNoImage][ColNoImage]=TKNo[RowNoImage][ColNoImage-1];
TKNo[RowNoImage][ColNoImage-1]=NoImage; //将此处置为无图块标志
break;
case FXleft :
if(RowNoImage==3) return false;
TKNo[RowNoImage][ColNoImage]=TKNo[RowNoImage+1][ColNoImage];
TKNo[RowNoImage+1][ColNoImage]=NoImage; //将此处置为无图块标志
break;
case FXright :
if(RowNoImage==0) return false;
TKNo[RowNoImage][ColNoImage]=TKNo[RowNoImage-1][ColNoImage];
TKNo[RowNoImage-1][ColNoImage]=NoImage; //将此处置为无图块标志
break;
}
return true; //表示有移动方向
}
public void CheckGame()
{
boolean Flag=true;
int Number=0;
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
if(TKNo[j][i]!=Number && TKNo[j][i]!=NoImage)
Flag=false;
Number++;
}
}
if(Flag)
EndGame=true; //表示结束当前游戏,开始新游戏。
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -