游戏小地图方案

Unity小地图的实现

游戏,特别是RPG类型,基本都需要添加小地图功能来辅助玩家。

实现小地图需解决的问题:

  1. 小地图(贴图)从哪里来?
  2. 如何把场景中单位的坐标转换到小地图上
  3. 小地图视角怎么跟玩家视角一致

思路:

  1. 让美术垂直90°方向以正交视角俯视整个场景,然后截取场景输出成图片,截取的大小让美术设置,一般不超过2048*2048
  2. 保存截图时的矩阵
  3. 通过第2点保存的矩阵,在游戏运行时把场景中单位的世界坐标转换到小地图下的局部坐标

实现:

  1. 根据设置(这里写死了800*600),设定截图窗口的大小,同时Camera视角校准为玩家视角,我这里是直接使用Scene窗口
if (GUILayout.Button("调整截图窗口大小"))
{   
    var windowSize = Vector2(800,600);
    var lastSceneView = SceneView.lastActiveSceneView;

    // 场景的Main Camera
    var mainCamera = UnityEngine.Camera.main;
    // SmoothFollow是镜头跟踪的组件,这里知道SmoothFollow里有个rotationAngle字段是记录玩家视角即可
    XS.SmoothFollow smoothFollow = null;

    if (mainCamera)
    {
        smoothFollow = mainCamera.GetComponent<XS.SmoothFollow>();
    }
    if (smoothFollow == null)
    {
        return;
    }

    lastSceneView.position = new Rect(Vector3.zero, windowSize);

    Quaternion currentRotation = Quaternion.Euler(90, smoothFollow.rotationAngle, 0);
    lastSceneView.LookAt(Vector3.zero, currentRotation, lastSceneView.size, true);
    lastSceneView.isRotationLocked = true;
}
  1. 截图时,以Scene的大小为图片宽高,并预先算出此时的world2Screen矩阵和screen2World矩阵,用于后面的逻辑运算
if (GUILayout.Button("截取小地图"))
{
    var lastSceneView = SceneView.lastActiveSceneView;
    var sceneCamera = lastSceneView.camera;
    if (!sceneCamera.orthographic)
    {
        return;
    }

    var width = sceneCamera.pixelWidth;
    var height = sceneCamera.pixelHeight;
    var cameraPos = sceneCamera.transform.position;
    var camreaSize = sceneCamera.orthographicSize;
    
    Matrix4x4 world2Screen = sceneCamera.projectionMatrix * sceneCamera.worldToCameraMatrix;
    Matrix4x4 screen2World = world2Screen.inverse;

    RenderTexture sceneCameraRT = RenderTexture.GetTemporary((int)width, (int)height, 32, RenderTextureFormat.ARGBFloat);
    sceneCamera.targetTexture = sceneCameraRT;
    sceneCamera.Render();
    sceneCamera.targetTexture = null;

    // targetData是用于保存数据组件,挂载在场景的一个空Object上
    string sceneName = targetData.gameObject.scene.name;

    var path = EditorUtility.SaveFilePanel("Save SmallMap", "", sceneName, "png");
    if (!string.IsNullOrEmpty(path))
    {
        if (SaveRenderTextureToPNG(sceneCameraRT, path))
        {
            targetData.smallMapCameraCenter = cameraPos;
            targetData.smallMapCameraSize = camreaSize;

            targetData.smallMapWorldToScreenMatrix = world2Screen;
            targetData.smallMapScreenToWorldMatrix = screen2World;
            targetData.smallMapCutSize = new Vector2(width, height);

            UnityEditor.EditorUtility.SetDirty(targetData);
            UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(targetData.gameObject.scene);
        }
        else
        {
            Debug.LogError("Save RenderTexture to file error");
        }
    }
    RenderTexture.ReleaseTemporary(sceneCameraRT);
}
  1. 根据第2点保存的两个矩阵和图片大小,通过以下接口(Lua实现)即可完成坐标转换,里面涉及的数学知识请自行查阅。
-- 世界坐标转图片的局部坐标
function manualWorldToScreenPoint(world2Screen, x, z, pixelWidth, pixelHeight)
    local temp = world2Screen * UnityEngine.Vector4(x, 10, z, 1.0)
    if temp.w == 0 then
        return UnityEngine.Vector3.zero
    else
        temp.x = (temp.x/temp.w + 1)*0.5 * pixelWidth
        temp.y = (temp.y/temp.w + 1)*0.5 * pixelHeight
        return temp.x, temp.y
    end
end

-- 图片的局部坐标转世界坐标
function manualScreenPointToWorld(screen2World, x, y, pixelWidth, pixelHeight)
    local in_x = 2.0 * (x / pixelWidth) - 1.0
    local in_y = 2.0 * (y / pixelHeight) - 1.0
    local in_z = 10
    local in_w = 1.0
    local pos = screen2World * UnityEngine.Vector4(in_x,in_y,in_z,in_w)
    if pos.w == 0 then
        return UnityEngine.Vector3.zero
    else
        pos.w = 1.0 / pos.w
        pos.x = pos.x*pos.w
        pos.y = pos.y*pos.w
        pos.z = pos.z*pos.w
        return pos.x, pos.z
    end
end

额外:

小地图一般需要添加小地图寻路功能,这里我使用的方案是给小地图添加PointerClick事件,根据点击的坐标点转换成世界坐标点,然后从在一点(当然是上移到场景上空)通过射线往下检测,得到与路面(路面需要设置特定Layer)的交点,这个交点就是目标点,接下来就是UnityEngine.AI.NavMeshAgent的事情了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,245评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,749评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,960评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,575评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,668评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,670评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,664评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,422评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,864评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,178评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,340评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,015评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,646评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,265评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,494评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,261评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,206评论 2 352