1. 程式人生 > >JAVA課程設計——華容道小遊戲

JAVA課程設計——華容道小遊戲

華容道遊戲簡介:

華容道,古老的中國遊戲,以其變化多端、百玩不厭的特點與魔方、獨立鑽石棋一起被國外智力專家並稱為“智力遊戲界的三個不可思議”。它與七巧板、九連環等中國傳統益智玩具還有個代名詞叫作“中國的難題”。華容道遊戲取自著名的三國故事,曹操在赤壁大戰中被劉備和孫權的“苦肉計”、“火燒連營”打敗,被迫退逃到華容道,又遇上諸葛亮的伏兵,關羽為了報答曹操對他的恩情,明逼實讓,終於幫助曹操逃出了華容道。遊戲就是依照“曹瞞兵敗走華容,正與關公狹路逢。只為當初恩義重,放開金鎖走蛟龍”這一故事情節,通過移動各個棋子,幫助曹操從初始位置移到棋盤最下方中部,從出口逃走。不允許跨越棋子,還要設法用最少的步數把曹操移到出口。曹操逃出華容道的最大障礙是關羽,關羽立馬華容道,一夫當關,萬夫莫開。關羽與曹操當然是解開這一遊戲的關鍵。四個劉備軍兵是最靈活的,也最容易對付,如何發揮他們的作用也要充分考慮周全。“華容道”有一個帶二十個小方格的棋盤,代表華容道。棋盤下方有一個兩方格邊長的出口,是供曹操逃走的。棋盤上共擺有十個大小不一樣的棋子,它們分別代表曹操、張飛、趙雲、馬超、黃忠和關羽,還有四個卒。“華容道”有幾十種佈陣方法,如“橫刀立馬”、“近在咫尺”、“過五關”、“水洩不通”、“小燕出巢”等等玩法。棋盤上僅有兩個小方格空著,玩法就是通過這兩個空格移動棋子,用最少的步數把曹操移出華容道。

很小的時候就用父親的手機玩過這個遊戲,記得當時用了好久才過得去一關,現在同樣覺得真的挺難的一個遊戲。

但當時卻玩的不亦樂乎,因為並沒有別的遊戲可以選擇,記得當時就覺得這個遊戲的人物角色太醜了,讓我這個三國迷無法忍受。沒想到好多年後的今年終於可以自己做出這個簡單的小遊戲,把每個角色定義成自己喜歡的樣子,也算是圓了小時候的一個夢想。

程式主要由一個框架類和功能類構成。

      1、框架類構造遊戲主視窗,遊戲頁面七大操作按鈕和十個遊戲角色的建立和初始化,以及地圖的構建。

      2、功能類包括滑鼠操作方法和鍵盤操作方法的新增,以及人物角色移動方法的具體實現。

演算法主要體現在人物的移動上。主要是操作方式,滑鼠和鍵盤都可進行操作,由使用者進行選擇使用哪種方式來進行遊戲。

1)、角色移動演算法分析:

 元件呼叫getBounds()方法可以返回一個和自己大小相等,位置相同的Rectangle物件,但Rectangle沒有可視的外觀,僅封裝元件的位置和大小,因此可以用元件返回的Rectangle物件判斷位置和大小資訊,檢查移動後的Rectangle物件和其他元件的是否相交即可。

2)、若選擇鍵盤,初始給特定一個小兵一個焦點,即從它開始進行移動,若玩家按下某方向鍵,當前小兵需要往某方向移動但是它不能往某方向移動(在邊界處或者被其他人物阻擋),則選擇當前可以往該方向移動的角色進行移動。

演算法具體實現:遍歷每一個角色,若當前角色可以執行該操作,用當前角色進行該操作。

用事先寫好的goc方法判斷其是否可以移動。

goc方法為boolen型別方法

Return True or False ,表示當前角色是否可進行移動

精確操作:鍵盤操作模式下,先用滑鼠點選某個角色(滑鼠點選即可給當前使用者得到焦點),然後使用方向鍵進行移動。

3)、滑鼠操作:玩家需注意點選當前角色人物的位置。

滑鼠操作下的移動與鍵盤略有不同,不存在需要自動獲取焦點的問題,但需要注意的是當同時點選一個角色的下半部分和右半部分時,也就是說當前的操作同時觸發兩個滑鼠事件,那麼它就會直接向右下方進行移動,但遊戲的規則中其實是不允許這樣進行移動的。

