UE4中的小地图有很多种实现办法,但是现在网上的办法大多是人物头顶绑摄像机,这样的办法大多low而且低效,不适合作为正式的游戏功能使用,这里使用RenderTarget渲染2D图片的办法,通过获得人物/npc/物体在现实世界中的位置以及地图边界位置,算出在2D地图上的相对位置,从而更新2D图标在地图上的位置。
需要用到RenderTarget(渲染目标)
参考链接:https://blog.csdn.net/hui211314ddhui/article/details/78236496
具体参考了这位老哥给出的项目中的做法,并做出了一些相应的优化。
大体步骤如下:
1.创建好相应地图,这里建议使用UE俯视图无光照模式下进行截图(个人采取笨办法将房顶隐藏了),可以用后处理等办法渲染出不同风格的地图,也可以创建好地图后进行后期描画。(具体操作后面会细说)
2.俯视图截图的地图边界坐标采样(获取到地图边界左上角的坐标,地图实际的长和宽)
3.在UMG中写RenderTarget逻辑。主要逻辑图为:
4.创建好相关接口进行代码复用,创建放大的地图。
1.创建好相应静态2D地图并进行边角采样
这里以官方“太阳神庙”项目进行距离。首先将视口调整为游戏模式(G)隐藏不必要的图标,相机调整为俯视图,无光照,放大俯视图到能鸟瞰全景,并将场景屋顶模型分类,批量隐藏。使用UE内置高分辨率屏幕截图(游戏视口左上角三角菜单内),同时将一些显眼的模型放入当前场景的四角,如下图:
这里推荐自建actor放到地图四角并用枚举变量标注actor位置,actor内将左上,左下,右上三个坐标分别传入gamemode中
2.创建渲染目标并写相关材质。
小地图功能总共需要三个渲染目标,一个TargetMap作为后台渲染模板,尺寸尽可能要大。一个MinMap作为小地图模板,小地图由目标地图DrawTexture而来,尺寸要小。一个可缩放的大地图LargeMap,同样通过目标地图DrawTexture而来,尺寸中等偏大。
创建小地图材质,将材质选为UserInterface和Masked。这是带透明通道的UMG或slate可用材质,创建圆形遮罩,如下图:
3.创建UMG并写相关逻辑。
这里推荐将小地图与大地图分别封装成一个单独的UMG。首先我们需要了解原理。
这种做法的原理为将截图做好的地图Draw描画给渲染目标RenderTarget,DrawTexture描画节点本身就有描画位置,大小,是否旋转,描画坐标等等的变量。将整个地图描画给渲染目标后再将玩家位置的图标描画给渲染目标,然后将NPC/物品位置的图片描画给渲染目标,这样TargetMap的描画就做好了。
如上图所示,左上角坐标为(3,2),通过坐标计算可得SizeX为7,SizeY为11,人物所处位置(5,5)可得
U = (5-3)/7≈0.28
V = (5-2)/11≈0.27
假设人物图标的大小为0.5*0.7,而渲染目标大小为MapSize,那么人物图标描画在地图上的X和Y坐标分别为:
X = (U*MapSizeX)-(0.5/2)
Y = (V*MapSizeY)-(0.7/2)
之所以要减去人物图标大小要除2是因为坐标需要处于图标正中心。
以上即为现实坐标换算为2D地图相对坐标的逻辑,了解清楚算法之后蓝图逻辑就是水到渠成的事了。
在小地图UMG中首先CastToGameMode获取到地图的边界。
再在小地图UMG的tick事件中执行如下逻辑:
BeginDrawCanvastoRenderTarget→DrawBKMap→DrawPlayer→DrawCustomMarker→EndDrawCanvastoRenderTarget
完成目标地图的制作,之后的小地图大地图都是要基于此目标地图进行描画的。
由于蓝图逻辑可读性差,所以本文不会放出详细的蓝图步骤,只会讲解思路算法与大概逻辑截图(必然很模糊)。
自己写的连连看才是好连连看。——鲁迅
大概蓝图逻辑如下:
首先BeginDraw开始描画并将描画目标的大小及长宽比例赋值给相应变量。
DrawBKMap直接将创建好的地图描画进渲染目标即可。关键节点DrawTexture,其他变量不用管,ScreenSize设置为渲染目标Size即可
然后开始描画人物图标,获取人物Location X,Y坐标,通过计算获得屏幕坐标赋值给ScreenPosition,自定义图标大小赋值给Size,获取人物的朝向,赋值给Rotation。具体的通过上面公式自己写算法即可。
地图上不光要有玩家,也要有NPC/任务物品等。这里采用给NPC/任务物品挂载组件的办法,组件中的逻辑为将挂载了组件的Actor增加到小地图UMG的Actor数组中,将Actor数组遍历,按照描画人物图标的方式描画Actor图标。由于组件有自定义图标,是否在地图上显示等变量,可以做到不同种类的物品可以显示不同图标。大概逻辑如下:
不会缩放的大地图制作完成。
接下来开始制作可以缩放的地图。
和上文步骤相同,创建MinMap渲染目标,以TargetMap为RenderTexture,Draw描画即可。这里要引入一个新变量,地图放大倍率。同时要做好相关的变量实现这个函数的多态。因为小地图和大地图,某种程度上是用同一种方法实现的。区别只是放大倍率不同,大地图可以通过拖动的方式查看其它区域,小地图一直跟随主角。小地图可以跟着镜头旋转,而大地图并不用旋转与遮罩。
将这些变量作为函数输入值即可,具体的DrawTexture中的CoordinatePosition=人物XY坐标转化的UV-(地图放大倍率/2),CoordinateSizeX=地图放大倍率,CoordinateSizeY=TargetMap渲染目标的长宽比MapSizeMult * 地图放大倍率(不乘原画长宽比的话如果大地图小地图长宽比不同情况下小地图渲染出来会出现拉伸情况)
大概逻辑如下:
至此小地图制作完成。
大地图的大概思路。做成一个单独UMG,按某个按键创建UMG,大地图中覆盖鼠标移动方法。取鼠标相对上一帧的移动差值
之后开始创建RenderTarget,逻辑如下:
这样就可以在人物不动时根据鼠标拖动来移动地图了,修改mapzoom也可以实现地图的缩放。
补充:在DrawMiniMap中没添加边界限定。会导致玩家走到地图边界后渲染出多余的地图
正确办法是加个判断。
当TempCoordX + MapZoom地图放大倍率 > 1时,TempCoordX -(TempCoordX + MapZoom地图放大倍率)
TempCoordY同理。