目錄
一.專案要求
二.專案平臺
三.專案實作程序
1.實作鍵盤控制:
2.游戲畫面及內容設定:
3.食物隨機產生:
4.觸碰墻與身體的判定:
5.移動與身體加長:
6.開始加載音樂
四、專案實作效果
1.運行界面:
2.完整代碼
一.專案要求
(1)實作貪吃蛇游戲基本功能,螢屏上隨機出現一個“食物”,稱為豆子, 上下左右控制“蛇”的移動,吃到“豆子”以后“蛇”的身體加長一點,
(2)“蛇”碰到邊界或蛇頭與蛇身相撞,蛇死亡,游戲結束,
(3)為游戲設計友好的互動界面;例如歡迎界面,游戲界面,游戲結束界面,要有開始鍵、暫停鍵和停止退出的選項,
(4)對蛇吃到豆子進行分值計算,可以設定游戲速度,游戲音樂 等拓展元素,
二.專案平臺
IDEA.Java Swing
三.專案實作程序
1.實作鍵盤控制:
public void keyPressed(KeyEvent e) {
// 鍵盤按下,未釋放
//獲取按下的鍵盤是哪個鍵
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_SPACE) { //如果按下的是空格鍵
if (isDie) { //失敗,游戲再來一遍
isDie = false;
init(); //重新初始化游戲
} else { //暫停游戲
isStart = !isStart;
}
repaint(); //重繪界面
}
//鍵盤控制走向
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";
}
}
2.游戲畫面及內容設定:
protected void paintComponent(Graphics g) {
super.paintComponent(g); //清屏
this.setBackground(Color.BLACK);//設定背景的顏色
//繪制積分框
Data.header.paintIcon(this, g, 0, 0);
//繪制游戲區域
g.fillRect(0, 75, 1000, 625);
//畫一條靜態的蛇
if (fx.equals("R")) {
Data.right.paintIcon(this, g, snakeX[0], snakeY[0]);
} else if (fx.equals("L")) {
Data.left.paintIcon(this, g, snakeX[0], snakeY[0]);
} else if (fx.equals("U")) {
Data.up.paintIcon(this, g, snakeX[0], snakeY[0]);
} else if (fx.equals("D")) {
Data.down.paintIcon(this, g, snakeX[0], snakeY[0]);
}
//蛇的身體長度通過length來控制
for (int i = 1; i < length; i++) {
Data.body.paintIcon(this, g, snakeX[i], snakeY[i]);
}
//畫食物
Data.food.paintIcon(this, g, foodx, foody);
//畫積分
g.setColor(Color.white); //設定畫筆顏色
g.setFont(new Font("微軟雅黑", Font.BOLD, 18));
g.drawString("長度:" + length, 750, 35);
g.drawString("分數:" + score, 750, 55);
//游戲提示:是否開始
if (isStart == false) {
//畫一段文字
g.setColor(Color.white); //設定畫筆顏色
g.setFont(new Font("微軟雅黑", Font.BOLD, 40));
g.drawString("按下空格開始游戲", 300, 300);
}
//失敗提醒
if (isDie) {
//畫一段文字
g.setColor(Color.red); //設定畫筆顏色
g.setFont(new Font("微軟雅黑", Font.BOLD, 40));
g.drawString("游戲失敗,按下空格重新開始", 200, 300);
}
}
3.食物隨機產生:
public void init() {
length = 3;
snakeX[0] = 100;
snakeY[0] = 100; //頭部坐標
snakeX[1] = 75;
snakeY[1] = 100; //第一個身體坐標
snakeX[2] = 50;
snakeY[2] = 100; //第二個身體坐標
fx = "R"; //默認蛇向右
foodx = 50 + 25 * random.nextInt(32);
foody = 125 + 75 * random.nextInt(6);
score = 0;
}
4.觸碰墻與身體的判定:
public void actionPerformed(ActionEvent e) {
//如果游戲處于開始狀態,并且游戲沒有結束
if (isStart && isDie == false) {
//右移
for (int i = length - 1; i > 0; i--) { //身體移動
snakeX[i] = snakeX[i - 1];
snakeY[i] = snakeY[i - 1];
}
if(fx.equals("R")){
snakeX[0] = snakeX[0] + 25; //頭部移動
// 邊界判斷
if(snakeX[0]>925 ) {isDie=true;}
}else if(fx.equals("L")){
snakeX[0] = snakeX[0] - 25; //頭部移動
// 邊界判斷
if(snakeX[0]<25){isDie=true;}
}else if(fx.equals("U")){
snakeY[0] = snakeY[0] - 25; //頭部移動
// 邊界判斷
if(snakeY[0]<100){isDie=true;}
}else if(fx.equals("D")){
snakeY[0] = snakeY[0] + 25; //頭部移動
// 邊界判斷
if(snakeY[0]>625){isDie=true;}
}
//如果小蛇的頭和食物坐標重合
if (snakeX[0] == foodx && snakeY[0] == foody) {
//長度+1
length++;
//重新生成食物
foodx = 25 + 25 * random.nextInt(32);
foody = 100 + 75 * random.nextInt(6);
score += 10;
}
//如果小蛇的頭和小蛇的身體坐標重合,失敗,(把小蛇設定為撞到身體不死)
for(int i=1;i<length;i++){
if(snakeX[0]==snakeX[i] && snakeY[0]==snakeY[i]){
isDie=true;
}
}
//重繪界面
repaint();
}
timer.start(); //讓時間動起來
}
5.移動與身體加長:
if (snakeX[0] == foodx && snakeY[0] == foody) {
//長度+1
length++;
//重新生成食物
foodx = 25 + 25 * random.nextInt(32);
foody = 100 + 75 * random.nextInt(6);
//積分+10
score += 10;
}
//如果小蛇的頭和小蛇的身體坐標重合,失敗,(把小蛇設定為撞到身體不死)
for(int i=1;i<length;i++){
if(snakeX[0]==snakeX[i] && snakeY[0]==snakeY[i]){
isDie=true;
}
}
//重繪界面
repaint();
}
6.開始加載音樂
public class Music extends Thread {
private String fileName;
private final int EXTERNAL_BUFFER_SIZE = 524288;
public Music(String wavFile) {
this.fileName = wavFile;
}
@SuppressWarnings("unused")
public void run() {
File soundFile = new File(fileName); // 播放音樂的檔案名
if (!soundFile.exists()) {
System.err.println("Wave file not found:" + fileName);
return;
}
while (true) { // 設定回圈播放
AudioInputStream audioInputStream = null; // 創建音頻輸入流物件
try {
audioInputStream = AudioSystem.getAudioInputStream(soundFile); // 創建音頻物件
} catch (UnsupportedAudioFileException e1) {
e1.printStackTrace();
return;
} catch (IOException e1) {
e1.printStackTrace();
return;
}
AudioFormat format = audioInputStream.getFormat(); // 音頻格式
SourceDataLine auline = null; // 源資料線
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
try {
auline = (SourceDataLine) AudioSystem.getLine(info);
auline.open(format);
} catch (LineUnavailableException e) {
e.printStackTrace();
return;
} catch (Exception e) {
e.printStackTrace();
return;
}
if (auline.isControlSupported(FloatControl.Type.PAN)) {
FloatControl pan = (FloatControl) auline.getControl(FloatControl.Type.PAN);
}
auline.start();
int nBytesRead = 0;
byte[] abData = new byte[EXTERNAL_BUFFER_SIZE];
try {
while (nBytesRead != -1) {
nBytesRead = audioInputStream.read(abData, 0, abData.length);
if (nBytesRead >= 0)
auline.write(abData, 0, nBytesRead);
}
} catch (IOException e) {
e.printStackTrace();
return;
} finally {
auline.drain();
// auline.close();
}
}
}
}
四、專案實作效果
1.運行界面:

