ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Unity小地图功能(纯UI,不加相机)

Unity小地图功能(纯UI,不加相机) 需求分析小地图图片可以用场景相机在高空正交视图截图得到如果不是多层地图缩略图需要遮罩。地图图片是它的子物体然后是确定显示区域显示地图图片的哪一块玩家标在哪地图图片和玩家图标的朝向可能是地图摆正或者玩家图标摆正数据管理上小地图图片和大地图预制体绑定二者可放在一个文件夹为了截图小地图需要一个放有大地图的专门场景小地图图片的制作场景相机向下看并且正交。保证所有地图在相机的旋转有统一的标准比如默认是世界z轴朝相机上方。制作小地图的场景需要光线充足没有雾没有影子。为了不破坏游戏场景应该给每个地图专门建一个场景制作小地图。地图、玩家图标的位置、朝向小地图一般不会显示整个地图小地图图片在遮罩里是移动的。如果玩家图标在遮罩里也是移动的机制就比较复杂把玩家图标固定在中心是个比较简单的机制。旋转朝向也有地图旋转和玩家旋转两种机制。一般玩家旋转用得比较多。玩家图标在中心小地图移动计算小地图位置玩家图标不是小地图的子对象。需要移动的是小地图需要计算的是小地图的位置。找地图上两个点得到场景里这两个点的世界位置x、z坐标和地图上的点在中心时小地图的局部位置建立对应关系。手动定位参考点难免有误差但是这两个参考点越远误差就越小。这两个参考点应该尽量世界位置小地图局部位置(0,0)(59.5,194.4)(20.265,28.48)(-234.3,-215.1)计算世界位置到小地图局部位置的倍率kx(59.5-(-234.3))/(-20.265)k1;kz(miniRef1.y-miniRef2.y)/(worldRef1.y-worldRef2.y)小地图锚点坐标公式xminiRef1.x(player.transform.position.x - worldRef1.x) * kxyminiRef1.y(player.transform.position.z - worldRef1.y) * kz这里倍率项是加号尽管玩家在世界的移动方向和小地图的移动方向相反但计算倍率时倍率已经是负数。计算玩家图标旋转是把玩家世界欧拉角的y轴复制给玩家图标局部欧拉角的z轴加负号。代码public class Minimap : MonoSingletonMinimap { public Image imageMap, imagPlayerIcon; public Vector2 miniRef1, miniRef2; public Vector2 worldRef1, worldRef2; float kx, kz; RectTransform mapRect; Transform player; const int updatePeriod 8; void Start() { kx (miniRef1.x - miniRef2.x) / (worldRef1.x - worldRef2.x); kz (miniRef1.y - miniRef2.y) / (worldRef1.y - worldRef2.y); mapRect imageMap.transform as RectTransform; player MyInput.Instance.player.transform; } void Update() { if (Time.frameCount % updatePeriod 0) { mapRect.anchoredPosition new Vector2( miniRef1.x (player.position.x - worldRef1.x) * kx, miniRef1.y (player.position.z - worldRef1.y) * kz); imagPlayerIcon.transform.localEulerAnglesnew Vector3(0,0,-player.localEulerAngles.y); } } }数据管理一个场景的小地图数据需要一个图片和4个Vector2坐标世界坐标和小地图局部坐标各2个。如果一个场景一个小地图适合放在场景文件夹也就是放光照烘焙数据、遮挡剔除的文件夹。如果多个场景共用一个地图小地图配置和地图放在一起。把这一套数据做成ScriptableObject配置数据[CreateAssetMenu(menuName Custom/小地图配置)] public class MiniMapSO : ScriptableObject { public Sprite minimap; public Vector2 miniRef1, miniRef2; public Vector2 worldRef1, worldRef2; }然后发现直接把这些数据在场景里配置好比读取ScriptableObject要方便。标注更多物体现在我们想在小地图上标注更多东西比如发现的敌人、传送点。之前我们把玩家图标固定在小地图范围中心让小地图图片移动。现在其他物体的图标应该放在什么层级不妨放在小地图图片的子级。我们需要一个根据物体的世界坐标计算出小地图局部坐标的公式还有该物体在小地图上图标的Sprite。小地图类的一个函数接受世界坐标和图标显示。定义一个标注对象的输入参数public struct MinimapMarkInfo { public Vector2 pos; public float angle; }然后小地图控制器得维护一个被绘制对象的字典想被绘制的对象给小地图发自己的id和Sprite让小地图把自己注册了。标记Sprite要么对象发给小地图要么小地图自己维护一个transform-图标的字典对象给小地图发自己的id和种类。结束绘制时只需给小地图发事件包含自己的id注销。位置是被显示对象发给小地图还是小地图自己读取如果被显示物体不断准备消息结构体发给小地图其实小地图如果已经在显示它还要把新来的消息和正在显示的Image对应上。之前显示玩家图标是人物给小地图发消息因为那个没有识别对象和Image对应关系的问题玩家图标是特殊唯一的。然后还发现小地图相对于父级位置的参考坐标和标记相对于小地图的参考坐标不通用。标记对应在地图右上角的局部坐标就是地图图片的宽高。如果地图用MVC视图业务分开我们说要维护一个显示对象列表视图必然要维护一个image列表如果用MVC那么要分成两个列表那么维护两个列表的数据一致是很麻烦的。地图要频繁更新位置那么这里不再使用MVC一个类做业务、视图。MVC本来是为了复用视图由控制器准备好参数传入现在每次调用视图是把已有的image修改位置那么参数必须能识别要移动哪个image要加一个imageId。然后视图对当前有的image更新位置没有的新建多余的删除。不用MVC还有问题我们是让被显示物体初始就把自己注册到地图控制器如果VC合一一开始没打开地图控制器也不存在。还是决定用MVC。位置换算在视图还是控制器本来决定肯定在控制器但是计算缩放系数需要image的尺寸只有视图才有。初始化就要算但是控制器初始化时视图还不存在拿不到结果属于是视图持有业务的关键数据只能把这部分业务迁移到视图。要么只能去UI上看一下尺寸手抄到控制器检查器。
返回列表