Java实现可视化走迷宫小游戏的示例代码

目录
  • 效果图
  • 数据层
  • 视图层
  • 控制层

效果图

数据层

本实例需要从 .txt 文件中读取迷宫并绘制,所以先来实现文件读取IO类 MazeData.java,该程序在构造函数运行时将外部文件读入,并完成迷宫各种参数的初始化,注意规定了外部 .txt 文件的第一行两个数字分别代表迷宫的行数和列数。此外还提供了各类接口来读取或操作私有数据。

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Scanner;

public class MazeData {

    public static final char ROAD = ' ';
    public static final char WALL = '#';

    private int N, M;   // 高,宽(行,列)
    private char[][] maze;

    private int entranceX, entranceY;   // 入口
    private int exitX, exitY;   // 出口

    public boolean[][] visited; // 记录寻路过程某位置是否被访问过
    public boolean[][] path;    // 存储迷宫的解
    public boolean showPath;    // 是否打印系统提示的开关

    public Position player; // 玩家所处位置

    public MazeData(String filename){
        if (filename == null)
            throw new IllegalArgumentException("Filename can not be null!");

        Scanner scanner = null;
        try {
            File file = new File(filename);
            if (!file.exists())
                throw new IllegalArgumentException("File " + filename + " doesn't exist");

            FileInputStream fis = new FileInputStream(file);
            scanner = new Scanner(new BufferedInputStream(fis), "UTF-8");

            // 读取第一行
            String nmline = scanner.nextLine();
            String[] nm = nmline.trim().split("\\s+");    // 正则 匹配任意空白字符
            N = Integer.parseInt(nm[0]);
            M = Integer.parseInt(nm[1]);

            maze = new char[N][M];
            visited = new boolean[N][M];
            path = new boolean[N][M];
            showPath = false;

            // 读取后续的N行
            for (int i = 0; i < N; i ++){
                String line = scanner.nextLine();

                // 每行保证有M个字符
                if(line.length() != M)
                    throw new IllegalArgumentException("Maze file " + filename + " is invalid");

                for (int j = 0; j < M; j ++) {
                    maze[i][j] = line.charAt(j);
                    visited[i][j] = false;
                    path[i][j] = false;
                }
            }
        }
        catch (IOException e){
            e.printStackTrace();
        }
        finally {
            if (scanner != null)
                scanner.close();
        }
        // 入口,第二行第一列
        entranceX = 1;
        entranceY = 0;
        // 出口,倒数第二行最后一列
        exitX = N - 2;
        exitY = M - 1;
    }

    public int N(){ return N; }
    public int M(){ return M; }
    public int getEntranceX(){return entranceX;}
    public int getEntranceY(){return entranceY;}
    public int getExitX(){return exitX;}
    public int getExitY(){return exitY;}
    public char getMaze(int i, int j){
        if (!inArea(i, j))
            throw new IllegalArgumentException("i or j is out of index in getMaze!");

        return maze[i][j];
    }

    // 判断点(x,y)是否在迷宫中
    public boolean inArea(int x, int y){
        return x >= 0 && x < N && y >= 0 && y < M;
    }
    // 控制台打印迷宫
    public void print(){
        System.out.println(N + " " + M);
        for(int i = 0 ; i < N ; i ++){
            for(int j = 0 ; j < M ; j ++)
                System.out.print(maze[i][j]);
            System.out.println();
        }
        return;
    }
}

将迷宫的各个位置封装成一个类 Position.java,便于操作

public class Position {

    private int x, y;

    public Position(int x, int y, Position prev){
        this.x = x;
        this.y = y;
    }

    public Position(int x, int y){
        this(x, y, null);
    }

    public int getX(){ return x; }
    public int getY(){ return y; }

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

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

}

视图层

AlgoFrame.java 是绘制界面的核心代码,使用java的JFrame控件,在上面添加JPanel画板,在JFrame中定义渲染方法render来调用画板的 paintComponent 方法实现绘制,其中需要用到自己定义的绘制辅助类 AlgoVisHelper.java,在里面封装了绘制矩形,设置画笔颜色,停顿等方法,也定义了一些颜色,也可以不用定义该辅助类而直接在 AlgoFrame.java 中使用awt包中的各种方法直接实现,如有需要可自行下载代码。