這裡通過把一個角色抽象為一個矩陣,然後模擬出它的長和寬,對點選的位置進行一定的數學限制即可實現。

比如向下可以以這樣的條件進行限制

If(y>h/2&&x>w/3&&x<(w*2)/3)

其他位置如法炮製,就可以完美的解決這個細節上的問題。

開始介面:


遊戲背景介面:


遊戲幫助介面

鍵盤操作介面:


滑鼠操作介面:


遊戲勝利介面:


注:以上素材gif圖片均來自網路,感謝原作者,這裡僅供娛樂。


貼下兩個類的程式碼:(還沒有進行良好的封裝)

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class Hua_Rong_Road extends JFrame implements MouseListener,KeyListener,ActionListener {
private static final int ERROR_MESSAGE = 0;
private static final int WARNING_MESSAGE = 0;
int cnt=0;
Person person[]=new Person[10];
JButton left,right,above,below;
JButton restart=new JButton("重新開始");
JButton about=new JButton("遊戲背景");
JButton help=new JButton("遊戲幫助");
JButton mouse=new JButton("滑鼠操作");
JButton key=new JButton("鍵盤操作");
JButton message=new JButton("當前步數:"+cnt);
JButton begin=new JButton("開始遊戲");
JButton star=new JButton();
String name[]={"曹操","關羽","張飛","黃忠","馬超","趙雲","兵","兵","兵","兵"};
public Hua_Rong_Road(){
	JOptionPane.showMessageDialog(this, "開始遊戲前,請先閱讀下方的遊戲幫助,遊戲背景可自行了解.");
	init();
	//setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
	setBounds(200,200,640,800);//設定窗體初始位置以及大小的一個函式
	setVisible(true);//視窗可見
	//person[9].requestFocus();//獲取焦點需要解除安裝setVisible後面才行
	validate();//使用validate方法是容器再次佈置其元件,確保佈局有效
}
public void init(){
	setLayout(null);
	message.setBackground(Color.ORANGE);
	add(restart);
	restart.setBounds(120, 640, 100, 50);
	//restart.setBackground(Color.RED);
	restart.addActionListener(this);
	add(about);
	about.addActionListener(this);
	about.setBounds(250,640,100,50);
	add(mouse);
	mouse.setBounds(280,40,100,50);
	mouse.addActionListener(this);
	add(key);
	key.setBounds(400, 40, 100, 50);
	key.addActionListener(this);
	add(help);
	help.setBounds(380, 640, 100, 50);
	help.addActionListener(this);
	add(message);
	message.setBounds(110,40,160,50);
	ImageIcon starr=new ImageIcon("timg (5).gif");
	star.setIcon(starr);
	star.setBounds(108,208,400,400);
	add(star);
	add(begin);
	begin.addActionListener(this);
	begin.setBounds(250,140,100,50);
	setVisible(true);
	left=new JButton();
	right=new JButton();
	above=new JButton();
	below=new JButton();
	add(left);
	add(right);
	add(above);
	add(below);
	//邊界類
	left.setBounds(98, 98, 10, 520);
	right.setBounds(508,98,10,520);
	above.setBounds(98, 98, 420, 10);
	below.setBounds(98, 608, 420, 10);
	validate();
}
//遊戲佈局
public	void map1()
{
for(int k=0;k<name.length;k++)
{
	person[k]=new Person(k,name[k]);
	add(person[k]);
}
person[0].setBounds(208,108,200,200);//曹操
ImageIcon caocao=new ImageIcon("timg.gif");
person[0].setIcon(caocao);
person[1].setBounds(208,308,200,100);//關羽
ImageIcon guanyu=new ImageIcon("timg (4).gif");
person[1].setIcon(guanyu);
person[2].setBounds(108,308,100,200);//張飛
ImageIcon zhangfei=new ImageIcon("timg (3).gif");
person[2].setIcon(zhangfei);
person[3].setBounds(408,308,100,200);//黃忠
ImageIcon huangzhong=new ImageIcon("2.gif");
person[3].setIcon(huangzhong);
person[4].setBounds(108,108,100,200);//馬超
ImageIcon machao=new ImageIcon("3.gif");
person[4].setIcon(machao);
person[5].setBounds(408,108,100,200);//趙雲
ImageIcon zhaoyun=new ImageIcon("4.gif");
person[5].setIcon(zhaoyun);
person[6].setBounds(108,508,100,100);//
ImageIcon bing1=new ImageIcon("6.gif");
person[6].setIcon(bing1);
person[7].setBounds(408,508,100,100);
ImageIcon bing2=new ImageIcon("7.gif");
person[7].setIcon(bing2);
person[8].setBounds(208,408,100,100);
ImageIcon bing3=new ImageIcon("8.gif");
person[8].setIcon(bing3);
person[9].setBounds(308,408,100,100);
ImageIcon bing4=new ImageIcon("9.gif");
person[9].setIcon(bing4);
}
public void keyTyped(KeyEvent e){}
public void keyReleased(KeyEvent e){}
public void keyPressed(KeyEvent e){//鍵盤按下
	Person man=(Person)e.getSource();
	if(e.getKeyCode()==KeyEvent.VK_DOWN)//下鍵
		gok(man,below);
	if(e.getKeyCode()==KeyEvent.VK_UP)//上鍵
		gok(man,above);
	if(e.getKeyCode()==KeyEvent.VK_LEFT)//左鍵
		gok(man,left);
	if(e.getKeyCode()==KeyEvent.VK_RIGHT)//右鍵
		gok(man,right);
}
//鍵盤模式下的移動
public void gok(Person man,JButton direction){
	cnt++;
	message.setText("當前步數:"+cnt);
	boolean move=true;//可以移動
	Rectangle manRect=man.getBounds();
	int x=man.getBounds().x;
	int y=man.getBounds().y;
	if(direction==below)
		y=y+100; 
	else if(direction==above)
		y=y-100;
	else if(direction==left)
		x=x-100;
	else if(direction==right)
		x=x+100;
	manRect.setLocation(x,y);
	Rectangle directionRect=direction.getBounds();
	for(int k=0;k<10;k++){
		Rectangle personRect=person[k].getBounds();
		if((manRect.intersects(personRect))&&(man.number!=k)){
			//intersects為矩形類的一個方法,可以判斷是否相交
			for(Person man2:person){//遍歷陣列
				if(goc(man2,direction)==true){
					return;
				}
			}
			move=false;
		}
	}
	if(manRect.intersects(directionRect)){
		for(Person man2:person){
			if(goc(man2,direction)==true){
				return;
			}
		}
		move=false;
	}
	if(move==true)
		{
		man.setLocation(x,y);
		}
	int cx,cy;//曹操的位置
	cx=person[0].getBounds().x;
	cy=person[0].getBounds().y;
	if(cx==208&&cy==208)
	{
		win();
		return ;

	}
}
public void win()
{
	JOptionPane.showMessageDialog(this, "恭喜少俠,成功幫曹操脫險,日後必大富大貴!\n"
			+ "操作"+cnt+"步.震驚天下!");
	JButton winn=new JButton();
	ImageIcon winner=new ImageIcon("timg (1).gif");
	winn.setIcon(winner);
	winn.setBounds(108,108,400,500);
	add(winn);
	setVisible(true);
	for(int k=0;k<name.length;k++)
	this.remove(person[k]);
}

//判斷是否可以進行移動
public boolean goc(Person man,JButton direction){
	boolean move=true;//可以移動
	Rectangle manRect=man.getBounds();
	int x=man.getBounds().x;
	int y=man.getBounds().y;
	if(direction==below)
		y=y+100; 
	else if(direction==above)
		y=y-100;
	else if(direction==left)
		x=x-100;
	else if(direction==right)
		x=x+100;
	manRect.setLocation(x,y);
	Rectangle directionRect=direction.getBounds();
	for(int k=0;k<10;k++){
		Rectangle personRect=person[k].getBounds();
		if((manRect.intersects(personRect))&&(man.number!=k))
			move=false;
	}
	if(manRect.intersects(directionRect))
		move=false;
	
	if(move==true)
		man.setLocation(x,y);
	
	return move;
}
public void gom(Person man,JButton direction){
	cnt++;
	message.setText("當前步數:"+cnt);
	boolean move=true;//可以移動
	Rectangle manRect=man.getBounds();
	int x=man.getBounds().x;
	int y=man.getBounds().y;
	if(direction==below)
		y=y+100; 
	else if(direction==above)
		y=y-100;
	else if(direction==left)
		x=x-100;
	else if(direction==right)
		x=x+100;
	manRect.setLocation(x,y);
	Rectangle directionRect=direction.getBounds();
	for(int k=0;k<10;k++){
		Rectangle personRect=person[k].getBounds();
		if((manRect.intersects(personRect))&&(man.number!=k))
			move=false;
	}
	if(manRect.intersects(directionRect))
		move=false;
	if(move==true)
		man.setLocation(x,y);
	int cx,cy;//曹操的位置
	cx=person[0].getBounds().x;
	cy=person[0].getBounds().y;
	if(cx==208&&cy==208)//正確位置應該為408,這裡為了快速結束遊戲,設定較為簡單
	{
		win();
		return ;
	}
}

@Override
//重新開始新的一局遊戲
public void actionPerformed(ActionEvent e) {
	JButton b=(JButton)e.getSource();
	if(b==restart)
	{
		dispose();
	new Hua_Rong_Road();
	}
	if(b==about)
	{
		JOptionPane.showMessageDialog(this, "華容道遊戲取自著名的三國故事,曹操在赤壁大戰中被\n"
				+ "劉備和孫權的“苦肉計”、“火燒連營”打敗,被迫退逃到華容道,又遇上諸葛亮的伏兵,\n"
				+ "關羽為了報答曹操對他的恩情,明逼實讓,終於幫助曹操逃出了華容道。\n"
				+ "曹操逃出華容道的最大障礙是關羽,關羽立馬華容道,一夫當關,萬夫莫開。\n"
				+ "關羽與曹操當然是解開這一遊戲的關鍵。\n"
				+ "四個劉備軍兵是最靈活的,也最容易對付,如何發揮他們的作用也要充分考慮周全。\n"
				+ "“華容道”有一個帶二十個小方格的棋盤,代表華容道。\n"
				+ "棋盤下方有一個兩方格邊長的出口,是供曹操逃走的。"	+ "");
	}
	if(b==help)
	{
		JOptionPane.showMessageDialog(this, "勝利條件:曹操到達地圖中下方位置!\n"
				+ "點選開始遊戲後,先在上方選擇遊戲方式\n"
				+ "鍵盤操作:使用小鍵盤的上下左右方向鍵控制角色的移動\n"
				+ "精確操作:鍵盤操作模式下,先用滑鼠點選某個角色,然後使用方向鍵進行移動。\n"
				+ "滑鼠操作:玩家通過點選當前角色人物的不同位置進行相應移動。\n"
				+ "注意,不能往左下,右下,左上,右上進行移動。\n"
				+ "選擇完成操作方式中途儘量不要更換", "開始之前必看", WARNING_MESSAGE);
	}
	if(b==key)
	{
		b.setBackground(Color.green);
		for(int k=0;k<name.length;k++)
		{
			person[k].addKeyListener(this);
		}
		person[9].requestFocus();//獲取焦點
	}
	if(b==mouse)
	{
		b.setBackground(Color.yellow);
		for(int k=0;k<name.length;k++)
		person[k].addMouseListener(this);
	}
	if(b==begin)
	{
		b.setBackground(Color.yellow);
		this.remove(begin);
		this.remove(star);
		map1();
	}
}
@Override
public void mouseClicked(MouseEvent e) {
	// TODO Auto-generated method stub
	
}
@Override
public void mousePressed(MouseEvent e) {
	Person man=(Person)e.getSource();
int x=-1,y=-1;
x=e.getX();
y=e.getY();
int w=man.getBounds().width;
int h=man.getBounds().height;
if(y>h/2&&x>w/3&&x<(w*2)/3)
	{
	gom(man,below);//下面
	}
if(y<h/2&&x>w/3&&x<(w*2)/3)
{
	gom(man,above);//上面
}
 if(x<w/2&&y>h/3&&y<(h*2)/3)
	{
	gom(man,left);//左
	}
 if(x>w/2&&y>h/3&&y<(h*2)/3)
{
	gom(man,right);//右
}
}
@Override
public void mouseReleased(MouseEvent e) {
	// TODO Auto-generated method stub
	
}
@Override
public void mouseEntered(MouseEvent e) {
	// TODO Auto-generated method stub
	
}
@Override
public void mouseExited(MouseEvent e) {
	// TODO Auto-generated method stub
	
}
}

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Person extends JButton implements FocusListener{
	int number;
	Person(int number,String s){
		this.number=number;
		addFocusListener(this);
	}
	public void focusGained(FocusEvent e){
		//setBackground(Color.GREEN);
	}
	public void focusLost(FocusEvent e){
		//setBackground(Color.RED);
	}

}


若需要執行,只需要new一個Hua_Rong_Road()即可。 參考文獻:

Java程式設計實用教程(第二版)》——耿祥義 張躍平編著。