java怎么做游戏?简单的贪吃蛇游戏

阳光 2021-01-14 21:59:13 java常见问答 5403

大家对贪吃蛇游戏一点也不会觉得陌生,这都是大家小时候常玩的游戏,但是大家学会java以后,就可以用java做这个小游戏啦!下面我们就给大家讲解一下做贪吃蛇游戏的方法。

用到了JSwing,下面是一些具体的思路:

实现:

蛇:

采用单链表记录首尾,整个蛇被分为lattice格子,放在map里

移动:

在实现的过程中发现最难得反而是蛇的定义和实现。一直想着怎么样用单独的方法表示出蛇来,但是如果将蛇单独实现,总有些细节实现起来特别麻烦。

其实蛇移动并非牵一发而动全身,其实身子是没有发生变化的,关键是两点:

a.头的移动

b.尾巴的移动

实现:

直接把蛇实现在地图的小格子里,不再单独设置子类或者ArrayList等,Map里加上蛇头的坐标,从而使得Map可以根据蛇头改变蛇的坐标(类似于变量交换)。为头部单独设置x,y,作为移动的方向(也可以作为静态变量x和y,不过没什么区别),为身子设置next指针,只要next.next不是尾巴,那么保持不变。如果next是尾巴,就把自己的设置为尾巴,并且改变next,使之成为普通地图块。(refresh方法)

控制方向:

使用键盘事件,目前仅设置了wasd四个。

窗口设计:

view extends JPanel,控制显示,然后在Lattice里调用Graphics.draw(...)实现对每个格子的显示

下面是核心的map部分代码(包括自动移动,检测食物,增加长度等等)。

import codes.myGame.snake.cell.Lattice;
import java.util.Random;
public class Smap
{
    private boolean getFood = false; //如果得到食物,该指针设为true,并且在随后的autoChange里增加蛇的长度
    private boolean gameOver = false;
    private boolean directionChange = false; //这里标志的作用是保证在一次运动期间只会进行一次转向,使游戏更流畅
    private int MAP_SIZE;
    private Lattice[][] map;
    private int directionX = 0; //下一次头在当前位置的哪个方向上
    private int directionY = 1; //下一次头在当前位置的哪个方向上
    private int[] head = new int[2]; //记录当前头的位置
    private int[] food = new int[2]; //记录当前食物的位置
    public Smap(int size)
    {
        MAP_SIZE = size;
        map = new Lattice[MAP_SIZE][MAP_SIZE];
        for (int i = 0; i < size; i++)
        {
            for (int j = 0; j < size; j++)
            {
                map[i][j] = new Lattice();
            }
        }
        map[MAP_SIZE / 2][MAP_SIZE / 2].setHead(true, map[MAP_SIZE / 2][MAP_SIZE / 2 - 1]); //初始化设置一个头结点,以及他的尾节点
        head[0] = MAP_SIZE / 2;
        head[1] = MAP_SIZE / 2;
        map[MAP_SIZE / 2][MAP_SIZE / 2 - 1].setRear(true, null);
        this.randFood();
    }
    //模拟蛇的自动移动
    public void autoChange()
    {
        this.setHead();
        if (food[0] == head[0] && food[1] == head[1])
        { //如果新的头部碰触到了食物,那么尾部增长
            getFood = true;
        }
        if (!gameOver) this.setRear();
        if (getFood) this.randFood();
        directionChange = false;
    }
    //根据键盘事件,改变头的下一次移动方向,注意 该移动方向是仅针对头部的
    //setDirection和setHead两个方法需要互斥进行,这里单线程,用synchronized即可
    //(否则,如果当前头部在边界位置,连续变幻方向可能导致在setHead里发生溢出)
    public synchronized void setDirection(int x, int y)
    {
        if (directionY != y && directionX != x && !directionChange)
        {
            directionX = x;
            directionY = y;
            directionChange = true;
        }
    }
    public boolean gameOver()
    {
        return gameOver; //头碰到身子,证明gameOver
    }
    private synchronized void setHead()
    {
        int i = head[0];
        int j = head[1];
        head[0] = (head[0] + directionX + MAP_SIZE) % MAP_SIZE;
        head[1] = (head[1] + directionY + MAP_SIZE) % MAP_SIZE;
        if (map[head[0]][head[1]].isBody()) gameOver = true;
        map[head[0]][head[1]].setHead(true, map[i][j]);
        map[i][j].setBody(true, null);
        map[i][j].setHead(false, null); //传入null表示不改变当前指向
    }
    //设置尾巴由于没法像头部那样直接设置,这里只能采用链表遍历的方式获取尾巴
    private void setRear()
    {
        if (!getFood)
        {
            Lattice temp = map[head[0]][head[1]];
            while (!temp.next.isRear()) temp = temp.next;
            temp.next()
                .setRear(false, null);
            temp.setRear(true, null);
            temp.setBody(false, null);
        }
    }
    private void randFood()
    {
        getFood = false;
        map[food[0]][food[1]].setFood(false); //先把当前的食物取消掉
        boolean flag = false; //设置下一个食物
        Random random = new Random();
        int x = random.nextInt(MAP_SIZE);
        int y = random.nextInt(MAP_SIZE);
        while (!flag)
        {
            x = random.nextInt(MAP_SIZE);
            y = random.nextInt(MAP_SIZE);
            if (!map[x][y].isHead() && !map[x][y].isRear() && !map[x][y].isBody()) flag = true;
        }
        map[x][y].setFood(true);
        food[0] = x;
        food[1] = y;
    }
    public Lattice get(int row, int col)
    {
        return map[row][col];
    }
    public int getMAP_SIZE()
    {
        return MAP_SIZE;
    }
}

