百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

怎样用JavaScript开发一个Web版的迷宫游戏?这是第二讲。

myzbx 2025-05-15 20:01 2 浏览

上篇,我们讲了更新画布尺寸,以及网格,出入口位置,可移动对象的生成。这篇,我们接上一篇,给大家讲下迷宫图的生成和游戏界面绘制。

生成迷宫图

迷宫图是由墙和走廊构成的,我们需要将墙打通,形成一条入口到出口的通路,这就需要一种算法来实现,我这里采用的是深度优先查找算法。具体什么是深度优先查找算法,大家可以自行头条搜索,我就不过多介绍了。

我是这样实现的:首先初始化几个变量,

  • curCell 当前遍历的目标墙(以下简称当前墙),我们取网格中的第一道墙给它
  • history 访问过一次的墙构成的数组
  • getWall 根据墙,获取相邻墙的函数

然后,我们根据当前墙,随机打通一道它的相邻墙,然后把打通的那道墙作为当前墙。在循环中,我们不断地将当前墙压入历史数组,当找不到可打的墙时,就从历史中弹出最后一道墙作为当前墙,这样一直循环,直到历史被清空,结束循环。

private genMap () {
    const startTime = Date.now()
    let curCell: Block = this.grid[0][0]
    const history: Block[] = [curCell]
    const { TOP, RIGHT, BOTTOM, LEFT } = Direction
    const getWall = (cell: Block, dir: Direction) => this.getBlock(cell, dir, BlockType.WALL)
    while (history.length) {
      curCell.flag = true
      const tCell = this.getBlock(curCell, TOP)
      const rCell = this.getBlock(curCell, RIGHT)
      const bCell = this.getBlock(curCell, BOTTOM)
      const lCell = this.getBlock(curCell, LEFT)
      const cells = [tCell, rCell, bCell, lCell].filter(_ => _ && !_.flag)
      if (cells.length) {
        history.push(curCell)
        const rndCell = cells[getRandInt(0, cells.length - 1)]
        let wall
        if (rndCell === tCell) {
          wall = getWall(curCell, TOP)
          curCell = tCell
        } else if (rndCell === rCell) {
          wall = getWall(curCell, RIGHT)
          curCell = rCell
        } else if (rndCell === bCell) {
          wall = getWall(curCell, BOTTOM)
          curCell = bCell
        } else {
          wall = getWall(curCell, LEFT)
          curCell = lCell
        }
        wall.type = BlockType.CELL
      } else {
        curCell = history.pop() as Block
      }
    }
    console.log(Date.now() - startTime)
  }

获取墙的坐标

我们的墙是根据行和列确定位置的,但是,绘制到画布上时,需要将行列转化为笛卡尔坐标系中的xy坐标。

画布的坐标原点在左上角,向右是x轴正方向,向下是y轴正方向,这和数学上的坐标系有一些差异。

private getWallCoord (wall: Block) {
    let x1
    let y1
    let x2
    let y2
    const { row, col } = wall
    const { wallWidth, cellWidth } = this
    const space = wallWidth + cellWidth
    if (row % 2) {
      if (col % 2) return
      x1 = col / 2 * space - wallWidth / 2
      y1 = y2 = (row + 1) / 2 * space
      x2 = x1 + space + wallWidth
    } else {
      x1 = x2 = (col + 1) / 2 * space
      y1 = row / 2 * space - wallWidth / 2
      y2 = y1 + space + wallWidth
    }
    return { x1, y1, x2, y2 }
  }

绘制游戏界面

我采用的双画布绘制,可移动目标单独绘制在一张画布上,其它静止的对象绘制在另一张画布上。目标移动过程中,需要不断重绘画布。这样做有一个好处,就是可以大幅减少计算量和重绘次数,这可以提高性能,因为我们仅需重绘可移动目标所在的画布。

绘制游戏界面之前,需要先将画布擦干净,然后进行一系列对象的绘制。流程是:

  1. 绘制入口
  2. 保存画布状态
  3. 绘制迷宫图
  4. 恢复上次保存的状态
  5. 绘制出口
  6. 绘制可移动目标,独享一张画布
private drawUI () {
    const { cvs, ctx, wallWidth } = this
    ctx.clearRect(0, 0, cvs.width, cvs.height)
    this.drawStartPosition()
    ctx.save()
    ctx.strokeStyle = this.wallColor
    ctx.lineWidth = wallWidth
    ctx.strokeRect(wallWidth / 2, wallWidth / 2, cvs.width - wallWidth, cvs.height - wallWidth)
    this.grid.forEach(rows => {
      rows.forEach(_ => {
        if (_.type === BlockType.WALL) {
          const coord = this.getWallCoord(_)
          if (coord) {
            ctx.beginPath()
            ctx.moveTo(coord.x1, coord.y1)
            ctx.lineTo(coord.x2, coord.y2)
            ctx.stroke()
          }
        }
      })
    })
    ctx.restore()
    this.drawEndPosition()
    this.drawBall()
  }