import java.awt.*;
import javax.swing.*;

public class AlgoFrame extends JFrame{

    private int canvasWidth;
    private int canvasHeight;

    public AlgoFrame(String title, int canvasWidth, int canvasHeight){

        super(title);

        this.canvasWidth = canvasWidth;
        this.canvasHeight = canvasHeight;

        AlgoCanvas canvas = new AlgoCanvas();
        setContentPane(canvas);
        pack();

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setResizable(false);

        setVisible(true);
    }

    public AlgoFrame(String title){

        this(title, 1024, 768);
    }

    public int getCanvasWidth(){return canvasWidth;}
    public int getCanvasHeight(){return canvasHeight;}

    private MazeData data;
    public void render(MazeData data){
        this.data = data;
        repaint();
    }

    private class AlgoCanvas extends JPanel{

        public AlgoCanvas(){
            // 双缓存
            super(true);
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);

            Graphics2D g2d = (Graphics2D)g;

            // 抗锯齿
            RenderingHints hints = new RenderingHints(
                    RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
            hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            g2d.addRenderingHints(hints);

            // 具体绘制
            int w = canvasWidth / data.M(); // 宽
            int h = canvasHeight / data.N();// 高

            for (int i = 0; i < data.N(); i ++){
                for (int j = 0; j < data.M(); j ++){
                    if (data.getMaze(i,j) == MazeData.WALL)
                        AlgoVisHelper.setColor(g2d, AlgoVisHelper.LightBlue);
                    else
                        AlgoVisHelper.setColor(g2d, AlgoVisHelper.White);

                    if (data.path[i][j] && data.showPath == true)
                        AlgoVisHelper.setColor(g2d, AlgoVisHelper.Yellow);

                    if (data.player.getX() == i && data.player.getY() == j)
                        AlgoVisHelper.setColor(g2d, AlgoVisHelper.Red);

                    AlgoVisHelper.fillRectangle(g2d, j*w, i*h, w, h);
                }
            }
        }

        @Override
        public Dimension getPreferredSize(){
            return new Dimension(canvasWidth, canvasHeight);
        }
    }
}

控制层

主函数 AlgoVisualizer.java ,其中在程序运行最开始时采用了基于递归的DFS算法将迷宫的解事先求出,用户按下空格则可以实现提示功能,红色表示玩家,键盘上下左右控制四个方向的移动。run()方法实现了所有的动画逻辑

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

public class AlgoVisualizer {

    private static int DELAY = 10;
    private static int blockSide = 8;

    private MazeData data;
    private AlgoFrame frame;

    private static final int d[][] = {{-1,0},{0,1},{1,0},{0,-1}}; // 四个方向移动

	public AlgoVisualizer(String mazeFile){
	    // 初始化数据
        data = new MazeData(mazeFile);

        int sceneHeight = data.N() * blockSide;
        int sceneWidth = data.M() * blockSide;

        // 初始化视图
        EventQueue.invokeLater(() -> {
            frame = new AlgoFrame("Maze Solver Visualization", sceneWidth, sceneHeight);
            frame.addKeyListener(new AlgoKeyListener());
            new Thread(() -> {
                run();
            }).start();
        });
    }

    public void run(){
	    setData(-1, -1, false);

	    data.player = new Position(data.getEntranceX(), data.getEntranceY());

        // 递归实现
        if(!autoGo(data.getEntranceX(), data.getEntranceY()))
            System.out.println("The maze has NO solution!");

        System.out.println("初始化已完成");

	    while (true){
            frame.render(data);
            AlgoVisHelper.pause(DELAY);
            setData(-1, -1, false);

            if (data.player.getX() == data.getExitX() && data.player.getY() == data.getExitY()){
                System.out.println("游戏结束");
                frame.render(data);
                AlgoVisHelper.pause(DELAY);
                break;
            }
        }
	    setData(-1, -1, false);
    }