下面是显示部分的代码:


显示分为两部分,一块是利用Graphics.draw()方法实现单个单元格的绘制,另一块设置view类继承自JPanel。负责绘制图画显示:

public class Lattice
{
    private boolean isBody = false;
    private boolean isHead = false;
    private boolean isFood = false;
    private boolean isRear = false;
    public Lattice next = null;
    public void setHead(boolean bool, Lattice next)
    {
        isHead = bool;
        if (next != null) this.next = next;
    }
    public void setBody(boolean bool, Lattice next)
    {
        isBody = bool;
        if (next != null) this.next = next; //传入参数为null时,不改变当前的next
    }
    public void setRear(boolean bool, Lattice next)
    {
        isRear = bool;
        this.next = next;
    }
    public void setFood(boolean bool)
    {
        isFood = bool;
    }
    public Lattice next()
    {
        return next;
    }
    public boolean isHead()
    {
        return isHead;
    }
    public boolean isFood()
    {
        return isFood;
    }
    public boolean isRear()
    {
        return isRear;
    }
    public boolean isBody()
    {
        return isBody;
    }
    public void refresh()
    {
        if (isHead)
        {
            isBody = true;
            isHead = false;
            // 怎么设置下一个头呢?(考虑把DirectionX,Y放到Smap里,而不是这里)
        }
        else if (isBody)
        {
            if (next.isRear)
            {
                next.isRear = false;
                isRear = true;
                isBody = false;
            }
        }
    }
    // 在这里设置细胞可见
    public void draw(Graphics g, int x, int y, int size)
    {
        g.setColor(black);
        g.drawRect(x, y, size, size);
        if (isHead)
        {
            g.setColor(red);
            g.fillRect(x, y, size, size);
        }
        else if (isBody || isRear)
        {
            g.setColor(black);
            g.fillRect(x, y, size, size);
        }
        else if (isFood)
        {
            g.setColor(blue);
            g.fillRect(x, y, size, size);
        }
    }
}

view部分:

import codes.myGame.snake.cell.Lattice;
import javax.swing.*;
import java.awt.*;
public class View extends JPanel
{
    private static final long serialVersionUID = -5258995676212660595 L;
    private static final int GRID_SIZE = 32; //填充的像素数量
    private Smap thisMap;
    public View(Smap map)
    {
        thisMap = map;
    }
    @Override
    public void paint(Graphics g)
    {
        super.paint(g);
        int size = thisMap.getMAP_SIZE();
        for (int row = 0; row < size; row++)
        {
            for (int col = 0; col < size; col++)
            {
                Lattice lattice = thisMap.get(row, col);
                if (lattice != null)
                {
                    lattice.draw(g, col * GRID_SIZE, row * GRID_SIZE, GRID_SIZE); //对应的格子的显示
                }
            }
        }
    }
    @Override
    public Dimension getPreferredSize()
    { //创建该div大小
        return new Dimension(thisMap.getMAP_SIZE() * GRID_SIZE + 1, thisMap.getMAP_SIZE() * GRID_SIZE + 1);
    }
}

这些就是用java做贪吃蛇游戏的方法了,大家是不是觉得很神奇,是的!学java除了能够游戏,还可以做网页,所以大家一定要认真学java!最后大家如果想要了解更多java实例知识,敬请关注奇Q工具网。

推荐阅读:

java初级入门教程有哪些?java入门必学知识点

java有多少基本类型?基本类型有哪些特点?

java怎么做缴费功能?流程分享