Unity中实现合理塔防寻路机制

news2024/12/4 17:04:09

前言

在一款TD游戏中,最重要的单位就两大类:防御塔(Tower)和敌人单位(Enemy)。在处理敌人单位的AI行为时,最基本也是最重要的就是自动寻路。在各式TD游戏中,防御塔的攻击方式以及敌人单位的Buff机制往往是能做出差异化的地方;而在寻路问题上,几乎是没有差异的,面对的都是同一套问题模型。

以魔兽争霸中的TD地图、KingdomRush为代表的这一类”固定路径,固定塔位“的寻路模型是最为常见的。本文对于寻路问题所参照实现的,则是久负盛名的Defense Grid(中文译名防御阵型);作为最经典的TD游戏之一,不仅是因为其在早年发布的第一部作品中就表现出了非常优秀3D画面,更重要的是在前述的寻路模式下引入了新的机制:允许在敌人单位的前进路线上放置防御塔或障碍物,从而在运行时动态地改变路径。这一创新极大的提高了可玩性,在此之后许多流行的TD游戏都有使用这种寻路方式 例如Infinitode、X-Morph、国产游戏重构Refactor等。

寻路问题的建模

我们首先要做的是根据游戏中的地图特征,将所有能够行走的地面抽象为数据结构,然后再决定合适的寻路算法。

对于路径建模有三种主流方式,我们以下图作为原版地图来说明:

image

格子(Grid)

image

格子模型将地图分割为许多大小相等的格子,利用二维数组存储起来。使用各种值表示数组中对应的位置类型 如0用来表示障碍物,1表示可行走的区域。

优点:

  • 实现简单
  • 易于在运行时动态修改

缺点:

  • 如果想更为细致地表达路径,则需要将格子分割地更小,从而导致内存占用更大且大范围寻路时计算代价更大