    // 返回值:求解是否成功
    private boolean autoGo(int x, int y){
        if(!data.inArea(x,y))
            throw new IllegalArgumentException("x,y are out of index in go function!");

        data.visited[x][y] = true;
        setData(x, y, true);

        if (x == data.getExitX() && y == data.getExitY())
            return true;

        for (int i = 0; i < 4; i ++){
            int newX = x + d[i][0];
            int newY = y + d[i][1];
            if (data.inArea(newX, newY) &&
                    data.getMaze(newX, newY) == MazeData.ROAD &&
                    !data.visited[newX][newY]){
                if (autoGo(newX, newY))
                    return true;
            }
        }
        setData(x, y, false);
        return false;
    }

    private void setData(int x, int y, boolean isPath){
	    if (data.inArea(x, y))
            data.path[x][y] = isPath;
    }

    private class AlgoKeyListener extends KeyAdapter{
	    @Override
        public void keyPressed(KeyEvent event){
	        if (event.getKeyCode() == KeyEvent.VK_LEFT){
	            System.out.println("go left");
                oneStep(data.player.getX(), data.player.getY(), 3);
            }
            else if (event.getKeyCode() == KeyEvent.VK_DOWN){
                System.out.println("go down");
                oneStep(data.player.getX(), data.player.getY(), 2);
            }
            else if (event.getKeyCode() == KeyEvent.VK_RIGHT){
                System.out.println("go right");
                oneStep(data.player.getX(), data.player.getY(), 1);
            }
            else if (event.getKeyCode() == KeyEvent.VK_UP){
                System.out.println("go up");
                oneStep(data.player.getX(), data.player.getY(), 0);
            }
            else if (event.getKeyChar() == ' '){
                System.out.println("显示提示");
                data.showPath = !data.showPath;
            }
        }
    }

    private void oneStep(int x, int y, int direction){
        int newX = x + d[direction][0];
        int newY = y + d[direction][1];
        if (data.inArea(newX, newY) &&
                data.getMaze(newX, newY) == MazeData.ROAD){
            data.player.setX(newX);
            data.player.setY(newY);
        }
    }

    public static void main(String[] args) {
        String mazefile = "maze_101_101.txt";
        AlgoVisualizer vis = new AlgoVisualizer(mazefile);
    }
}

