以後的23,725天,每一天都是精彩的,現在做,一切還來的及,相信自己!
阿新 • • 發佈:2019-02-04
簡介:
(1)玩法,玩家通過控制上、下、左、右四鍵來控制蛇來尋找地圖上的食物,當蛇吃下食物時蛇身變長
(2)基本步驟:
首先,自定義窗體,在窗體上新增面板。
然後,繪製地圖、蛇頭、蛇身、鍵的監聽和執行緒操作
然後,解決蛇要吃的食物問題
還有,解決碰壁問題
最後,實現是否退出遊戲
總結:這個遊戲實現了基本功能,有待有共同愛好的你繼續完善
貪吃蛇遊戲的窗體: package frame; import java.awt.BorderLayout; /** * 窗體 * * @author Administrator * */ public class GameJFrame extends JFrame { private JPanel contentPane; /** * Create the frame. */ public GameJFrame() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(539, 451); contentPane = new GameJPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); contentPane.setLayout(new BorderLayout(0, 0)); setContentPane(contentPane); this.setLocationRelativeTo(null); this.setTitle("貪吃蛇遊戲"); this.setVisible(true); } }
遊戲面板的操作,繪製遊戲面板、蛇身、判斷蛇身碰壁、及鍵盤按鈕處理: package frame; import java.awt.Color; import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.io.IOException; import java.util.Iterator; import java.util.Random; import java.util.Vector; import javax.imageio.ImageIO; import javax.swing.JOptionPane; import javax.swing.JPanel; import snake.domain.Box; /** * 遊戲面板 * * @author Administrator * */ public class GameJPanel extends JPanel implements Runnable, KeyListener { // 宣告食物 private Box food, head; private int headX = 220, headY = 120; private Vector<Box> snake; // 宣告蛇頭的區域範圍 private int minY = 20, maxY = 380; private int minX = 20, maxX = 480; private final int DIR_DEFAULT = -1; private final int DIR_UP = 1; private final int DIR_DOWN = 2; private final int DIR_LEFT = 3; private final int DIR_RIGHT = 4; // 遊戲是否退出的識別符號 private boolean isExit = true; private boolean isDeath = true; // 隨機數 private Random random; // 在區域性中已經宣告所以沒必要在宣告 // private int randomX, randomY; // private int foodX, foodY; private Image image; public GameJPanel() { // 這是用的一種工具流的方法載入圖片 /* * // 載入圖片放到建構函式中,在全域性變數中宣告 try { * image=ImageIO.read(getClass().getClassLoader * ().getResourceAsStream("images//z.jpg")); } catch (IOException e) { * // TODO Auto-generated catch block e.printStackTrace(); } */ image = Toolkit.getDefaultToolkit().getImage("src//images//z.jpg"); // 絕對路徑 // image=Toolkit.getDefaultToolkit().getImage("E:\\javaproject1\\javalianxi2\\SnakGamePaneJPanel\\src\\images\\z.jpg"); // 相對路徑 // image=Toolkit.getDefaultToolkit().getImage(GameJPanel.class.getResource("../images/z.jpg")); // 例項化隨機物件 random = new Random(); initGame(); // 註冊監聽事件 addKeyListener(this); // 設定焦點事件使貪吃蛇能動起來受鍵盤控制 this.setFocusable(true); // 啟動執行緒 new Thread(this).start(); } private void initGame() { // 例項化集合 snake = new Vector<Box>(); // 例項化 head = new Box(headX, headY, DIR_DEFAULT); // 新增到集合 snake.add(head); // 例項化食物 initFood(); } /** * 重新產生食物 */ private void initFood() { // 隨機產生的數字 // 因為在這一個地方使用,所以沒必要在全域性中宣告 int randomX = random.nextInt(24) + 1;// 1--25 int randomY = random.nextInt(19) + 1;// 1--20 // 計算出食物的座標 int foodX = randomX * Box.BOXSIZE; int foodY = randomY * Box.BOXSIZE; // 獲取了蛇頭下一個位置的x與y座標 int xy[] = getNextHeadXY(head.getDIR()); // 判斷食物的座標是否與蛇頭下個位置一致 if (xy[0] == foodX && xy[1] == foodY) { initFood(); return; } // 怎麼排除食物與蛇頭或蛇身的位置衝突問題 for (int i = 0; i < snake.size(); i++) { // 獲取蛇頭與蛇身,蛇頭的下一個位置也不能產生食物 Box body = snake.get(i); if (body != snake.lastElement()) { if (foodX == body.getX() && foodY == body.getY()) { initFood(); return; } } } // 例項化食物 food = new Box(foodX, foodY); } @Override public void paint(Graphics g) { super.paint(g);// 重新繪製的過程 g.setColor(Color.red); /** * 畫橫線 */ g.fill3DRect(0, 0, 20, 40, true); for (int col = 0; col < 450; col += 40) { g.drawImage(image, 0, col, null); g.drawImage(image, 500, col, null); } for (int row = 0; row <= 480; row += 20) { g.drawImage(image, row, 0, null); g.drawImage(image, row, 400, null); } g.drawLine(20, 20, 500, 20); g.drawLine(20, 20, 20, 400); g.drawLine(500, 20, 500, 400); g.drawLine(20, 400, 500, 400); /** * 畫豎線 */ /* * for (int col = 20; col < 330; col += 20) { g.drawLine(col, minY, col, * maxY); } */ // 設定繪製食物的顏色 g.setColor(Color.red); // 繪製食物 g.fill3DRect(food.getX(), food.getY(), Box.BOXSIZE, Box.BOXSIZE, true); /** * 遍歷集合 */ for (int i = 0; i < snake.size(); i++) { if (i == 0) { // 設定繪製蛇頭的顏色 g.setColor(Color.green); } else { g.setColor(Color.yellow); } // 獲取集合中指定位置的物件 Box box = snake.get(i); // 繪製蛇頭 g.fill3DRect(box.getX(), box.getY(), Box.BOXSIZE, Box.BOXSIZE, true); } } @Override public void run() { try { while (isDeath) { if (isExit) { // 判斷是否碰撞 if (checkHit()) { // 例項化食物 initFood(); } if (moveHead()) {// 移動蛇頭 moveSnakeBody(); } else { displayMsg(); }// 移動蛇身 // 重新繪製這個面板 this.repaint(); Thread.sleep(200); } } } catch (Exception ex) { ex.getStackTrace(); } } private void moveSnakeBody() { // 宣告蛇頭 Box head = null; // 宣告每個蛇身物件 Box body = null; int headDir = 0; int temp = 0; /* * Iterator<Box> it=snake.iterator(); while(it.hasNext()){ Box * box=it.next(); } */ if (snake.size() > 1) { // 遍歷集合 for (int i = 0; i < snake.size(); i++) { if (i == 0) { head = snake.get(i); headDir = head.getDIR();// 獲取蛇頭的方向 } else { body = snake.get(i); int dir = body.getDIR();// 拿到蛇身的方向 switch (dir) { case DIR_UP: body.setY(body.getY() - 20); break; case DIR_DOWN: body.setY(body.getY() + 20); break; case DIR_LEFT: body.setX(body.getX() - 20); break; case DIR_RIGHT: body.setX(body.getX() + 20); break; } temp = dir;// 記錄第一個蛇身的方向{記錄蛇頭的方向(每次都是把上一個捨身當做蛇頭來處理)} dir = headDir;// 把蛇身的方向賦值給下一個蛇身 body.setDIR(dir);// 保證了第一個蛇身的方向與蛇頭一致(改變蛇身方向) headDir = temp;// 把第一個蛇身當做蛇頭(把每一個蛇身當做蛇頭) } } } } /** * 檢測碰撞問題 */ private boolean checkHit() { // 根據座標是否完全相同 if (head.getX() == food.getX() && head.getY() == food.getY()) { // 首先獲取最後一個集合物件 保證了要吃的食物與最後一個集合物件的方向一致 Box box = snake.lastElement(); int dir = box.getDIR(); switch (dir) { case DIR_UP: food.setX(box.getX()); food.setY(box.getY() + 20); break; case DIR_DOWN: food.setX(box.getX()); food.setY(box.getY() - 20); break; case DIR_LEFT: food.setX(box.getX() + 20); food.setY(box.getY()); break; case DIR_RIGHT: food.setX(box.getX() - 20); food.setY(box.getY()); break; } food.setDIR(box.getDIR()); // 新增到集合中 snake.add(food); return true; } return false; } /** * 移動蛇頭 */ private boolean moveHead() { /* * //獲取集合的迭代器 Iterator<Box> it=snake.iterator(); int i=0; //遍歷 * while(it.hasNext()){ //獲取蛇身 Box body=it.next(); if(i!=0){ //比較一遍 * if(body.getX()==head.getX()&&body.getY()==head.getY()){ return false; * } } i++; } */ boolean flag = true; int dir = head.getDIR();// 獲取蛇頭的方向 // 宣告下一個位置的蛇頭物件{這是一種方法} /* * Box tempHead = new Box(); // 首先我能不能根據蛇頭的方向來獲取蛇頭移動的下一個位置 switch (dir) * { case DIR_UP: tempHead.setX(head.getX()); tempHead.setY(head.getY() * - Box.BOXSIZE); * * break; case DIR_DOWN: tempHead.setX(head.getX()); * tempHead.setY(head.getY() + Box.BOXSIZE); break; case DIR_LEFT: * tempHead.setX(head.getX() - Box.BOXSIZE); tempHead.setY(head.getY()); * break; case DIR_RIGHT: tempHead.setX(head.getX() + Box.BOXSIZE); * tempHead.setY(head.getY()); break; } */ /* * // 宣告下一個位置的蛇頭座標 int x = 0, y = 0; // 首先我能不能根據蛇頭的方向來獲取蛇頭移動的下一個位置 * switch (dir) { case DIR_UP: x = head.getX(); y = head.getY() - * Box.BOXSIZE; * * break; case DIR_DOWN: x = head.getX(); y = head.getY() + Box.BOXSIZE; * break; case DIR_LEFT: x = head.getX() - Box.BOXSIZE; y = head.getY(); * break; case DIR_RIGHT: x = head.getX() + Box.BOXSIZE; y = * head.getY(); break; } */ // 先定義陣列,再封裝方法 /** * 根據蛇頭方向獲取蛇頭下一個位置的座標 [0]代表是x座標 [1]代表是y座標 */ // 獲取蛇頭下一個位置的座標,存放在陣列中 int[] xy = getNextHeadXY(dir); /* // 移動蛇頭時候要處理碰撞身體問題 for (int i = 0; i < snake.size(); i++) { // 獲取蛇身 Box body = snake.get(i); // 這是加了一個判斷使蛇頭能吃掉一個蛇身而不死亡 * if(body==snake.lastElement()){ * * }else{ // 判斷蛇身與蛇頭移動下一個位置的座標是否相同 if (body.getX() == x&& * body.getY() ==y) { return false; } } // 方法改進 // 最後一個不要判斷,當蛇頭移動到最後一個的時候,最後一個移走了 if (body != snake.lastElement()) { // 判斷蛇身與蛇頭移動下一個位置的座標是否相同 if (body.getX() == xy[0] && body.getY() == xy[1]) { return false; } }*/ // 進一步改進 // 移動蛇頭時候要處理碰撞身體問題 int size=snake.size(); for (int i = 0; i < size; i++) { // 獲取蛇身 Box body = snake.get(i); if(size==2){ if (body.getX() == xy[0] && body.getY() == xy[1]) { return false; } } // 方法改進 // 最後一個不要判斷,當蛇頭移動到最後一個的時候,最後一個移走了 if (body != snake.lastElement()) { // 判斷蛇身與蛇頭移動下一個位置的座標是否相同 if (body.getX() == xy[0] && body.getY() == xy[1]) { return false; } } } // 如果蛇頭碰不到蛇身再處理 switch (dir) { case DIR_UP: if (head.getY() <= minY) { flag = false; } else { head.setY(head.getY() - Box.BOXSIZE); } break; case DIR_DOWN: if (head.getY() >= maxY) { flag = false; } else { head.setY(head.getY() + Box.BOXSIZE); } break; case DIR_LEFT: if (head.getX() <= minX) { flag = false; } else { head.setX(head.getX() - Box.BOXSIZE); } break; case DIR_RIGHT: if (head.getX() >= maxX) { flag = false; } else { head.setX(head.getX() + Box.BOXSIZE); } break; } return flag; } private int[] getNextHeadXY(int dir) { // 宣告下一個位置的蛇頭座標 int xy[] = new int[2]; // 首先我能不能根據蛇頭的方向來獲取蛇頭移動的下一個位置 switch (dir) { case DIR_UP: xy[0] = head.getX(); xy[1] = head.getY() - Box.BOXSIZE; break; case DIR_DOWN: xy[0] = head.getX(); xy[1] = head.getY() + Box.BOXSIZE; break; case DIR_LEFT: xy[0] = head.getX() - Box.BOXSIZE; xy[1] = head.getY(); break; case DIR_RIGHT: xy[0] = head.getX() + Box.BOXSIZE; xy[1] = head.getY(); break; } return xy; } // 進一步改動 /* * public void displayMsg() { isExit = false; */ public void displayMsg() { isExit = false; int temp = JOptionPane.showConfirmDialog(null, "遊戲死亡", "提示", JOptionPane.OK_OPTION); // temp==0代表要 if (temp == 0) { isDeath = false; } else { isExit=true; initGame(); } } /** * 鍵入某個鍵時呼叫這個方法 */ @Override public void keyTyped(KeyEvent e) { // TODO Auto-generated method stub } /** * 按下某個鍵時呼叫這個方法 */ @Override public void keyPressed(KeyEvent e) { int KeyCode = e.getKeyCode(); switch (KeyCode) { case KeyEvent.VK_UP: // 加一個判斷使按與蛇頭方向相反時不會死掉 if (head.getDIR() == DIR_DOWN) { break; } else { head.setDIR(DIR_UP); break; } case KeyEvent.VK_DOWN: if (head.getDIR() == DIR_UP) { break; } else { head.setDIR(DIR_DOWN); break; } case KeyEvent.VK_LEFT: if (head.getDIR() == DIR_RIGHT) { break; } else { head.setDIR(DIR_LEFT); break; } case KeyEvent.VK_RIGHT: if (head.getDIR() == DIR_LEFT) { break; } else { head.setDIR(DIR_RIGHT); break; } // 按下空格建的時候暫停遊戲 case KeyEvent.VK_SPACE: // 這是解釋過程 /* * isExit=false; isExit=true; */ isExit = !isExit; break; } } /** * 釋放某個鍵時呼叫這個方法 */ @Override public void keyReleased(KeyEvent e) { } }
遊戲主面板: package frame; import java.awt.BorderLayout; public class IndexJFrame extends JFrame implements ActionListener{ private JPanel contentPane; private JButton play_btn,ins_btn,score_btn,about_btn; /** * Launch the application. */ public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { IndexJFrame frame = new IndexJFrame(); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } /** * Create the frame. */ public IndexJFrame() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize( 539, 451); contentPane = new JPanel(); contentPane.setBackground(new Color(204, 204, 51)); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); contentPane.setLayout(null); play_btn = new JButton("開始遊戲"); play_btn.setBounds(174, 139, 157, 23); contentPane.add(play_btn); ins_btn = new JButton("遊戲說明"); ins_btn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { } }); ins_btn.setBounds(174, 185, 157, 23); contentPane.add(ins_btn); score_btn = new JButton("最高紀錄"); score_btn.setBounds(174, 228, 157, 23); contentPane.add(score_btn); about_btn = new JButton("關於我們"); about_btn.setBounds(174, 276, 157, 23); contentPane.add(about_btn); this.setLocationRelativeTo(null); //註冊事件 play_btn.addActionListener(this); ins_btn.addActionListener(this); score_btn.addActionListener(this); about_btn.addActionListener(this); } @Override public void actionPerformed(ActionEvent e) { String command=e.getActionCommand(); switch (command) { case "開始遊戲": this.dispose(); new GameJFrame();//遊戲介面 break; } } }
食物的實現
package snake.domain;
/**
* 把方格當做了蛇頭和蛇身的替代品
* 食物
* @author Administrator
*
*/
public class Box {
private int x;// 方格的x座標
private int y;// 方格的y座標
public static final int BOXSIZE = 20;
private int DIR;// 運動的方向
public Box() {
super();
// TODO Auto-generated constructor stub
}
public Box(int x, int y) {
super();
this.x = x;
this.y = y;
}
public Box(int x, int y, int dIR) {
super();
this.x = x;
this.y = y;
DIR = dIR;
}
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;
}
public int getDIR() {
return DIR;
}
public void setDIR(int dIR) {
DIR = dIR;
}
}
Snake2
package snake2;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
import java.util.Vector;
import javax.swing.JPanel;
public class GameJPanel extends JPanel implements KeyListener, Runnable {
/**
*
*/
// 定義蛇頭
private Node headNode;
// 遊戲結束標誌
private boolean temp = true;
// 蛇頭的方向
private int headNodeDir = 2;
// 定義1,2,3,4,-1分別表示上,下,左,右,停止
private static final int DIR_UP = 1;
private static final int DIR_DOWN = 2;
private static final int DIR_LEFT = 3;
private static final int DIR_RIGHT = 4;
private static final int DIR_STOP = -1;
// 產生隨機數物件
private Random random;
// 宣告食物
private Node eatNode;
// 宣告蛇身
private Vector<Node> nodeBody;
public GameJPanel() {
// 建立蛇身
headNode = new Node(130, 210, headNodeDir);
// 新增監聽
this.addKeyListener(this);
// 例項化隨機數類物件
random = new Random();
// 隨機產生座標,並且產生食物
randomCoord();
// 例項化蛇身集合
nodeBody = new Vector<Node>();
}
private void randomCoord() {
int col = random.nextInt(10);
int eatNodeX = col * 20 + 50;
int row = random.nextInt(15);
int eatNodeY = row * 20 + 50;
// 例項化
eatNode = new Node(eatNodeX, eatNodeY, DIR_STOP);
}
@Override
public void paint(Graphics g) {
super.paint(g);
// 設定顏色
g.setColor(Color.red);
// 繪製行的直線
for (int row = 50; row <= 350; row += 20) {
g.drawLine(50, row, 250, row);
}
// 繪製列的直線
for (int col = 50; col <= 250; col += 20) {
g.drawLine(col, 50, col, 350);
}
// 繪製蛇頭
g.setColor(new Color(0.5f, 0.6f, 0.7f));
g.fillRect(headNode.getNodeX(), headNode.getNodeY(), 20, 20);
//繪製食物
g.setColor(new Color(0.8f,0.8f,0.8f));
g.fillRect(eatNode.getNodeX(), eatNode.getNodeY(), 20, 20);
}
@Override
public void run() {
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
package snake2;
/**
* 建立每個節點
* 節點既可以是蛇頭,也可以是蛇身
* @author Administrator
*
*/
public class Node {
private int nodeX,nodeY;
private int nodeDir;
public Node(int nodeX,int nodeY,int nodeDir) {
this.nodeX=nodeX;
this.nodeY=nodeY;
this.nodeDir=nodeDir;
}
public int getNodeX() {
return nodeX;
}
public void setNodeX(int nodeX) {
this.nodeX = nodeX;
}
public int getNodeY() {
return nodeY;
}
public void setNodeY(int nodeY) {
this.nodeY = nodeY;
}
public int getNodeDir() {
return nodeDir;
}
public void setNodeDir(int nodeDir) {
this.nodeDir = nodeDir;
}
}
package snake2;
public class SnakeGame {
public static void main(String[] args) {
new SnakeJFrame();
}
}
package snake2;
import java.awt.Container;
import javax.swing.JFrame;
import frame.GameJPanel;
public class SnakeJFrame extends JFrame {
public GameJPanel gameJPanel;
public SnakeJFrame() {
this.setTitle("貪吃蛇遊戲");
this.setVisible(true);
this.setBounds(300,200,330,430);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//首先獲取Container
Container c=this.getContentPane();
gameJPanel=new GameJPanel();
//新增面板
c.add(gameJPanel);
new Thread(gameJPanel).start();//啟動執行緒
}
}