学习5 游戏中的人工智能(迷宫寻宝)

说明:

<学习>系列所有的源代码均由《计算机游戏程序设计》提供。本人会在这些代码中融入自己的想法,对其进行迭代优化,旨在个人学习。

 

实现效果:

(因为雾效粒子太逼真导致gif动图随便一录就几十M,而博客里只能上传5m以下的图……费劲功夫减时长 减帧数 减质量才弄出一张……)

 

学习目标:

1. 理解A*寻路算法原理。

2. 进一步熟悉地图编辑器的使用。

3. 实现游戏中的人工智能。

主要修改内容:

1.修改窗口大小。

2增加“危险”区域,自动寻路过程中路过即死。

3.增加重新开始游戏功能。

4.增加自动生成地图功能,以实现“是男人就下100层”玩法。

三、实验步骤与过程

1.完成游戏编译

老套路编译运行游戏:

图 1

2.修改窗口大小

AppDelegate.cpp文件中修改自设窗口大小为1024*768,游戏窗口尺寸刚好。

图 2

再次运行游戏,成功容纳所有游戏内容:

图 3

 

3.增加“危险”区域

用TiledMap编辑原地图,进行些许改动并加上“墓碑”(ID为290),如下图红框内所示:

图 4

 

为实现以下功能:

  • 当玩家宝藏设置在“墓碑”处,或途径“墓碑”,屏幕中央提示“Dangerous!”信息
  • 当玩家到达“墓碑”处时,“笑脸”角色会停在“墓碑”处,屏幕中央“Dangerous!”改换显示为“Die!”,此时点击屏幕没有反应。
  • 如果“宝箱”刚好在“墓碑”处,则当“笑脸”角色到达时,“宝箱”也会消失,但是不会显示“Found Treasure!”。

下面介绍两种实现原理:

  • 算路径时就判断检测该路径上是否有“墓碑”,有则提示“Dangerous!”; 设置“墓碑”为精灵,在update函数中不断检验“笑脸”精灵是否和“墓碑”精灵相碰,相碰则通过用stopActionByTag等方法停止角色运动,判断为角色死亡。
  • 算路径时就判断检测该路径上是否有“墓碑”,有则提示“Dangerous!”; 在为“笑脸”角色决定运动路径时就只加入遇到“墓碑”前的路径即可(白色的预测路径的线段还是完整的),因此实际运动时的目标点为途经的“墓碑”,如果到达“墓碑”则角色死亡。

下面用第二种方法来实现这一部分功能:

moveOnPath函数:

图 5

 

Judge函数:

图 6

 

4.增加重新开始游戏功能

下面添加键盘按键监听事件,按Z键重启游戏。

代码为:

图 7

5 . 自动生成地图

下面在原Demo基础上实现一个“是男人就下100层”的游戏,但实际上不可能去用TiledMap绘制100层地图。所以除了第一二层地图外,第三层以下的地图采用“自动生成随机地图”系统来实现。

 

下面介绍“自动生成随机地图”原理:

(由于网上已经有很成熟的该算法基础原理,下面引用网上的原理图来进行讲解。引用图网址为:https://zhuanlan.zhihu.com/p/27381213)

① 先生成基础大地图。下图中灰色格子“0”代表墙,黄色格子“1”代表通路。可见墙的格子一般要比路的格子多。

图 9

 

② 选择一个黄色格子“1”为起点,并且把该点涂红,红色表示已被检测并可联通的通路(见下图标为“起”的红色格子);然后在它的周围随机找另一个黄色的1(这里的“周围”指的是上下左右4个方向,斜边不算),找到后则把该格子、以及两格子间的灰色格子“0”一起“打通”涂为红色,此时它们就算是被确认的红色“通路”。

图 10

 

③ 一直重复②的过程,直到类似下图这种“找不到下一个黄色1的格子”的情况:

图 11

 

④ 这时候,原路往回走(即不停去找前一个格子),直到找到一个格子,这个格子周围有黄色的1,那么从这个格子开始重复②的步骤。

图 12

 

⑤ 重复以上的过程,直到最终填充完整个地图,并记录最后一个到达的终点即可。

图 13

 

代码实现要点:

  • 第三层后,取消掉“向上的楼梯”,只保留“向下的楼梯”。而角色的起始点位置为上一层楼梯的位置。因此,编写上述原理第①步的代码生成基础大地图时,要调整代码使角色的起始位置在“路”上,而不是在“墙”上。否则后续代码还要判断许多种情况,带来麻烦。
  • 路径关系通过节点间的parent属性决定,确定谁是谁的parent,而parent属性为nullptr的则表示当前格还没被检验。
  • 随机生成地图路径过程中不断记录当前被拓展的最新格子。直到地图生成完毕后,记录的该格子将被设置为“终点”格子。
  • “墙”“楼梯”“墓碑”都是由图片精灵组成的。
  • “墓碑”随机生成0~3个。为保证“起点”到“终点”的路径一定是安全无阻的,“墓碑”一定不能被设置在这主路径上。实现方法可以为随机生成“墓碑”坐标后,判断该“墓碑”坐标是否在这条安全的路径上。(“终点”通过parent属性回溯到“起点”)。

 

代码为:

对应上文“随机生成地图”原理的第①步的initRandMap方法:

图 14

    对应上文“随机生成地图”原理的②~④步的createRandMap方法:

图 15

 

绘制随机地图的函数drawRandMap:

图 16

 

随机生成的地图:

图 17

图 18

 

 

6 . 其他新增项

  • 修改了源代码中“点击角色屏幕会出现‘NO WAY’的BUG”(只需判断点击的是否为角色,如果是的话不执行寻路算法即可,不细述)

 

  • 修改了源代码“笑脸”和“宝箱”间的碰撞方式 以及 图片尺寸。  因为update函数中的碰撞方式为“俩精灵”sprite碰撞,按原代码逻辑,精灵碰撞后则视为“笑脸找到宝箱,运动结束”并执行后续代码,但是,假设精灵间只是刚好接触到边,也算是产生了碰撞,而此时“笑脸”精灵并没有完全停止运动。代码逻辑矛盾,容易引发错误。因此碰撞检测方案更改为“精灵坐标中心相等”。    又由于“笑脸”和“宝箱”和普通格子的边长都是32*32比例,因此,在原有的碰撞检测方法中,“笑脸”只要在“宝箱”旁边的一个格子时,就算是发生碰撞了(边相触了),因此,图片可适当改为30*30大小。

图 19

 

  • 为增加趣味性,修改原“笑脸”图片,并且角色在“NO WAY”状态时,“笑脸”变为“喷口水脸”。角色在“DIE”状态时,“笑脸”变为“吓哭脸”。

“滑稽笑脸”:

“喷水脸”:

“哭脸”:

 

  • 增加背景音乐,并且可通过右下角的“开关按钮”来控制背景音乐的有无。

    代码:

图 20

图 21

 

    见右下角开关:

图 22

  • 增加音效。 添加在上下楼梯,与死亡时的音效。

图 23

 

  • 增加粒子系统。 particle2dx在线编辑粒子效果,实现“雾气”粒子特效,为游戏增加阴深神秘感。

    初始化函数init中:

图 24

 

演示效果:

图 25

  • 为场景切换添加2种随机特效(如上下楼、重启游戏)。

图 26

 

  • 每层开始时都提示当前层数,突破100层时会有成功提示。(层数提示数秒会自动消失)

图 27

图 28

  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
基于强化学习迷宫寻宝是一种常见的强化学习应用。在这个应用,智能体需要在迷宫找到宝藏,并且需要尽可能快地找到它。在这个过程,智能体需要学习如何在迷宫移动,以及如何在不同的位置上采取不同的行动。这个过程可以通过两种不同的强化学习算法来实现:Sarsa和Q-Learning。 Sarsa算法是一种在线学习算法,它可以在智能体与环境交互的同时进行学习。在Sarsa算法,智能体会根据当前状态和行动来更新它的策略,并且会在下一个状态和行动使用这个策略。这个过程会一直持续到智能体找到宝藏或者达到了最大的迭代次数。 Q-Learning算法是一种离线学习算法,它可以在智能体与环境交互之后进行学习。在Q-Learning算法,智能体会根据当前状态和行动来更新它的价值函数,并且会在下一个状态选择最大的价值函数来更新策略。这个过程会一直持续到智能体找到宝藏或者达到了最大的迭代次数。 下面是一个基于Sarsa算法的迷宫寻宝的Python代码示例: ```python import numpy as np # 定义迷宫 maze = np.array([ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 0, 1, 1, 1, 0, 1, 0], [0, 1, 1, 0, 1, 0, 1, 0, 1, 0], [0, 1, 1, 0, 1, 0, 1, 0, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0, 1, 0], [0, 1, 0, 0, 0, 0, 1, 0, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 1, 0, 0, 0, 0, 1, 0, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] ]) # 定义起点和终点 start = (1, 1) end = (8, 8) # 定义动作和策略 actions = ['up', 'down', 'left', 'right'] policy = np.zeros((10, 10, 4)) q_table = np.zeros((10, 10, 4)) # 定义参数 alpha = 0.1 gamma = 0.9 epsilon = 0.1 max_iter = 1000 # 定义Sarsa算法 def sarsa(): for i in range(max_iter): # 初始化状态和行动 state = start action = np.random.choice(actions) while state != end: # 选择行动 if np.random.uniform() < epsilon: action = np.random.choice(actions) else: action = actions[np.argmax(q_table[state[0], state[1]])] # 更新状态和行动 next_state = tuple(np.array(state) + np.array([0, -1]) * (action == 'up') + np.array([0, 1]) * (action == 'down') + np.array([-1, 0]) * (action == 'left') + np.array([1, 0]) * (action == 'right')) next_action = np.random.choice(actions) if np.random.uniform() < epsilon else actions[np.argmax(q_table[next_state[0], next_state[1]])] # 更新Q值 q_table[state[0], state[1], actions.index(action)] += alpha * (maze[next_state[0], next_state[1]] + gamma * q_table[next_state[0], next_state[1], actions.index(next_action)] - q_table[state[0], state[1], actions.index(action)]) # 更新状态和行动 state = next_state action = next_action # 运行Sarsa算法 sarsa() # 输出策略 for i in range(10): for j in range(10): policy[i, j, np.argmax(q_table[i, j])] = 1 print(policy[:, :, 0], '\n', policy[:, :, 1], '\n', policy[:, :, 2], '\n', policy[:, :, 3]) ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值