今天我闲着没事想用二维数组做一个文字游戏,所以就有了这篇文章。

先看看最终效果图:

java实现打字游戏 java写文字游戏_i++


首先我们想一下,推箱子这个游戏有什么特点?有一个正方形的游戏区域,有玩家,有箱子,有终点。

所以第一步在先创建几个数据用于代表他们

先创建一个vector2类用于存储各种会动物品的坐标

//这个类用来存储坐标
public class Vector2
{
    private int posX;
    private int posY;

    {
        posX = 0;
        posY = 0;
    }

    public Vector2(int x,int y)
    {
        this.posX = x;
        this.posY = y;
    }

    public int getPosX()
    {
        return this.posX;
    }

    public int getPosY()
    {
        return this.posY;
    }

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

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

BoxGame里写我们的main方法,是我们整个游戏的入口点

public class BoxGame
{
    //创建一个二维数组表示我们的整个地图
    public static String[][] map = new String[10][10];

    //玩家坐标
    public static Vector2 playerPos = new Vector2();

    //箱子坐标
    public static Vector2 boxPos = new Vector2();

    //代表围墙的字符
    public static final String WALL = "H";

    //代表玩家的字符
    public static final String PLAYER = "&";

    //代表箱子的字符
    public static final String BOX = "o";

    //代表终点的字符
    public static final String ENDPOINT = "*";

    public static void main(string[] args)
    {
        
    }
}

然后再创建一个地图编辑器类,用于管理地图状态,绘制地图等相关操作。

先写几个方法出来,一会再逐个编写方法体

public class mapEditor
{
    //用于初始化墙壁(就是固定在游戏边框的)
    public static void initWall()
    {}

    //用于编辑地图
    public static void EditMap()
    {}

    //用于打印出当前地图的信息
    public static void printMap()
    {}

