java实现贪吃蛇小游戏

项目 2:贪吃蛇游戏开发
1、 项目概述

1.1 项目目标和主要内容
(1)本实验使用java语言开发,开发环境是idea,实现一个简易的贪吃蛇游戏。实现贪吃蛇游戏基本功能,屏幕上随机出现一个“食物”,称为豆子,上下左右控制“蛇”的移动,吃到“豆子”以后“蛇”的身体加长一点,得分增加,“蛇”碰到边界或,蛇头与蛇身相撞,蛇死亡,游戏结束。为游戏设计初始欢迎界面,游戏界面,游戏结束界面。
(2)进行交互界面的设计,有开始键、暂停键和停止退出的选项。对蛇吃到豆子进行分值计算,设置游戏速度,游戏音乐等拓展元素。

1.2 项目的主要功能

2、 项目设计

程序流程图:
在这里插入图片描述
2.1 项目总体框架

项目框架图:
在这里插入图片描述
2.2 系统详细设计
【1】 模块划分描述

整体分3个类结构,包括框架类、面板类和蛇的设计类。

【2】 类关系描述

在JFrame窗口容器里添加设置组件大小、组件的可见性以及组件的位置。
在面板类中,设置游戏区域大小、键盘操作功能、食物坐标以及颜色填充等。
在蛇类设计中,画蛇及其位置和大小、画食物及其位置设置、蛇运动设计等。

2.3 其他描述

定义类节点Node
定义蛇类Snack,Graphics,绘图类,画蛇,蛇的初始方向是向右,Right=3。
随机设置食物的位置:
rx = (int)(Math.random() * (GameWidth - 10) + GameLocX);
ry = (int)(Math.random() * (GameHeight - 10) + GameLocY);
蛇的运动以及判断其是否咬到自己或撞到墙。

所有代码:
//框架类
import javax.swing.JFrame;

public class greedySnackMain extends JFrame {
snackWin snackwin;
static final int Width = 800 , Height = 600 , LocX = 200 , LocY = 80;

public greedySnackMain() {
    super("GreedySncak_SL");
    snackwin = new snackWin();
    //在JFrame窗口容器里添加其他组件
    add(snackwin);
    //设置组件的大小
    this.setSize(Width, Height);
    //设置组件的可见性
    this.setVisible(true);
    //设置组件的位置
    this.setLocation(LocX, LocY);
    //snackwin.requestFocus();
}

public static void main(String[] args) {
    new greedySnackMain();
}

}

//面板类
import java.awt.Color;

import java.awt.FlowLayout;
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 javax.swing.JButton;
import javax.swing.JPanel;

public class snackWin extends JPanel implements ActionListener, KeyListener {

//用数字代表方向
static final int Up = 0 , Down = 1 , Left = 2 , Right = 3;
//GameWidth/GameHeight :游戏区域的宽、高
//GameLocX / GameLocY:游戏区域的左上角位置的坐标
static final int GameLocX = 50, GameLocY = 50 , GameWidth = 700 , GameHeight = 500 , Size = 10;//Size:每次移动的位置大小以及增加的长度
//rx,ry:食物的坐标
static int rx , ry , score = 0 , speed = 5;
boolean startFlag = false;


JButton startButton , stopButton , quitButton;
Snack snack;

public snackWin() {
    snack = new Snack();
   //随机设置食物的位置
    rx = (int)(Math.random() * (GameWidth - 10) + GameLocX);
    ry = (int)(Math.random() * (GameHeight - 10) + GameLocY);

    startButton = new JButton("开始");
    stopButton = new JButton("暂停");
    quitButton = new JButton("退出");

    setLayout(new FlowLayout(FlowLayout.LEFT));
    // 添加三个按键:开始、暂停、退出
    this.add(startButton);
    this.add(stopButton);
    this.add(quitButton);
    // 添加三个按键的监听事件
    startButton.addActionListener(this);
    stopButton.addActionListener(this);
    quitButton.addActionListener(this);
    this.addKeyListener(this);
    new Thread(new snackThread()).start();
}

public void paint(Graphics g)
{
    super.paint(g); //没有会将button刷掉
    //设置画笔颜色
    g.setColor(Color.blue);
    //用蓝色 填充一个矩形区域
    g.fillRect(GameLocX, GameLocY, GameWidth, GameHeight);
    g.setColor(Color.black);
    //drawRect用于画矩形;X、Y为左上角的位置,width和height为矩形的宽和高
    //用黑色化一个矩形
    g.drawRect(GameLocX, GameLocY, GameWidth, GameHeight);
    //绘制字符串
    g.drawString("Score: " + score + "        Speed: " + speed + "      速度最大为100" , 250, 25);
    //用绿色填充一个长宽为10的矩形 表示 食物
    g.setColor(Color.green);
    g.fillRect(rx, ry, 10, 10);
    //画蛇
    snack.draw(g);
}

public void actionPerformed(ActionEvent e) {
    //当开始按钮被点击时,开始按钮将不能再被点击
    if(e.getSource() == startButton) {
        startFlag = true;
        startButton.setEnabled(false);
        stopButton.setEnabled(true);
    }
    if(e.getSource() == stopButton) {
        startFlag = false;
        startButton.setEnabled(true);
        stopButton.setEnabled(false);
    }
    //退出程序
    if(e.getSource() == quitButton) {
        System.exit(0);
    }
    this.requestFocus();
}

/**
 * 当键盘被按下时调用
 */
public void keyPressed(KeyEvent e) {
   //当还没按下开始按钮时,按键不可用
    if(!startFlag)
        return ;

    switch(e.getKeyCode()) {
    //如果蛇的长度为1,则表示刚开始,什么方向都可以;
    //若蛇的长度不为1,则表示它在运动,此时不能操作它向反方向运动
        case KeyEvent.VK_UP:
            if(snack.length() != 1 && snack.getDir() == Down) break;
            snack.changeDir(Up);
            break;
        case KeyEvent.VK_DOWN:
            if(snack.length() != 1 && snack.getDir() == Up) break;
            snack.changeDir(Down);
            break;
        case KeyEvent.VK_LEFT:
            if(snack.length() != 1 && snack.getDir() == Right) break;
            snack.changeDir(Left);
            break;
        case KeyEvent.VK_RIGHT:
            if(snack.length() != 1 && snack.getDir() == Left) break;
            snack.changeDir(Right);
            break;
    }
}

public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}

