ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java实验——贪吃蛇小游戏

2022-06-19 17:34:57  阅读:197  来源: 互联网

标签:direction Java img int frame 小游戏 void 贪吃蛇 public


一、项目简介

贪吃蛇能够被键盘wasd控制移动,小蛇每吃到一个食物,分数加1,撞到自己,则显示游戏结束。游戏可以被space键暂停继续。

 

二、功能架构图

 

 

 

 

三、功能详解

  在600*600像素的方框中(蛇的主要移动范围),定义蛇移动一次以30*30的像素移动。

  •  窗口的创建,单独创建一个窗口类,用来设置窗口的信息,后续信息逐步添加
public class GameWin extends JFrame {
    public void init(){
        this.setVisible(true);
        this.setSize(600,600);
        this.setLocationRelativeTo(null);
        this.setTitle("贪吃蛇小游戏");
    }

    public static void main(String[] args) {
        GameWin gameWin = new GameWin();
        gameWin.init();
    }
}
  •  创建整个游戏的物体的父类,大部分是get和set方法,还有构造方法,唯一注意的地方就只有一个paintSelf的方法,绘制自身的方法
import java.awt.*;

public class GameObj {
    Image img;
    int x;
    int y;
    int width = 30;
    int height = 30;
    GameWin frame;

    public Image getImg() {
        return img;
    }

    public void setImg(Image img) {
        this.img = img;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public GameWin getFrame() {
        return frame;
    }

    public void setFrame(GameWin frame) {
        this.frame = frame;
    }

    public GameObj() {
    }

    public GameObj(Image img, int x, int y,GameWin frame) {
        this.img = img;
        this.x = x;
        this.y = y;
        this.frame = frame;
    }

    public void paintSelf(Graphics g){
        g.drawImage(img,x,y,null);
    }
}
  •   创建游戏的工具类,将蛇的头部,身体还有食物,放进工作区中,将贴图 引入工具类中,再定义一个方法用来绘制文字。
import java.awt.*;

public class GameUtils {
    public static Image headImage = Toolkit.getDefaultToolkit().getImage("img/head.png");
    public static Image bodyImage = Toolkit.getDefaultToolkit().getImage("img/body.png");
    public static Image foodImage = Toolkit.getDefaultToolkit().getImage("img/food.png");

    public static void drawWord(Graphics g,String str,Color color,int size,int x,int y){
        g.setColor(color);
        g.setFont(new Font("仿宋",Font.BOLD,size));
        g.drawString(str,x,y);
    }

}
  •   创建蛇的头部(蛇的头部要继承游戏物体的父类GameObj),在蛇的头部类中,要增加一个蛇头的默认方向,默认方向向右。
  • 先在窗口类中重写一个paint方法,然后在窗口创建蛇头对象,在paint方法中绘制蛇头,调用paintSelf方法。
import java.awt.*;

public class HeadObj extends GameObj {
    private String direction = "right";

    public String getDirection() {
        return direction;
    }

    public void setDirection(String direction) {
        this.direction = direction;
    }

    public HeadObj(Image img, int x, int y, GameWin frame) {
        super(img, x, y, frame);
    }

    @Override
    public void paintSelf(Graphics g) {
        super.paintSelf(g);
    }
}
  •   在蛇的头部类中添加一个move 方法,对蛇的方向进行判断。在paintSelf中调用move方法。在蛇头移动的过程中,要不停的repaint,在窗口类中的初始化窗口中不停的repaint,线程休眠200毫秒

 