2.完整代碼
package com.zsx.snake;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
public class GamePanel extends JPanel implements KeyListener, ActionListener {
int length; //蛇的長度
int[] snakeX = new int[600]; //蛇的坐標X
int[] snakeY = new int[500]; //蛇的坐標Y
String fx; //R:右 L:左 U:上 D:下
static boolean isStart = false; //游戲是否開始
boolean isDie = false; //判斷蛇是否死亡
Timer timer = new Timer(125, this);//定時器
//定義食物:
int foodx;
int foody;
Random random = new Random();
//定義墻體
//int wallx[]=new int[100];
//int wally[]=new int[100];
//積分系統
int score;
//這里可設定障礙
public void map1() {
//wallx[0]=250+75;wally[0]=475;
//wallx[1]=250+75;wally[1]=500;
//wallx[2]=250+75;wally[2]=525;
//wallx[3]=250+75;wally[3]=550;
//wallx[4]=250+75;wally[4]=575;
//wallx[5]=250+100;wally[5]=475;
//wallx[6]=250+100;wally[6]=575;
//wallx[7]=250+125;wally[7]=475;
//wallx[8]=250+125;wally[8]=575;
}
//初始化資料
public void init() {
length = 3;
snakeX[0] = 100;
snakeY[0] = 100; //頭部坐標
snakeX[1] = 75;
snakeY[1] = 100; //第一個身體坐標
snakeX[2] = 50;
snakeY[2] = 100; //第二個身體坐標
fx = "R"; //默認蛇向右
foodx = 50 + 25 * random.nextInt(32);
foody = 125 + 75 * random.nextInt(6);
// for(int a=0;a<9;a++){
// if(foodx==wallx[a]&&foody==wally[a]){
// foodx = 100;
// foody = 100;
// break;
// }
// }
score = 0;
}
//構造器呼叫初始化資料
public GamePanel() {
init();
//獲取鍵盤的監聽事件
this.setFocusable(true);
this.addKeyListener(this);
timer.start(); //讓時間動起來
}
//畫板:畫界面,畫蛇
//Graphics:畫筆
protected void paintComponent(Graphics g) {
super.paintComponent(g); //清屏
this.setBackground(Color.BLACK);//設定背景的顏色
//繪制積分框
Data.header.paintIcon(this, g, 0, 0);
//繪制游戲區域
g.fillRect(0, 75, 1000, 625);
//呼叫地圖1
//map1();
//for(int a=0;a<21;a++){
// Data.wall.paintIcon(this, g, wallx[a], wally[a]);
//}
//畫一條靜態的蛇
if (fx.equals("R")) {
Data.right.paintIcon(this, g, snakeX[0], snakeY[0]);
} else if (fx.equals("L")) {
Data.left.paintIcon(this, g, snakeX[0], snakeY[0]);
} else if (fx.equals("U")) {
Data.up.paintIcon(this, g, snakeX[0], snakeY[0]);
} else if (fx.equals("D")) {
Data.down.paintIcon(this, g, snakeX[0], snakeY[0]);
}
//蛇的身體長度通過length來控制
for (int i = 1; i < length; i++) {
Data.body.paintIcon(this, g, snakeX[i], snakeY[i]);
}
//畫食物
Data.food.paintIcon(this, g, foodx, foody);
//畫積分
g.setColor(Color.white); //設定畫筆顏色
g.setFont(new Font("微軟雅黑", Font.BOLD, 18));
g.drawString("長度:" + length, 750, 35);
g.drawString("分數:" + score, 750, 55);
//游戲提示:是否開始
if (isStart == false) {
//畫一段文字
g.setColor(Color.white); //設定畫筆顏色
g.setFont(new Font("微軟雅黑", Font.BOLD, 40));
g.drawString("按下空格開始游戲", 300, 300);
}
//失敗提醒
if (isDie) {
//畫一段文字
g.setColor(Color.red); //設定畫筆顏色
g.setFont(new Font("微軟雅黑", Font.BOLD, 40));
g.drawString("游戲失敗,按下空格重新開始", 200, 300);
}
}
//接受鍵盤的輸入:監聽
@Override
public void keyPressed(KeyEvent e) {
// 鍵盤按下,未釋放
//獲取按下的鍵盤是哪個鍵
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_SPACE) { //如果按下的是空格鍵
if (isDie) { //失敗,游戲再來一遍
isDie = false;
init(); //重新初始化游戲
} else { //暫停游戲
isStart = !isStart;
}
repaint(); //重繪界面
}
//鍵盤控制走向
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 actionPerformed(ActionEvent e) {
//如果游戲處于開始狀態,并且游戲沒有結束
if (isStart && isDie == false) {
//右移
for (int i = length - 1; i > 0; i--) { //身體移動
snakeX[i] = snakeX[i - 1];
snakeY[i] = snakeY[i - 1];
}
//碰到墻壁
// for(int i=0;i<9;i++){
// if(snakeX[0]==wallx[i]&&snakeY[0]==wally[i]){
// isDie=true;
// }
//}
//通過控制方向讓頭部移動
//這里可以控制蛇撞到四周墻壁不死
/* if (fx.equals("R")) {
snakeX[0] = snakeX[0] + 25; //頭部移動
//邊界判斷
for (int i = 0; i < snakeX.length; i++) {
if (snakeX[i] > 1000) {
snakeX[i] = snakeX[0] - 1000; //{isDie=true;}
}
}
} else if (fx.equals("L")) {
snakeX[0] = snakeX[0] - 25; //頭部移動
//邊界判斷
for (int i = 0; i < snakeX.length; i++) {
if (snakeX[i] < 0) {
snakeX[i] = snakeX[0] + 1000; //{isDie=true;}
}
}
//if(snakeX[0]<25){isDie=true;}
} else if (fx.equals("U")) {
snakeY[0] = snakeY[0] - 25; //頭部移動
//邊界判斷
for (int i = 0; i < snakeY.length; i++) {
if (snakeY[i] < 90) {
snakeY[i] = snakeY[0] + 600; //{isDie=true;}
}
}
//if(snakeY[0]<75){isDie=true;}
} else if (fx.equals("D")) {
snakeY[0] = snakeY[0] + 25; //頭部移動
//邊界判斷
for (int i = 0; i < snakeY.length; i++) {
if (snakeY[i] > 600) {
snakeY[i] = snakeY[0] - 525; //{isDie=true;}
}
}
//if(snakeY[0]>625){isDie=true;}
}*/
if(fx.equals("R")){
snakeX[0] = snakeX[0] + 25; //頭部移動
// 邊界判斷
if(snakeX[0]>925 ) {isDie=true;}
}else if(fx.equals("L")){
snakeX[0] = snakeX[0] - 25; //頭部移動
// 邊界判斷
if(snakeX[0]<25){isDie=true;}
}else if(fx.equals("U")){
snakeY[0] = snakeY[0] - 25; //頭部移動
// 邊界判斷
if(snakeY[0]<100){isDie=true;}
}else if(fx.equals("D")){
snakeY[0] = snakeY[0] + 25; //頭部移動
// 邊界判斷
if(snakeY[0]>625){isDie=true;}
}
//如果小蛇的頭和食物坐標重合
if (snakeX[0] == foodx && snakeY[0] == foody) {
//長度+1
length++;
//重新生成食物
foodx = 25 + 25 * random.nextInt(32);
foody = 100 + 75 * random.nextInt(6);
// for(int a=0;a<9;a++){
// if(foodx==wallx[a]&&foody==wally[a]){
// foodx = 100;
// foody = 100;
// break;
// }
// }
//積分+10
score += 10;
}
//如果小蛇的頭和小蛇的身體坐標重合,失敗,(把小蛇設定為撞到身體不死)
for(int i=1;i<length;i++){
if(snakeX[0]==snakeX[i] && snakeY[0]==snakeY[i]){
isDie=true;
}
}
/*for(int i=1;i<length;i++){
if(snakeX[0]==snakeX[i] && snakeY[0]==snakeY[i]){
isDie=true;
}
}*/
//重繪界面
repaint();
}
timer.start(); //讓時間動起來
}
@Override
public void keyReleased(KeyEvent arg0) {
// 釋放某個鍵 不實作
}
@Override
public void keyTyped(KeyEvent arg0) {
// 鍵盤按下,彈起 不實作
}
}
public class Data {
//頭部的圖片
public static URL headerURL = Data.class.getResource("/image/header.png");
public static ImageIcon header = new ImageIcon(headerURL);
//蛇的頭部:
public static URL upURL = Data.class.getResource("/image/up.png");
public static URL downURL = Data.class.getResource("/image/down.png");
public static URL leftURL = Data.class.getResource("/image/left.png");
public static URL rightURL = Data.class.getResource("/image/right.png");
public static ImageIcon up = new ImageIcon(upURL);
public static ImageIcon down = new ImageIcon(downURL);
public static ImageIcon left = new ImageIcon(leftURL);
public static ImageIcon right = new ImageIcon(rightURL);
//蛇的身體
public static URL bodyURL = Data.class.getResource("/image/body.png");
public static ImageIcon body = new ImageIcon(bodyURL);
//食物:
public static URL foodURL = Data.class.getResource("/image/food.png");
public static ImageIcon food = new ImageIcon(foodURL);
//墻的圖片
public static URL wallURL = Data.class.getResource("/image/wall.png");
public static ImageIcon wall = new ImageIcon(wallURL);
}
public class GameJMenuBar extends JMenuBar implements ActionListener {
public void init() {
//創建選單物件
JMenu menu1 = new JMenu("游戲選項");
JMenu menu2 = new JMenu("幫助");
//添加選單到工具列物件
this.add(menu1);
this.add(menu2);
//創建選單項物件
JMenuItem item1 = new JMenuItem("退出");
//添加選單項到選單物件menu1中
menu1.add(item1);
//創建選單項物件
JMenuItem item3 = new JMenuItem("操作方法");
//添加選單項到選單物件menu1中
menu2.add(item3);
//創建選單項物件
JMenuItem item2 = new JMenuItem("注意事項");
//添加選單項到選單物件menu1中
menu2.add(item2);
item1.addActionListener(this);// 為選單項添加事件監聽器
item2.addActionListener(this);// 為選單項添加事件監聽器
item3.addActionListener(this);// 為選單項添加事件監聽器
}
public GameJMenuBar() {
init();
}
@Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (cmd.equals("退出")) {
System.exit(0);
}
if (cmd.equals("注意事項")) {
JPanel panel = new JPanel(new GridLayout(0, 1, 5, 5));
JLabel Label1 = new JLabel("請注意正確使用");
JLabel Label2 = new JLabel("游戲結束請按空格重新開始");
JLabel Label3 = new JLabel("暫停游戲也可以按空格");
panel.add(Label1);
panel.add(Label2);
panel.add(Label3);
GamePanel.isStart = false;
JOptionPane.showMessageDialog(this, panel, "注意事項", JOptionPane.PLAIN_MESSAGE);
repaint(); //重繪界面
}
if (cmd.equals("操作方法")) {
JPanel panel = new JPanel(new GridLayout(0, 1, 5, 5));
JLabel Label1 = new JLabel("按下空格可以暫停/開始游戲");
//JLabel Label2 = new JLabel("目前死亡的唯一方式:暫停,并退出");
JLabel Label2 = new JLabel("目前死亡的唯一方式:碰到自己的身體");
JLabel Label3 = new JLabel("按下方向鍵可以控制蛇的移動");
panel.add(Label1);
panel.add(Label2);
panel.add(Label3);
GamePanel.isStart = false;
JOptionPane.showMessageDialog(this, panel, "操作方法", JOptionPane.PLAIN_MESSAGE);
repaint(); //重繪界面,repaint()方法用來重新繪制影像,影像發生改變時立即顯示,paint()方法用來繪制影像,
}
}
}
public class Music extends Thread {
private String fileName;
private final int EXTERNAL_BUFFER_SIZE = 524288;
public Music(String wavFile) {
this.fileName = wavFile;
}
@SuppressWarnings("unused")
public void run() {
File soundFile = new File(fileName); // 播放音樂的檔案名
if (!soundFile.exists()) {
System.err.println("Wave file not found:" + fileName);
return;
}
while (true) { // 設定回圈播放
AudioInputStream audioInputStream = null; // 創建音頻輸入流物件
try {
audioInputStream = AudioSystem.getAudioInputStream(soundFile); // 創建音頻物件
} catch (UnsupportedAudioFileException e1) {
e1.printStackTrace();
return;
} catch (IOException e1) {
e1.printStackTrace();
return;
}
AudioFormat format = audioInputStream.getFormat(); // 音頻格式
SourceDataLine auline = null; // 源資料線
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
try {
auline = (SourceDataLine) AudioSystem.getLine(info);
auline.open(format);
} catch (LineUnavailableException e) {
e.printStackTrace();
return;
} catch (Exception e) {
e.printStackTrace();
return;
}
if (auline.isControlSupported(FloatControl.Type.PAN)) {
FloatControl pan = (FloatControl) auline.getControl(FloatControl.Type.PAN);
}
auline.start();
int nBytesRead = 0;
byte[] abData = new byte[EXTERNAL_BUFFER_SIZE];
try {
while (nBytesRead != -1) {
nBytesRead = audioInputStream.read(abData, 0, abData.length);
if (nBytesRead >= 0)
auline.write(abData, 0, nBytesRead);
}
} catch (IOException e) {
e.printStackTrace();
return;
} finally {
auline.drain();
// auline.close();
}
}
}
}
public class StartGame {
static final int WIDTH = 1000;
static final int HEIGHT = 750;
public static void main(String args[]) {
//1、繪制一個靜態視窗 JFrame
JFrame jf = new JFrame();
jf.setTitle("王校長吃面包");
//設定界面大小
jf.setSize(WIDTH, HEIGHT);
//視窗大小不可以改變
jf.setResizable(false);
Toolkit kit = Toolkit.getDefaultToolkit();
Dimension screenSize = kit.getScreenSize();
//獲取螢屏的寬度和高度
int width = screenSize.width;
int height = screenSize.height;
int x = (width - WIDTH) / 2;
int y = (height - HEIGHT) / 2;
//背景音樂啟動
Music audioPlayWave = new Music("music.wav");// 開音樂 音樂名
audioPlayWave.start();
@SuppressWarnings("unused")
int musicOpenLab = 1;
jf.setLocation(x, y);
//設定關閉事件
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//2、面板 JPanel
jf.add(new GamePanel());
//3、選單欄 JMenuBar
jf.setJMenuBar(new GameJMenuBar());
jf.setVisible(true);
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/385406.html
標籤:其他
上一篇:油田小游戲發布啦~
