实验项目二 贪吃蛇游戏开发




实验系列目录

计算器;贪吃蛇;基于A*算法的迷宫开发




前言

因为前面已经将第一个实验项目完成得差不多,(只剩完善那个历史记录功能)而且一个星期是真的好快啊,所以速度得开始第二个贪吃蛇项目的构建啦。(附图为贪吃蛇项目的要求)




一、为游戏设计友好的交互界面

 首先要初始化静态界面,建立一个数据中心类用来存放所有的静态游戏素材。但是正常的游戏界面应该全部都放在面板上,所以我们建立一个游戏面板类。

当然还可以再添加背景图片,以及背景音乐。举一个例子:

package com.music;

import java.applet.AudioClip;
import java.io.*;
import java.applet.Applet;
import java.awt.Frame;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import javax.swing.JFrame;
public class Music extends JFrame{
    File f;
    URI uri;
    URL url;
    Music(){
        try {
            f = new File("Taylor Swift-Sparks Fly.wav");
            uri = f.toURI();
            url = uri.toURL();  //解析地址
            AudioClip aau;
            aau = Applet.newAudioClip(url);
            aau.loop();  //循环播放
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void main(String args[]) {
        new Music();
    }
}




二、




1.贪吃蛇的基本功能

 首先需要绘制静态小蛇,并且赋予小蛇初始位置。然后,游戏状态,状态监听需要是实现键盘监听事件KeyListener,重写keyPressed方法。

 初始静态界面

  • 游戏主窗口的创建,大小不可变

public class StratGame {
    public static void main(String[] args) {
        JFrame frame= new JFrame();
        frame.setBounds(10,10,915,730);
        //窗口大小不变
        frame.setResizable(false);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        //正常的游戏界面都应该在面板上
        frame.add(new GamePanel());
        frame.setVisible(true);
    }
}

  数据中心类

  • 存放所有静态游戏素材
//存放外部数据
public class Data {
    //头部
    //使用相对路径存放素材
    public static URL upURL=Data.class.getResource("/statics/up.png");
    public static URL downURL=Data.class.getResource("/statics/down.png");
    public static URL leftURL=Data.class.getResource("/statics/left.png");
    public static URL rightURL=Data.class.getResource("/statics/right.png");
    public static URL bodyURL=Data.class.getResource("/statics/body.png");
    public static URL foodURL=Data.class.getResource("/statics/food.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 ImageIcon body=new ImageIcon(bodyURL);
    public static ImageIcon food=new ImageIcon(foodURL);
}

游戏面板类 

  • 正常的游戏界面放在面板上,于是新建一个游戏面板类,继承JPanel

//游戏面板
public class GamePanel extends JPanel{
    //1.绘制组件函数,我们游戏中的所有东西都使用画笔来画
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);//清屏作用,不用出现闪屏
        //绘制静态面板
        this.setBackground(Color.WHITE);
        Data.header.paintIcon(this, g, 25, 0);// 游戏头部,广告栏
        g.fillRect(25, 65, 850, 600);// 默认游戏界面
    }
}

新建静态小蛇 

//游戏面板
public class GamePanel extends JPanel{
    //定义蛇的数据结构
    int length;//蛇的长度
    int[] snakeX = new int[600];//蛇的X坐标
    int[] snakeY = new int[500];//蛇的Y坐标
    //构造器
    public GamePanel() {
        init();
    }
    //初始化小蛇
    public void init() {
        length = 3;
        snakeX[0] = 100;snakeY[0] = 100;//脑袋坐标
        snakeX[1] = 75;snakeY[1] = 100;//第一块身体坐标
        snakeX[2] = 50;snakeY[2] = 100;//第二块身体坐标
    }
    //1.绘制组件函数,我们游戏中的所有东西都使用画笔来画
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);//清屏作用,不用出现闪屏
        //绘制静态面板
        this.setBackground(Color.WHITE);
        Data.header.paintIcon(this, g, 25, 0);// 游戏头部,广告栏
        g.fillRect(25, 65, 850, 600);// 默认游戏界面
        //2.绘制静态小蛇
        Data.right.paintIcon(this, g, snakeX[0], snakeY[0]);//绘制初始头的位置       
        for (int i = 1; i < length; i++) {
            Data.body.paintIcon(this, g, snakeX[i], snakeY[i]);// 第一个身体的坐标
        }
    }
}

 让小蛇移动

  • 修改gamePanel类,并且赋予小蛇初始位置



 