    //用于进行玩家主角的移动操作
    public static void movement()
    {}
}

先编写初始化墙壁的方法吧,添加一个布尔参数,用于决定是否清空除了墙壁外的中间部分位置

因为后期拓展关卡起来,每通过一关都是要重新绘制一个不一样的关卡的。

public static void initwall(boolean clear)
{
    //将地图的边框填充上墙壁字符,代表有墙壁
    for (int x =0;x<10;x++)
    {
        if (x == 0 || x == 9)
        {
            for (int i=0;i<10;i++)
            {
                BoxGame.map[x][i] = BoxGame.WALL;
            }
        }
        else
        {
            BoxGame.map[x][0] = BoxGame.WALL;
            BoxGame.map[x][9] = BoxGame.WALL;
        }
    }
    //如果是清除模式,连地图中间的所有内容都清空
    if (clear)
    {
        for (int x=1;x<9;x++)
        {
            for (int i=1;i<9;i++)
            {
                BoxGame.map[x][i] = " ";
            }
        }
    }
}

然后是编辑地图方法,添加两个参数,一个是坐标的列表,一个是对应指定坐标的内容(填充进地图内指定坐标)

public static void EditMap(List<Vector2> vector2, String[] info)
{
    for (int x=0;x<info.length;x++)
    {
        BoxGame.map[vector2.get(x).getPosY][vector2.get(x).getPosX] = info[x];
    }
}

非常简便~


接下来我们继续编写打印地图的方法,只需要遍历数组中的信息然后加到一个字符串中打印出来就可以啦~实现方法有很多

public static void printMap()
{
    //创建一个变量用来存储所有需要打印的信息
    String printInfo = "";
    for (int x=0;x<10;x++)
    {
        for (int i=0;i<10;i++)
        {
            printInfo += BoxGame.map[x][i];
            //为了美观让每个字符之间有一个空格
            printInfo += " ";
        }
        //每存储一行添加一个换行符
        printInfo += "\n";
    }
    System.out.println(printInfo);
}

内容也是非常滴简单。


最后来编写我们整个程序最核心的部分,用于判断玩家移动的函数,游戏的主要逻辑判断。

修改返回值为boolean值,当玩家推动箱子的位置为终点时,返回true表示通关

否则返回false表示未通关

添加一个string参数,用于接收玩家发出的指令,A左移D右移W上移S下移

public static boolean movement(String dir)
{
    //判断玩家发出的指令
    switch(dir)
    {
        //向上移动
        case "W":
        {
            //由于我们打印地图的方法,越往上索引越低,所以是跟正常的反过来的,向上是Y-1。
            //判断玩家上方是否为空位
            if(BoxGame.map[BoxGame.playerPos.getPosY() - 1][BoxGame.playerPos.getPosX()].equals(" "))
            {
                //如果为空位的话直接移动,先把当前位置清空
                BoxGame.map[BoxGame.playerPos.getPosY()][BoxGame.playerPos.getPosX()] = " ";
                //然后更新玩家坐标向上移动
                BoxGame.playerPos.setPosY( BoxGame.playerPos.getPosY() - 1);
                //在移动后的位置填充玩家字符,表示移动成功
                BoxGame.map[BoxGame.playerPos.getPosY()][BoxGame.playerPos.getPosX()] = BoxGame.PLAYER;
            }
            //如果上方是箱子
            else if(BoxGame.map[BoxGame.playerPos.getPosY() - 1][BoxGame.playerPos.getPosX()].equals(BoxGame.BOX))
            {
                //再判断箱子的上方是不是终点
                if(BoxGame.map[BoxGame.boxPos.getPosY() - 1][BoxGame.boxPos.getPosX()].eqauls(BoxGame.ENDPOINT))
                {
                    //如果是,返回true,关卡胜利
                    return true;
                }
                //如果箱子上方是墙壁
                else if(BoxGame.map[BoxGame.boxPos.getPosY() - 1][BoxGame.boxPos.getPosX()].eqauls(BoxGame.WALL))
                {
                    //无法移动
                    return false;
                }
                //如果箱子上方是空位
                else
                {
                    //先移动箱子
                    //将箱子当前位置清空
                    BoxGame.map[BoxGame.boxPos.getPosY()][BoxGame.boxPos.getPosX()] = " ";
                    //更新箱子坐标
                    BoxGame.boxPos.setPosY(BoxGame.boxPos.getPosY() - 1);
                    //将新坐标填入箱子字符,表示箱子移动
                    BoxGame.map[BoxGame.boxPos.getPosY()][BoxGame.boxPos.getPosX()] = BoxGame.BOX;

                    //接下来再更新玩家信息,上面做过注释了,操作相同,这里不再赘述。
                    BoxGame.map[BoxGame.playerPos.getPosY()][BoxGame.playerPos.getPosX()] = " ";
                    BoxGame.playerPos.setPosY( BoxGame.playerPos.getPosY() - 1);
                    BoxGame.map[BoxGame.playerPos.getPosY()][BoxGame.playerPos.getPosX()] = BoxGame.PLAYER;
                }
            }
            break;
        }
        //向下移动
        case "S":
        {
            //操作大庭相径,不过是坐标位置不同,不做赘述。
            if(BoxGame.map[BoxGame.playerPos.getPosY() + 1][BoxGame.playerPos.getPosX()].equals(" "))
            {
                BoxGame.map[BoxGame.playerPos.getPosY()][BoxGame.playerPos.getPosX()] = " ";
                BoxGame.playerPos.setPosY( BoxGame.playerPos.getPosY() + 1);
                BoxGame.map[BoxGame.playerPos.getPosY()][BoxGame.playerPos.getPosX()] = BoxGame.PLAYER;
            }
            else if(BoxGame.map[BoxGame.playerPos.getPosY() + 1][BoxGame.playerPos.getPosX()].equals(BoxGame.BOX))
            {
                if(BoxGame.map[BoxGame.boxPos.getPosY() + 1][BoxGame.boxPos.getPosX()].eqauls(BoxGame.ENDPOINT))
                {
                    return true;
                }
                else if(BoxGame.map[BoxGame.boxPos.getPosY() + 1][BoxGame.boxPos.getPosX()].eqauls(BoxGame.WALL))
                {
                    return false;
                }
                else
                {
                    BoxGame.map[BoxGame.boxPos.getPosY()][BoxGame.boxPos.getPosX()] = " ";
                    BoxGame.boxPos.setPosY(BoxGame.boxPos.getPosY() + 1);
                    BoxGame.map[BoxGame.boxPos.getPosY()][BoxGame.boxPos.getPosX()] = BoxGame.BOX;

                    BoxGame.map[BoxGame.playerPos.getPosY()][BoxGame.playerPos.getPosX()] = " ";
                    BoxGame.playerPos.setPosY( BoxGame.playerPos.getPosY() + 1);
                    BoxGame.map[BoxGame.playerPos.getPosY()][BoxGame.playerPos.getPosX()] = BoxGame.PLAYER;
                }
            }
            break;
        }
        //向左移动
        case "A":
        {
            if(BoxGame.map[BoxGame.playerPos.getPosY()][BoxGame.playerPos.getPosX() - 1].equals(" "))
            {
                BoxGame.map[BoxGame.playerPos.getPosY()][BoxGame.playerPos.getPosX()] = " ";
                BoxGame.playerPos.setPosX( BoxGame.playerPos.getPosX() - 1);
                BoxGame.map[BoxGame.playerPos.getPosY()][BoxGame.playerPos.getPosX()] = BoxGame.PLAYER;
            }
            else if(BoxGame.map[BoxGame.playerPos.getPosY()][BoxGame.playerPos.getPosX() - 1].equals(BoxGame.BOX))
            {
                if(BoxGame.map[BoxGame.boxPos.getPosY()][BoxGame.boxPos.getPosX() - 1].eqauls(BoxGame.ENDPOINT))
                {
                    return true;
                }
                else if(BoxGame.map[BoxGame.boxPos.getPosY()][BoxGame.boxPos.getPosX() - 1].eqauls(BoxGame.WALL))
                {
                    return false;
                }
                else
                {
                    BoxGame.map[BoxGame.boxPos.getPosY()][BoxGame.boxPos.getPosX()] = " ";
                    BoxGame.boxPos.setPosX(BoxGame.boxPos.getPosX() - 1);
                    BoxGame.map[BoxGame.boxPos.getPosY()][BoxGame.boxPos.getPosX()] = BoxGame.BOX;

                    BoxGame.map[BoxGame.playerPos.getPosY()][BoxGame.playerPos.getPosX()] = " ";
                    BoxGame.playerPos.setPosX( BoxGame.playerPos.getPosX() - 1);
                    BoxGame.map[BoxGame.playerPos.getPosY()][BoxGame.playerPos.getPosX()] = BoxGame.PLAYER;
                }
            }
            break;
        }
        //向右移动
        case "D":
        {
            if(BoxGame.map[BoxGame.playerPos.getPosY()][BoxGame.playerPos.getPosX() + 1].equals(" "))
            {
                BoxGame.map[BoxGame.playerPos.getPosY()][BoxGame.playerPos.getPosX()] = " ";
                BoxGame.playerPos.setPosX( BoxGame.playerPos.getPosX() + 1);
                BoxGame.map[BoxGame.playerPos.getPosY()][BoxGame.playerPos.getPosX()] = BoxGame.PLAYER;
            }
            else if(BoxGame.map[BoxGame.playerPos.getPosY()][BoxGame.playerPos.getPosX() + 1].equals(BoxGame.BOX))
            {
                if(BoxGame.map[BoxGame.boxPos.getPosY()][BoxGame.boxPos.getPosX() + 1].eqauls(BoxGame.ENDPOINT))
                {
                    return true;
                }
                else if(BoxGame.map[BoxGame.boxPos.getPosY()][BoxGame.boxPos.getPosX() + 1].eqauls(BoxGame.WALL))
                {
                    return false;
                }
                else
                {
                    BoxGame.map[BoxGame.boxPos.getPosY()][BoxGame.boxPos.getPosX()] = " ";
                    BoxGame.boxPos.setPosX(BoxGame.boxPos.getPosX() + 1);
                    BoxGame.map[BoxGame.boxPos.getPosY()][BoxGame.boxPos.getPosX()] = BoxGame.BOX;

                    BoxGame.map[BoxGame.playerPos.getPosY()][BoxGame.playerPos.getPosX()] = " ";
                    BoxGame.playerPos.setPosX( BoxGame.playerPos.getPosX() + 1);
                    BoxGame.map[BoxGame.playerPos.getPosY()][BoxGame.playerPos.getPosX()] = BoxGame.PLAYER;
                }
            }
            break;
        }
    }
    return false;
}

到此地图编辑器类已经完成,不过我们只完成了游戏的逻辑,还没有制作出一个关卡~

接下来我们使用之前制作的editmap方法来制作一个关卡:

public static void loadLevel_1()
{
    //先初始化墙壁
    mapEditor.initwall(true);
    //创建一个list用来一会传入editmap方法
    List<Vector2> list=new ArrayList<>();
    //设置关卡中玩家和箱子的坐标
    playerPos.setPosX(1); playerPos.setPosY(1); boxPos.setPosY(2); boxPos.setPosX(2);
    list.add(new Vector2(1,1)); list.add(new Vector2(2,2)); list.add(new Vector2(8,5));
    list.add(new Vector2(1,3)); list.add(new Vector2(2,3)); list.add(new Vector2(3,3));
    list.add(new Vector2(2,5)); list.add(new Vector2(3,5)); list.add(new Vector2(3,6));
    list.add(new Vector2(3,8)); list.add(new Vector2(4,8)); list.add(new Vector2(5,4));
    list.add(new Vector2(5,5)); list.add(new Vector2(5,6)); list.add(new Vector2(6,4));
    //创建一个数组用于存储上面按顺序的每个坐标对应的字符
    String[] info =new String[]{PLAYER,BOX,ENDPOINT,
    WALL,WALL,WALL,
    WALL,WALL,WALL,
    WALL,WALL,WALL,
    WALL,WALL,WALL};
    //调用editmap方法
    mapEditor.EditMap(list,info);
}

制作完关卡我们还需要一个游戏主循环方法:

先在BoxGame里添加一个静态变量

//用于接收用户输入字符
private static Scanner inputManager=new Scanner(System.in);

然后再编写我们的主循环

public static void mainloop()
{
    //打印地图
    mapEditor.printMap();
    //提示信息
    System.out.println("输入W向上移动,S向下移动,A向左移动,D向右移动");
    //获取用户输入
    String info=inputManager.next();
    //传入移动方法,判断是否胜利
    if (mapEditor.movement(info))
    {
        //胜利则提示胜利
        System.out.println("恭喜你!赢得了游戏!");
    }
    //否则游戏继续
    else
    {
        mainloop();
    }
}

mainloop方法和loadlevel_1方法我都放在boxgame里,你们随自己喜欢就好~

最后再main方法中调用

public static void main(String[] args)
{
    loadLevel_1();
    mainloop();
}

这时候打包出来,或者在编译器中运行,就可以看见我们的游戏啦。

java实现打字游戏 java写文字游戏_Game_02

至此我们整个项目已经完成,因为我只做了一个关卡所以整个游戏只有一个关卡,小伙伴们可以动动手指,添加自己想要的关卡,修改代码达成有下一关的效果~因为我们已经写好了所有用来拓展的方法,所以做起来应该是很简单的。

收