基于JAVA的贪吃蛇小游戏开发

基于JAVA的贪吃蛇小游戏开发

开发了 一款基于JAVA的贪吃蛇小游戏,大家可以拿来在正式着手项目的时候拿这个练练手,话不多说,

成果图:

1.游戏面板初始化时如上,按空格键开始游戏
2.在游戏过程中,通过吃面板上随机生成的食物来增加自身长度,可以通过按空格键来暂停游戏。
3.当贪吃蛇撞击到自身时,则判定游戏失败,按空格初始化游戏数据重新开始。

步骤一:贪吃蛇的界面绘制

启动类

首先是编写游戏的启动类,这里定义的start类需要继承JFrame父类,在通常的游戏开发时,包括项目开发,在编写启动类时,不应该放入其他不相关的代码,其唯一功能就是启动项目的入口。

public class Start extends JFrame{
public static void main(String args[]){
JFrame jFrame=new JFrame("贪吃蛇游戏");
jFrame.setVisible(true);//可见
jFrame.setBounds(300,300,920,700);
jFrame.setResizible(false);//不可拖动
jFrame.setDefaultCloseOperation(WindowConstans.EXIT_ON_CLOSE);//可关闭
jFrame.add(new PanelGame());//添加自定义面板
}
}

Data类

在编写完启动类后,需要图片的素材包括(贪吃蛇的各个方向的头部,身体部分,食物)以及一个存放这些图片数据的Data类,将这些素材转化为ImageIcon图标,这里利用的时static帆方法,目的是更加快捷的访问到存储的图片素材。

public class Data{
public static URL bodyUrl=Data.class.getResource("//素材的路径");
public static ImageIcon body=new ImageIcon(bodyUrl);

public static URL foodUrl=Data.class.getResource("//素材的路径");
public static ImageIcon food=new ImageIcon(foodUrl);

public static URL foodUrl=Data.class.getResource("//素材的路径");
public static ImageIcon food=new ImageIcon(foodUrl);
                     .
                     .
                     .
                     .
                     .
                                 
}

PanelGame操作类

在游戏的开发时,用的最多的就是面板类,所以它需要继承的是JPanel父类
,且需要覆写里面的paintComponent方法,其主要功能是利用画笔添加多个需要的组件。

publi class PanelGame extends Jpanel{
@Override
    protected void paintComponent(Graphics g) {
    super.paintComponent(g);//清屏
    this.setBackground(Color.White);//面板颜色
    g.fillRect(25,75,850,600);//面板大小
    Data.paintIcon(this,g,25,11);//将头部图标插入
    }
}

步骤二:绘制静态的贪吃蛇

在定义静态贪吃蛇的时候,需要在PanelGame类里定义一些变量,以及在init()方法中时初始化的这些变量。

int length;//长度
String direction;//默认头部方向
int snake_X=new int[500];//贪吃蛇的左标范围
int snake_Y=new int[500];
boolean isStart=false;//默认游戏状态

public PanelGame(){//构造方法
init();
}

public void init(){//初始化游戏数据
length=3;
direction="Right";
snake_X[0]=100;snake_Y[0]=100;//头部坐标
snake_X[1]=100;snake_Y[1]=100;//第一个身体坐标
snake_X[2]=100;snake_Y[2]=100;//第二个身体坐标
}

利用继承覆写的paintComponent方法再将贪吃蛇添加到面板上并设置游戏默认状态时的数据