//游戏面板
public class GamePanel extends JPanel implements KeyListener, ActionListener {
    //定义蛇的数据结构
    int length;//蛇的长度
    int[] snakeX = new int[600];//蛇的X坐标
    int[] snakeY = new int[500];//蛇的Y坐标
    String fx;//蛇的初始方向
    //游戏状态,默认不开始!
    boolean isStart=false;//默认是不开始!
    //定时器
    Timer timer=new Timer(100,this);//监听当前类,100毫秒刷新一次
    //构造器
    public GamePanel() {
        init();
        //获得焦点和键盘事件
        this.setFocusable(true);//获得焦点事件
        this.addKeyListener(this);//获得键盘监听事件
        timer.start();//游戏一开始就开始
    }
    //初始化小蛇
    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";//初始化方向向右
    }
    //1.绘制组件函数,我们游戏中的所有东西都使用画笔来画
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);//清屏作用,不用出现闪屏
        //绘制静态面板
        this.setBackground(Color.WHITE);
        Data.header.paintIcon(this, g, 25, 0);// 游戏头部,广告栏
        g.fillRect(25, 65, 850, 600);// 默认游戏界面
        //2.绘制静态小蛇
        Data.right.paintIcon(this, g, snakeX[0], snakeY[0]);//绘制初始头的位置       
        for (int i = 1; i < length; i++) {
            Data.body.paintIcon(this, g, snakeX[i], snakeY[i]);// 第一个身体的坐标
        }
        //画游戏状态
        if (!isStart) {
            g.setColor(Color.white);
            g.setFont(new Font("微软雅黑", Font.BOLD, 40));//设置字体
            g.drawString("按下空格开始游戏!", 300, 450);
        }
    }
    //键盘事件监听
    @Override
    public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();//获得键盘按键是哪一个
        if (keyCode==KeyEvent.VK_SPACE){//如果按下空格,则取反游戏状态
            isStart=!isStart;
            repaint();
        }
    }
    //事件监听----需要用到固定的时间来刷新,1s十次
    @Override
    public void actionPerformed(ActionEvent e) {
        if(isStart){//如果游戏是开始状态,就让小蛇动起来
            //移动
            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]>850){snakeX[0]=25;}
            repaint();//重画页面
        }
        timer.start();//定时器开启!
    }
    @Override
    public void keyReleased(KeyEvent e) {
    }
    @Override
    public void keyTyped(KeyEvent e) {
    }
}

 小蛇吃食物

  • 定义食物坐标,并且需要一个random来使食物随机生成在界面上
 //定义一个食物
    int foodx;
    int foody;
    Random random = new Random();
  • 将定义的食物画在面板上
//画食物

        Data.food.paintIcon(this,g,foodx,foody);

  • 在监听事件中,判定吃食物
    //吃食物判断
    if (snakeX[0]==foodX && snakeY[0]==foodY){
        length++;//长度+1
        //再次随机生成食物
        //初始化食物,把食物随机分布在界面上
        foodX=25+25*random.nextInt(34);
        foodY=75+25*random.nextInt(24);
    }


2.边界设定

只需要在控制小蛇移动方向后面稍作更改就可以了。 然后,小蛇只要撞墙也会被判定死亡状态。

//通过控制方向让头部移动
            if (fx == "R") {
                snakeX[0] = snakeX[0] + 25;// 头部移动
                if (snakeX[0] > 850){// 当向右运动超出边界时,蛇死,游戏结束
                    isFail = true;}
            } else if (fx == "L") {
                snakeX[0] = snakeX[0] - 25;
                if (snakeX[0] < 25){
                    isFail = true;}
            } else if (fx == "U") {
                snakeY[0] = snakeY[0] - 25;
                if (snakeY[0] < 75){
                    isFail = true;}
            } else if (fx == "D") {
                snakeY[0] = snakeY[0] + 25;
                if (snakeY[0] > 650){
                    isFail = true;}
            }

3.死亡判断

定义boolean类型,新建游戏状态。

boolean isFail= false;//默认游戏状态失败

将失败状态绘制在画板上。

if (isFail){
    g.setColor(Color.red);
    g.setFont(new Font("微软雅黑", Font.BOLD, 40));//设置字体
    g.drawString("失败,按下空格重新开始!", 300, 450);
}

 监听键盘事件,判断游戏状态。当小蛇撞到自己时,判定为死亡状态。

if (keyCode==KeyEvent.VK_SPACE){//如果按下空格,则取反游戏状态
    if (isFail){
        //重新开始
        isFail=false;
        init();//重新开始重置游戏初始状态
    }else {
        isStart=!isStart;
    }
    repaint();
}
//失败判断,撞到自己算失败
for (int i=1;i<length;i++){
    if (snakeX[0]==snakeX[i] && snakeY[0]==snakeY[i]){
        isFail=true;
    }
}

4. 分值计算

  • 新增游戏初始分数
//初始化分数
int score;
//初始化小蛇
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=25+25*random.nextInt(34);
    foodY=75+25*random.nextInt(24);
    //初始分数
    score=0;
}
  • 画分数和长度至画板上
//画积分和长度
g.setColor(Color.WHITE);
g.setFont(new Font("宋体", Font.BOLD, 15));
g.drawString("长度:"+length,750,35);
g.drawString("分数:"+score,750,50);
  • 事件判断吃到食物分数增加10
//吃食物判断
if (snakeX[0]==foodX && snakeY[0]==foodY){
    length++;//长度+1
    score=score+10;
    //再次随机生成食物
    //初始化食物,把食物随机分布在界面上
    foodX=25+25*random.nextInt(34);
    foodY=75+25*random.nextInt(24);
}




总结

目前,游戏交互界面还没有头绪。因为是按照b站上播放量最多的那个视频做的。

可能感触最深的是,设置不让蛇头回头。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值