斜角地图逻辑原理解析和Isometric地图编辑器设计方案

本文主要是介绍斜角地图逻辑原理解析和Isometric地图编辑器设计方案,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

当我要做的一款游戏,而无法即时地查看地图各图形元件的拼接效果,而导致不得不中止时,当时找过不少公开的地图编辑器,希望能拿来即用,但不是因为拼接效果不满意,就是因为生成的文件不是太满意。无奈之下决心自己动手写一个工具时,才知道有多少困难。

论坛里的相关帖子,基本上都试着各种关键词看了一遍,说实在的,感觉上,除了几个原来做过斜角地图编辑的,其余帖子里基本上是迷茫的
感觉坛子里像wangqiang99x,闪刀浪子,恋水泥人,wxsr等几位应该还是比较熟悉的,但看了一下他们的帖子,还是感觉有些不够,直到看过杜宇欣的文章,才算解决了斜角地图中的各个障碍

在前一篇斜角地图原理解释及斜角图形绘制实例细述已经对斜角地图的原理进行了细致的阐述。这里就不再重复了,只从斜角地图的逻辑原理方面进行解析。

关于地图中的图形元件的拼接原理,请参考这篇文章闪刀浪子的地图编辑器对应的地图解析类及教程的前半部分,或者只看这个图

因为所有的图片都是矩形的,所以拼接时必然要有所叠加,这就是图片的遮挡。

而要处理图片的遮挡关系,才能使所有这些图片构成的地图所呈现的画面显示出立体效果。
而这种遮挡关系就是地图景深的处理,那么景深的处理都会涉及哪些关键点呢,下面请一个个来看。

1、图片之间的遮挡,这是景深呈现的关键

2、图形元件所代表的意义,即处于某个位置的图形元件是山水建筑物,还是路面等,以标识游戏当中的角色是可以通行还是受阻碍的

3、图形元件是否允许与用户的交互,即一个图形元件放到地图上,如果就是代表一棵树,一片小山,而这些又仅仅是表征地图地形的一个障碍物,那么则不会影响用户的键盘鼠标消息

4、如何通过鼠标当前位置(或角色当前位置),来了解所处的是哪里(什么地形,会不会产生事件等)

5、如何通过网格中某个单元格的纵列位置,来获得屏幕坐标。比如角色在某一个位置,而房子在另一个位置,现在角色要走到房子里,这就要获取某个建筑物所在的坐标,以使角色行走到目标位置

6、碰撞处理和寻路等,如果是地国中有运动的角色等类物体,就必须处理这方面的问题,这暂时不属于地图逻辑原理,也不属于地图编辑器的设计,暂不展开讨论

为了表述方便,我专门截图制作了下面的一张图片来进行一些要素的标注
 

从上图可以看出,以等距地图网格对象的顶点top为坐标系原点T(0,0),以汉字撇捺两个方向的纵列为坐标系的两个坐标轴,即Pie轴与top-right方向平行,Na轴与top-left平行。

这样比其他文章里建立的u-v坐标系在使用时更容易理解,也计算时也更便捷。
在接下来的计算中,各单元格也与网格坐标一样,全部以其顶点坐标代表该单元格的位置(屏幕坐标x,y);
而建立的Pie-Na坐标系,仅是通过单元格相对原点T的撇向序号,捺向序号(Pie,Na)数值对来表示该单元格在此网格上的序列位置。

我们通过分析一下网格的两个单元格关系,就可以得出此坐标系下的计算公式。
看图中标注的两个绿色点M(1,2),N(3,1),我们首先看一下,M点相对原点T其屏幕坐标是什么关系
Mx = cellHalfWidth * (Mpie - Mna) = -1 * cellHalfWidth,即相对原点T向左半个单元格宽度
My = cellHalfHeight * (Mpie + Mna) = 3 * cellHalfHeight,即相对原点T向下3倍的半个单元格高度

我们再用此公式来套一下N点,看下是否如实
Nx = cellHalfWidth * (Npie - Nna) = 2 * cellhalfWidth,看下图中,是不是刚好相差一个单元格宽度?
Ny = cellHalfHeight * (Npie + Nna) = 4 * cellHalfHeight,看下图中,也刚好相差2个单元格高度。

好吧,再看点M和N之间又如何呢
Width(M-N) = cellHalfWidth * ((Npie -Mpie) - (Nna-Mna)) = cellHalfWidth * (2 - (-1)) = 3 * cellHalfWidth,再对照一下图中,嗯,刚好是3倍的半个单元格宽度
Height(M-N) = cellHalfHeight * ((Npie - Mpie) + (Nna - Mna)) = cellHalfHeight * (2 + (-1)) = 1 * cellHalfHeight,看下图中,这个也没错!

那么经过一番验证,我们的公式就可以确定没问题了,
即,在上述以网格顶点T为原点的Pie-Na坐标中,任一单元格的屏幕位置Q(x,y)都有如下公式:
Qx = cellHalfWidth * (Qpie - Qna) + Tx
Qy = cellHalfHeight * (Qpie + Qna) + Ty

