1. 程式人生 > >以後的23,725天,每一天都是精彩的,現在做,一切還來的及,相信自己!

以後的23,725天,每一天都是精彩的,現在做,一切還來的及,相信自己!

簡介:

(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();//啟動執行緒
		
	}
}