到此这篇关于Java实现可视化走迷宫小游戏的示例代码的文章就介绍到这了,更多相关Java走迷宫游戏内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java递归实现迷宫游戏

    目录 1.问题由来 2.问题的描述 3.思路分析 4.代码实现 5.结果输出 1.问题由来 迷宫实验是取自心理学的一个古典实验.在该实验中,把一只老鼠从一个无顶大盒子的门放入,在盒中设置了许多墙,对行进方向形成了多处阻挡.盒子仅有一个出口,在出口处放置一块奶酪,吸引老鼠在迷宫中寻找道路以到达出口.对同一只老鼠重复进行上述实验,一直到老鼠从入口到出口,而不走错一步.老鼠经多次试验终于得到它学习走迷宫的路线. 2.问题的描述 有一个迷宫地图,有一些可达的位置,也有一些不可达的位置(障碍.墙壁.边界)

  • Java实现经典游戏复杂迷宫

    目录 前言 主要设计 功能截图 代码实现 总结 前言 人类建造迷宫已有5000年的历史.在世界的不同文化发展时期,这些奇特的建筑物始终吸引人们沿着弯弯曲曲.困难重重的小路吃力地行走,寻找真相.迷宫类小游戏应运而生.在游戏中,迷宫被表现为冒险舞台里,藏有各式各样奇妙与谜题或宝藏的危险区域.型态有洞窟.人工建筑物.怪物巢穴.密林或山路等.迷宫内有恶徒或凶猛的生物(真实存在或想像物体都有)徘徊,其中可能会有陷阱.不明设施.遗迹等. <复杂迷宫>游戏是用java语言实现,采用了swing技术进行了界面

  • Java小项目之迷宫游戏的实现方法

    项目要求: 一个网格迷宫由n行n列的单元格组成,每个大院个要么是空地(用0表示),要么是障碍物(用1表示),你的任务是找一条从起点到终点的移动序列,其中只能上下左右移动到相邻单元格.任何时候都不能在有障碍物的单元格中,也不能走到迷宫之外,起点为左上角和终点右下角. 项目功能: 解决迷宫路径查找问题,寻找一条从左上角迷宫入口到右下角迷宫出口的一条有效路径,0代表可走,1代表能走,找到请输出最终的迷宫和路径信息,找不到请输出不存在有效路径. 思路: 1.定义一个迷宫节点类型(MazeNode)的二维

  • Java实现简单的迷宫游戏详解

    目录 前言 主要设计 功能截图 代码实现 窗口布局 核心算法 总结 前言 人类建造迷宫已有5000年的历史.在世界的不同文化发展时期,这些奇特的建筑物始终吸引人们沿着弯弯曲曲.困难重重的小路吃力地行走,寻找真相.迷宫类小游戏应运而生.在游戏中,迷宫被表现为冒险舞台里,藏有各式各样奇妙与谜题或宝藏的危险区域.型态有洞窟.人工建筑物.怪物巢穴.密林或山路等.迷宫内有恶徒或凶猛的生物(真实存在或想像物体都有)徘徊,其中可能会有陷阱.不明设施.遗迹等. <简单迷宫>游戏是用java语言实现,采用了sw

  • Java实现的迷宫游戏

    完整项目地址: https://github.com/richenyunqi/Maze-game 软件总体框架 该软件主要分为如下三个模块: 参数设置模块 按钮功能模块按钮功能模块 迷宫主界面模块迷宫主界面模块 软件各模块介绍 参数设置模块 1.迷宫大小相关参数: ROWS(即迷宫行数,默认设置为奇数,最小值为11,最大值为99,默认值为11): COLS(即迷宫列数,默认设置为奇数,最小值为11,最大值为99,默认值为11): Lattice's width(即组成迷宫的格子的宽度,迷宫格子默

  • Java编写迷宫小游戏

    缘起: 去年(大三上学期)比较喜欢写小游戏,于是想试着写个迷宫试一下. 程序效果: 按下空格显示路径: 思考过程: 迷宫由一个一个格子组成,要求从入口到出口只有一条路径. 想了一下各种数据结构,似乎树是比较合适的,从根节点到每一个子节点都只有一条路径.假设入口是根节点,出口是树中某个子节点,那么,从根节点到该子节点的路径肯定是唯一的. 所以如果能构造一棵树把所有的格子都覆盖到,也就能够做出一个迷宫了. 另外还要求树的父节点和子节点必须是界面上相邻的格子. 在界面显示时,父节点和子节点之间共用的边

  • Java实现可视化走迷宫小游戏的示例代码

    目录 效果图 数据层 视图层 控制层 效果图 数据层 本实例需要从 .txt 文件中读取迷宫并绘制,所以先来实现文件读取IO类 MazeData.java,该程序在构造函数运行时将外部文件读入,并完成迷宫各种参数的初始化,注意规定了外部 .txt 文件的第一行两个数字分别代表迷宫的行数和列数.此外还提供了各类接口来读取或操作私有数据. import java.io.BufferedInputStream; import java.io.File; import java.io.FileInput

  • 基于Unity3D实现3D迷宫小游戏的示例代码

    目录 一.前言 二.构思 三.正式开发 3-1.搭建场景 3-2.设置出入口 3-3.添加角色 3-4.实现角色移动 3-5.出入口逻辑 四.总结 一.前言 闲来无事,从零开始整个<3D迷宫>小游戏. 本篇文章会详细介绍构思.实现思路,希望可以帮助到有缘人. 二.构思 首先,要实现一个小游戏,心里肯定要有一个大概的想法,然后就是将想法完善起来. 我的想法就是一个用立体的墙搭建的迷宫,然后控制人物在迷宫中移动,最后找到出口,就这么简单. 当然,这是一个雏形,比如可以加点音效.背景.关卡.解密等.

  • C++实现走迷宫小游戏

    本文实例为大家分享了C++实现走迷宫小游戏的具体代码,供大家参考,具体内容如下 源码下载:C++实现走迷宫小游戏 主程序代码: #include<conio.h> #include<stdlib.h> #include<time.h> #include<string.h> #include<windows.h> #include<iostream> using namespace std; char pr[10]={1,' ','E'

  • C语言键盘控制走迷宫小游戏

    本文实例为大家分享了C语言键盘控制走迷宫小游戏的具体代码,供大家参考,具体内容如下 在看了<啊哈C语言>之后想写一个游戏demo 游戏的截图 首先是启动界面 然后是初始化 接下来是键盘操控 地图的复杂度也很容易修改. 也支持退出.按s键选择退出游戏这个选项即可. 下面是源代码 #include <stdio.h> #include <stdlib.h> void startUp(); void gameInstructions(); void menu(char c);

  • JS实现的走迷宫小游戏完整实例

    本文实例讲述了JS实现的走迷宫小游戏.分享给大家供大家参考,具体如下: 先来看看运行效果截图: 完整实例代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml

  • Java实现接月饼小游戏的示例代码

    目录 前言 主要设计 功能截图 代码实现 游戏启动类 核心类 画面绘制 总结 前言 <接月饼小游戏>是一个基于java的自制游戏,不要被月亮砸到,尽可能地多接月饼. 此小项目可用来巩固JAVA基础语法,swing的技巧用法. 主要设计 设计游戏界面,用swing实现 设计背景 设计得分物体-月饼,碰到加一分 设计障碍物-月亮,碰到会死亡 监听鼠标的左右键,用来控制篮子左右移动 设计积分系统 将resource文件夹设为resource(Project Manage中可以设置),因为要用里面的图

  • Java实现贪吃蛇大作战小游戏的示例代码

    目录 效果展示 项目介绍 项目背景 总体需求 实现过程 代码展示 项目结构 总结 大家好,今天尝试用swing技术写一个贪吃蛇大作战小游戏,供大家参考. 效果展示 效果展示 一.游戏界面 二.得分情况 项目介绍 项目背景 “贪吃蛇大作战”游戏是一个经典的游戏,它因操作简单.娱乐性强,自从计算机实现以来,深受广大电脑玩家的喜爱,本项目基于Java技术,开发了一个 操作简单.界面美观.功能较齐全 的“贪吃蛇”游戏.通过本游戏的开发,达到学习Java技术和熟悉软件开发流程的目的. 总体需求  本系统主

  • JS+Canvas实现接球小游戏的示例代码

    目录 写在最前 git地址 成果展示 实现思路 详细说明 写在最后 写在最前 看了canvas的动画系列,已经抑制不住内心的冲动想写个小游戏了,还是那个套路——多写写,你才能了解它.加上这两天下班后我都没有机会去摸摸篮球,所以就写了个接球的小游戏(准确的说不能叫游戏,太简单了,叫动画吧...). 都是一些基础的实现,有时间你也可以试试,废话说到这里,我们开始吧. git地址 https://github.com/ry928330/ballGame.git 成果展示 实现思路 这里我们采用疑问的句

  • C语言实现扫雷小游戏的示例代码

    目录 一.扫雷 1.演示效果 2.完整代码 二.代码解析 1.初始化雷盘 2.打印雷盘 3.布置雷 4.排雷 5.游戏函数主体 6.菜单函数 7.头文件.宏定义及主函数 一.扫雷 扫雷小游戏主要是利用字符数组.循环语句和函数实现. 设计思路:雷盘大小为9*9,但是为了后续能更好的统计出雷的个数在定义数组的时候定义大小为11*11,先定义两个字符数组,一个用来记录雷的位置,另一个用来展现给玩家,初始化雷盘,将两个字符数组分别全部赋值为字符0和字符*,打印棋盘,随机设置雷所在位置,根据玩家输入的坐标

  • Java实现升级版布谷鸟闯关游戏的示例代码

    目录 前言 主要设计 功能截图 代码实现 游戏启动类 核心类 线程类用于重复绘图 总结 前言 <布谷鸟闯关-升级版>是一个基于java的布谷鸟闯关游戏,鼠标左键点击控制鸟的位置穿过管道间的缝隙,需要做碰撞检测,监听键盘事件,背景图片的切换,障碍物管道产生时y轴上需要随机位置. 主要设计 1.设计游戏界面,用swing实现 2.设计背景 3.设计移动墙 4.设计布谷鸟 5.设计障碍物 6.设计背景音乐和音效 7.新增用户账号注册登录功能 8.引用mysql数据库,管理用户账号密码和储存排行榜等信

随机推荐