  •  实现键盘控制蛇头的简单移动,在蛇的头部类的构造方法中添加键盘监听事件。在蛇的头部类中,新加一个改变蛇头部移动的方法,在键盘监听事件中添加changeDirection方法
  public void changeDirection(KeyEvent e){
        switch(e.getKeyCode()){
            case KeyEvent.VK_A:
                if(!direction.equals("right")){
                    direction = "left";
                }
                break;
            case KeyEvent.VK_D:
                if(!direction.equals("left")){
                    direction = "right";
                }
                break;
            case KeyEvent.VK_W:
                if(!direction.equals("down")){
                    direction = "up";
                }
                break;
            case KeyEvent.VK_S:
                if(!direction.equals("up")){
                    direction = "down";
                }
                break;
            default:
                break;

        }

  

  •  对蛇越界进行处理,如果蛇从一个边界穿出,从相反方向穿进。在paintSelf方法中对蛇头坐标进行判断

 

  •  对蛇身的添加,先创建蛇身的类,在窗口类中定义蛇身的集合,在init中对蛇身进行初始化,在paint中反向遍历身体的集合(以防止身体的重叠)。在蛇头移动的代码之前,添加蛇身的移动,从第二个身体开始,都是上一个身体的坐标,第一个是在头移动之前,头部的坐标。
import java.awt.*;

public class BodyObj extends GameObj {
    public BodyObj(Image img, int x, int y, GameWin frame) {
        super(img, x, y, frame);
    }

    @Override
    public void paintSelf(Graphics g) {
        super.paintSelf(g);
    }
}
  •   蛇食物随机生成,蛇的食物随机生成范围是x:0-570,y:30-570。并且只能是30的倍数。新建一个食物类,在类中定义一个随机函数,写一个获取食物的方法,返回值是食物类。在窗口类中获取食物类的对象,在paint方法中绘制食物。
import java.awt.*;
import java.util.Random;

public class FoodObj extends GameObj {
    Random r = new Random();
    public FoodObj() {
        super();
    }
    public FoodObj getFood(){
        return new FoodObj(GameUtils.foodImage,r.nextInt(20)*30,( r.nextInt(19)+1)*30,this.frame );
    }

    public FoodObj(Image img, int x, int y, GameWin frame) {
        super(img, x, y, frame);
    }

    @Override
    public void paintSelf(Graphics g) {
        super.paintSelf(g);
    }
}
  •   蛇吃食物,吃完后,食物再次随机生成。在头部类中paintSelf方法中获取窗口类中的食物对象(一定要在蛇头移动之前),添加判断,判断食物是否和蛇头重合。如果重合就把新的随机生成的食物对象,赋值给窗口类中的foodObj。

 

  •  蛇身体的增长,蛇吃到食物,蛇就应该增长一节,在头的paintSelf方法中,定义两个变量用来记录蛇身的最后一节坐标,获取蛇身最后一节的对象,把对象的坐标给X和Y。在move后,给一个新的身体对象,添加到蛇的身体的集合中。

 

  •  设置计分面板(之前先将窗口扩大),蛇每吃一个食物,分数加一,在窗口类中添加静态变量分数,在paint方法中,把分数绘制出来。在头部类中,找到蛇吃食物的地方,分数累加。在paint中画线,以区分蛇的移动区域和计分面板
  • 添加游戏开始的提示语,首先在窗口类中定义游戏状态的变量,有五种状态(0未开始,1游戏中,2暂停,3失败,4通关),绘制提示语,新建一个方法prompt(在里面绘制提示语),然后在paint方法中调用prompt方法
  • 添加游戏开始和暂停的键盘事件,在窗口类的初始化窗口中,添加键盘事件,在键盘事件中添加对状态的判断,状态的相应改变

 

 

  • 蛇头与身体的碰撞判断,在头部类的move方法中,判断蛇头的坐标与身体的坐标重合,则游戏失败,把游戏状态改为3.在prompt中添加游戏失败的提示语

 

 

  •  简单处理一下零散的地方,排除bug......

四、课程设计感想

 

有利于工程开发思维的培养,稳固知识点,增强团队分工合作的意识。
意识到了自己知识水平还有很大缺陷,和高手之间还有很长的路要走。

  

 

五、展望

1,界面字有闪烁问题:双缓存解决

游戏单调问题:增加关卡设置,增加障碍物,增加通关界面

游戏运行效率不高:改进小蛇移动时候,贴图的移动方法,可以只改变蛇头和蛇尾使小蛇移动,增加多线程的应用

2,进一步学习Java高级开发工具类,学习多线程,学习网络开发, docker容器,学习一些开发web技术

 

  

 

六、完整代码呈现,以及游戏截图,代码块有注释

 

  •  GameWin.java
package com.draw.test01;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;

public class GameWin extends JFrame {
    //继承了Jframe类便具有了创建窗口,监听鼠标键盘事件的功能

    //记录分数
    public static int score = 0;
    //游戏状态 0未开始 1游戏中 2暂停 3失败 4通关
    public static int state = 0;
    int winWidth = 800;
    int winHeight = 600;

    //蛇的头部
    HeadObj headObj = new HeadObj(GameUtils.rightImg,30,30,this);//窗口引用是当前对象this

    //蛇身体的集合
    public List<BodyObj> bodyObjList = new ArrayList<BodyObj>();

    //food
    public FoodObj foodObj = new FoodObj().getFood();
    public void init(){
        //设置窗口是否可见
        this.setVisible(true);
        //设置窗口大小
        this.setSize(winWidth,winHeight);
        //设置窗口标题
        this.setTitle("贪吃蛇小游戏");
        //蛇身体的初始化
        bodyObjList.add(new BodyObj(GameUtils.bodyImg,30,570,this));
        bodyObjList.add(new BodyObj(GameUtils.bodyImg,0,570,this));

        //添加键盘事件
        this.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if(e.getKeyCode() == KeyEvent.VK_SPACE){
                    switch(state){
                        case 0:
                        case 2:
                            state =1;
                            break;
                        case 1:
                            state = 2;
                            repaint();
                            break;
                        default:
                            break;
                    }
                }
            }
        });
        while(true){
            if(state == 1){
                repaint();
            }
            try {
                Thread.sleep(200);//每次重绘过后,线程休眠,1秒刷新5次
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }

    //重写paint方法
    @Override
    public void paint(Graphics g) {
        //super.paint(g);
        //灰色背景
        g.setColor(Color.GRAY);
        //填充矩形
        g.fillRect(0,0,winWidth,winHeight);
        //网格线
        g.setColor(Color.LIGHT_GRAY);
        //for(int i=1;i<=20;i++){

            g.drawLine(600,30,600,600);
        //    g.drawLine(30*i,0,30*i,600);
        //}
        //反向遍历身体的集合,防止想要的数据被覆盖
        for (int i = bodyObjList.size()-1; i >= 0 ; i--) {
            bodyObjList.get(i).paintSelf(g);
        }

        //在paint 方法中绘制蛇头
        headObj.paintSelf(g);
        //食物的绘制
        foodObj.paintSelf(g);
        //将分数绘制出来
        GameUtils.drawWord(g,score+" 分",Color.BLUE,50,650,300);
        g.setColor(Color.GRAY);
        prompt(g);
    }

    //绘制提示语
    void prompt(Graphics g){
        if(state == 0){
            g.fillRect(120,240,400,70);
            GameUtils.drawWord(g,"按下空格开始游戏",Color.yellow,35,150,290);

        }
        if(state == 2){
            g.fillRect(120,240,400,70);
            GameUtils.drawWord(g,"按下空格继续游戏",Color.BLUE,35,150,290);

        }
        if(state == 3){
            g.fillRect(120,240,400,70);
            GameUtils.drawWord(g,"回家种地去吧",Color.RED,35,150,290);

        }
    }

    public static void main(String[] args) {
        GameWin gamewin = new GameWin();
        gamewin.init();
    }
}

  

