这些坑别踩!游戏随机地图生成开发经验分享

当时虽然简单实现了目的,但后来自己也感到世界地图的呈现并不十分完美,恐怕也就只值95分。为了精益求精且给自己找点事做,便想对大地图的呈现方式做些微调。
 

之前略有瑕疵的世界地图


为何选择2D?

素材好找,地图较大时绘制的开销也不会很大。

为何选择六边形瓦片?

组合种类多,且六边形的表现效果略好于四边形(个人感觉)。

其实,最主要的原因是木有素材,在Unity商店中找了一圈后发现选择实在不多,因此最终决定使用2D+六边形瓦片地图的表现形式。我是从素材出发调整项目,有点本末倒置实属无奈。
 


我选择了一套很精致的六边形瓦片,结合这套素材的特点,我对组成地图的瓦片进行了简单的分类。
 


使用上述瓦片组成的地图,除了具备了一般瓦片地图的特点外,还会根据地块间的连接情况,显示道路。

想要实现的目标

1、指定尺寸后生成地图,地图上随机分布着各种类型的地块。

2、英雄随机出生在城市里,会自己选择目的地并进行探索。

3、可通行的地块间有道路相连。

由于英雄的探索逻辑之前的文章已经阐述过,这里就不再赘述,本文重点介绍地图的随机生成。

请先看下最终随机生成的效果:
 

雪地

沼泽

森林

沙漠


名词解释

先做一下名词解释,以便后文理解:

格子:可想象为插地块的槽,如5x5的地图,在初始化时会有25个空的格子等待用地块填充。

地块:一个被确定了用途的格子,可以是一个城市、村庄或是一座山等,注意它只是数据,并不能直接显示。

瓦片:配合地块显示的图片,如这个地块是城市,便会在上面放置一个城市的六边形瓦片(图片)。

功能地块:城市、村庄、可探索地块。

普通地块:可以通行但并没有功能的地块,也是唯一可铺设道路的地块。

障碍地块:不可以通行也没有功能的地块。
 

配合图片更易理解


走过的弯路

起初,我的思路是:

1、随机生成若干障碍地块。

2、随机生成功能地块,并在生成时随机通行方向。

3、遍历1~2步生成的地块,围绕它们生成普通地块,并在生成时随机通行方向。

4、遍历所有普通地块,遍历时检查围绕它的六个地块,若周围地块存在道路,但无法与当前被遍历的地块连接(通过寻路器判断),则连接它们(通过寻路器连接),以保证所有地块之间都是相通的。
 

随机地图生成的步骤图

1~3:生成基本地块

4:连接地块

围绕中心生成普通地块并随机通行方向


存在的问题

地图虽然是随机生成,但是道路混乱,很多路口的连接毫无逻辑,与现实中道路的情况有差距。
 


通过上图不难发现,地图上总会存在些莫名其妙的岔路,不仅影响美观,同时会在一定程度上加大寻路的尝试次数。

经过几次尝试后,最终还是从鲁迅先生那里找到了一些灵感,想到了解决方法。

他是这样讲的:
 


不好意思,弄错了,应该是下面这句。
 


两个关键点:

1、道路的存在是为了连接目的地,因此不如尝试从结果出发。

2、人生并没有很多次可以选择的机会,只会在几个岔路口中作出选择,并一直走下去,直到终点。

调整后的生成步骤

1、随机若干城市、村庄、探索地块

从结果出发,生成一定数量的功能地块,随机分布在地图上。
 


2、随机若干岔路

注意,岔路是普通地块。
 


3、连接岔路和功能地块

遍历每个岔路,连接离它最近的城市、村庄或探索点。买二手游戏账号平台此举的目的是为了将整个地图分割成几个相对独立的小块,也保证了每个目的地只有一条通路可以到达。


4、清除没有连接功能地块的岔路

移除没有用到的岔路,是为了避免后期连接时出现太多道路分支。
 


5、就近连接岔路

将此前分割的几块小地图连接起来,我使用的方法是:遍历每一个岔路,并查找与其最近的普通地块,如果通过寻路无法到达,则连接它们。
 


6、做一次连接检测

