⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ptgame.java

📁 拼图---键盘操作: log清晰
💻 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 + -