用Java開發貪食蛇小游戲
一、實驗內容
1、實作貪吃蛇游戲基本功能,螢屏上隨機出現一個“食物”,稱為豆子,上下左右控制“蛇”的移動,吃到“豆子”以后“蛇”的身體加長一點,得分增加,“蛇”碰到邊界或,蛇頭與蛇身相撞,蛇死亡,游戲結束,為游戲設計初始歡迎界面,游戲界面,游戲 結束界面,
2、進行互動界面的設計,要有開始鍵、暫停鍵和停止退出的選項,對蛇吃到豆子進行分值計算,可以設定游戲速度,游戲音樂等拓展元素,
二、貪食蛇游戲邏輯架構

三、貪食蛇開發流程
1、準備開發環境
(1)打開eclipse,
(2)新建SnakeGame專案,在該專案下新建Snake主類和Panel類;新建一個folder:resource存放資源,在該檔案resource下再新建兩個folder:sound和image,把游戲所需圖片檔案和音頻檔案放進去,
圖片音頻resource鏈接: https://pan.baidu.com/s/1nm_vPxHb_jVVNGcUfVxBWg
提取碼: jfdv

2、設計游戲圖紙

3、畫出白布視窗frame
JFrame frame = new JFrame();
frame.setBounds(200, 50, 800, 600);
frame.setResizable(false);// 設定視窗不可更改
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);// 使視窗可視
4、在視窗上添加畫布
frame.add(new Panel());
5、在畫布上添加標題
ImageIcon title;// 定義游戲界面開頭欄圖示
title.paintIcon(this, g, 5, 0);// 用畫筆g畫title圖示
6、在畫布上添加黑色游戲框,添加游戲背景圖(游戲區)
g.fillRect(5, 35, 775, 525);// 用畫筆g畫游戲界面黑框
g.drawImage(bj, 5, 35, this);// 添加游戲界面背景圖片
7、在游戲區放上靜態的蛇
for (int i = 1; i < len; i++) {// 不能從0開始,0用來存放蛇頭了
body.paintIcon(this, g, snakex[i], snakey[i]);
}
8、初始化蛇
public void initSnake() {
len = 3;
snakex[0] = 55;//一定要注意初始坐標的選取,不能隨意取,
snakey[0] = 35;
snakex[1] = 30;
snakey[1] = 35;
snakex[2] = 5;
snakey[2] = 35;
foodx = 5 + 25 * rand.nextInt(30);// 橫坐標可容納30個food呼叫rand方法隨機生成
foody = 35 + 25 * rand.nextInt(21);// 縱坐標可容納21個food
fx = "R";// 重新初始化蛇頭方向,不然每次一重新開始又立馬撞到自己然后over掉!
score = 0;
}
9、控制蛇頭的方向
if (fx == "R") {
right.paintIcon(this, g, snakex[0], snakey[0]);// 蛇頭放在頭節點,即第一個陣列元素中
} else if (fx == "L") {
left.paintIcon(this, g, snakex[0], snakey[0]);
} else if (fx == "U") {
up.paintIcon(this, g, snakex[0], snakey[0]);
} else if (fx == "D") {
down.paintIcon(this, g, snakex[0], snakey[0]);
}
10、放上游戲開始、游戲結束提示
// 畫跳出的游戲開始提示字符
if (isStarted == false) {
g.setColor(Color.white);// 重新設定畫筆字體顏色
g.setFont(new Font("arial", Font.BOLD + Font.ITALIC, 45));// 重新設定畫筆字體型別,加粗,大小
g.drawString("Press Space to Your Show Time", 50, 475);// 畫它,放在視窗中坐標為(75,300)的地方
g.setColor(Color.red);
begin.paintIcon(this, g, 250, 150);
}
// 畫游戲結束界面
if (isFailed) {
g.setColor(Color.white);
g.setFont(new Font("arial", Font.BOLD, 40));
g.drawString("Press Space to Restart", 200, 360);
g.setColor(Color.red);
g.setFont(new Font("arial", Font.BOLD + Font.ITALIC, 73));// 同時設定粗體與斜體用加號
g.drawString("Game Over ! ", 200, 250);
fail.paintIcon(this, g, 0, 380);
}
11、按空格鍵控制游戲開始
12、讓蛇動起來
if (isStarted && !isFailed) {
// 遞回方法,每間隔一個時鐘周期,蛇移動一格,后一節身體的坐標變成前一節身體的坐標,蛇頭直接向前移動一格,一直畫一直畫
for (int i = len - 1; i > 0; i--) {
snakex[i] = snakex[i - 1];
snakey[i] = snakey[i - 1];
}
13、實作轉向
if (fx == "R") {
snakex[0] = snakex[0] + 25;// 向右移動就橫坐標加25
if (snakex[0] > 755)// 當向右運動超出邊界時,蛇死,游戲結束
Failed();
} else if (fx == "L") {
snakex[0] = snakex[0] - 25;
if (snakex[0] < 5)
Failed();
} else if (fx == "U") {
snakey[0] = snakey[0] - 25;
if (snakey[0] < 35)
Failed();
} else if (fx == "D") {
snakey[0] = snakey[0] + 25;
if (snakey[0] > 535)
Failed();
}
13、添加食物,吃掉食物
// 當蛇吃到食物時身體會變長
if (snakex[0] == foodx && snakey[0] == foody) {
eat.loop(2);
foodx = 5 +25*rand.nextInt(30);// 食物被吃掉后繼續隨機生成
foody = 35 +25*rand.nextInt(21);// 21是用黑框寬度525除以每一格的寬度25得來的,算對很重要,不然運行起來會有毛病
len++;// 蛇身變長一節
score = score + 100;// 每吃掉一個食物,分數增加100
}
14、游戲結束功能
背景音樂停止播放
游戲結束音樂響起
蛇不動了
游戲結束界面跳出
15、實作重新開始功能
本游戲通過空格鍵控制游戲的暫停和開始,如果游戲尚未結束,按空格鍵可實作暫停;如果游戲已經結束,按空格鍵可實作游戲重新開始,
16、添加分數和長度
g.setColor(Color.white);// 設定畫筆字體顏色
g.setFont(new Font("華文行楷", Font.BOLD, 20));// 設定畫筆字體型別,加粗,大小
g.drawString("Len:" + len, 550, 24); // 在視窗右上角畫len字串
g.drawString("Score:" + score, 630, 24);// 畫Score字串
17、添加背景音樂
18、讓背景音樂回圈播放
bgm.loop(Clip.LOOP_CONTINUOUSLY);// 回圈播放背景音樂
19、實作音樂播放和停止
private void Failed() {
over.loop(1);// 游戲結束時播放死亡音樂
bgm.stop();// 游戲結束時使背景音樂暫停
isFailed = true;// 設定游戲處于結束狀態
}
20、將源代碼匯出成可執行檔案(后面有空再補充)
(1)

(2)

(3)
找到該游戲專案的主類
找到該游戲的主類 選擇匯出的目的地
選擇Finish

(4)成功匯出到目的地

四、測驗演示
1、視頻鏈接:Java貪食蛇游戲演示
(因無法上傳視頻只能提供視頻鏈接和部分截圖了)
2、游戲開始界面
3、有游戲結束界面
五、完整源程式代碼
Snake類
import javax.swing.JFrame;
public class Snake {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setBounds(200, 50, 800, 600);
frame.setResizable(false);// 設定視窗不可更改
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Panel());
frame.setVisible(true);// 使視窗可視
}
}
Panel 類
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.sound.sampled.*;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;
//新建畫布Panel
public class Panel extends JPanel implements KeyListener, ActionListener {
// 定義組件
ImageIcon title;// 定義游戲界面開頭欄圖示
ImageIcon body;// 定義蛇身圖示
ImageIcon up;// 定義向上的蛇頭圖示
ImageIcon down;// 向下的蛇頭圖示
ImageIcon right;// 向右的蛇頭圖示
ImageIcon left;// 向左的蛇頭圖示
ImageIcon food;// 食物圖示
ImageIcon begin;// 游戲開始圖示
ImageIcon fail;// 游戲結束圖示
BufferedImage bj = null;
/*
* 游戲區的背景,定義成bufferedImage型別,該型別物件生成的圖片在記憶體里有一個影像緩沖區,
* 可利用該緩沖區對圖片進行操作,比如設定影像透明與否、大小變換等等
*/
int len = 3;// 定義蛇的初始長度為3
int score = 0;// 添加分數
int[] snakex = new int[650];// 定義蛇身陣列x
int[] snakey = new int[650];// 定義蛇身陣列y
int foodx;// 定義食物橫坐標
int foody;// 定義食物縱坐標
String fx = "R";// U、L、R、D代表四個方向的蛇頭
boolean isStarted = false;// 定義布爾型別標志游戲是否開始
boolean isFailed = false;// 蛇是否陣亡標志
boolean isVictory = false;// 游戲勝利
Timer timer = new Timer(100, this);// 定義一個時鐘,即每間隔100ms,蛇重畫一次,連貫起來便形成蛇在運動的視覺效果
Random rand = new Random();// 引進隨機函式,用于隨機生成食物
Clip bgm;// 背景音樂
Clip over;// 游戲結束音樂
Clip eat;// 吃到食物時的音樂
// Panel的建構式
public Panel() {
loadImages();// 加載圖片;load方法加載指定的檔案名作為作為動態庫,檔案名引數必須是一個完整的路徑名
initSnake();// 初始化蛇的方法
this.setFocusable(true);// 設定獲取鍵盤焦點,focusable表示移動游標時是否能聚焦到組件上
this.addKeyListener(this);// 添加鍵盤監聽器方法,方法摘要有:keyPressed(按下某鍵時),keyReleased(釋放某鍵時),keyTyped(鍵入某鍵時)
timer.start();// 啟動時鐘方法
loadBGM();// 加載音樂
}
// 游戲界面設計畫組件, 呼叫繪制容器組件方法paintComponent
public void paintComponent(Graphics g) {// 添加一個畫筆g
super.paintComponent(g);// 呼叫父類方法
this.setBackground(Color.DARK_GRAY);// 設定畫布Panel背景色
title.paintIcon(this, g, 5, 0);// 用畫筆g畫title圖示
g.fillRect(5, 35, 775, 525);// 用畫筆g畫游戲界面黑框
g.drawImage(bj, 5, 35, this);// 添加游戲界面背景圖片
g.setColor(Color.white);// 設定畫筆字體顏色
g.setFont(new Font("華文行楷", Font.BOLD, 20));// 設定畫筆字體型別,加粗,大小
g.drawString("Len:" + len, 550, 24); // 在視窗右上角畫len字串
g.drawString("Score:" + score, 630, 24);// 畫Score字串
// 利用String 變數fx實作動態畫蛇頭,即可根據蛇運動的方向相應地調整蛇頭的方向
if (fx == "R") {
right.paintIcon(this, g, snakex[0], snakey[0]);// 蛇頭放在頭節點,即第一個陣列元素中
} else if (fx == "L") {
left.paintIcon(this, g, snakex[0], snakey[0]);
} else if (fx == "U") {
up.paintIcon(this, g, snakex[0], snakey[0]);
} else if (fx == "D") {
down.paintIcon(this, g, snakex[0], snakey[0]);
}
// 用回圈的方法畫蛇身,此時的蛇還是靜態的
for (int i = 1; i < len; i++) {// 不能從0開始,0用來存放蛇頭了
body.paintIcon(this, g, snakex[i], snakey[i]);
}
// 畫食物
food.paintIcon(this, g, foodx, foody);
// 畫跳出的游戲開始提示字符
if (isStarted == false) {
g.setColor(Color.white);// 重新設定畫筆字體顏色
g.setFont(new Font("arial", Font.BOLD + Font.ITALIC, 45));// 重新設定畫筆字體型別,加粗,大小
g.drawString("Press Space to Your Show Time", 50, 475);// 畫它,放在視窗中坐標為(75,300)的地方
g.setColor(Color.red);
begin.paintIcon(this, g, 250, 150);
}
// 畫游戲結束界面
if (isFailed) {
g.setColor(Color.white);
g.setFont(new Font("arial", Font.BOLD, 40));
g.drawString("Press Space to Restart", 200, 360);
g.setColor(Color.red);
g.setFont(new Font("arial", Font.BOLD + Font.ITALIC, 73));// 同時設定粗體與斜體用加號
g.drawString("Game Over ! ", 200, 250);
fail.paintIcon(this, g, 0, 380);
}
}
// 初始化蛇,用initSnake方法
public void initSnake() {
len = 3;
snakex[0] = 55;//一定要注意初始坐標的選取,不能隨意取,
snakey[0] = 35;
snakex[1] = 30;
snakey[1] = 35;
snakex[2] = 5;
snakey[2] = 35;
foodx = 5 + 25 * rand.nextInt(30);// 橫坐標可容納30個food呼叫rand方法隨機生成
foody = 35 + 25 * rand.nextInt(21);// 縱坐標可容納21個food
fx = "R";// 重新初始化蛇頭方向,不然每次一重新開始又立馬撞到自己然后over掉!
score = 0;
}
// 自動生成的鍵盤監聽器方法
@Override
public void keyTyped(KeyEvent e) {
}
// 定義回應鍵盤按下的行為的方法
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
// 當按下空格鍵時
if (keyCode == KeyEvent.VK_SPACE) {
if (isFailed) {// 先判斷當前游戲狀態
isFailed = false;
initSnake();// 輸了,初始化蛇
} else {
isStarted = !isStarted;
}
repaint();// 重畫界面
// 通過空格鍵控制音樂的暫停和開始
if (isStarted) {
bgm.loop(Clip.LOOP_CONTINUOUSLY);// 回圈播放背景音樂
} else {
bgm.stop();// 停止播放背景音樂
}
}
// 當按下"——>"鍵時
else if (keyCode == KeyEvent.VK_LEFT) {
fx = "L";
}
// 當按下"<——"鍵時
else if (keyCode == KeyEvent.VK_RIGHT) {
fx = "R";
}
// 當按下向上鍵時
else if (keyCode == KeyEvent.VK_UP) {
fx = "U";
}
// 當按下向下鍵時
else if (keyCode == KeyEvent.VK_DOWN) {
fx = "D";
}
}
@Override
public void keyReleased(KeyEvent e) {
}
// 定義操作事件的方法
@Override
public void actionPerformed(ActionEvent e) {// 事件監聽器ActionEvent在動作發生時呼叫,對應的處理方法為actionPerformed
// 當游戲已經開始并且沒有結束時,用回圈的方法畫蛇身,此處可實作蛇的動態運動效果
if (isStarted && !isFailed) {
// 遞回方法,每間隔一個時鐘周期,蛇移動一格,后一節身體的坐標變成前一節身體的坐標,蛇頭直接向前移動一格,一直畫一直畫
for (int i = len - 1; i > 0; i--) {
snakex[i] = snakex[i - 1];
snakey[i] = snakey[i - 1];
}
// 當蛇吃到食物時身體會變長
if (snakex[0] == foodx && snakey[0] == foody) {
eat.loop(2);
foodx = 5 +25*rand.nextInt(30);// 食物被吃掉后繼續隨機生成
foody = 35 +25*rand.nextInt(21);// 21是用黑框寬度525除以每一格的寬度25得來的,算對很重要,不然運行起來會有毛病
len++;// 蛇身變長一節
score = score + 100;// 每吃掉一個食物,分數增加100
}
// 定義蛇移動的方法
if (fx == "R") {
snakex[0] = snakex[0] + 25;// 向右移動就橫坐標加25
if (snakex[0] > 755)// 當向右運動超出邊界時,蛇死,游戲結束
Failed();
} else if (fx == "L") {
snakex[0] = snakex[0] - 25;
if (snakex[0] < 5)
Failed();
} else if (fx == "U") {
snakey[0] = snakey[0] - 25;
if (snakey[0] < 35)
Failed();
} else if (fx == "D") {
snakey[0] = snakey[0] + 25;
if (snakey[0] > 535)
Failed();
}
// 當蛇碰到自身時,游戲結束
for (int i = 1; i < len; i++) {// for回圈的作用是不管蛇頭碰到哪一節身體都會over,遍歷一遍看看是哪一節
if (snakex[i] == snakex[0] && snakey[i] == snakey[0]) {
Failed();
}
}
repaint();// 每一次行為后都要重畫以實作動態性與實時性
}
timer.start();// 時鐘開始
}
// 游戲結束時的方法
private void Failed() {
over.loop(1);// 游戲結束時播放死亡音樂
bgm.stop();// 游戲結束時使背景音樂暫停
isFailed = true;// 設定游戲處于結束狀態
}
// 加載音樂的方法
private void loadBGM() {
InputStream is;// 定義位元組輸入流變數
AudioInputStream ais;// 該類為inputstream的直接子類,用于讀取音頻
FloatControl gainControl;// 該類提供對一系列浮點值的控制,此處定義用來控制音頻音量大小
try {
bgm = AudioSystem.getClip();
is = this.getClass().getClassLoader().getResourceAsStream("sound/background.wav");// 通過類加載器找到位元組流
ais = AudioSystem.getAudioInputStream(is);// 轉換成音頻位元組流
bgm.open(ais);
gainControl = (FloatControl) bgm.getControl(FloatControl.Type.MASTER_GAIN);
gainControl.setValue(-10.0f);// 控制調整bgm的音量大小
eat = AudioSystem.getClip();
is = this.getClass().getClassLoader().getResourceAsStream("sound/eat.wav");
ais = AudioSystem.getAudioInputStream(is);
eat.open(ais);
gainControl = (FloatControl) eat.getControl(FloatControl.Type.MASTER_GAIN);
gainControl.setValue(3.0f);
over = AudioSystem.getClip();
is = this.getClass().getClassLoader().getResourceAsStream("sound/over.wav");
ais = AudioSystem.getAudioInputStream(is);
over.open(ais);
gainControl = (FloatControl) over.getControl(FloatControl.Type.MASTER_GAIN);
gainControl.setValue(3.0f);
} catch (LineUnavailableException e) {
e.printStackTrace();
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// 加載圖片的方法
private void loadImages() {
InputStream is;// 定義輸入流物件is
try {// 之所以整這么麻煩是為了把圖片等資源都整合在當前SnakeGame專案的一個檔案夾里,方便后面將整個源代碼匯出成exe程式
is = getClass().getClassLoader().getResourceAsStream("images/title.png");// 通過類加載器查找圖片
title = new ImageIcon(ImageIO.read(is));// 讓title畫出其相對應的圖示
is = getClass().getClassLoader().getResourceAsStream("images/bj.jpg");
bj = ImageIO.read(is);
is = getClass().getClassLoader().getResourceAsStream("images/body.png");
body = new ImageIcon(ImageIO.read(is));
is = getClass().getClassLoader().getResourceAsStream("images/up.png");
up = new ImageIcon(ImageIO.read(is));
is = getClass().getClassLoader().getResourceAsStream("images/down.png");
down = new ImageIcon(ImageIO.read(is));
is = getClass().getClassLoader().getResourceAsStream("images/right.png");
right = new ImageIcon(ImageIO.read(is));
is = getClass().getClassLoader().getResourceAsStream("images/left.png");
left = new ImageIcon(ImageIO.read(is));
is = getClass().getClassLoader().getResourceAsStream("images/food.png");
food = new ImageIcon(ImageIO.read(is));
is = getClass().getClassLoader().getResourceAsStream("images/fail.png");
fail = new ImageIcon(ImageIO.read(is));
is = getClass().getClassLoader().getResourceAsStream("images/begin.png");
begin = new ImageIcon(ImageIO.read(is));
} catch (IOException e) {
e.printStackTrace();
}
}
}
本代碼還可繼續擴展:
(1)設定分數等級及晉級機制
(2)設定不同速度模式
(3) 根據蛇長到一定程度速度也相應加快,增加挑戰性
(4)添加不同種類食物,添加獎勵機制和障礙物機制 (5)添加開始、暫停、結束、退出等按鈕(需添加滑鼠監聽器)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/234334.html
標籤:其他