本篇文章到此就结束了,童鞋们都理解了吗?下一讲,下篇见!感谢阅读!

#头条创作挑战赛##前端##程序员##JavaScript#

相关推荐

js实现一款简单踩白块小游戏(曾经很火)

效果图如下所示:htmljscss总结以上所述是小编给大家介绍的js实现一款简单踩白块小游戏,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对小编的支持!...

腾讯游戏健康系统怎么解除 腾讯游戏健康系统解除解绑官网

[海峡网]腾讯游戏健康系统怎么解除?腾讯游戏健康系统解除解绑官网是多少?不少玩家都想解除腾讯游戏健康系统!那么是否有方法呢?下面,就来看看官方是怎么说的吧!腾讯游戏健康系统怎么解除?目前腾讯游戏健康系...

Grok 现在可以生成文档、代码和浏览器游戏

xAI宣布新增一款名为“GrokStudio”的新工具,该工具允许用户创建和编辑文档及代码,甚至可以生成基本的浏览器游戏。该公司在其官方X账号的一篇文章中表示,该功能可供Grok.com上的免...

世界首款程序猿专属游戏公布 地狱级难度让人抓狂!

似乎大家对于程序员的印象都很固定,如果硬要用一个词来形容这份工作,“苦逼”肯定可以入选,关于这些IT从业人员的段子也是一抓一大把,在这里就不再伤害那些网络工程师脆弱的小心灵了,近日一款专门为这些程序...

游戏开发之旅-JavaScript原型类构建

本节是第四讲的第十五小节,上一节我们为大家介绍了JavaScript面向对象编程(OOP)的基础概念,本节为大家介绍原型链的原理以及如何构造原型类。基于原型的语言(Prototype-BasedLa...

打游戏了!解锁编程学习新姿势,极空间部署『CodeCombat』

打游戏了!解锁编程学习新姿势,极空间部署『CodeCombat』哈喽小伙伴们好,我是Stark-C~这几年的AI大火,让大家再次看到了互联网科技的神奇与魅力。考虑到今后各大行业的发展方向,编程已成为许...

DeepSeek如何写在线游戏?附带提示词,直接拿去用!

想做一个属于自己的小游戏网站?不会写代码也没关系,现在你只需要一个工具:DeepSeek大模型!它不仅能帮你写网页,还能一口气搞定贪吃蛇、2048、飞机大战等小游戏!关键是:完全免费,还能中文交流!新...

微信小游戏的开发方式及特点

微信小游戏是基于微信小程序的一个新增类目,它结合了H5游戏和微信社交的优势,为开发者提供了一个快速、便捷的开发游戏平台。北京木奇移动技术有限公司,专业的软件外包开发公司,欢迎交流合作。开发方式微信小游...

DeepSeek最新玩法,5分钟搭建html实用工具

大家好,我是程序员小灰。说起AI编程,早已不是一个新鲜的概念。早在2023年初,小灰就曾经尝试利用GPT-4帮我生成Python小游戏的代码。到了2024年,随着Cursor等AI编程工具的兴起,AI...

网页游戏的开发流程

网页游戏的开发流程可以根据项目的规模和复杂性而有所不同,但通常包括以下一般步骤,希望对大家有所帮助。北京木奇移动技术有限公司,专业的软件外包开发公司,欢迎交流合作。1.需求分析:确定游戏的概念、目标受...

最热的第三人称射击单机游戏分享

在这个快节奏的时代,第三人称射击游戏已经成为了许多玩家的最爱。而单机游戏更是其中的佼佼者,它们拥有着更加丰富的情节和精美的画面。今天我们要分享的是一款最热的第三人称射击单机游戏。这款游戏名为《使命召唤...

十款免费的第三人称射击单机游戏分享

本文将为大家推荐十款免费的第三人称射击单机游戏,这些游戏不仅免费,而且质量上乘,值得玩家们一试。从经典之作到新近大作,从PC端到移动平台,涵盖了各种类型和风格的游戏。无论你是喜欢动作射击还是喜欢策略战...

推荐一些有趣的在线编程游戏,让你学习编程事半功倍

▌Robocode让坦克们互相博弈的游戏,你可以看到它们飞奔,碾碎一切挡道的东西。机器人配有雷达与火炮,选手在躲避对手进攻的同时攻击对手,以此来较量得分的多少。这个游戏很有意思,曾经令我沉迷…你可以用...

用DEEPSEEK 写的小游戏,直接运行太牛了!~

由于DEEPSEEK服务器繁忙,通过OLLAMA来部署各种大模型都可以,电脑配置不够高,能用DEEPSEEKR114B,也只能在CMD下运行,AI可视化软件Chatbox跑不动,具体写内容如下&g...

2021年游戏项目的十大编程语言:C++、Java、Net均上榜

前两天在某平台刷到了大家讨论腾讯游戏相关开发是不是真的薪资很高,然后就看到了Analticslnsight发布关于2021年游戏项目的十大编程语言。C++C++的效率做游戏是一个很重要的原因,近年来...