Fixing Pathfinding Once and For All (个人翻译)

原文:http://www.xuebuyuan.com/1907012.html?mobile=1

原文的原文:http://www.ai-blog.net/archives/2008_07.html (并不能打开)

个人翻译,欢迎指正


(正文开始)

我通常会尽力避免说一些会被误解为是对其他游戏或者行业开发者的批评的话。

但是这次我得破个例。

我得谈一谈路径搜索(pathfinding)方面的几个问题。为了证明这些问题的存在,我觉得有必要录个视频(并没有见到,估计在墙外--译者注)......which will hopefully be taken in the humorous and lighthearted spirit in which it was intended(不知道怎么翻译,下同)。

所有这些片段都是上周使用这些游戏的最新版本录制的。

As you can see, 我们与鲁棒的路径规划之间还隔着十万八千里呢。。。。。。甚至一些百万销量/3A质量的游戏中都不乏问题。

虽然并不见得是一个普遍问题,一些现代游戏里确实也有高质量的路径搜索,在“上面”所展示的那些游戏里的大多数情况下,路径搜索工作的还都凑合。

But 依然有非常多的游戏,其中的pathfinding与上世纪90年代的游戏相比毫无进步。

(Note:之所以你在这里看到的游戏大都是PC上的RPG游戏,只是因为方便。我现在刚好有这些游戏。这里所探讨的问题其实是与游戏类型和平台都没有关系的。在主机游戏中也同样存在大量类似问题)

据我所知,这些游戏中的大多数都是利用路径点(waypoint graphs)进行寻路的。我认为这正是你在”上面“视频中发现的一些pathfinding问题的原因所在,同时也是我们在行业中面对的大多数pathfinding问题的罪魁祸首。

我相信现如今waypoint graphs是应废除掉的。本文将阐述waypoint方法的局限,并lays out a five-point argument for a better approach.(译注大概是陈述5条与navmash相比的不足)

Back in the 1980s and 1990s,  技术, 在pathfinding中使用waypoint是有一定道理的。

But, 现如今游戏已经发展成为一个数十亿美元的行业,我们的目标平台也拥有着数个核心和持续增长的内存,这已足够承担起正确的pathfinding。

在现今行业的AI开发者中有着这样一句话:“路径搜索问题已经解决了。(pathfinding is solved.)”在现代游戏中面临的所有pathfinding问题我们都已经有了好的解决方法,我们只是不总是用它们而已。

There's no reason not to have pathfinding that works in every game, every time.

下面我来做一个详细的解释。


为什么waypints已不再适用

让我先给你们看看典型的waypoint长什么样。这里是魔兽世界中暴风城的一角:


图1.魔兽世界中暴风城的一角

这是一个典型的waypoint在该区域中可能看上去的样子:


图2.注有waypoint的图1

There's another way to do it, 它涉及使用凸多边形来决定哪里是AI角色可行走的。这种表示法可以给AI提供更多的环境信息,并提供对做出更加智能化决定的支持。

这里是导航网格(navigation mesh)看上去的样子:


图3.注有navmash的图1

下面是waypoint的5大条“罪状”:(译注:简单翻译,原文语气没这么激烈,莫较真 ;D)

1. Some kinds of game worlds require a ridiculous number of waypoints.(一些游戏中需要的waypoints数量超乎你的想象)

宽阔的区域中通常需要大量的waypoints散落在地图的各个角落以求角色能够灵活的移动。

on the other handA navigation mesh 通常仅需要少数的多边形来表示这片区域就足够了。

来一个例子:

下面是魔兽世界中一个叫“Halaa”的城镇,这是一个相当大且颇开阔的区域,NPC们通常需要在该区域内进行寻路。为了简化,我去掉了一些诸如旗帜、喷泉之类的细节。


图4. Halaa镇的简化版

在基于waypoint的系统中,为了覆盖整个地图,我们需要放置大量的waypoints。即便如此,我们的NPC们依然会在行走时出现大量的之字形路线。除非我们放置比这里展示的还要多得多的waypoints。


图5.Halaa with a waypoint graph

on the other hand, 采用 navigation mesh, 我们就可以使用很少的凸多边形来描述这块区域


图6.Halaa with a navigation mesh

navigation mesh的简单意味着当我们在运行时调用pathfinding算法时将不再需要搜寻那么多的节点,而这导致pathfinding会更快。