选择从一个功能地块出发,尝试到达其他所有的功能地块,如果都可以联通即为通过;如果发现有联通失败的功能地块,可以选择找到连接这个功能地块的岔路,重新做一次步骤5,或重新随机生成一次地图。

7、补齐剩余的地块

遍历所有格子,找到没有填充地块的格子,全部填充为障碍地块。
 


8、根据地块类型及信息,铺设瓦片
 


连起来看一遍:
 


修改后的优点:每个功能地块只有一条路可以到达,地图整洁,分支少,也提升了寻路效率。
 


不足之处:
 


1、一些道路和功能地块的连接关系可能存在不自然,可通过设置每一种瓦片的通路方向解决这个问题。

2、在为障碍地块放置瓦片时风格过于零散,可通过调整随机方式或增加二级瓦片风格解决这个问题。
 

将不能玩的小游戏的大地图替换后的局部表现


至此,英雄可在新地图中愉快的玩耍了,他们很开心,就像过年了一样,恭喜。

其他

除了上述主要内容外,还有些琐事没有记录在正文内,就写在下面吧。

瓦片遮挡关系

本文跳过了很多内容,比如在铺设瓦片时如何调整瓦片间的遮挡关系。因为它们并非本文想要说明的重点,而且比较容易实现,就没有做详细的说明。我使用简单粗暴的SortingLayer+OrderInLayer的方法来控制,只是道路需要特殊处理一下,注意一下瓦片所在行即可。

寻路器

地图寻路器至少应该具备以下两个功能:

1、传统寻路

在已经铺设好地块的地图上进行寻路,并没有什么特别之处。

2、铺路

可以从目的地到终点进行铺路,在地图没有构建好之前会被经常使用,它的原理是在传统寻路中,对地块采用较特殊的处理方式:

当格子里有地块信息时,如果这个地块是功能地块,则统一认为是障碍地块,无法通行,以避免破坏之前生成的功能地块;

当格子里的地块是普通地块或没有地块信息时,则均认为是可以六向通行的普通地块。

铺路得到的结果,是考虑绕过了功能地块的最近路径,因为一个功能地块只能有一条通路到达;反之如果允许铺路结果通过功能地块,那么功能地块可能会变成一个岔路,看起来会很乱。

调用铺路的地方可根据寻路结果,按照路径及通路方向生成新的地块或重构普通地块的通路情况,以实现从目的地到终点的联通。
 


寻路的优化

在这我使用了A-Star寻路,六边形与四边形并没有什么差别,只是多了两条边而已。

网上有很多关于A-Star的介绍,这里就不再赘述,只是说一下我做的修改,可以稍微提高一些寻路速度。当然,如果你一点都不了解A-Star,跳过这段即可。

1、移除了关闭列表。

我为每个地块设置了一个通用的对象位置,这样在判断某一个地块是否为关闭时,只要尝试访问这个地块上保存的对象即可,可以减少一次遍历操作。

2、尝试记录一个此好的选择

在将一个地块周围的地块加入开启列表时,会尝试记录一个次好的选择。当最好的地块已经走不通时,无需从开启列表中循环遍历来挑选下一个最好的地块,直接选择刚才次好的地块即可。

3、保持探索方向

尽量从上次探索的方向继续探索,如从地块A走到地块B,地块B在地块A的三点钟方向,那么在查找地块B周围的地块时,优先从三点钟方向开始遍历。若沿着这个方向的地块还不错(可以被选择),那么应该优先选择它做为下一个地块,因为通向目的地的路多是直的。

当然,网上也有很多关于A-Star算法的优化方法,篇幅有限,这里就不再列举了。

瓦片管理器

建立一个瓦片管理器是很有必要的。

1、瓦片管理器管理所有的瓦片信息,每个地块只需凭借一个ID即可从瓦片管理器中获取瓦片信息。

2、瓦片管理器将封装对资源管理器的调用,需要使用瓦片的对象无需关心瓦片是如何被加载的,后期如更换资源管理方式时,修改范围小。

混合多种风格的地图

为了实现即有特点又无特点的地图风格,也就是类似“五彩斑斓的黑”的效果。我建议把瓦片风格进行细致的分类,这样在生成地图时既可以选择统一的风格,也可以进行多重风格混搭(当然前提是混合的风格要搭配,你需要具备一定的审美水平,最好能找个美术妹子来分类和把关)。
 