  • GameUtils.java
package com.draw.test01;

import java.awt.*;

//游戏的工具类
public class GameUtils {
    //蛇头
    //public static Image upImg = Toolkit.getDefaultToolkit().getImage("img/test.png");
    //public static Image dowmImg = Toolkit.getDefaultToolkit().getImage("img/test.png");
    //public static Image leftImg = Toolkit.getDefaultToolkit().getImage("img/test.png");
    public static Image rightImg = Toolkit.getDefaultToolkit().getImage("img/test.png");
    //蛇身
    public static Image bodyImg = Toolkit.getDefaultToolkit().getImage("img/body.png");
    //蛇的食物
    public static Image foodImg = Toolkit.getDefaultToolkit().getImage("img/food.png");

    public static void drawWord(Graphics g,String str,Color color,int size,int x,int y){
        g.setColor(color);
        g.setFont(new Font("仿宋",Font.BOLD,size));
        g.drawString(str, x, y);
    }

}
  •   GameObj.java
package com.draw.test01;

import java.awt.*;

//创建游戏物体的父类
public class GameObj {
    //picture
    Image img;
    //coordinate
    int x;
    int y;
    int width = 30;
    int height = 30;
    //窗口类的引用
    GameWin frame ;

    public Image getImg() {
        return img;
    }

    public void setImg(Image img) {
        this.img = img;
    }

    public int getX() {
        return x;
    }

    public GameObj(Image img, int x, int y, GameWin frame) {
        this.img = img;
        this.x = x;
        this.y = y;
        this.frame = frame;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public GameWin getFrame() {
        return frame;
    }

    public void setFrame(GameWin frame) {
        this.frame = frame;
    }
    //无参构造
    public GameObj() {
    }
    //有参构造
    public GameObj(Image img, int x, int y, int width, int height, GameWin frame) {
        this.img = img;
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.frame = frame;
    }

    //绘制自身
    public void paintSelf(Graphics g){
        g.drawImage(img,x,y,null);
    }
}
  •   HeadObj.java
package com.draw.test01;

import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.List;

//蛇的头部
public class HeadObj extends GameObj{


