“华容道”是一款比较古老的游戏,其源于三国时期著名的历史故事。华容道作为一个经典游戏,各部分的设计都恰到好处,非常巧妙,因此成为世界游戏界的三大不可思议。
“华容道”游戏初始时曹操被围在华容道最里层,玩家需要移动其他角色,使曹操顺利到达出口。玩家先选择需要移动的角色,然后拖动鼠标,被选中的角色就会向鼠标拖动的方向移动。最后,当成功地将曹操移动到出口时,游戏结束。
本次开发的“华容道”运行效果如下图所示:
素材及完整源码链接: https://pan.baidu.com/s/1_vOhAYk07h9dXBaez_lW3g 提取码: sni6
“华容道”整体可以看成5*4的网格,其中张飞、赵云、关羽、马超、黄忠各占两个格子,兵占一个格子,曹操最大占4个格子。在这里玩家鼠标的操作可以看成对带图标的JButton的拖动。声明变量W表示一个格子的边长,自定义数据结构Node类,用于保存每个关卡按钮的初始位置,使用继承自JButton的Person类用于每个带人物图标按钮的显示。
在这里我约定Node的x,y下标等同于图片按钮左上角对应的二维数组的x,y下标,id表示每个按钮的人物ID,direction为true时横放,direction为false时竖放。比如Node(0,0,0,true),表示曹操按钮位于左上角。
Node类:
package 华容道;
public class Node {
private int id;
private boolean direction;//true为横放,false为竖放
private int x;//左上角数组x下标
private int y;//左上角数组y下标
public Node(int id,int x,int y,boolean direction){
this.id = id;
this.x = x;
this.y = y;
this.direction = direction;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public boolean getDirection() {
return direction;
}
public void setDirection(boolean direction) {
this.direction = direction;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
Person类是带人物ID的JButton
Person类:
package 华容道;
import java.awt.Color;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JButton;
public class Person extends JButton{
int id;//编号
String name;
public Person(int id,String str){
super("");
name = str;
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
MapFactory是存储游戏关卡数据的工厂类,MapFactory同时也支持历史记录的读写
MapFactory类:
package 华容道;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
public class MapFactory {
//ID编号对应关系:0曹操,1赵云,2张飞,3关羽,4马超,5黄忠,6小兵,7小兵,8小兵,9小兵
//Node(id,x,y,direction),id对应每个角色,x,y对应左上角数组下标,direction为true时,横放,false时,竖放
static String[] array;
public static Node[][] map = new Node[][]{
{//七步成诗
new Node(0,2,2,true),new Node(1,2,0,false),new Node(2,0,1,false),
new Node(3,0,3,false),new Node(4,0,0,false),new Node(5,2,1,false),
new Node(6,4,0,true),new Node(7,4,1,true),new Node(8,4,2,true),new Node(9,4,3,true)
},
{//横刀立马
new Node(0,0,1,true),new Node(1,0,3,false),new Node(2,2,3,false),
new Node(3,2,1,true),new Node(4,0,0,false),new Node(5,2,0,false),
new Node(6,4,0,true),new Node(7,3,1,true),new Node(8,3,2,true),new Node(9,4,3,true)
},
{//屯兵东路
new Node(0,0,0,true),new Node(1,0,3,false),new Node(2,0,2,false),
new Node(3,2,0,true),new Node(4,3,0,false),new Node(5,3,1,false),
new Node(6,2,2,true),new Node(7,2,3,true),new Node(8,3,2,true),new Node(9,3,3,true)
},
{//插翅难飞
new Node(0,0,1,true),new Node(1,0,0,false),new Node(2,4,2,true),
new Node(3,4,0,true),new Node(4,2,1,false),new Node(5,0,3,false),
new Node(6,2,0,true),new Node(7,3,0,true),new Node(8,2,3,true),new Node(9,3,3,true)
},
{//巧过五关
new Node(0,0,1,true),new Node(1,2,2,true),new Node(2,3,2,true),
new Node(3,4,1,true),new Node(4,3,0,true),new Node(5,2,0,true),
new Node(6,0,0,true),new Node(7,1,0,true),new Node(8,0,3,true),new Node(9,1,3,true)
},
{//层层设防
new Node(0,0,1,true),new Node(1,1,3,false),new Node(2,1,0,false),
new Node(3,4,1,true),new Node(4,2,1,true),new Node(5,3,1,true),
new Node(6,0,0,true),new Node(7,3,0,true),new Node(8,0,3,true),new Node(9,3,3,true)
},
{//近在咫尺
new Node(0,3,2,true),new Node(1,0,1,false),new Node(2,3,0,true),
new Node(3,2,0,true),new Node(4,0,3,false),new Node(5,0,2,false),
new Node(6,0,0,true),new Node(7,1,0,true),new Node(8,2,2,true),new Node(9,2,3,true)
},
{//兵临曹营
new Node(0,0,1,true),new Node(1,3,1,false),new Node(2,3,2,false),
new Node(3,2,1,true),new Node(4,2,0,false),new Node(5,2,3,false),
new Node(6,0,0,true),new Node(7,1,0,true),new Node(8,0,3,true),new Node(9,1,3,true)
},
{//众志成城
new Node(0,1,1,true),new Node(1,3,1,false),new Node(2,3,3,false),
new Node(3,0,2,true),new Node(4,0,0,false),new Node(5,2,0,false),
new Node(6,0,1,true),new Node(7,1,3,true),new Node(8,2,3,true),new Node(9,4,2,true)
},
{//佳人梳妆
new Node(0,1,0,true),new Node(1,3,1,false),new Node(2,3,2,false),
new Node(3,0,2,true),new Node(4,1,2,false),new Node(5,2,3,false),
new Node(6,3,0,true),new Node(7,4,0,true),new Node(8,1,3,true),new Node(9,4,3,true)
}
};
//返回指定关卡布局信息的拷贝(避免直接引用)
public static Node[] getMap(int level){
Node[] temp = new Node[10];
for(int i=0;i<10;i++){
temp[i] = map[level-1][i];
}
return temp;
}
public static int getRecord(int level){
FileOutputStream fos = null;
DataOutputStream dos = null;
FileInputStream fis = null;
DataInputStream dis = null;
File file = new File("D://GameRecordAboutSwing");
if(!file.exists()){
file.mkdirs();
}
File record = new File("D://GameRecordAboutSwing/recordKlotskiGame.txt");
try{
if(!record.exists()){//如果不存在,新建文本
record.createNewFile();
fos = new FileOutputStream(record);
dos = new DataOutputStream(fos);
String s = "9999,9999,9999,9999,9999,9999,9999,9999,9999,9999";
dos.writeBytes(s);
System.out.println(record.isFile());;
}
//读取记录
fis = new FileInputStream(record);
dis = new DataInputStream(fis);
String str = dis.readLine();
array = str.split(",");
}catch(Exception e){
e.printStackTrace();
}finally{
try {
if(fis!=null)
fis.close();
if(dis!=null)
dis.close();
if(fos!=null)
fos.close();
if(dos!=null)
dos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return Integer.parseInt(array[level-1]);
}
public static void writeRecord(int level,int step){
FileOutputStream fos = null;
DataOutputStream dos = null;
File record = new File("D://GameRecordAboutSwing/recordKlotskiGame.txt");
try {
//清空原有记录
FileWriter fileWriter =new FileWriter(record);
fileWriter.write("");
fileWriter.flush();
fileWriter.close();
//重新写入文本
fos = new FileOutputStream(record);
dos = new DataOutputStream(fos);
array[level-1] = step+"";
StringBuilder s = new StringBuilder();
s.append(array[0]);
for(int i=1;i
MapUtil是地图工具类,方法直接调用工厂类方法
MapUtil类:
package 华容道;
public class MapUtil {
public MapUtil(){
}
public Node[] getMap(int level){
return MapFactory.getMap(level);
}
//获取关卡历史记录
public int getRecord(int level){
return MapFactory.getRecord(level);
}
//更新指定关卡记录
public void updateRecode(int level,int record){
MapFactory.writeRecord(level, record);
}
}
GamePanel是继承自JPanel类的游戏面板类,内部包含游戏的主要逻辑:
①图片的获取
//获取图片
private void getIcons() {
for(int i=0;i<15;i++){
if(i==0){
pics[i] = Toolkit.getDefaultToolkit().getImage("D:/Game/KlotskiGame/pic"+i+".png").getScaledInstance(2*W, 2*W,Image.SCALE_SMOOTH);
}else if(i==1||i==2||i==3||i==4||i==5){
pics[i] = Toolkit.getDefaultToolkit().getImage("D:/Game/KlotskiGame/pic"+i+".png").getScaledInstance(2*W, W,Image.SCALE_SMOOTH);
}else if(i==6||i==7||i==8||i==9){
pics[i] = Toolkit.getDefaultToolkit().getImage("D:/Game/KlotskiGame/pic"+i+".png").getScaledInstance(W, W,Image.SCALE_SMOOTH);
}else{
pics[i] = Toolkit.getDefaultToolkit().getImage("D:/Game/KlotskiGame/pic"+i+".png").getScaledInstance(W,2*W,Image.SCALE_SMOOTH);
}
icons[i] = new ImageIcon(pics[i]);
}
repaint();
}
②按钮图片显示和按钮位置的初始化
遍历地图按钮位置信息数组map,然后根据map数组元素对应的图标ID,对相应的人物图标按钮数组persons依次进行图标和位置的初始化。在这里只有黄忠、赵云、关羽、马超、张飞存在横放竖放的选择,竖放的图标ID = 横放的图标ID+9
//对游戏布局进行初始化
private void initialize() {
for(int i=0;i<10;i++){
switch(map[i].getId()){
case 0://曹操,占四格
persons[i] = new Person(0,"曹操");
persons[i].setIcon(icons[0]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, 2*W, 2*W);
break;
case 1://赵云,占两格
persons[i] = new Person(1,"赵云");
if(map[i].getDirection()){//横放
persons[i].setIcon(icons[1]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, 2*W, W);
}else{//竖放
persons[i].setIcon(icons[10]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, W, 2*W);
}
break;
case 2://张飞,占两格
persons[i] = new Person(2,"张飞");
if(map[i].getDirection()){//横放
persons[i].setIcon(icons[2]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, 2*W, W);
}else{//竖放
persons[i].setIcon(icons[11]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, W, 2*W);
}
break;
case 3://关羽,占两格
persons[i] = new Person(3,"关羽");
if(map[i].getDirection()){//横放
persons[i].setIcon(icons[3]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, 2*W, W);
}else{//竖放
persons[i].setIcon(icons[12]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, W, 2*W);
}
break;
case 4://马超,占两格
persons[i] = new Person(4,"马超");
if(map[i].getDirection()){//横放
persons[i].setIcon(icons[4]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, 2*W, W);
}else{//竖放
persons[i].setIcon(icons[13]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, W, 2*W);
}
break;
case 5://黄忠,占两格
persons[i] = new Person(5,"黄忠");
if(map[i].getDirection()){//横放
persons[i].setIcon(icons[5]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, 2*W, W);
}else{//竖放
persons[i].setIcon(icons[14]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, W, 2*W);
}
break;
case 6://小兵,占一格
persons[i] = new Person(6,"小兵");
persons[i].setIcon(icons[6]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, W, W);
break;
case 7://小兵,占一格
persons[i] = new Person(7,"小兵");
persons[i].setIcon(icons[7]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, W, W);
break;
case 8://小兵,占一格
persons[i] = new Person(8,"小兵");
persons[i].setIcon(icons[8]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, W, W);
break;
case 9://小兵,占一格
persons[i] = new Person(9,"小兵");
persons[i].setIcon(icons[9]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, W, W);
break;
}
persons[i].addMouseListener(this);
persons[i].addKeyListener(this);
this.add(persons[i]);
}
}
③判断鼠标拖拽方向
记录下鼠标按下的像素点p1,再记录鼠标松开时的像素点p2,用p2去减去p1,得到x的位移量和y的位移量,如果x的位移量大于y的位移量,说明是水平方向拖拽,然后再判断p2.x-p1.x是正数还是负数,如果是正数,说明是水平向右拖拽,否则是水平向左拖拽。
private String getDirection(){
int dx,dy;
String direction;
dx = p2.x - p1.x;
dy = p2.y - p1.y;
if(dx==0&&dy==0){
return "no move";
}
if(Math.abs(dx)>Math.abs(dy)){//水平方向的偏移大于竖直方向的偏移,即水平方向运动
if(dx>0){//释放点在按压点右边
direction = "right";
}else{
direction = "left";
}
}else{//竖直方向的偏移大于水平方向的偏移,即竖直方向运动
if(dy>0){//释放点在按压点下边
direction = "down";
}else{
direction = "up";
}
}
return direction;
}
@Override
public void mousePressed(MouseEvent e) {
if(e.getSource()==null)//没有选中任何按钮,直接返回
return ;
p1.x = e.getX();
p1.y = e.getY();
}
@Override
public void mouseReleased(MouseEvent e) {
if(e.getSource()==null)
return ;
Person man = (Person) e.getSource();
p2.x = e.getX();
p2.y = e.getY();
String direction = getDirection();
boolean canMoveFlag;
if(direction.equals("up")){
canMoveFlag = getCanMoveFlag(man,UP);
if(canMoveFlag)
move(man,UP);
}else if(direction.equals("down")){
canMoveFlag = getCanMoveFlag(man,DOWN);
if(canMoveFlag)
move(man,DOWN);
}else if(direction.equals("left")){
canMoveFlag = getCanMoveFlag(man,LEFT);
if(canMoveFlag)
move(man,LEFT);
}else if(direction.equals("right")){
canMoveFlag = getCanMoveFlag(man,RIGHT);
if(canMoveFlag)
move(man,RIGHT);
}
}
④判断是否可以向某个方向拖拽
getCanMoveFlag(Person man,int direction)根据传入的JButton对象和拖拽方向,获取是否可以移动的标记。
先获取传入的按钮对应的矩形对象,然后根据不同方向对该矩形移动一个单位格,然后对每个人物按钮对应的矩形对象判断是否相交,如果跟每个按钮对应的矩形都不相交,再跟边界的四个矩形进行是否相交的判断,最后返回canMoveFlag;
Rectangle leftBoundary = new Rectangle(leftX-10, leftY, 10, 5*W);
Rectangle rightBoundary = new Rectangle(leftX+4*W, leftY, 10, 5*W);
Rectangle upBoundary = new Rectangle(leftX, leftY-10, 4*W, 10);
Rectangle downBoundary = new Rectangle(leftX, leftY+5*W, 4*W, 10);
private boolean getCanMoveFlag(Person man, int direction) {
boolean canMoveFlag = true;
Rectangle manRect = man.getBounds();//返回点击的人物按钮对应的矩形对象
int x = manRect.x;
int y = manRect.y;
if(direction ==UP){
y -= W;
}else if(direction == DOWN){
y += W;
}else if(direction == LEFT){
x -= W;
}else if(direction == RIGHT){
x += W;
}
manRect.setLocation(x, y);//矩形进行了移动
for(int i=0;i<10;i++){
if(persons[i].getId()!=man.getId()){//位移后的矩形与其他人物图块对应的矩形进行碰撞检测
Rectangle personRect = persons[i].getBounds();
if(personRect.intersects(manRect)){//如果两矩形相交,说明不能移动
canMoveFlag = false;
}
}
}
//检测是否超出游戏区域
if(manRect.intersects(upBoundary)||manRect.intersects(downBoundary)||manRect.intersects(leftBoundary)||manRect.intersects(rightBoundary)){
canMoveFlag = false;
}
return canMoveFlag;
}
⑤移动按钮并判断是否过关
如果可以向某个方向移动按钮,则改变根据方向改变按钮的位置,step++,然后判断曹操是否位于终点
private void move(Person man, int direction) {
switch(direction){
case UP:man.setLocation(man.getX(), man.getY()-W);break;
case DOWN:man.setLocation(man.getX(), man.getY()+W);break;
case LEFT:man.setLocation(man.getX()-W, man.getY());break;
case RIGHT:man.setLocation(man.getX()+W, man.getY());break;
}
step++;
GameClient.helpPanel.nowStep.setText(""+step);
if(isWin(man)){
if(level==10){JOptionPane.showMessageDialog(this, "恭喜通过最后一关");}
else{
String msg;
if(step
GamePanel类:
package 华容道;
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class GamePanel extends JPanel implements ActionListener,MouseListener,KeyListener{
int leftX=50,leftY=50;
int level,W=100;
int step = 0;//存储当前步数
int record;//存储当前关卡记录
Icon[] icons;
Image[] pics;
Node[] map;
Person[] persons;
Point p1 = new Point(0,0);//鼠标按下时点击的像素坐标
Point p2 = new Point(0,0);//鼠标释放时点击的像素坐标
Rectangle leftBoundary = new Rectangle(leftX-10, leftY, 10, 5*W);
Rectangle rightBoundary = new Rectangle(leftX+4*W, leftY, 10, 5*W);
Rectangle upBoundary = new Rectangle(leftX, leftY-10, 4*W, 10);
Rectangle downBoundary = new Rectangle(leftX, leftY+5*W, 4*W, 10);
public static final int UP=1,DOWN=2,LEFT=3,RIGHT=4;
MapUtil mapUtil = new MapUtil();
public GamePanel(int level){
this.level = level;
map = mapUtil.getMap(level);
persons = new Person[10];
icons = new Icon[15];
pics = new Image[15];
setLayout(null);
setSize(400, 500);
getIcons();
initialize();
HelpPanel.restart.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent e){
step = 0;
for(int i=0;i<10;i++){
GameClient.gamePanel.remove(persons[i]);
}
repaint();
map = mapUtil.getMap(level);
GameClient.panel.remove(GameClient.helpPanel);
GameClient.helpPanel = new HelpPanel(level);
GameClient.panel.add(GameClient.helpPanel,BorderLayout.EAST);
GameClient.helpPanel.validate();
GameClient.gamePanel.validate();
GameClient.panel.validate();
initialize();
setVisible(true);
GameClient.gamePanel.requestFocus();
repaint();
}
});;
}
public void paint(Graphics g){
setLayout(null);
g.clearRect(0, 0, getWidth(), getHeight());
for(int i=0;i<10;i++){
persons[i].requestFocus();
persons[i].paintComponents(g);
}
}
//获取图片
private void getIcons() {
for(int i=0;i<15;i++){
if(i==0){
pics[i] = Toolkit.getDefaultToolkit().getImage("D:/Game/KlotskiGame/pic"+i+".png").getScaledInstance(2*W, 2*W,Image.SCALE_SMOOTH);
}else if(i==1||i==2||i==3||i==4||i==5){
pics[i] = Toolkit.getDefaultToolkit().getImage("D:/Game/KlotskiGame/pic"+i+".png").getScaledInstance(2*W, W,Image.SCALE_SMOOTH);
}else if(i==6||i==7||i==8||i==9){
pics[i] = Toolkit.getDefaultToolkit().getImage("D:/Game/KlotskiGame/pic"+i+".png").getScaledInstance(W, W,Image.SCALE_SMOOTH);
}else{
pics[i] = Toolkit.getDefaultToolkit().getImage("D:/Game/KlotskiGame/pic"+i+".png").getScaledInstance(W,2*W,Image.SCALE_SMOOTH);
}
icons[i] = new ImageIcon(pics[i]);
}
repaint();
}
//对游戏布局进行初始化
private void initialize() {
for(int i=0;i<10;i++){
switch(map[i].getId()){
case 0://曹操,占四格
persons[i] = new Person(0,"曹操");
persons[i].setIcon(icons[0]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, 2*W, 2*W);
break;
case 1://赵云,占两格
persons[i] = new Person(1,"赵云");
if(map[i].getDirection()){//横放
persons[i].setIcon(icons[1]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, 2*W, W);
}else{//竖放
persons[i].setIcon(icons[10]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, W, 2*W);
}
break;
case 2://张飞,占两格
persons[i] = new Person(2,"张飞");
if(map[i].getDirection()){//横放
persons[i].setIcon(icons[2]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, 2*W, W);
}else{//竖放
persons[i].setIcon(icons[11]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, W, 2*W);
}
break;
case 3://关羽,占两格
persons[i] = new Person(3,"关羽");
if(map[i].getDirection()){//横放
persons[i].setIcon(icons[3]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, 2*W, W);
}else{//竖放
persons[i].setIcon(icons[12]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, W, 2*W);
}
break;
case 4://马超,占两格
persons[i] = new Person(4,"马超");
if(map[i].getDirection()){//横放
persons[i].setIcon(icons[4]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, 2*W, W);
}else{//竖放
persons[i].setIcon(icons[13]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, W, 2*W);
}
break;
case 5://黄忠,占两格
persons[i] = new Person(5,"黄忠");
if(map[i].getDirection()){//横放
persons[i].setIcon(icons[5]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, 2*W, W);
}else{//竖放
persons[i].setIcon(icons[14]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, W, 2*W);
}
break;
case 6://小兵,占一格
persons[i] = new Person(6,"小兵");
persons[i].setIcon(icons[6]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, W, W);
break;
case 7://小兵,占一格
persons[i] = new Person(7,"小兵");
persons[i].setIcon(icons[7]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, W, W);
break;
case 8://小兵,占一格
persons[i] = new Person(8,"小兵");
persons[i].setIcon(icons[8]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, W, W);
break;
case 9://小兵,占一格
persons[i] = new Person(9,"小兵");
persons[i].setIcon(icons[9]);
persons[i].setBounds(leftX+map[i].getY()*W, leftY+map[i].getX()*W, W, W);
break;
}
persons[i].addMouseListener(this);
persons[i].addKeyListener(this);
this.add(persons[i]);
}
}
private String getDirection(){
int dx,dy;
String direction;
dx = p2.x - p1.x;
dy = p2.y - p1.y;
if(dx==0&&dy==0){
return "no move";
}
if(Math.abs(dx)>Math.abs(dy)){//水平方向的偏移大于竖直方向的偏移,即水平方向运动
if(dx>0){//释放点在按压点右边
direction = "right";
}else{
direction = "left";
}
}else{//竖直方向的偏移大于水平方向的偏移,即竖直方向运动
if(dy>0){//释放点在按压点下边
direction = "down";
}else{
direction = "up";
}
}
return direction;
}
@Override
public void mousePressed(MouseEvent e) {
if(e.getSource()==null)//没有选中任何按钮,直接返回
return ;
p1.x = e.getX();
p1.y = e.getY();
}
@Override
public void mouseReleased(MouseEvent e) {
if(e.getSource()==null)
return ;
Person man = (Person) e.getSource();
p2.x = e.getX();
p2.y = e.getY();
String direction = getDirection();
boolean canMoveFlag;
if(direction.equals("up")){
canMoveFlag = getCanMoveFlag(man,UP);
if(canMoveFlag)
move(man,UP);
}else if(direction.equals("down")){
canMoveFlag = getCanMoveFlag(man,DOWN);
if(canMoveFlag)
move(man,DOWN);
}else if(direction.equals("left")){
canMoveFlag = getCanMoveFlag(man,LEFT);
if(canMoveFlag)
move(man,LEFT);
}else if(direction.equals("right")){
canMoveFlag = getCanMoveFlag(man,RIGHT);
if(canMoveFlag)
move(man,RIGHT);
}
}
private void move(Person man, int direction) {
switch(direction){
case UP:man.setLocation(man.getX(), man.getY()-W);break;
case DOWN:man.setLocation(man.getX(), man.getY()+W);break;
case LEFT:man.setLocation(man.getX()-W, man.getY());break;
case RIGHT:man.setLocation(man.getX()+W, man.getY());break;
}
step++;
GameClient.helpPanel.nowStep.setText(""+step);
if(isWin(man)){
if(level==10){JOptionPane.showMessageDialog(this, "恭喜通过最后一关");}
else{
String msg;
if(step
HelpPanel类是继承自JPanel的辅助面板类,负责显示关卡名字和步数
HelpPanel类:
package 华容道;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class HelpPanel extends JPanel{
String[] names = new String[]{"七步成诗","横刀立马","屯兵东路","插翅难飞","巧过五关","层层设防","近在咫尺","兵临曹营","众志成城","佳人梳妆"};//十个关卡的名字
int level;
JPanel panelNorth = new JPanel(new GridLayout(4,2,10,30));
static JLabel nowStep = new JLabel("0");
JLabel nowName = new JLabel("");
JLabel record = new JLabel("9999");
static JButton restart = new JButton("重置");
public HelpPanel(int level){
this.level = level;
this.setVisible(true);
this.setLayout(new BorderLayout());//当前面板
panelNorth.add(new JLabel("关卡名字:"));
panelNorth.add(nowName);
panelNorth.add(new JLabel("当前步数:"));
panelNorth.add(nowStep);
panelNorth.add(new JLabel("历史记录:"));
panelNorth.add(record);//历史记录
panelNorth.add(restart);
this.add(panelNorth,BorderLayout.NORTH);
initialize();
}
public void setLevel(int level){
this.level = level;
initialize();
}
private void initialize() {
// System.out.println("level is "+level);
// System.out.println(names[level-1]);
nowName.setText(names[level-1]+"");
nowStep.setText("0");
record.setText(""+MapFactory.getRecord(level));
}
}
游戏窗口类GameClient类用于装载游戏面板和辅助面板。
GameClient类:
package 华容道;
import java.awt.BorderLayout;
import java.awt.Container;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GameClient extends JFrame{
static GamePanel gamePanel;
static HelpPanel helpPanel;
static Container panel;//窗口容器
public GameClient(){
helpPanel = new HelpPanel(1);
gamePanel = new GamePanel(1);//设置关卡
gamePanel.setLayout(new BorderLayout());
panel = this.getContentPane();
panel.setLayout(new BorderLayout());
panel.add(helpPanel,BorderLayout.EAST);
panel.add(gamePanel,BorderLayout.CENTER);
this.setSize(650,650);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle("华容道");
this.setVisible(true);
this.setResizable(false);
}
public static void main(String[] args) {
new GameClient();
}
}
这次游戏开发中途遇到了一些显示问题的bug(第二关开始最后一个人物按钮变成全屏),导致出现了很多复杂的静态变量引用,不过目前已经解决,实现略繁琐,就不细说了。
ps:根据关卡名字均可以在百度上找到解密过程,(#^.^#)
素材及完整源码链接: https://pan.baidu.com/s/1_vOhAYk07h9dXBaez_lW3g 提取码: sni6