2. They make characters "zig-zag" as they move.(角色在移动时会走“之字形”路线)

使用waypoints graphs 你的角色必须沿着你创建的路线行走。就像是角色在通过铁轨移动,这意味着几乎从来都无法做到线路最优。。。因为最优路径几乎从来不会与你的图恰好匹配。

这造成了非自然的pathfinding——尤其是,角色会不自然地走起“之字形”路线。

来看个例子,我们希望角色从A走到B:


图7.Halaa中的两点

在waypoint中路径看起来会像这样:


图8.利用waypoint graph从A到B路径

As you can see, 角色在沿着黄色路径行走时将会一而再的转弯。

理想情况下, 在找到路径之后,我们可以利用某种方法对其进行调整使之更平滑一些。。。比如在节点之间创建平滑的样条曲线(Catmull-Rom spline )。

问题在于,waypoint网没有提供关于路径之外的任何信息,这导致想要进行安全可靠的路径平滑和调整是绝不可能的。

当样条线必须创建在waypoint graph之外时,你该怎么去创建它呢?事实上你沿着这样的曲线行走恐怕一不小心就会掉下桥去了。

你可能会想一定存在某种更简单的方法。不幸的是,在waypoint方法中,这样的方法并不存在。我们与waypoint graph哪怕有一丝偏差,就有可能会掉下悬崖或撞上南墙。我们永远无法知道这一点,因为graph没有保存任何相关数据。

因此,为了保全性命,我们必须保持最悲观的姿态,时刻紧紧依附在waypint 网上。

然而,另一方面,navigation mesh形成的路径将看上去像这样:


图9.通过navmesh从A到B

由于我们已知哪里是可安全行走的区域, 所以只要你喜欢,你可以以任何方式平滑路径,只要你保证路径在网格内便可。

“哦,”你说,“但是我只需要在waypoint中加入更多的链接来把所有的路线都平滑起来!我把地图中所有的节点都两两连接起来。”

“但那样会照成指数爆炸的,”我答道......“以上图为例,你将需要多添加40-50个额外的连接。随着区域的增加,你需要的连接数会到达O(N^2)级别。”

“OK,”你说,“这样的话,那我就使用3个相互邻接的waypoints作为一组来表示一个‘open’从而标记出一个区域,这样我的AI就可以在该区域中随意行走了。”

“这不正是一个多边形区域吗......而你已经有了navigation mesh了呀”,我答道。

navigation mesh可以精确地告诉我们哪些区域是AI可以行走的这一事实意味着我们可以使用样条曲线轻松地平滑路径。我们唯一需要做的就是确保样条曲线始终在网格内部。

如下图,回到我们的例子,红色是waypoint path, 蓝色是在navmesh中的平滑路径:

图10.一条waypoint path(红)和一条平滑了的navigation mesh path (蓝)

3. They don't allow path correction. That makes robust dynamic obstacle avoidance difficult, if not impossible.( (waypoint)不允许路径更正,导致实现出鲁棒的动态障碍物避免虽非不可能,但也是极其困难的)


waypoint graph 没有保存任何graph之外的数据,在graph之外的任何一点角色是否可以合法行走都无从知晓。

这使得pathfinding system几乎不可能处理好具有动态障碍物的情况。

让我们在桥上放个大檀木箱子。

在waypoint graph中,呃。。。我们完蛋了——如果箱子刚好挡住了graph,那么应该从左还是从右边绕过去呢?我们将毫无头绪。甚至,如果箱子完全把路堵死了,我们会需要绕一个大弯才行。当然我们也可以猜一个(方向)——只要你不怕淹死。


图11. 在桥上放一个沉重的箱子