    //方向 up down left right
    private String direction = "right";


    public HeadObj(Image img, int x, int y, GameWin frame) {
        super(img, x, y, frame);
        //在构造方法中添加键盘监听事件
        this.frame.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                //super.keyPressed(e);//键盘按下、、获取到了键盘事件e
                changeDirection(e);
            }
        });
    }

    //控制移动方向
    public void changeDirection(KeyEvent e){
        switch(e.getKeyCode()){
            case KeyEvent.VK_A:
                if(!direction.equals("right")){
                    direction = "left";
                }
                break;
            case KeyEvent.VK_D:
                if(!direction.equals("left")){
                    direction = "right";
                }
                break;
            case KeyEvent.VK_S:
                if(!direction.equals("up")){
                    direction = "down";
                }
                break;
            case KeyEvent.VK_W:
                if(!direction.equals("down")){
                    direction = "up";
                }
                break;
            default:
                break;
        }
    }

    public String getDirection() {
        return direction;
    }

    public void setDirection(String direction) {
        this.direction = direction;
    }
    public void move (){
        //在蛇头移动之前先把蛇身移动
        List<BodyObj> bodyObjList = this.frame.bodyObjList;
        for (int i = bodyObjList.size() - 1; i >= 1; i--) {
            bodyObjList.get(i).x = bodyObjList.get(i-1).x;
            bodyObjList.get(i).y = bodyObjList.get(i-1).y;
            if(this.x == bodyObjList.get(i).x&&this.y == bodyObjList.get(i).y){
                GameWin.state = 3;
            }
        }
        bodyObjList.get(0).x = this.x;
        bodyObjList.get(0).y = this.y;
        switch(direction){
            case "up":
                y -= height;
                break;
            case "down":
                y += height;
                break;
            case "left":
                x -= width;
                break;
            case "right":
                x += width;
                break;
        }
    }
    @Override
    public void paintSelf(Graphics g) {
        super.paintSelf(g);
        //获取窗口类中的食物对象,蛇吃食物
        FoodObj food = this.frame.foodObj;
            //身体最后一节的坐标
        Integer X = null;
        Integer Y = null;
        if(food.x == this.x&&food.y== this.y){
            //获取蛇最后一节的坐标
            BodyObj lastBody = this.frame.bodyObjList.get(this.frame.bodyObjList.size()-1);
            X = lastBody.x;
            Y = lastBody.y;
            //蛇每吃一个食物,分数加一
            GameWin.score++;
            this.frame.foodObj = food.getFood();
        }
        move();
        if(X != null && Y != null){
            this.frame.bodyObjList.add(new BodyObj(GameUtils.bodyImg,X,Y,this.frame));
        }

        //越界处理
        if(x<0){
            x = 570;
        }
        else if(x>570){
            x = 0;
        }
        else if(y<30){
            y = 570;
        }
        else if(y>570){
            y = 30;
        }
    }
}
  •   BodyObj.java
package com.draw.test01;

import java.awt.*;

public class BodyObj extends GameObj{

    public BodyObj(Image img, int x, int y, GameWin frame) {
        super(img, x, y, frame);
    }

    @Override
    public void paintSelf(Graphics g) {
        super.paintSelf(g);
    }
}
  •   FoodObj.java
package com.draw.test01;

import java.awt.*;
import java.util.Random;

public class FoodObj extends GameObj{
    //定义随机函数
    Random random = new Random();
    public FoodObj() {
        super();
    }

    public FoodObj(Image img, int x, int y, GameWin frame) {
        super(img, x, y, frame);
    }
    //获取食物
    public FoodObj getFood(){
        return new FoodObj(GameUtils.foodImg,random.nextInt(20)*30,(random.nextInt(19)+1)*30,this.frame);
    }

    @Override
    public void paintSelf(Graphics g) {
        super.paintSelf(g);
    }
}
  •   运行效果截图,其他的自己去敲代码观察运行效果吧

 

标签:direction,Java,img,int,frame,小游戏,void,贪吃蛇,public
来源: https://www.cnblogs.com/veitsun/p/16390085.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有