Greedy-Snake
先看效果圖吧,開始游戲界面

點擊 開始 按鈕后的效果

上代碼啦
先定義一個啟動程式開始我們的代碼好吧,
// StartMyGreedySnake.java
public class StartMyGreedySnake {
public static void main(String[] args) {
new StartView(); // 啟動游戲界面
}
}
首先設計一個進入游戲的視窗
用 StartView 類實作
// StartView.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class StartView implements MouseListener {
// 創建開始游戲歡迎界面
private Frame jf = new Frame("貪吃蛇");
// 提示性標簽
private JLabel jl;
// 設定進入游戲按鈕
private JButton jb;
// 實作按鈕方法
private void setButton() {
jf.setLayout(null);
jb = new JButton("開始游戲"); // 按鈕提示內容
jb.setBounds(300, 500, 400, 70);
jb.setFont(new Font("楷體_2312", Font.BOLD, 50)); // 按鈕字體及大小
jb.setBackground(new Color(177, 120, 205, 205));
jf.add(jb); // 加入視窗
jb.addMouseListener(this); // 為按鈕添加監聽
}
// 實作標簽方法
private void setLabel() {
jf.setLayout(null);
jl = new JLabel("歡迎來到貪吃蛇游戲"); // 標簽內容
jl.setFont(new Font("楷體_2312", Font.BOLD, 30)); // 字體
jl.setBackground(new Color(196, 34, 169)); // 字體顏色
jl.setBounds(380, 100, 400, 80); // 相對位置
jf.add(jl); // 加到視窗
}
StartView() {
// 設定視窗背景顏色
jf.setBackground(new Color(190, 44, 79));
// 設定按鈕資訊
setButton();
// 設定標簽并加入視窗
setLabel();
// 設定點擊右上角的關閉視窗結束程式運行
jf.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
// 設定視窗絕對位置
jf.setLocation(500, 200);
// 設定視窗大小
jf.setSize(1000, 800);
// 視窗大小不可變
jf.setResizable(false);
// 視窗可見
jf.setVisible(true);
}
@Override
public void mouseClicked(MouseEvent e) {
if (e.getSource().equals(jb)) {
// 進入游戲視窗
new SnakeGameView().showView();
// 設定原視窗不可見
jf.setVisible(false);
// 釋放原視窗資源
jf.dispose();
}
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}
然后是實作游戲界面有關的代碼
定義一個 Node 節點類用以設定和獲得蛇頭節點和蛇蛋位置
// Node.java
public class Node {
private int nodeX;
private int nodeY;
public Node(int nodeX, int nodeY) {
this.nodeX = nodeX;
this.nodeY = nodeY;
}
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;
}
}
寫一個 Snake 類,用鏈表表示蛇身,并實作蛇的移動,產生蛇蛋和判斷蛇是否越界等,
// Snake.java
import java.util.LinkedList;
import java.util.Random;
public class Snake {
private LinkedList<Node> snakeBody;
private Random random;
//Snake的方向 0上, 1 右 , 2 下 , 3 左
private int direction = 0;
private SnakeGameView snakeGameView;
public Snake(int snakeHeadX, int snakeHeadY, SnakeGameView snakeGameView) {
random = new Random();
snakeBody = new LinkedList<>();
snakeBody.add(new Node(snakeHeadX, snakeHeadY));
this.snakeGameView = snakeGameView;
}
//獲取Snake的方向
public int getDirection() {
return direction;
}
//設定Snake方向
public void setDirection(int direction) {
this.direction = direction;
}
//獲取Snake頭部結點
public Node getSnakeHead() {
return snakeBody.getFirst();
}
//獲取Snake尾部結點
public Node getSnakeTail() {
return snakeBody.getLast();
}
//獲取Snake的Body
public LinkedList<Node> getSnakeBody() {
return snakeBody;
}
//Snake移動
public void snakeMove() {
switch (direction) {
case 0:
snakeBody.addFirst(new Node(getSnakeHead().getNodeX(), getSnakeHead().getNodeY() - DrawView.VIEW_NUMBER));
break;
case 1:
snakeBody.addFirst(new Node(getSnakeHead().getNodeX() + DrawView.VIEW_NUMBER, getSnakeHead().getNodeY()));
break;
case 2:
snakeBody.addFirst(new Node(getSnakeHead().getNodeX(), getSnakeHead().getNodeY() + DrawView.VIEW_NUMBER));
break;
case 3:
snakeBody.addFirst(new Node(getSnakeHead().getNodeX() - DrawView.VIEW_NUMBER, getSnakeHead().getNodeY()));
break;
}
snakeBody.removeLast();
}
//Snake 吃Egg
public void eatEgg(Node egg) {
if (snakeBody.getFirst().getNodeX() == egg.getNodeX() && snakeBody.getFirst().getNodeY() == egg.getNodeY()) {
snakeBody.add(egg);
//產蛋
snakeGameView.setEgg(random.nextInt(DrawView.VIEW_WIDTH - 1) * DrawView.VIEW_NUMBER,
random.nextInt(DrawView.VIEW_WIDTH - 1) * DrawView.VIEW_NUMBER);
SnakeGameView.gameScore = SnakeGameView.gameScore + 10;
snakeGameView.getGameScores().setText(SnakeGameView.gameScore + "");
}
}
//Snake越界
public void snakeRunInterface() {
if (this.getSnakeHead().getNodeX() < 0 || this.getSnakeHead().getNodeY() < 0 ||
this.getSnakeHead().getNodeX() > (DrawView.VIEW_WIDTH * DrawView.VIEW_NUMBER) ||
this.getSnakeHead().getNodeY() > (DrawView.VIEW_WIDTH * DrawView.VIEW_NUMBER)) {
SnakeGameView.gameState = false;
}
}
}
寫一個 GameControl 類,用以獲得鍵盤上方向鍵和 Enter、Esc 鍵的功能
// GameControl.java
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class GameControl implements KeyListener {
private Snake snake;
public GameControl(Snake snake) {
this.snake = snake;
}
public void keyReleased(KeyEvent ke) {
switch (ke.getKeyCode()) {
case KeyEvent.VK_UP:
snake.setDirection(0);
break;
case KeyEvent.VK_RIGHT:
snake.setDirection(1);
break;
case KeyEvent.VK_DOWN:
snake.setDirection(2);
break;
case KeyEvent.VK_LEFT:
snake.setDirection(3);
break;
case KeyEvent.VK_ENTER:
if (SnakeGameView.gameState == true)
SnakeGameView.gameState = false;
else
SnakeGameView.gameState = true;
break;
case KeyEvent.VK_ESCAPE:
System.exit(0);
break;
}
}
public void keyPressed(KeyEvent arg0) {
}
public void keyTyped(KeyEvent arg0) {
}
}
寫一個 DrawView 類,用以畫圖形界面,包括網格,蛇身,蛇蛋
// DrawView.java
import java.awt.*;
public class DrawView extends Panel {
//畫板的寬度高度
public static final int VIEW_WIDTH = 40;
public static final int VIEW_HEIGHT = 40;
public static final int VIEW_NUMBER = 15;
private Image iBuffer;
private Graphics gBuffer;
private Snake snake;
private Node egg;
public DrawView(Snake snake, Node egg) {
this.snake = snake;
this.egg = egg;
}
public void paint(Graphics g) {
snake.snakeMove();
this.drawGridding(g);
this.drawSnake(g);
this.drawEgg(g);
snake.eatEgg(egg);
}
public void update(Graphics g) {
if (iBuffer == null) {
iBuffer = createImage(DrawView.VIEW_WIDTH * DrawView.VIEW_NUMBER + 1, DrawView.VIEW_HEIGHT * DrawView.VIEW_NUMBER + 1);
gBuffer = iBuffer.getGraphics();
}
gBuffer.setColor(getBackground());
gBuffer.fillRect(0, 0, DrawView.VIEW_WIDTH * DrawView.VIEW_NUMBER + 1, DrawView.VIEW_HEIGHT * DrawView.VIEW_NUMBER + 1);
paint(gBuffer);
g.drawImage(iBuffer, 0, 0, this);
}
//畫網格
public void drawGridding(Graphics g) {
g.setColor(new Color(105, 84, 68));
for (int i = 0; i < VIEW_WIDTH; i++) {
g.drawLine(0, i * VIEW_NUMBER, VIEW_WIDTH * VIEW_NUMBER, i * VIEW_NUMBER);
}
for (int i = 0; i < VIEW_HEIGHT; i++) {
g.drawLine(i * VIEW_NUMBER, 0, i * VIEW_NUMBER, VIEW_WIDTH * VIEW_NUMBER);
}
}
//畫Snake
public void drawSnake(Graphics g) {
for (int i = 0; i < snake.getSnakeBody().size(); i++) {
g.setColor(new Color(110, 191, 64));
if (i == 0)
g.setColor(new Color(255,255,255));
g.fillRect(snake.getSnakeBody().get(i).getNodeX(), snake.getSnakeBody().get(i).getNodeY(), VIEW_NUMBER, VIEW_NUMBER);
}
}
//畫Egg
public void drawEgg(Graphics g) {
g.setColor(Color.yellow);
g.fillRect(egg.getNodeX(), egg.getNodeY(), VIEW_NUMBER, VIEW_NUMBER);
}
}
再寫一個 GameRunThread 類,用執行緒控制游戲開始
package greedysnake3;
public class GameRunThread implements Runnable {
private int runTime = 200;
private DrawView drawView;
private Snake snake;
public GameRunThread(DrawView drawView, Snake snake) {
this.drawView = drawView;
this.snake = snake;
}
public void run() {
while (true) {
snake.snakeRunInterface();
if (SnakeGameView.gameState) {
drawView.repaint();
try {
Thread.sleep(runTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
最后寫游戲界面類,在這個類里呼叫其他類的方法以實作游戲功能
// SnakeGameView.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Random;
public class SnakeGameView extends Frame implements MouseListener {
// 定義游戲視窗名
//JFrame jf = new JFrame("Greedy-Snake");
// 宣告畫筆
private DrawView drawView;
// 宣告開始,重新開始,退出游戲按鈕
JButton start, reset, exit;
// 宣告分數標簽
JLabel grade;
// 宣告分數文本框
JTextField score;
// 宣告游戲操作方法文本域
JTextArea hint;
private Random random;
public static boolean gameState = true;
public static int gameScore = 0;
private Snake snake;
private Node egg;
private GameRunThread grt;
public static Thread thread;
public SnakeGameView() {
random = new Random();
//初始化Snake
snake = new Snake(10 * DrawView.VIEW_NUMBER + random.nextInt(19) * DrawView.VIEW_NUMBER,
10 * DrawView.VIEW_NUMBER + random.nextInt(19) * DrawView.VIEW_NUMBER, this);
//初始化Egg
egg = new Node(random.nextInt(DrawView.VIEW_WIDTH - 1) * DrawView.VIEW_NUMBER,
random.nextInt(DrawView.VIEW_WIDTH - 1) * DrawView.VIEW_NUMBER);
//初始化畫板
drawView = new DrawView(snake, egg);
grt = new GameRunThread(drawView, snake);
thread = new Thread(grt);
// 初始化畫板
setPanel();
// 設定按鈕
setButton();
// 設定標簽
setLabel();
// 設定文本框
setText();
// 初始化文本域操作方法
setJTA();
}
//設定雞蛋
public void setEgg(int eggX, int eggY) {
this.egg.setNodeX(eggX);
this.egg.setNodeY(eggY);
}
// 獲得分數
public JTextField getGameScores() {
return score;
}
public void showView() {
drawView.setBackground(new Color(51, 51, 51));
drawView.setBounds(20, 50, DrawView.VIEW_WIDTH * DrawView.VIEW_NUMBER + 1, DrawView.VIEW_HEIGHT * DrawView.VIEW_NUMBER + 1);
this.setTitle("Greedy-Snake");
this.setSize(1000, 800);
this.setLocation(500, 200);
this.setLayout(null);
this.setBackground(new Color(2, 250, 250));
this.add(drawView);
this.addKeyListener(new GameControl(snake));
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
System.exit(0);
}
});
this.setVisible(true);
}
// 初始化畫板
private void setPanel() {
drawView = new DrawView(snake, egg);
grt = new GameRunThread(drawView, snake);
thread = new Thread(grt);
}
// 實作按鈕方法
private void setButton() {
this.setLayout(null);
// 設定開始按鈕
start = new JButton("開始");
start.setBounds(800, 60, 180, 50);
start.setFont(new Font("宋體", 1, 18));
this.add(start);
// 設定重新開始按鈕
reset = new JButton("重新開始");
reset.setFont(new Font("宋體", 1, 18));
reset.setBounds(800, 150, 180, 50);
this.add(reset);
// 設定退出按鈕
exit = new JButton("退出游戲");
exit.setFont(new Font("宋體", 1, 18));
exit.setBounds(800, 240, 180, 50);
this.add(exit);
// 初始化按鈕添加監聽器
initial();
}
// 給各按鈕添加監聽器
void initial() {
start.addMouseListener(this);
reset.addMouseListener(this);
exit.addMouseListener(this);
}
// 設定標簽的方法
private void setLabel() {
this.setLayout(null);
grade = new JLabel("分數");
grade.setFont(new Font("宋體", 1, 20));
grade.setBounds(800, 330, 100, 50);
this.add(grade);
}
// 顯示分數的方法
private void setText() {
this.setLayout(null);
score = new JTextField("0", JTextField.CENTER);
score.setFont(new Font("宋體", 1, 20));
score.setBounds(800, 420, 100, 50);
score.setEditable(false);
this.add(score);
}
// 顯示操作方法
private void setJTA() {
this.setLayout(null);
hint = new JTextArea("操作指導 ← 向左 → 向右 ↑ 向上 ↓ 向下 Esc 退出");
hint.setFont(new Font("宋體", 0, 24));
hint.setBackground(new Color(243, 5, 100));
hint.setBounds(40, 700, 920, 60);
hint.setEditable(false);
this.add(hint);
}
@Override
public void mouseClicked(MouseEvent e) {
if (e.getSource().equals(start)) {
SnakeGameView newSnake = new SnakeGameView();
newSnake.initial();
this.setVisible(false);
this.dispose();
new SnakeGameView().showView();
thread.start();
}
if (e.getSource().equals(reset)) {
SnakeGameView newSnake = new SnakeGameView();
newSnake.initial();
this.setVisible(false);
this.dispose();
new SnakeGameView().showView();
thread.start();
}
if (e.getSource().equals(exit)) {
System.exit(0);
}
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}
注,核心原始碼摘自 鏈接
本來自己照著想寫一個自己的貪吃蛇,奈何學習完后,就差一點點了,還是沒能成功,所以最后在上面大佬的代碼上加以改進寫出了這個還是帶有 bug 的貪吃蛇小游戲,望讀者盡力閉坑,不過這里面的很多東西還是值得加以學習的
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/232523.html
標籤:其他
上一篇:RT-Thread Studio學習筆記之部署FlashDB——基于片外flash及FAL
下一篇:課程資源快速搜索