对于2D画面的小地图,是该模型最适合的场景。笔者在刚上大学时写过一个2D的塔防游戏,当时就是以这种方式来处理地图的(https://www.cnblogs.com/geek1116/p/5953456.html)

路径点(WayPoint)

image

这种方式需要在手动标注出所有可以行走的点,这些点互相连接的直线就是单位行走的路径。通常在这些连接边上还需要带上权重,用邻接表的数据结构存储。

优点:

  • 内存占用小
  • 在此基础上做寻路算法的计算代价小

缺点:

  • 需要人工添加路径点,且在地图变动后都需要再次调整路径点,工作量大
  • 由于单位只能沿着路径点行走,行为方式在观感上会表现的较为生硬,不够灵活;在大地图范围寻路以及需要考虑单位碰撞的场景下,该问题更为明显

对于传统的固定线路的塔防中,WayPoint是非常适合的建模方式

导航网格(NavMesh)

image

通过一系列的算法将可行走地形转换为由若干凸多边形组成的网格,并维护多边形之间的邻接关系。在导航网格中求两点之间的移动路径,需要根据两点所在的多边形以及多边形之间的邻接关系,按照某种寻路算法找出需要经过的所有多边形;再根据拐点算法计算途中的各个拐点来得出”平滑“的移动路径。

优点:

  • 相比于前两种模型,NavMesh更能表达出地形的特征
  • 适用于3D地形

缺点:

  • 建模过程复杂,自己从零造轮子的话实现成本很大
  • 不便于动态修改;在修改地形后再重新烘焙NavMesh的过程比较耗时,想要运行时执行这一过程的话性能代价较大

Unreal Engine、Unity等游戏引擎中的导航系统内部原理都是基于NavMesh的

寻路算法

三种经典的路径规划算法:

  • 广度优先搜索(BFS)
  • Dijkstra最短路算法
  • A*算法(A star)

在游戏开发中实现寻路问题时,A*算法通常是不二之选。这也是Unity中采用的寻路算法。

如果是以WayPoint的方式作地图建模的话,那么数据结构存储的是一个无向加权图,在此之上进行路径规划,Dijkstra算法通常会是一个合适的选择。

在塔防游戏中选择合适的寻路方案

回到我们的主题,要以Defense Grid为蓝本在Unity中实现敌人单位的寻路。

最简单粗暴是使用游戏引擎自带的导航系统,给定一个终点后剩下的都交给导航系统去处理了。这种方式下单位在地图上寻路时所走的都是近似最短路的路线。这种方式不能说是错的,但从游戏设计的角度讲 这种表现方式显得”很蠢“:在游戏实际运行中,敌人单位是一波一波出现的,但同一波次中的若干敌人在前进时会显得完全没有”集体意识“,大家都各自为战,最终会挤到同一条直线上。如下所示:

image

以右上方红点设为目的地,三个单位都只从自身位置考虑,算出当前到终点的最短路线;当经过第一个拐点后,它们仨都会位于同一直线上前行。

笔者曾关注过的塔防作品中确实见到过极个别真是这么实现的......

我们在前文提到过,对于固定路线的这类型地图寻路中可以采用WayPoint的方式建模,单位的前进路线则按着路径点之间的走,但这仍然会存在上述的问题。在Unity中做个demo,尝试下在两个拐

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1412278.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Springboot注解@Aspect(一)之@Aspect 作用和Aop关系详解

目录 Aspect的使用 配置 作用 通知相关的注解 例子 结果: Aspect作用和Spring Aop关系 示例 标签表达式 Aspect的使用 配置 要启用 Spring AOP 和 Aspect 注解,需要在 Spring 配置中启用 AspectJ 自动代理,但是在 Spring Boot 中&a…

shell脚本-函数及数组

一.函数 1.函数的作用 语句块定义成函数约等于别名,定义函数,再引用函数 封装的可重复利用的具有特定功能的代码 2.函数的基本格式 法一: [function] 函数名 {命令序列[return x] #使用return或者exit可以显式的结束函数 }法二&…

对比一下Confluence,其实HelpLook搭建知识库也不错

随着越来越多的企业转向远程工作和分散团队,寻找一种适合团队协作和知识共享的工具变得更为重要。HelpLook和Confluence是两个我认为比较相似的知识库软件,它们都提供了丰富的功能和卓越的用户体验。接下来就对HelpLook和Confluence进行详细的介绍和对比…

【Spring 篇】MyBatis DAO层实现:数据之舞的精灵

欢迎来到MyBatis DAO层的神奇世界,这里将为你揭示DAO层的奥秘,让你成为数据之舞的精灵。无论你是初学者还是想要深入了解DAO层的开发者,这篇博客将引导你踏入MyBatis DAO层的王国,一探其中的精彩。 舞台1:DAO层的角色…

【大数据面试题】HBase面试题附答案

目录 1.介绍下HBase 2.HBase优缺点 3.介绍下的HBase的架构 4.HBase的读写缓存 5.在删除HBase中的一个数据的时候,它是立马就把数据删除掉了吗? 6.HBase中的二级索引 7.HBase的RegionServer宕机以后怎么恢复的? 8.HBase的一个region由哪些东西组成? 9.…

安科瑞电化学储能电能管理系统解决方案——安科瑞赵嘉敏

1 概述 在我国新型电力系统中,新能源装机容量逐年提高,但是新能源比如光伏发电、风力发电是不稳定的能源,所以要维持电网稳定,促进新能源发电的消纳,储能将成为至关重要的一环,是分布式光伏、风电等新能源消…

LeetCode 40.组合总和 II

组合总和 II 给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用 一次 。 注意:解集不能包含重复的组合。 方法一、回溯 由于题目要求解集…

第十九周周报

文章目录 摘要文献阅读DeepHuman: 3D Human Reconstruction from a Single Image(ICCV 2019)贡献摘要网络结构总结 PIFu: Pixel-Aligned Implicit Function for High-Resolution Clothed Human Digitization贡献摘要网络结构总结 Animated 3D human avatars from a single imag…

多项式乘法逆(p4238 NTT)

题目路径&#xff1a; https://www.luogu.com.cn/problem/P4238 思路&#xff1a; 代码&#xff1a; #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<string> #include<cstring> #include<cmath> #include<ctime> #include&l…

有什么办法可以让模糊的老照片变清晰?这几个方法收藏好!

照片盒子里的老照片&#xff0c;宛如一扇陈旧的时光之门&#xff0c;等着我们去开启。那些尘封的记忆&#xff0c;似乎已经被时间遗忘&#xff0c;但当我们轻轻拂去尘埃&#xff0c;那些熟悉的画面便再次浮现在眼前。然而&#xff0c;岁月无情&#xff0c;这些宝贵的瞬间在时间…

node.js漏洞总结

js开发的web应用和php/Java最大的区别就是js可以通过查看源代码的方式查看到编写的代码&#xff0c;但是php/Java的不能看到&#xff0c;也就是说js开发的web网页相当于可以进行白盒测试。 流行的js框架有&#xff1a; 1. AngularJS 2. React JS 3. Vue 4. jQuery 5. Backbone…

Linux | makefile简单教程 | Makefile的工作原理

前言 在学习完了Linux的基本操作之后&#xff0c;我们知道在linux中编写代码&#xff0c;编译代码都是要手动gcc命令&#xff0c;来执行这串代码的。 但是我们难道在以后运行代码的时候&#xff0c;难道都要自己敲gcc命令嘛&#xff1f;这是不是有点太烦了&#xff1f; 在vs中…

Docker安装多个nginx容器时,要注意端口设置:

Docker安装多个nginx容器时&#xff0c;要注意端口设置&#xff1a; docker run -id --namemynginx4 -p 8089:80 nginx 安装多个nginx容器时&#xff0c;要注意端口设置&#xff1a;宿主机80端口已经被暂用&#xff0c;所以宿主机端口一定不能设置位80&#xff0c;但是容器上80…

Vulnhub靶场DC-7

本机192.168.223.128 目标192.168.223.136 主机发现 nmap -sP 192.168.223.0/24 端口发现 nmap -sV -p- -A 192.168.223.136 开启了22 80端口 80端口apache服务 先进入web界面看一下 提示&#xff1a;DC7加了一些新的东西&#xff0c;让我看看盒子之外的东西&#xff0c;与…

C++ 利用容器适配器,仿函数实现栈,队列,优先级队列(堆),反向迭代器,deque的介绍与底层

C 利用容器适配器,仿函数实现栈,队列,优先级队列【堆】,反向迭代器,deque的介绍与底层 一.容器适配器的介绍二.利用容器适配器实现栈和队列1.stack2.queue 三.仿函数介绍1.什么是仿函数2.仿函数的使用3.函数指针的使用1.函数指针的用处2.利用函数指针完成回调3.利用仿函数完成回…

docker 体验怀旧游戏(魂斗罗等)

docker run --restart always -p 8081:80 --name fc-games -d registry.cn-hangzhou.aliyuncs.com/bystart/fc-games:latest ip:8081访问 jsnes: js制作了一个网页版的NES模拟&#xff0c;可以在网页上玩fc游戏 (gitee.com)

创建第一个 Spring 项目(IDEA社区版)

文章目录 创建 Spring 项目创建一个普通的 Maven 项目添加 Spring 依赖IDEA更换国内源 运行第一个 Spring 项目新建启动类存储 Bean 对象将Bean注册到Spring 获取并使用 Bean 对象 创建 Spring 项目 创建一个普通的 Maven 项目 首先创建一个普通的 Maven 项目 添加 Spring 依…

Tomcat好帮手---JDK

目录 1、Tomcat好帮手---JDK 2、安装JDK 部署Tomcat参考博主博客 部署TOMCAT详解-CSDN博客 1、Tomcat好帮手---JDK JDK是 Java 语言的软件开发工具包&#xff0c;JDK是整个java开发的核心&#xff0c;它包含了JAVA的运行环境&#xff08;JVMJava系统类库&#xff09;和JAVA…

2024年新提出的算法:一种新的基于数学的优化算法——牛顿-拉夫森优化算法|Newton-Raphson-based optimizer,NRBO

1、简介 开发了一种新的元启发式算法——Newton-Raphson-Based优化器&#xff08;NRBO&#xff09;。NRBO受到Newton-Raphson方法的启发&#xff0c;它使用两个规则&#xff1a;Newton-Raphson搜索规则&#xff08;NRSR&#xff09;和Trap Avoidance算子&#xff08;TAO&#…

视频压缩怎么才能保持画质清晰?这样设置参数~

很多时候我们都需要压缩视频&#xff0c;但在减小视频大小的时候我们也会担心画质清晰度问题&#xff0c;那怎么既能压缩视频大小&#xff0c;又能保证视频清晰度呢&#xff1f;下面就来了解下吧~ 视频压缩分为无损压缩和有损压缩&#xff0c;如果想保持画质清晰&#xff0c;可…