Width(Q) = cellHalfWidth * (Qpie - Qna)        //含正负,在原点左侧为负,右则为正
Height(Q) = cellHalfHeight * (Qpie + Qna)      //肯定为正

对于任意两点U(ux,uy),V(vx,vy)都有如下公式:
Vx = cellHalfWidth * (Vpie - Vna) + Ux
Vy = cellHalfHeight * (Vpie + Vna) + Uy

V到U的距离为
Width(V-U) = cellHalfWidth * ((Vpie-Upie) - (Vna-Una))        //含正负,V在U点左侧为负,右则为正
Height(V-U) = cellHalfHeight * ((Vpie-Upie) + (Vna-Una))      //肯定为正

看起来,上下两个公式没多大不同,不过在使用时,可以一目了然,还是比较方便,所以不嫌麻烦都列出来了

这解决了上面所说的哪个问题了,通过单元格的序列位置求出其屏幕位置,是不是第5个问题解决了呢。

大海航行靠舵手,在斜角地图的逻辑中,有了这样一个公式的出现,就可以顺次搞定以上的1~5的问题了,下面就不这么罗嗦了。

4、通过任一点屏幕坐标,求所在单元格的序列位置
直接把上面公式一翻转,再根据前一篇(还不知道斜角地图原理和细节的看这里)中所述的单元格的宽=2*单元格的高
可得出如下公式:
参数点Q(x,y)为Cell中任一点,其与网格的顶点坐标的距离在X、Y轴方向长度分别是Width(Q),Height(Q);
Qpie = (2 * Height(Q) + Width(Q)) / (cellHalfWidth * 2)
Qna = (2 * Height(Q) - Width(Q)) / (cellHalfHeight * 2)


3、是否允许用户交互,我们只要给图形元件设置这样一个属性即可

2、图元类型,同理,我们只需标识一下此图元的类型即可

1、遮挡关系,现在再去看下图中的单元格序列坐标,就可以看到,凡是单元格序列坐标小的,必然被单元格序列坐标大的遮挡
再来看稍微复杂点的单元格之间的遮挡关系,比如M,N

如果图片的宽度仅为单元格顶点left-right,则像M,N这样的点,根本不会发生遮挡关系,因为Mright与Nleft相距半个单元格宽度的,但如果其宽度都超出left-right的宽度,并

且都又比较高,这时仍然会发生遮挡关系的,那么该如何处理这个遮挡关系呢,非常快速,加减法而已
(Npie - Mpie) + (Nna - Mna) > 0,则N挡M,小于零,则M挡N。

那么又必然会存在相等的,比如M(1,2)与Q(2,1)看起来是平行的,这时怎么办呢
像这类,根本就是完全平行,即使是在视觉效果上,所以,怎么处理都无所谓了,左挡右,或者右挡左,都非常合理,完全视自己喜好了

但是在代码中,一般是不需要这么进行3次加减法运算,多数都会拦截在对pie,na序列值的if语句处。
当然,如果是循环设置地图上所有的图元遮挡关系,pie,na的两个for循环中更是直接

说到这里,斜角地图的逻辑原理,就已经没什么东西了,再来看地图编辑器该如何来设计

通常,我们会为地图绘制一幅背景图的,然后我们可能在这个背景图上添加一些建筑物等物体(甚至包括地面,NPC等),让整个游戏世界看起来像是真实世界的映射。

我们首先来看一下会有哪些东西要出现在这个地图当中

1、地图背景

2、网格对象

3、放置的物体(建筑、地面、NPC等)

4、角色对象

5、有时也需要一个可通行路径对象

一般来说,地图这个大容器可能会被塞进去很多的对象,当非常多的可视对象,尤其是交互类对象时,会使得相关的一些处理,比如遮挡关系的处理,碰撞检测,寻路等非常耗费系统资源,所以我们在规划时,就要考虑到可能出现的这些问题

对于上述前三类对象,是必须放置到地图这个容器当中去的。

而第3项,放置的物体有可能会包含两类,一类是非交互性物体,一类是交互性物体;
而处理方式,一般也有两种方式,即放置进的物体都是非交互性物体,而交互性物体放置到地图外面的另一专门层里,并且使之与地图容器对象等大,这个层容器里面,全部是响应用户的一些对象,但都是看不到的,当鼠标或角色移动到此类对象范围内时,就表现出交互性的半透明效果叠在地图中同样位置的对象上面,因为可响应用户的对象在地图中远远少于非交互对象。但这样一来,寻路和角色在运动时的遮挡处理也复杂化了,因为既然把交互对象移出了地图容器,那么地图容器一般都会设为完全不响应用户,角色有属于自己的层对象来容纳,而遮挡关系就只能靠贴图算法来实现了,当同屏幕有数量非常多的角色对象时,而主程能力又很给力时,有个优秀的贴图算法,可以实现非常高的效率和承载能力