class snackThread implements Runnable
{
    public void run() {
        while(true) {
            try {
              //通过线程休眠时间控制蛇的速度
                Thread.sleep(100 - speed >= 0 ? 100 - speed : 0);
                repaint(); // 调用paint(),重绘组件(刷新界面)
                if(startFlag) {
                    snack.move();
                }
            }
            catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

}

//蛇类,对蛇的设计
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JOptionPane;

/**

  • 存放每个点的X、Y坐标
    */
    class Node {
    private int x , y;
    public Node() {}
    public Node(int a , int b){
    x = a;
    y = b;
    }
    public Node(Node tmp) {
    x = tmp.getX();
    y = tmp.getY();
    }
    int getX() {
    return x;
    }
    int getY() {
    return y;
    }
    void setX(int a) {
    x = a;
    }
    void setY(int b) {
    y = b;
    }
    }

public class Snack {

static final int DIR [][] = {{0 , -1} , {0 , 1} , {-1 , 0} , {1 , 0}};
private List<Node> lt = new ArrayList<Node>();
private int curDir; //当前运动方向

/**
 *  初始化
 *  蛇的初始方向是向右,Right=3
 */
public Snack() {
    curDir = 3;
    lt.add(new Node(350 , 250));
}

/**
 *  List的长度表示蛇的长度
 * @return
 */
int length() {
    return lt.size();
}

int getDir() {
    return curDir;
}

/**
 * Graphics,绘图类
 *  画蛇
 *  找到每个下标指向的X、Y值,即组成蛇的每一点所在位置
 */
void draw(Graphics g)
{
    g.setColor(Color.red);
    for(int i = 0; i < lt.size(); i++) {
        g.fillRect(lt.get(i).getX(), lt.get(i).getY(), 10, 10);
    }
}

/**
 *  判断蛇是否咬到自己
 *  如果蛇的头部(0)与其他位置重合,则表示蛇咬到自己了
 * @return
 */
boolean Dead() {
    for(int i = 1; i < lt.size(); i++) {
        if(lt.get(0).getX() == lt.get(i).getX() && lt.get(0).getY() == lt.get(i).getY())
            return true;
    }
    return false;
}

/**
 * 头部移动的位置
 * @return tmp:头部的位置坐标
 */
Node headMove()
{
    //当向上或向下时,curDir为0/1,此时X轴不变(即 snackWin.Size * DIR[curDir][0]的值为0),Y轴变化
    //当向左或向右时,curDir为2/3,此时Y轴不变(即 snackWin.Size * DIR[curDir][1]的值为0),X轴变化
    int tx = lt.get(0).getX() + snackWin.Size * DIR[curDir][0];
    int ty = lt.get(0).getY() + snackWin.Size * DIR[curDir][1];

    //用一个矩形代表蛇的一个节点,矩形的长宽为10,故设置Size也为10
    //当头部的位置大于游戏区域的宽度证明它到达了最右边,此时提示“snake hit the wall”
    if(tx > snackWin.GameLocX + snackWin.GameWidth - snackWin.Size) {
        JOptionPane.showMessageDialog(null, "Snake hit the wall", "Message",
                JOptionPane.ERROR_MESSAGE);
        System.exit(1);
    }
    //当头部的位置小于左边的X坐标,证明它向左走并到达最左边,此时提示“snake hit the wall”
    if(tx < snackWin.GameLocX) {
        JOptionPane.showMessageDialog(null, "Snake hit the wall", "Message",
                JOptionPane.ERROR_MESSAGE);
        System.exit(1);
    }
    //与上同
    if(ty > snackWin.GameLocY + snackWin.GameHeight - snackWin.Size) {
        JOptionPane.showMessageDialog(null, "Snake hit the wall", "Message",
                JOptionPane.ERROR_MESSAGE);
        System.exit(1);
    }
    if(ty < snackWin.GameLocY) {
        JOptionPane.showMessageDialog(null, "Snake hit the wall", "Message",
                JOptionPane.ERROR_MESSAGE);
        System.exit(1);
    }
    Node tmp = new Node(tx, ty);
    return tmp;
}

void move()
{
    //头部的位置
    Node head = headMove();
    //新添加的节点的位置
    Node newNode = new Node();
    boolean eat = false;

    //abs()返回参数的绝对值
    //通过判断头部的X/Y坐标位置和食物的X/Y坐标位置,由于头部大小是10,故距离小于10就代表吃到了
    if(Math.abs(head.getX() - snackWin.rx) < 10 && Math.abs(head.getY() - snackWin.ry) < 10) {
        eat = true;
        newNode = new Node(lt.get(lt.size() - 1));
        snackWin.rx = (int)(Math.random() * (snackWin.GameWidth - 10) + snackWin.GameLocX);
        snackWin.ry = (int)(Math.random() * (snackWin.GameHeight - 10) + snackWin.GameLocY);
    }

    //把前一个点的位置给后一点(即移动)
    for(int i = lt.size() - 1; i > 0; i--)
        lt.set(i, lt.get(i - 1));
    lt.set(0, head);

    if(Dead()) {
    //弹出对话框,告知游戏结束
        JOptionPane.showMessageDialog(null, "Snake eating itself", "Message",
                JOptionPane.ERROR_MESSAGE);
        System.exit(1);
    }
    //如果吃到了食物,则eat为true。此时添加节点、分数加一,速度加一
    if(eat) {
        lt.add(newNode);
        snackWin.score++;
        snackWin.speed++;
    }
}

/**
 *  改变蛇的方向
 * @param dir
 */
void changeDir(int dir) {
    curDir = dir;
}

}

运行结果:
在这里插入图片描述

  • 4
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Java实现贪吃游戏可以使用Java Swing和AWT库来实现界面和交互,使用Java集合框架来实现身体的存储和移动,以及使用定时器来控制游戏的速度和刷新。 具体实现步骤如下: 1. 定义一个Snake类代表,包含头的坐标、的长度以及的方向等属性,以及包含身体的坐标列表等属性和方法。 2. 定义一个Food类代表食物,包含食物的坐标等属性和方法。 3. 定义一个GamePanel类代表游戏面板,继承自JPanel类,包含游戏的主要逻辑和交互,如的移动、食物的生成和判断、游戏结束等。 4. 在GamePanel类中,使用定时器Timer来控制游戏的速度和刷新,以及使用Java集合框架来实现身体的存储和移动,以及检测头是否撞墙或撞到自己身体等。 下面是Java代码实现的伪代码: ```java // 定义Snake类 class Snake { // 头的坐标 int x, y; // 的长度 int length; // 的方向 int direction; // 身体的坐标列表 List<Point> body; // 的移动方法 void move(); // 检测头是否撞到自己身体的方法 boolean checkCollision(); } // 定义Food类 class Food { // 食物的坐标 int x, y; // 食物的生成方法 void generate(); } // 定义GamePanel类 class GamePanel extends JPanel implements ActionListener { // 和食物的实例 Snake snake; Food food; // 定时器 Timer timer; // 构造方法 public GamePanel() { // 初始化和食物 snake = new Snake(); food = new Food(); food.generate(); // 创建定时器 timer = new Timer(100, this); timer.start(); } // 绘制游戏界面的方法 void paintComponent(Graphics g); // 处理定时器事件的方法 void actionPerformed(ActionEvent e); // 处理按键事件的方法 void keyPressed(KeyEvent e); // 判断游戏是否结束的方法 boolean isGameOver(); } ``` 上述代码中,Snake类包含头的坐标、长度和方向等属性,以及身体的坐标列表和移动、检测撞墙和撞到自己身体等方法。Food类包含食物的坐标和生成方法。GamePanel类继承自JPanel类,包含游戏的主要逻辑和交互,如的移动、食物的生成和判断、游戏结束等,并使用定时器控制游戏的速度和刷新。在main方法中,创建GamePanel实例并添加到JFrame中即可实现贪吃游戏

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值