然而,在navmesh中就简单多了,因为我们知道哪些区域是可以行走的。我们只消做个简单的光线投影,就可以轻松绕过。(We do a bit of raycasting against the barrel and adjust our path around it, keeping our path (and ourselves) safely on the navigation mesh.


图12.绕过箱子

当然,如果你在waypoint graph中放的节点比草都密,用waypoint也是可以做到的。(同时你pathfinding的速度也必然慢的离奇)。

我不知道你怎么想, 但我可是宁愿我的A*算法运行在一个大的多边形上而不是数百个waypoints上。

4. They don't work robustly for characters that move differently.(不同角色移动不同时waypoint方法力不从心)

当角色具有不同大小、转弯角度等属性时,waypoint工作得不是很好。这意味着在游戏中对于不同类型的单位一个waypoint graph是不够的。
当我们考虑AI pathfinding时,我们倾向于从人在游戏世界中的导航的角度来思考。
但AI系统需要控制多种不同的单位——坦克,飞机,轮船,气垫船,摩托,半兽人,哥布林,龙,笨拙的巨人怪,飞鸟,等等等等。在许多情况下,这些单位需要根据其不同的大小、形状及移动方式进行不同的pathfinding。一个好的pathfinding应当能够考虑到所有这些条件。
来看个例子。现在我们在沙漠中有一个由沙袋环绕的混凝土浇灌的地堡:
图13.沙漠中的地堡
现在我们有一个士兵,它可以紧挨着沙袋跑过(下图中的红箭头)。
而一辆装甲车则必须与沙袋保持一定距离,以免撞上(蓝色箭头)。

图14.士兵(red)和坦克(blue)离沙袋最近的可能路线
显然, waypoint方法仅使用一张graph是搞不定的。你至少需要两张waypoint graph。加上个“摩托”,那你就需要三张。And so on。对每一类具有不同移动方式的unit,你就多需要一个waypoint。
而在navmesh中,就简单多了。

图15.地堡外围部分navmesh
请注意一下从拐角处发出的两条亮白线。由于我们已知士兵的碰撞半径是1米,而装甲车的则是5米,这样一来,在同一个mesh上建两条path来就轻轻松松了。我们只消计算出紧沿着沙袋的路径,然后根据目标单位是士兵还是装甲车将路径从转角处向外推1m或5m就行啦。

图16.根据同一个navmesh计算的两条路径
再来一个例子。假设我们有一个骑着摩托的士兵,与步兵不同的是,摩托没法在拐角处做急转弯。
在下面的例子中,显然骑兵可以轻松地从其当前位置到达顶部的房间(红箭头),但是却不能转向右边的高速公路,因为角度太小,做不了这么急的转弯(黄线)。我们的pathfinding算法应当有能力处理这一情况。

图17.摩托车可以轻松到达顶部(red),但无法到达右侧(orange)
在navmesh中,做到这一点也是相当easy的。我们只消在做pathfinding时测试一下路径的转弯角度和距离,并排除掉那些需要在短距离内进行急转弯的路径即可。
然而在waypoint方法中,想要做到这一点本质上是不可能的。在最低限度上,我们将需要为骑兵单独添加一张waypoint graph。显然,这是极其繁重的。

5. They don't have enough data to support what your AI needs beyond pathfinding.(除了pathfinding之外别的什么都不支持)

AI搜索空间不只是用来导航,AI们还需要根据路径数据来决定如何在世界中移动。
一个游戏角色需要始终向pathfinding系统询问诸如“这里可以走吗?移到那里如何?”之类的信息。
游戏越来越倾向于使用由动画驱动的运动系统,这给予了动画师们控制角色位置的权利(Games are increasingly moving to animation-driven movement systems that give animators control over the position of game characters. )。这意味着,为了弄清楚当我们执行动画X后的结果是什么,我们需要弄明白当X执行完角色将会在哪里,以及那里是否是在墙里,悬崖边等设计者不希望角色出现的地方。
来瞧个例子。下图中的持剑男有四种移动:左扫、右扫、后撤,以及一种先向上跳20尺高然后落在前方8尺处的进攻动作。

图18.拥有四种动画的持剑男,这些动画伴随有位移
为了确保我的持剑男进攻或后撤时不会跳进砖墙,我需要预测每个动作的最终位置,并检查其是否违背了navmesh。
诚然,通过你的碰撞检测系统进行光线投射(raycasting)也是可行的。这通常可以给你提供有用的信息,而且对于游戏世界中的动态障碍物,这通常也是AI们检测到它们的唯一方法。
But, 射线法是很昂贵的,而且当你仅关心静态场景时,navmesh是更为简单方便的。
尽管我可以利用raycasting来获知在我和点(X,Y,Z)之间是否有障碍物,碰撞系统依然没法告诉我我的持剑男是否会落在那些关卡设计师其实希望角色走进去的地方。。。只有navmesh能告诉我这些(the collision system can't tell me if the swordsman will land in a position that the level designers actually want characters to walk in ... only a navigation mesh can tell me that.)。
说了这么多如果依然不能说服你,那就让我试着回答一些关于waypoint graphs 和navigation meshes的常见问题,看能不能解决你剩下的疑问。

Q & A

 

 

But isn't it slower to do pathfinding on a navigation mesh?(在navmesh中进行pathfinding会不会更慢啊?)

一点也不。和waypoint graph 一样,navmesh也是图,并且二者核心的pathfinding方式是非常相似的。区别在于navmesh中每一个节点有一个多边形与之关联。
下图显示了节点与多边形的联系

图19.navmesh中潜在的graph(red)
任何时候当你使用A*算法进行寻路时,你总是把它用在某种类型的图上的,而不论该图是栅格图、waypoint图、navmesh,还是其他别的什么图。
在大多数情况下,navmesh的性能与waypoint是相当的。而在那些需要更少节点的地图中(如图6),navmesh的速度是明显更快的。

But don't navigation meshes take a lot more memory than waypoints?(占用更多内存)

正确运用怎不会。
navmesh是一种非常简单而紧凑的方法。一般情况下, 一个navmesh只需要占用一小部分内存用于静态场景中潜在的渲染几何(a nav mesh will only require a tiny fraction of the memory required by the underlying rendering geometry for the static game world.)。相对于碰撞网格(collection mesh)一个nav mesh是很小的,因为它只关心少数的几个表面(不关心诸如墙壁、天花板之类的不可行走的表面)并用少量的大的多边形就可以覆盖一个区域。
在最坏情况下,nav mesh 比waypoint使用更少的节点(A navigation mesh tends to use a few more points for each graph node than a waypoint graph in the worst case. )。在另一些情况下, 如图6中的城镇,一个nav mesh甚至是更小的,因为它是一种更简单的表现方式。

Most of the examples you showed were role-playing games. Why don't I see the same kinds of problems in first-person shooters?(如果不是RPG游戏,在FPS游戏中没这问题吧?)

问题依然存在的。只是在很多FPS游戏中比较难发现。
-大多数AI们在你发现他们pathfinding有瑕疵之前就被你杀掉了。
-AI们通常在一看到你时就停下来然后向你射击,他们的路径相对比较短。
-在很多单人模式中,AI们并不怎么移动,而是固定在某些设定好的位置
-很多现代FPS游戏往往会提供AI战友,他们会帮助你快速地杀掉大多数AI敌人,导致它们并没有机会移动太远。
例如在半条命2中,通过一点小小的试验便很容易发现,梯子上的守卫是固定在一条连接楼梯中点的简单waypoint直线上的。即便如此,这名守卫依然能够胜任其职责,因为当他看到你时可以直接向你射击。
当你移除远距离武器,而只允许角色使用近战武器时——就像《光晕》中的某些星盟士兵,F.E.A.R.中的刺客,或者《银河战士》中的战士——waypoint方法就不是那么有吸引力了(这也是上述这三个游戏使用navmesh而不是waypoint的原因之一......)。

Look, I understand everything you said, but designers need to be able to put down cover points, patrol paths, and so on. That's just essential for creating the AI in our games.(你说的这些我都明白,但是关于AI很关键的一点是,设计者需要能够在地图上放置覆盖点、巡逻路径之类的)

你依然能够做到!
解决之法是将两种表示分离。一个(nav mesh)用来pathfinding和navigation,一个(designer-placed points)告诉AI如何使用世界(tell the AI how to use the world)。
nav mesh不会妨碍你编写脚本(scripting)。它只是为你的AI们能够独立自主地寻路提供了额外信息。
来看个例子。我们有一条巡逻路径(紫色),用于某些守卫的绕城巡逻,另外还有一个特殊标记(红色),标记了一名渔翁每天在护城河边的钓鱼地点。一些覆盖点(黄色)表示这是当风暴城的巫师和术士打成一团时角色们的可以用来掩护的点。

图20.各种各样的地形标记点(AI 提示)和一个nav mesh

OK, but isn't it a lot of work to place a navigation mesh?(好吧, 但是弄个导航网格出来肯定很费事吧?)

通常来说,手动放置一个nav mesh不会比放置一个waypoint 网需要更多劳动。无论二者哪一种计数,你创建它所花的时间相对于在游戏中测试它所花的时间来说根本不值一提。
根据我的经验,在一个中等规模的FPS游戏中,创建一个nav mesh将需要1-3个小时。
创建一个nav mesh编辑器也是相当简单的。你只需要实现在游戏地图中放置顶点、选择一组顶点并将其指定为nav mesh中的一个多边形这两个功能。你可以根据邻接多边形之间有哪些共享顶点来检测nav mensh的连通性。
同时,你还可以利用一些中间件,比如 xaitmentNavPowerPathEngine 和 Kynapse
它们不仅能帮你创建nav mesh,还能为你处理运行时的pathfinding。目前这些中间件正变得越来越鲁棒和可行。

What if I want to have AIs walk up and down stairs? My designers don't want to have to lay down a nav mesh polygon for every single step in the staircase.(让AI们爬楼梯会怎样?设计师们可不想在每一级台阶上都放一个 nav mesh)

一个nav mesh仅仅是表示了一块可行走区域。它并不会取代碰撞网格——你的NPC们依然使用碰撞系统处理游戏中的碰撞。
你应该能够在nav mesh中使用一个矩形覆盖整个楼梯。

Can't I just give each point in my waypoint graph a radius, so I have circles instead of points? That gives me a representation of what areas are walkable. That's how they do it in robotics, too ...(我能把waypoint网中的每个节点一个半径将其替换为一个个的圆形吗?这样我就能表示出哪些区域是可行走的了。在机器人学中他们就是这样做的)

在某些情况下这种方法是可行的。但是游戏中的大多数地图都会有大量的人类建筑,充满了生硬的街道和楼房。圆形不能很好的表示这些区域,想做到多边形那样的覆盖范围会很困难。
下面是在暴风城中使用圆形的情况

图21.使用圆形扩展waypoint方法
轶事( Quick anecdote )(新鲜事简单报? ;D):
当我为机甲战士4:复仇(MechWarrior 4: Vengeance team)做开发时,我们艰难地发现基于圆的方式在野外工作的很好但是当我们忽然将其用到城镇里时却很糟糕。我们的小组最终还是使它工作的起来,但是我们的教训是:永远不要把圆和城镇环境混在一起!
Also,拥有转角也是很重要的,像图16那个沙漠地堡的例子,我们可以利用navmesh中的转角为不同的单位创建不同的路径。而圆则没有“转角”,这样一来想要为不同的单位创建正确的路径就很困难了。

My game already has a collision mesh. Can't I just use that for pathfinding?(能用碰撞网格代替导航网格不?)

你可以尝试,但这并不是好主意。
碰撞网格是针对碰撞进行优化的,而非寻路。这导致它的多边形数量比你做寻路所需要的多得多,这样你的寻路函数就会很慢了。
例如,在一条鹅卵石小道上你的碰撞网格中多边形的数量可能多达1000个,而nav mesh仅用一个矩形可能就够了,一个屋顶在碰撞网格中可能需要50个多边形,而在nav mesh中则根本不需要表示它(假设我们的角色永远也不会飞檐走壁)。
Also,nav mesh(以及其他的表示方式)的另一个优势是它不仅告诉你哪里是角色可以行走的,还告诉你哪里是设计师希望你的角色行走的。
如果你让设计师们手动创建导航网格,你就给了他们诸如“不要让AI们走到这里。我就是这么任性。”的权利。像这样的信息,你在碰撞网格中可找不到。

All the examples as presented show the nav mesh as a 2D projection onto the space. How would you handle a case like a bridge over a road, wherein you could go over or under. Or a building with multiple floors?(3D的场景怎么处理?比如立交桥,6层小楼这样?)

这样的情况对nav mesh来说小菜一碟。下面是《魔兽世界》中外域主城(Shattrath City)的一部分,你可以看到其nav mesh可能的样子(为了简化,我忽落了远处桥上的nav mesh部分)。

图22.桥上桥下的部分nav mesh
在nav mesh 中,每一个多边形同时还保存了一个“高度”属性。它指出该多边形可用的垂直间隙有多少(indicating how much vertical clearance that is available for that polygon.)。因此,你看到的从桥底穿过的多边形会知道它只有7尺的间隙(clearence),这样高于7尺的单位将不能使用这些多边形。
在多层楼的情况下,每一层可以有一个自己的nav mesh, nav mesh之间的楼梯使用额外的多边形连接(当然,电梯的话会有些棘手)。

I don't believe in a one-size-fits-all approach. Different games require different representations for pathfinding.(我不相信存在一劳永逸的办法,不同的游戏就需要不同的方法)

如果你是在做一个完全2D的策略游戏,那么基于栅格的方法通常是更好的,因为栅格可以让你随机访问任何一个单元。
否则,导航网格法真的就是目前已知的最好的,最鲁棒的3D环境下的路径搜索和地形推理(terrain reasoning)方法了。

Suppose I were interested in implementing navigation meshes in my game. Has anything been published to help me figure out how to build the meshes, do pathfinding on them, and optimize them for my game?(假设我信了你,那现在在哪里有哪些东西可以帮助我理解如何建立网格,并在其上进行路径搜索,以及为我的游戏优化它们?(译注:就是read more))

下面是我知道的一些:

"Simplified 3D Movement and Pathfinding Using Navigation Meshes" by Greg Snook (Game Programming Gems)

"Polygon Soup for the Programmer's Soul: 3D Pathfinding" by Greg Hjelstrom and Patrick Smith (GamaSutra.com)

"Building a Near-Optimal Navigation Mesh" by Paul Tozour (AI Game Programming Wisdom)

"Efficient Navigation Mesh Implementation" by John C. O'Neill (Journal of Game Development, March 2004)

"Search Space Representations" by Paul Tozour (AI Game Programming Wisdom 2)

"A Fast Approach To Navigation Meshes" by Stephen White and Christopher Christensen (Game Programming Gems 3)

"Choosing a Relationship Between Path-Finding and Collision" by Thomas Young (Game Programming Gems 3)

"Improving on Near-Optimality: More Techniques for Building Navigation Meshes" by Fredrik Farnstrom (AI Game Programming Wisdom 3)

"Smoothing a Navigation Mesh Path" by Geraint Johnson (AI Game Programming Wisdom 3)

"Dynamically Updating a Navigation Mesh via Efficient Polygon Subdivision" by Paul Marden and Forrest Smith (AI Game Programming Wisdom 4)

"Intrinsic Detail in Navigation Mesh Generation" by Colt McAnlis and James Stewart (AI Game Programming Wisdom 4)

"Navigation Mesh Generation: An Empirical Approach" by David Hamm (AI Game Programming Wisdom 4)

"Navigation Mesh Generation in Highly Dynamic Worlds" by Ramon Axelrod (AI Game Programming Wisdom 4)

"Crowds in a Polygon Soup: Next-Gen Path Planning" by David Miles (http://www.navpower.com/gdc2006_miles_david_pathplanning.ppt)

如果你还知道更多,请  e-mail 我。

How many games have actually used navigation meshes successfully?(成功案例有哪些?)

简单说几个:
。。。还有很多很多。
这样你就知道:别人家的乖孩子都在做。

OK, maybe it works for you, but we used waypoints in all of our previous games, and they worked fine.

Like they say, if it ain't broke, don't fix it ... and we haven't run into any of the problems you're talking about.

(你用着好,我们一直用waypoint也用得挺好的啊。俗话说的好“没破你修啥”。。。你上面说的问题我们也并没有遇到呀)

人要有远见,想象10年20年以后吧。
二十年以后:

In that kind of time frame, do you think your games might have lots of different types of AI-controlled characters with different shapes, sizes, and movement capabilities?

Will players have AI henchmen that they expect to be just as intelligent as themselves?

Will your game worlds be significantly larger, more complex, and more dynamic than they are today?

Will you have huge crowds of AI characters -- so many that just using simple steering and obstacle avoidance are no longer adequate to make them coordinate with each other effectively?

Will your games have realistic physics and huge amounts of physically-simulated objects, and will players be able to use the physics to mess with the AI characters in every way imaginable?

Will players be able to change the game world until it's virtually unrecognizable?

Will there be AIs in multiplayer that are expected to pass for human players?

(blablabla...自己看吧——译注)
(总之)
几十年后游戏会是什么样子谁也不知道,但是很明显我们需要更加先进的AI。而这其中便要求我们给游戏角色更多的数据以供他们感知器所处的世界,找出优良的路径,轻松应对复杂多变的游戏世界。































  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值