但是一般较为常用的方法,还是采用非交互性物体和交互性物体都放置在地图容器中,而且角色也同样放置在地图容器中,这种处理方案一般在遇到地图在有大量物体,并且角色数量在3~4位数时,通常会遇到瓶颈,CPU和内存飞速上涨,而且会出现画面卡顿的现象。但是一般的小游戏都可以满足了,只要尽量消减一下地图中的非交互性对象数量即可,但话又说回来,如果采用消减地图中非交互性对象的数量,则一定会采用通行路径的处理办法,因为地图上大量不可通行的位置都在地图背景图片中来表现来的

newscreen348447000.png (42.56 KB, 下载次数: 20)

newscreen348447000.png

这篇关于斜角地图逻辑原理解析和Isometric地图编辑器设计方案的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/719253

相关文章

Spring Security 单点登录与自动登录机制的实现原理

《SpringSecurity单点登录与自动登录机制的实现原理》本文探讨SpringSecurity实现单点登录(SSO)与自动登录机制,涵盖JWT跨系统认证、RememberMe持久化Token... 目录一、核心概念解析1.1 单点登录(SSO)1.2 自动登录(Remember Me)二、代码分析三、

MySQL CTE (Common Table Expressions)示例全解析

《MySQLCTE(CommonTableExpressions)示例全解析》MySQL8.0引入CTE,支持递归查询,可创建临时命名结果集,提升复杂查询的可读性与维护性,适用于层次结构数据处... 目录基本语法CTE 主要特点非递归 CTE简单 CTE 示例多 CTE 示例递归 CTE基本递归 CTE 结

Spring Boot 3.x 中 WebClient 示例详解析

《SpringBoot3.x中WebClient示例详解析》SpringBoot3.x中WebClient是响应式HTTP客户端,替代RestTemplate,支持异步非阻塞请求,涵盖GET... 目录Spring Boot 3.x 中 WebClient 全面详解及示例1. WebClient 简介2.

在MySQL中实现冷热数据分离的方法及使用场景底层原理解析

《在MySQL中实现冷热数据分离的方法及使用场景底层原理解析》MySQL冷热数据分离通过分表/分区策略、数据归档和索引优化,将频繁访问的热数据与冷数据分开存储,提升查询效率并降低存储成本,适用于高并发... 目录实现冷热数据分离1. 分表策略2. 使用分区表3. 数据归档与迁移在mysql中实现冷热数据分

C#解析JSON数据全攻略指南

《C#解析JSON数据全攻略指南》这篇文章主要为大家详细介绍了使用C#解析JSON数据全攻略指南,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、为什么jsON是C#开发必修课?二、四步搞定网络JSON数据1. 获取数据 - HttpClient最佳实践2. 动态解析 - 快速

Spring Boot3.0新特性全面解析与应用实战

《SpringBoot3.0新特性全面解析与应用实战》SpringBoot3.0作为Spring生态系统的一个重要里程碑,带来了众多令人兴奋的新特性和改进,本文将深入解析SpringBoot3.0的... 目录核心变化概览Java版本要求提升迁移至Jakarta EE重要新特性详解1. Native Ima

spring中的@MapperScan注解属性解析

《spring中的@MapperScan注解属性解析》@MapperScan是Spring集成MyBatis时自动扫描Mapper接口的注解,简化配置并支持多数据源,通过属性控制扫描路径和过滤条件,利... 目录一、核心功能与作用二、注解属性解析三、底层实现原理四、使用场景与最佳实践五、注意事项与常见问题六

MySQL逻辑删除与唯一索引冲突解决方案

《MySQL逻辑删除与唯一索引冲突解决方案》本文探讨MySQL逻辑删除与唯一索引冲突问题,提出四种解决方案:复合索引+时间戳、修改唯一字段、历史表、业务层校验,推荐方案1和方案3,适用于不同场景,感兴... 目录问题背景问题复现解决方案解决方案1.复合唯一索引 + 时间戳删除字段解决方案2:删除后修改唯一字

nginx -t、nginx -s stop 和 nginx -s reload 命令的详细解析(结合应用场景)

《nginx-t、nginx-sstop和nginx-sreload命令的详细解析(结合应用场景)》本文解析Nginx的-t、-sstop、-sreload命令,分别用于配置语法检... 以下是关于 nginx -t、nginx -s stop 和 nginx -s reload 命令的详细解析,结合实际应

MyBatis中$与#的区别解析

《MyBatis中$与#的区别解析》文章浏览阅读314次,点赞4次,收藏6次。MyBatis使用#{}作为参数占位符时,会创建预处理语句(PreparedStatement),并将参数值作为预处理语句... 目录一、介绍二、sql注入风险实例一、介绍#(井号):MyBATis使用#{}作为参数占位符时,会