//贪吃蛇头部图片需要通过方向来匹配
if(direction.equals("Right")){
Data.right.paintIcon(this,g,snake_X[0],snake_Y[0]);
}else if(direction.equals("Left")){
Data.left.paintIcon(this,g,snake_X[0],snake_Y[0]);
else if(direction.equals("Up")){
Data.up.paintIcon(this,g,snake_X[0],snake_Y[0]);
else if(direction.equals("Down")){
Data.down.paintIcon(this,g,snake_X[0],snake_Y[0]);
}
for(int i=1;i<length;i++){
Data.body.paintIcon(this,g,snake_X[i],snake_Y[i]);
}
if(!isstart){//暂停下的初始化数据
g.setBackground(Color.White);
g.setFont(new Font("微软雅黑",Font.bold,40));
g.drawString("按空格键开始游戏",250,300);
}

步骤三:让贪吃蛇动起来

让静态的贪吃蛇变成动态首先要实现keyListener的接口,在必须覆写的三个方法中选择使用keyPressed方法实现功能

public void keyPressed(KeyEvent e){
int keyCode =e.getKeyCode();//匹配键盘中按下的哪个键
if(keyCode==KeyEvent.VK_SPACE){//若按下的是空格键
isStart=!isStart;//取反
repaint();//特别注意:repaint()一定要选择含有5个参数(tm,x,y,width,height)的的方法
}
}

若想要监听事件被开启,需要在PanelGame的构造器中添加获得监听事件的相关方法

this.setFocusable(true);//获得焦点事件
this.addKeyListener(this);//添加当前键盘监听事件

步骤四:键盘控制贪吃蛇移动

实现键盘控制贪吃蛇的移动首先要实现ActionListener的接口,会自动覆写actionPerformed方法,之后先创建一个定时器

Timer timer=new Timer(1000,this);//以毫秒为单位

在覆写的actionPerformed()方法中,编写通过键盘控制贪吃蛇方向的代码以及在边界情况下,贪吃蛇的移动情况

if(isStart){//游戏启动时
for(int i=length-1;i>0;i--){//无论方向如何变换,身体始终移向前一个身体的位置,例如:shake_X[2]=snake_X[1];
snake_X[i]=snake_X[i-1];
snake_Y[i]=snake_Y[i-1];
}
if(direction.equals("Right")){
snake_X[0]+=25;//头部移动
if(snake_X[0]>850){snake_X[0]=25;}//当超出边界的情况下
}
if(direction.equals("Left")){
snake_X[0]-=25;
if(snake_X[0]<25){snake_X[0]=850;}
}
if(direction.equals("Up")){
snake_Y[0]-=25;
if(snake_Y[0]<75){snake_Y[0]=650;}
}
if(direction.equals("Down")){
snake_Y[0]+=25;
if(snake_Y[0]>650){snake_Y[0]=75;}
}
repaint();//刷新页面
}

在之前覆写的keyPressed()的方法中,添加相关关于监听通过方向来控制贪吃蛇移动的事件

if (keyCode==KeyEvent.VK_UP){//匹配到向上的按键
direction="Up";//方向改为向上
}
if(keyCode==KeyEvent.VK_DOWN){
direction="Down";
}
if(keyCode==KeyEvent.VK_LEFT){
direction="Left";
}
if(keyCode==KeyEvent.VK_RIGHT){
direction="Right";
}

最后在PanelGame构造器中和actionPerformed()方法中同时启动定时器,否则无法开启定时器功能。

timer.start();//启动定时器

步骤五:绘制食物并判定

接下来就是简单的绘制贪吃蛇所需要的食物,其过程非常简单。首先需要在定义变量的地方定义食物的坐标,这里要用到java.util中的Random()随机生成数的方法来在面板上随机生成食物的坐标。

int food_X;//定义食物的变量
int food_Y;
Random random=new Random();//随机函数

其次,init()方法中初始化食物的坐标,

food_X=25+25*random.nextInt(34);//初始化食物坐标,且不得超过边界外
food_Y=25+25*random.nextInt(24);

在if(isStart)的判定里,添加贪吃蛇吃食物增加自身长度的判定

if(snake_X[0]==food_X&&snake_Y[0]==food_Y){//若头部坐标与食物坐标重合,则表示为吃到食物
length++;
food_X=25+25*random.nextInt(34);//重新生成下一个食物
food_Y=25+25*random.nextInt(24);
}

步骤六:添加失败判定和积分系统

到目前为止,整个小游戏缺少最重要的就是失败的判定系统,当贪吃蛇撞击到自己的身体时,则判定为游戏失败,首先,先定义变量,默认状态为游戏不失败状态。

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

在paintComponent()方法中,用画笔添加相关内容:

if (isFail){//游戏失败时的提示
            g.setColor(Color.red);
            g.setFont(new Font("微软雅黑",Font.BOLD,40));
            g.drawString("游戏失败,按下空格键重新开始",250,300);
        }

在游戏开始和游戏失败后都需要按空格键来开启或重新开启游戏,所以就需要修改keyPressed()的判定,如下:

if(isFail){
//游戏失败,重新开始
isFail=false;
init();//调用初始化方法
}else{
isStart=!isStart;//取反
}
repaint();

并且isFail==false添加到游戏启动的判定中

if (isStart && isFail==false){//游戏启动时

在游戏启动的判定中,添加游戏失败时的判定:

for(int i=0;i<length;i++){
if(snake_X[0]==snake_X[i]&&snake_Y[0]==snake_Y[i]){//贪吃蛇撞击到自己的身体时,则判定为游戏失败
isFail=true;
}
}

最后添加积分系统:

  1. 定义变量名称:int score;
  2. 初始化变量:score=0;
  3. 添加到画板当中:g.setColor(Color.black); g.setFont(new Font("微软雅黑",Font.BOLD,20)); g.drawString("分数"+score,750,50); g.drawString("长度"+length,750,30);
  4. 贪吃蛇吃到食物,积分自增:score++;

为了防止以上的内容有理不清顺序的小伙伴,特地把整个PanelGame类的代码放在下面,给大家参考:

package wang;
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 PanelGame extends JPanel implements KeyListener, ActionListener {
    int length;//贪吃蛇长度
    int score;//分数
    String direction;//默认方向
    int[] snake_X=new int[500];//贪吃蛇的坐标
    int[] snake_Y=new int[500];
    int food_X;//食物的坐标
    int food_Y;
    Random random=new Random();//随机数
    boolean isStart=false;//默认状态
    boolean isFail=false;//默认是不失败的状态
    Timer timer=new Timer(100,this);//创建一个定时器

    public PanelGame(){
        init();
        this.setFocusable(true);//获得焦点事件
        this.addKeyListener(this);//添加当前键盘监听事件
        timer.start();//在游戏开始时就启动定时器
    }

    //初始化游戏数据
    public void init(){
        length=3;
        score=0;
        direction="Right";
        snake_X[0]=100;snake_Y[0]=100;//贪吃蛇的头部坐标
        snake_X[1]=75;snake_Y[1]=100;//贪吃蛇的第一个身体坐标
        snake_X[2]=50;snake_Y[2]=100;//贪吃蛇的第二个身体坐标
        food_X=25+25*random.nextInt(34);//在面板内随机生成食物的坐标
        food_Y=75+25*random.nextInt(24);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);//清屏
        this.setBackground(Color.white);
        g.fillRect(25,75,850,600);//设置面板大小
        Data.header.paintIcon(this,g,25,11);//将头部广告添加进去

        Data.food.paintIcon(this,g,food_X,food_Y);//生成食物

        //添加积分与长度栏
        g.setColor(Color.black);
        g.setFont(new Font("微软雅黑",Font.BOLD,20));
        g.drawString("分数"+score,750,50);
        g.drawString("长度"+length,750,30);

        //贪吃蛇头部图片匹配
        if (direction.equals("Right")){
            Data.right.paintIcon(this,g,snake_X[0],snake_Y[0]);
        }
        else if (direction.equals("Left")){
            Data.left.paintIcon(this,g,snake_X[0],snake_Y[0]);
        }
        else if (direction.equals("Up")){
            Data.up.paintIcon(this,g,snake_X[0],snake_Y[0]);
        }
        else if (direction.equals("Down")){
            Data.down.paintIcon(this,g,snake_X[0],snake_Y[0]);
        }
        //贪吃蛇身体坐标
        for (int i = 1; i <length ; i++) {
            Data.body.paintIcon(this,g,snake_X[i],snake_Y[i]);
        }

       //暂停状态下的初始化数据
        if (!isStart){
           g.setColor(Color.WHITE);
           g.setFont(new Font("微软雅黑",Font.BOLD,40));
           g.drawString("按下空格键开始游戏",250,300);
        }
        //失败时的游戏提示
        if (isFail){
            g.setColor(Color.red);
            g.setFont(new Font("微软雅黑",Font.BOLD,40));
            g.drawString("游戏失败,按下空格键重新开始",250,300);
        }
    }

    @Override
    //切换游戏状态
    public void keyPressed(KeyEvent e) {
        int keyCode=e.getKeyCode();//匹配的是哪一个键
        if (keyCode==KeyEvent.VK_SPACE){//匹配空格键
            if (isFail){
                //重新开始
                isFail=false;
                init();
            }
            else {
                isStart=!isStart;//取反
            }
            repaint();//刷新页面
        }
        if (keyCode==KeyEvent.VK_UP){//匹配向上的按键
            direction="Up";//将方向设置为上
        }
        else if (keyCode==KeyEvent.VK_DOWN){
            direction="Down";
        }
        else if (keyCode==KeyEvent.VK_LEFT){
            direction="Left";
        }
        else if (keyCode==KeyEvent.VK_RIGHT){
            direction="Right";
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (isStart && isFail==false){//游戏启动时
            if (snake_X[0]==food_X&&snake_Y[0]==food_Y){//当贪吃蛇头部坐标与食物坐标重合,则长度自增,食物再次随机生成
                length++;
                score++;
                food_X=25+25*random.nextInt(34);
                food_Y=75+25*random.nextInt(24);
            }
            for (int i = length-1; i >0 ; i--) {//无论移动方向如何,后一节身体移动到前一节位置,snake[1]=snake[0]
                snake_X[i]=snake_X[i-1];
                snake_Y[i]=snake_Y[i-1];
            }

            if (direction.equals("Right")){
                snake_X[0]=snake_X[0]+25;//头部移动
                if (snake_X[0]>850){snake_X[0]=25;}//边界设置:若头部超过边界外,则重置到左边
            }

            else if (direction.equals("Left")){
                snake_X[0]=snake_X[0]-25;
                if (snake_X[0]<25){snake_X[0]=850;}
            }

            else if (direction.equals("Up")){
                snake_Y[0]=snake_Y[0]-25;
                if (snake_Y[0]<75){snake_Y[0]=650;}
            }

            else if (direction.equals("Down")){
                snake_Y[0]=snake_Y[0]+25;
                if (snake_Y[0]>650){snake_Y[0]=75;}
            }
            //判定游戏失败时的条件:当贪吃蛇头部与身体部分的坐标相重合时
            for (int i = 1; i <length ; i++) {
                if (snake_X[0]==snake_X[i]&&snake_Y[0]==snake_Y[i]){
                    isFail=true;
                }
            }
            repaint();//刷新页面
        }
        timer.start();//启动定时器
    }
    @Override
    public void keyTyped(KeyEvent e) {
    }
    @Override
    public void keyReleased(KeyEvent e) {
    }
}

到这我们这个游戏就算是大功告成了,但是游戏仍然有很多不足的地方,例如:在撞到边界的时候,也会判定游戏失败,在长度达到一定程度后,贪吃蛇移动速度加快等等,这些就交由给大家完成吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值