在二中,我們做出了界面,這篇博客,我們就要設法移動角色來實現推箱子了。
1.角色移動
我們需要先寫一個按鈕監聽類,這樣,當我們按到上下左右使其上下左右移動。
其中,code是按鍵所對應的值,通過System.out.println(code);我們能很輕鬆的獲取到我們按鍵所對應的數字
/**
* 內部遊戲按鍵監聽類
*/
class PanelListenner extends KeyAdapter {
// 當按鍵按下
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
switch (code) {
case KeyEvent.VK_UP:
break;
case KeyEvent.VK_DOWN:
break;
case KeyEvent.VK_LEFT:
break;
case KeyEvent.VK_RIGHT:
break;
case 87:
// w
break;
case 65:
// a
break;
case 83:
// s
break;
case 68:
// d
break;
default:
break;
}
}
}
按鍵做好了,我們需要移動啊
所以,我們需要做一個移動的方法,放到按鍵監聽裏面
其中playerx和playery爲角色座標
Move(1);即爲向上走。
/**
* 角色移動
* @param direction 方向 1234wasd
*/
private void Move(int direction) {
// TODO Auto-generated method stub
switch (direction) {
// 0牆 1地板 2空箱子 3 箱子 4箱子點 5出生點
case 1:
playerx -= 1;
break;
case 2:
playery -= 1;
break;
case 3:
playerx += 1;
break;
case 4:
playery += 1;
break;
default:
break;
}
}
然後我們在構造方法中添加監聽。且在監聽類中加入移動方法
然而還是不能移動,這是怎麼回事呢?,其實啊,我們雖然做了 移動的方法,但是我們沒有刷新界面。所以我們還要做一個線程來不停地刷新界面才能實現。
2.刷新面板
新建刷線面板類,繼承Thread。每0.01秒刷新面板一次。其中10爲10ms(毫秒)。可調。
package cn.edu.caztc.sokobangame;
import javax.swing.JPanel;
public class UpdateThread extends Thread{
JPanel panel;
public UpdateThread(JPanel panel) {
this.panel = panel;
}
@Override
public void run() {
while(true){
panel.repaint();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
整合代碼,完成移動效果
package cn.edu.caztc.sokobangame;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
/**
* 遊戲主體
*
* @author 莫言情難忘
*
*/
public class MainGame extends JFrame implements MapConfig {
int[][][] map1 = new int[18][18][1];// 地圖數組
int playerx = 0;// 玩家座標
int playery = 0;// 玩家座標
boolean diy = false;//
int level = 1;// 關卡
// 遊戲面板
JPanel panel;
public MainGame() {
// TODO Auto-generated constructor stub
this.setTitle("推箱子");
this.setSize(900, 950);
this.setLayout(new FlowLayout());
this.setDefaultCloseOperation(3);
// 設置窗體居中
this.setLocationRelativeTo(null);
// 不可拉伸
this.setResizable(false);
JMenuBar menuBar = new JMenuBar();
this.add(menuBar, BorderLayout.NORTH);
JMenu menu = new JMenu("菜單");
menuBar.add(menu);
JMenuItem menuItem = new JMenuItem("選關");
menuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
// System.out.println("選關");
}
});
menu.add(menuItem);
JMenuItem menuItem_1 = new JMenuItem("重新開始");
menuItem_1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// 重新開始
}
});
menu.add(menuItem_1);
JMenuItem menuItem_2 = new JMenuItem("關於");
menuItem_2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// System.out.println("關於");
JOptionPane.showMessageDialog(null, "莫言情難忘開發,csdn:莫言情難忘,個人QQ:1179307527", "關於",
JOptionPane.PLAIN_MESSAGE);
}
});
JMenu menu_1 = new JMenu("\u81EA\u5B9A\u4E49");
menuBar.add(menu_1);
JMenuItem menuItem_3 = new JMenuItem("地圖編輯器");
menuItem_3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
menu_1.add(menuItem_3);
menuBar.add(menuItem_2);
GetMAP(level, diy);
// 創建遊戲面板
panel = setpanel();
this.add(panel);
this.setVisible(true);
// 安裝鍵盤監聽器
PanelListenner plis = new PanelListenner();
this.addKeyListener(plis);
// 啓動刷新面板線程
UpdateThread ut = new UpdateThread(panel);
ut.start();
}
/**
* 讀取地圖數據
*
* @param level 關卡
* @param diy
*/
void GetMAP(int level, boolean diy) {
String stringdiy = "";
if (diy) {
stringdiy = "diy";
}
try {
DataInputStream in = new DataInputStream(
new BufferedInputStream(new FileInputStream(PATH + "\\" + stringdiy + level + ".map")));
int i = in.readInt();
int j = in.readInt();
for (int ii = 0; ii < i; ii++) {
for (int jj = 0; jj < j; jj++) {
map1[ii][jj][0] = in.readInt();
if (map1[ii][jj][0] == 5) {
playerx = ii;
playery = jj;
map1[ii][jj][0] = 1;
}
}
}
} catch (Exception e) {
// TODO: handle exception
}
}
/**
* 自定義內部遊戲面板類
*
* @author 莫言情難忘
*
*/
class MyPanel extends JPanel {
@Override
public void paint(Graphics g) {
super.paint(g);
for (int i = 0; i < MAP_HEIGHT / SOUREC_HEIGHT; i++) {
for (int j = 0; j < MAP_WIDTH / SOUREC_WIDTH; j++) {
g.drawImage(GetGameImage(map1[i][j][0]), getDrawX(j), getDrawY(i), SOUREC_WIDTH, SOUREC_HEIGHT,
null);
}
}
g.drawImage(icon106.getImage(), getDrawX(playery), getDrawY(playerx), SOUREC_WIDTH, SOUREC_HEIGHT, null);
}
// 將數組下標轉化成對應的圖片左上角座標
public int getDrawX(int j) {
int x = j * 50;
return x;
}
// 將數組下標轉化成對應的圖片左上角座標
public int getDrawY(int i) {
int y = i * 50;
return y;
}
}
/**
* 設置遊戲面板
*/
public JPanel setpanel() {
JPanel panel = new MyPanel();
panel.setPreferredSize(new Dimension(MAP_WIDTH, MAP_HEIGHT));
panel.setLayout(null);
panel.setBackground(Color.black);
return panel;
}
/**
* 獲取到數字對應的圖片
*
* @param i 數字
* @return
*/
Image GetGameImage(int i) {
if (i > 5) {
i = 0;
}
return allicons[i].getImage();
}
/**
* 內部遊戲按鍵監聽類
*/
class PanelListenner extends KeyAdapter {
// 當按鍵按下
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
switch (code) {
case KeyEvent.VK_UP:
Move(1);
break;
case KeyEvent.VK_DOWN:
Move(3);
break;
case KeyEvent.VK_LEFT:
Move(2);
break;
case KeyEvent.VK_RIGHT:
Move(4);
break;
case 87:
Move(1);
break;
case 65:
Move(3);
break;
case 83:
Move(2);
break;
case 68:
Move(4);
break;
default:
break;
}
}
}
/**
* 角色移動
*
* @param direction 方向 1234wasd
*/
private void Move(int direction) {
// TODO Auto-generated method stub
switch (direction) {
// 0牆 1地板 2空箱子 3 箱子 4箱子點 5出生點
case 1:
playerx -= 1;
break;
case 2:
playery -= 1;
break;
case 3:
playerx += 1;
break;
case 4:
playery += 1;
break;
default:
break;
}
}
}
3.碰撞判斷
姑且稱之爲碰撞判斷吧,我們角色雖然移動成功了。但是它肆無忌憚的移動也不好啊。我們要爲其加上限制。
我們先寫一個檢查方法,判斷其是否可以移動。
/**
* 檢查能不能走,前方有牆或者兩個箱子超界等
*
* @param direction 方向 1234wasd
* @return
*/
boolean check(int direction) {
switch (direction) {
case 1:
//判斷1.超界 2.前面是牆 3.前面是箱子或者空箱子 再前面是箱子或者牆或者空箱子
if (playerx==0) {
return false;
}else if (map1[playerx-1][playery][0]==0) {
return false;
}else if (map1[playerx-1][playery][0]==2||map1[playerx-1][playery][0]==3) {
if (map1[playerx-2][playery][0]==2||map1[playerx-2][playery][0]==3||map1[playerx-2][playery][0]==0) {
return false;
}
}
break;
case 2:
if (playery==0) {
return false;
}else if (map1[playerx][playery-1][0]==0) {
return false;
}else if (map1[playerx][playery-1][0]==2||map1[playerx][playery-1][0]==3) {
if (map1[playerx][playery-2][0]==2||map1[playerx][playery-2][0]==3||map1[playerx][playery-2][0]==0) {
return false;
}
}
break;
case 3:
if (playerx==17) {
return false;
}else if (map1[playerx+1][playery][0]==0) {
return false;
}else if (map1[playerx+1][playery][0]==2||map1[playerx+1][playery][0]==3) {
if (map1[playerx+2][playery][0]==2||map1[playerx+2][playery][0]==3||map1[playerx+2][playery][0]==0) {
return false;
}
}
break;
case 4:
if (playery==17) {
return false;
}else if (map1[playerx][playery+1][0]==0) {
return false;
}else if (map1[playerx][playery+1][0]==2||map1[playerx][playery+1][0]==3) {
if (map1[playerx][playery+2][0]==2||map1[playerx][playery+2][0]==3||map1[playerx][playery+2][0]==0) {
return false;
}
}
break;
default:
break;
}
return true;
}
將此方法整合到代碼中,雖然能實現限制的功能。但是他不推箱子啊
so:我們修改move方法,使其加上一些判斷能實現推箱子
/**
* 角色移動
*
* @param direction 方向 1234wasd
*/
private void Move(int direction) {
// TODO Auto-generated method stub
switch (direction) {
// 0牆 1地板 2空箱子 3 箱子 4箱子點 5出生點
case 1:
if (map1[playerx - 1][playery][0] == 2) {
if (map1[playerx - 2][playery][0] == 4) {
map1[playerx - 1][playery][0] = 1;
map1[playerx - 2][playery][0] = 3;
} else {
map1[playerx - 1][playery][0] = 1;
map1[playerx - 2][playery][0] = 2;
}
} else if (map1[playerx - 1][playery][0] == 3) {
map1[playerx - 1][playery][0] = 4;
map1[playerx - 2][playery][0] = 2;
}
playerx -= 1;
break;
case 2:
if (map1[playerx][playery - 1][0] == 2) {
if (map1[playerx][playery - 2][0] == 4) {
map1[playerx][playery - 1][0] = 1;
map1[playerx][playery - 2][0] = 3;
} else {
map1[playerx][playery - 1][0] = 1;
map1[playerx][playery - 2][0] = 2;
}
} else if (map1[playerx][playery - 1][0] == 3) {
map1[playerx][playery - 1][0] = 4;
map1[playerx][playery - 2][0] = 2;
}
playery -= 1;
break;
case 3:
if (map1[playerx + 1][playery][0] == 2) {
if (map1[playerx + 2][playery][0] == 4) {
map1[playerx + 1][playery][0] = 1;
map1[playerx + 2][playery][0] = 3;
} else {
map1[playerx + 1][playery][0] = 1;
map1[playerx + 2][playery][0] = 2;
}
} else if (map1[playerx + 1][playery][0] == 3) {
map1[playerx + 1][playery][0] = 4;
map1[playerx + 2][playery][0] = 2;
}
playerx += 1;
break;
case 4:
if (map1[playerx][playery + 1][0] == 2) {
if (map1[playerx][playery + 2][0] == 4) {
map1[playerx][playery + 1][0] = 1;
map1[playerx][playery + 2][0] = 3;
} else {
map1[playerx][playery + 1][0] = 1;
map1[playerx][playery + 2][0] = 2;
}
} else if (map1[playerx][playery + 1][0] == 3) {
map1[playerx][playery + 1][0] = 4;
map1[playerx][playery + 2][0] = 2;
}
playery += 1;
break;
default:
break;
}
}
整合後代碼及效果
package cn.edu.caztc.sokobangame;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
/**
* 遊戲主體
*
* @author 莫言情難忘
*
*/
public class MainGame extends JFrame implements MapConfig {
int[][][] map1 = new int[18][18][1];// 地圖數組
int playerx = 0;// 玩家座標
int playery = 0;// 玩家座標
boolean diy = false;//
int level = 1;// 關卡
// 遊戲面板
JPanel panel;
public MainGame() {
// TODO Auto-generated constructor stub
this.setTitle("推箱子");
this.setSize(900, 950);
this.setLayout(new FlowLayout());
this.setDefaultCloseOperation(3);
// 設置窗體居中
this.setLocationRelativeTo(null);
// 不可拉伸
this.setResizable(false);
JMenuBar menuBar = new JMenuBar();
this.add(menuBar, BorderLayout.NORTH);
JMenu menu = new JMenu("菜單");
menuBar.add(menu);
JMenuItem menuItem = new JMenuItem("選關");
menuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
// System.out.println("選關");
}
});
menu.add(menuItem);
JMenuItem menuItem_1 = new JMenuItem("重新開始");
menuItem_1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// 重新開始
}
});
menu.add(menuItem_1);
JMenuItem menuItem_2 = new JMenuItem("關於");
menuItem_2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// System.out.println("關於");
JOptionPane.showMessageDialog(null, "莫言情難忘開發,csdn:莫言情難忘,個人QQ:1179307527", "關於",
JOptionPane.PLAIN_MESSAGE);
}
});
JMenu menu_1 = new JMenu("\u81EA\u5B9A\u4E49");
menuBar.add(menu_1);
JMenuItem menuItem_3 = new JMenuItem("地圖編輯器");
menuItem_3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
menu_1.add(menuItem_3);
menuBar.add(menuItem_2);
GetMAP(level, diy);
// 創建遊戲面板
panel = setpanel();
this.add(panel);
this.setVisible(true);
// 安裝鍵盤監聽器
PanelListenner plis = new PanelListenner();
this.addKeyListener(plis);
// 啓動刷新面板線程
UpdateThread ut = new UpdateThread(panel);
ut.start();
}
/**
* 讀取地圖數據
*
* @param level 關卡
* @param diy
*/
void GetMAP(int level, boolean diy) {
String stringdiy = "";
if (diy) {
stringdiy = "diy";
}
try {
DataInputStream in = new DataInputStream(
new BufferedInputStream(new FileInputStream(PATH + "\\" + stringdiy + level + ".map")));
int i = in.readInt();
int j = in.readInt();
for (int ii = 0; ii < i; ii++) {
for (int jj = 0; jj < j; jj++) {
map1[ii][jj][0] = in.readInt();
if (map1[ii][jj][0] == 5) {
playerx = ii;
playery = jj;
map1[ii][jj][0] = 1;
}
}
}
} catch (Exception e) {
// TODO: handle exception
}
}
/**
* 自定義內部遊戲面板類
*
* @author 莫言情難忘
*
*/
class MyPanel extends JPanel {
@Override
public void paint(Graphics g) {
super.paint(g);
for (int i = 0; i < MAP_HEIGHT / SOUREC_HEIGHT; i++) {
for (int j = 0; j < MAP_WIDTH / SOUREC_WIDTH; j++) {
g.drawImage(GetGameImage(map1[i][j][0]), getDrawX(j), getDrawY(i), SOUREC_WIDTH, SOUREC_HEIGHT,
null);
}
}
g.drawImage(icon106.getImage(), getDrawX(playery), getDrawY(playerx), SOUREC_WIDTH, SOUREC_HEIGHT, null);
}
// 將數組下標轉化成對應的圖片左上角座標
public int getDrawX(int j) {
int x = j * 50;
return x;
}
// 將數組下標轉化成對應的圖片左上角座標
public int getDrawY(int i) {
int y = i * 50;
return y;
}
}
/**
* 設置遊戲面板
*/
public JPanel setpanel() {
JPanel panel = new MyPanel();
panel.setPreferredSize(new Dimension(MAP_WIDTH, MAP_HEIGHT));
panel.setLayout(null);
panel.setBackground(Color.black);
return panel;
}
/**
* 獲取到數字對應的圖片
*
* @param i 數字
* @return
*/
Image GetGameImage(int i) {
if (i > 5) {
i = 0;
}
return allicons[i].getImage();
}
/**
* 內部遊戲按鍵監聽類
*/
class PanelListenner extends KeyAdapter {
// 當按鍵按下
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
switch (code) {
case KeyEvent.VK_UP:
if (check(1)) {
Move(1);
}
break;
case KeyEvent.VK_DOWN:
if (check(3)) {
Move(3);
}
break;
case KeyEvent.VK_LEFT:
if (check(2)) {
Move(2);
}
break;
case KeyEvent.VK_RIGHT:
if (check(4)) {
Move(4);
}
break;
case 87:
if (check(1)) {
Move(1);
}
break;
case 65:
if (check(3)) {
Move(3);
}
break;
case 83:
if (check(2)) {
Move(2);
}
break;
case 68:
if (check(4)) {
Move(4);
}
break;
default:
break;
}
}
}
/**
* 檢查能不能走,前方有牆或者兩個箱子超界等
*
* @param direction 方向 1234wasd
* @return
*/
boolean check(int direction) {
switch (direction) {
case 1:
// 判斷1.超界 2.前面是牆 3.前面是箱子或者空箱子 再前面是箱子或者牆或者空箱子
if (playerx == 0) {
return false;
} else if (map1[playerx - 1][playery][0] == 0) {
return false;
} else if (map1[playerx - 1][playery][0] == 2 || map1[playerx - 1][playery][0] == 3) {
if (map1[playerx - 2][playery][0] == 2 || map1[playerx - 2][playery][0] == 3
|| map1[playerx - 2][playery][0] == 0) {
return false;
}
}
break;
case 2:
if (playery == 0) {
return false;
} else if (map1[playerx][playery - 1][0] == 0) {
return false;
} else if (map1[playerx][playery - 1][0] == 2 || map1[playerx][playery - 1][0] == 3) {
if (map1[playerx][playery - 2][0] == 2 || map1[playerx][playery - 2][0] == 3
|| map1[playerx][playery - 2][0] == 0) {
return false;
}
}
break;
case 3:
if (playerx == 17) {
return false;
} else if (map1[playerx + 1][playery][0] == 0) {
return false;
} else if (map1[playerx + 1][playery][0] == 2 || map1[playerx + 1][playery][0] == 3) {
if (map1[playerx + 2][playery][0] == 2 || map1[playerx + 2][playery][0] == 3
|| map1[playerx + 2][playery][0] == 0) {
return false;
}
}
break;
case 4:
if (playery == 17) {
return false;
} else if (map1[playerx][playery + 1][0] == 0) {
return false;
} else if (map1[playerx][playery + 1][0] == 2 || map1[playerx][playery + 1][0] == 3) {
if (map1[playerx][playery + 2][0] == 2 || map1[playerx][playery + 2][0] == 3
|| map1[playerx][playery + 2][0] == 0) {
return false;
}
}
break;
default:
break;
}
return true;
}
/**
* 角色移動
*
* @param direction 方向 1234wasd
*/
private void Move(int direction) {
// TODO Auto-generated method stub
switch (direction) {
// 0牆 1地板 2空箱子 3 箱子 4箱子點 5出生點
case 1:
if (map1[playerx - 1][playery][0] == 2) {
if (map1[playerx - 2][playery][0] == 4) {
map1[playerx - 1][playery][0] = 1;
map1[playerx - 2][playery][0] = 3;
} else {
map1[playerx - 1][playery][0] = 1;
map1[playerx - 2][playery][0] = 2;
}
} else if (map1[playerx - 1][playery][0] == 3) {
map1[playerx - 1][playery][0] = 4;
map1[playerx - 2][playery][0] = 2;
}
playerx -= 1;
break;
case 2:
if (map1[playerx][playery - 1][0] == 2) {
if (map1[playerx][playery - 2][0] == 4) {
map1[playerx][playery - 1][0] = 1;
map1[playerx][playery - 2][0] = 3;
} else {
map1[playerx][playery - 1][0] = 1;
map1[playerx][playery - 2][0] = 2;
}
} else if (map1[playerx][playery - 1][0] == 3) {
map1[playerx][playery - 1][0] = 4;
map1[playerx][playery - 2][0] = 2;
}
playery -= 1;
break;
case 3:
if (map1[playerx + 1][playery][0] == 2) {
if (map1[playerx + 2][playery][0] == 4) {
map1[playerx + 1][playery][0] = 1;
map1[playerx + 2][playery][0] = 3;
} else {
map1[playerx + 1][playery][0] = 1;
map1[playerx + 2][playery][0] = 2;
}
} else if (map1[playerx + 1][playery][0] == 3) {
map1[playerx + 1][playery][0] = 4;
map1[playerx + 2][playery][0] = 2;
}
playerx += 1;
break;
case 4:
if (map1[playerx][playery + 1][0] == 2) {
if (map1[playerx][playery + 2][0] == 4) {
map1[playerx][playery + 1][0] = 1;
map1[playerx][playery + 2][0] = 3;
} else {
map1[playerx][playery + 1][0] = 1;
map1[playerx][playery + 2][0] = 2;
}
} else if (map1[playerx][playery + 1][0] == 3) {
map1[playerx][playery + 1][0] = 4;
map1[playerx][playery + 2][0] = 2;
}
playery += 1;
break;
default:
break;
}
}
}