貪吃蛇小遊戲
1. 簡介
這是用Java的Swing工具實現的一個小程序。
與傳統的貪吃蛇遊戲一樣,通過“上、下、左、右”控制方向覓食,隨着吃的食物越多,身體會變得越長,移動速度也會變得越快。
死亡條件:①頭碰到身體。②頭碰到牆壁。
關於這個程序的源代碼及打包資源,我上傳到資源下載和GitHub倉庫了,可以直接去下載:
資源下載地址:CSDN資源下載
GitHub地址:Gluttonous-Snake
2. 程序代碼部分
我這裏的開發環境是:
- IDEA_2019.2.3
- Java_8
2.1 目錄結構
2.2 代碼實現
- StartGames.java
package com.jacks.snake;
import javax.swing.*;
/**
* 程序啓動類,main方法
*/
public class StartGames {
public static void main(String[] args) {
/**
* 繪製一個遊戲窗口 JFrame
*/
JFrame frame = new JFrame("貪吃蛇小遊戲 作者:赤魂丶");//窗口標題
frame.setBounds(10,10,900,720); //設置窗口的大小
frame.setResizable(false); //窗口大小不可以改變
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //設置關閉事件,遊戲關閉,程序結束
/**
* 添加面板 Panel
*/
frame.add(new GamePanel());//添加面板
frame.setVisible(true);//展示窗口
}
}
- Data.java
package com.jacks.snake;
import javax.swing.*;
import java.net.URL;
/**
* 遊戲的數據存放類
*/
class Data {
//頂部圖片背景
private static URL headerUrl = Data.class.getResource("/statics/header.png");
static ImageIcon header = new ImageIcon(headerUrl);
//蛇頭
private static URL upUrl = Data.class.getResource("/statics/up.png");
private static URL downUrl = Data.class.getResource("/statics/down.png");
private static URL leftUrl = Data.class.getResource("/statics/left.png");
private static URL rightUrl = Data.class.getResource("/statics/right.png");
static ImageIcon up = new ImageIcon(upUrl);
static ImageIcon down = new ImageIcon(downUrl);
static ImageIcon left = new ImageIcon(leftUrl);
static ImageIcon right = new ImageIcon(rightUrl);
// 身體
private static URL bodyUrl = Data.class.getResource("/statics/body.png");
static ImageIcon body = new ImageIcon(bodyUrl);
//食物
private static URL foodUrl = Data.class.getResource("/statics/food.png");
static ImageIcon food = new ImageIcon(foodUrl);
}
- GamePanel.java
package com.jacks.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;
/**
* 遊戲的業務邏輯類,製作 JPanel 面板
*/
public class GamePanel extends JPanel implements KeyListener, ActionListener {
/*
蛇的相關屬性
*/
private int length; //蛇長度
private int[] snakeX = new int[600]; //蛇的X座標
private int[] snakeY = new int[500]; //蛇的Y座標
private String fx; //蛇頭方向
/*
食物的相關屬性
*/
private int foodX;
private int foodY;
private Random random = new Random();
/*
系統相關屬性
*/
private int speed;
private Timer timer = new Timer(speed, this);//定時器
private boolean isStart = false; //遊戲是否開始
private int isFail = 0; //遊戲是否失敗,默人不失敗
private int score; //分數系統
private int scoreM = 0; //歷史最高分
/**
* 初始化函數
*/
private void init() {
speed = 100;
timer.setDelay(speed);
length = 3;
snakeX[0] = 100;
snakeY[0] = 100;
snakeX[1] = 75;
snakeY[1] = 100;
snakeX[2] = 50;
snakeY[2] = 100;
foodX = 25 + 25 * random.nextInt(34);
foodY = 75 + 25 * random.nextInt(24);
score = 0;
fx = "R";
}
/**
* 構造函數
*/
GamePanel() {
init();
//獲取鍵盤的監聽事件
this.setFocusable(true);
this.addKeyListener(this);
timer.start();//定時器啓動
}
@Override
protected void paintComponent(Graphics g) {//TODO:畫靜態界面
super.paintComponent(g); //清屏
this.setBackground(Color.BLACK); //背景顏色
Data.header.paintIcon(this, g, 25, 11);//繪製頭部的廣告欄
g.fillRect(25, 75, 850, 600);//繪製遊戲區域
switch (fx) {//TODO:根據控制畫蛇頭方向
case "R":
Data.right.paintIcon(this, g, snakeX[0], snakeY[0]);
break;
case "L":
Data.left.paintIcon(this, g, snakeX[0], snakeY[0]);
break;
case "U":
Data.up.paintIcon(this, g, snakeX[0], snakeY[0]);
break;
case "D":
Data.down.paintIcon(this, g, snakeX[0], snakeY[0]);
break;
}
for (int i = 1; i < length; i++) {//TODO:根據長度畫蛇的身體
Data.body.paintIcon(this, g, snakeX[i], snakeY[i]);
}
Data.food.paintIcon(this, g, foodX, foodY);//TODO:畫食物
// 畫積分
g.setColor(Color.WHITE);//TODO:畫計分系統
g.setFont(new Font("華文楷體", Font.BOLD, 18));
g.drawString("當前長度:" + length, 520, 35);
g.drawString("當前分數:" + score, 370, 35);
if (score >= scoreM) scoreM = score;
g.drawString("歷史最高分:" + scoreM, 370, 50);
if (!isStart) {//TODO:用字符串提示遊戲開始
g.setColor(Color.RED);
g.setFont(new Font("華文楷體", Font.BOLD, 45));//字體、加粗、大小
g.drawString("按下空格開始遊戲", 300, 300);
}
if (isFail == 1) {//TODO:用字符串提示遊戲失敗
g.setColor(Color.RED);
g.setFont(new Font("華文楷體", Font.BOLD, 40));//字體、加粗、大小
g.drawString("遊戲失敗,你啃到自己了,按空格重新開始!", 35, 300);
} else if (isFail == 2) {//TODO:提示遊戲失敗
g.setColor(Color.RED);
g.setFont(new Font("華文楷體", Font.BOLD, 40));//字體、加粗、大小
g.drawString("遊戲失敗,您撞到牆了,按空格重新開始!", 35, 300);
}
}
// TODO:監聽鍵盤輸入
// 按下不釋放
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();//記錄按鍵
if (keyCode == KeyEvent.VK_SPACE) {//TODO:按下空格暫停或重啓遊戲
if (isFail != 0) {//失敗後按空格重啓
isFail = 0;
init();
} else {//爲失敗按空格爲暫停
isStart = !isStart;
}
repaint();//刷新界面
}
if (keyCode == KeyEvent.VK_LEFT && !fx.equals("R")) {//TODO:用鍵盤控制移動方向
fx = "L";
} else if (keyCode == KeyEvent.VK_RIGHT && !fx.equals("L")) {
fx = "R";
} else if (keyCode == KeyEvent.VK_UP && !fx.equals("D")) {
fx = "U";
} else if (keyCode == KeyEvent.VK_DOWN && !fx.equals("U")) {
fx = "D";
}
}
@Override
public void actionPerformed(ActionEvent e) {//TODO:控制遊戲狀態
if (isStart && isFail == 0) {//TODO:遊戲開啓並且沒有失敗
for (int i = length - 1; i > 0; i--) {//TODO:移動身體
snakeX[i] = snakeX[i - 1];
snakeY[i] = snakeY[i - 1];
}
switch (fx) {//TODO:判斷是否碰到邊界
case "R":
snakeX[0] = snakeX[0] + 25;
if (snakeX[0] > 850) {
isFail = 2;
init();
// snakeX[0] = 25;
}
break;
case "L":
snakeX[0] = snakeX[0] - 25;
if (snakeX[0] < 25) {
isFail = 2;
init();
//snakeX[0] = 850;
}
break;
case "U":
snakeY[0] = snakeY[0] - 25;
if (snakeY[0] < 75) {
isFail = 2;
init();
//snakeY[0] = 650;
}
break;
case "D":
snakeY[0] = snakeY[0] + 25;
if (snakeY[0] > 650) {
isFail = 2;
init();
//snakeY[0] = 75;
}
break;
}
//判斷吃食物
if (snakeX[0] == foodX && snakeY[0] == foodY) {
length++; //蛇長度加1
score += 10; //分數+10
if (length <= 7) {
speed -= 5;
} else if (length <= 10) {
speed -= 2;
} else if (length <= 20) {
speed -= 1;
} else if (length % 3 == 0) {
speed -= 1;
}
timer.setDelay(speed);
//生成新食物
foodX = 25 + 25 * random.nextInt(34);
foodY = 75 + 25 * random.nextInt(24);
}
// 吃到自己失敗
for (int i = 1; i < length; i++) {
if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) {
isFail = 1;
break;
}
}
//刷新界面
repaint();
}
timer.start();//定時器啓動
}
/*
以下是未用到的按鍵監聽函數複寫
*/
@Override
public void keyTyped(KeyEvent e) {
//鍵盤按下並釋放
}
@Override
public void keyReleased(KeyEvent e) {
//釋放某個鍵
}
}
註釋已經寫的很詳細了,就不再過多贅述了。