结合素材特点对瓦片进行风格分类

一张混合了雪山和火山两种风格的地图


还有一个小插曲,在实践了初版方案后,碰巧赶上了Unity2018.2版本的发布,其中刚好包含了对六边形瓦片的支持。但是尝试后发现对于遮挡关系很难灵活控制(可能是我没有找到合适的方法),最终还是放弃了这个功能。

<think>好的,用户遇到了Git合并时本地更改会被覆盖的问题,需要解决方案。根据之前的引用资料,解决方法主要有commit、stash和revert三种。首先,我得确认用户的具体情况,比如他们的本地更改是否已经完成,是否需要保留,或者是否可以丢弃。用户可能不太清楚这三种方法的适用场景,需要详细解释每个选项的步骤和优缺点。比如,commit适用于需要保留更改的情况,stash适合临时保存以便后续恢复,而revert则是直接撤销更改,适用于不需要保留的情况。需要结构清晰,分点说明,每个方法都给出操作步骤和适用场景,帮助用户理解哪种情况最适合他们。还要注意使用中文,避免技术术语过于复杂,让用户容易理解。同时,生成相关问题,可能涉及如何恢复stash的内容,或者如何避免频繁冲突等,扩展用户的知识点。另外,要确保LaTeX格式正确,但在这个问题中可能用不上数学公式,所以主要关注代码块和引用标识。检查引用是否正确,比如引用[^1]和[^2]的来源是否相关,用户提供的引用内容是否准确对应解决方案。 最后,确保回答真实可靠,操作步骤准确无误,避免误导用户。可能还需要提醒用户根据具体情况选择方法,比如如果有未完成的实验性代码,stash可能是更好的选择,而如果是确定要保留的修改,则应该commit。</think>要解决Git合并时本地更改被覆盖的问题,可根据不同场景选择以下三种方法: ### 一、提交本地更改(commit) **适用场景**:当本地更改已测试通过且需要保留到版本历史中。 **操作步骤**: 1. 将改动添加到暂存区: ```bash git add . # 添加所有文件 # 或指定文件 git add file1.txt file2.py ``` 2. 提交更改并添加描述: ```bash git commit -m "完成用户登录模块优化" ``` 3. 执行合并操作: ```bash git merge origin/main ``` **优点**:保留完整的开发记录,便于后续追溯[^1]。 ### 二、暂存更改(stash) **适用场景**:需要临时保存未完成的修改(如调试代码),优先处理合并操作。 **操作步骤**: 1. 保存当前工作状态: ```bash git stash # 可选添加备注 git stash save "用户登录模块调试代码" ``` 2. 查看暂存记录列表: ```bash git stash list ``` 3. 合并远程分支: ```bash git merge origin/main ``` 4. 恢复暂存内容: ```bash git stash pop # 恢复并删除最近一次暂存 # 或指定特定暂存 git stash apply stash@{1} ``` **优点**:保持工作目录整洁,特别适合处理紧急合并任务[^2]。 ### 三、撤销本地更改(revert) **适用场景**:本地修改可丢弃(如实验性代码或错误修改)。 **操作步骤**: 1. 撤销所有未提交的修改: ```bash git checkout -- . # 全部文件 # 或指定文件 git checkout -- file1.txt ``` 2. 执行合并操作: ```bash git merge origin/main ``` **风险提示**:此操作不可逆,需确认文件无需保留。 --- ### 对比决策表 | 方法 | 保留记录 | 可恢复性 | 适用阶段 | |---------|----------|----------|------------------| | commit | ✅ | ✅ | 功能开发完成时 | | stash | ❌ | ✅ | 开发中途临时切换 | | revert | ❌ | ❌ | 放弃无效修改 | ### 扩展应用场景 - 当存在多个暂存时,可用`git stash list`查看记录,通过`git stash apply stash@{n}`精准恢复 - 合并后出现冲突时,可使用`git mergetool`可视化工具解决冲突 - 长期分支开发推荐使用`git rebase`保持提交历史线性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值