游戲小地圖方案

Unity小地圖的實現(xiàn)

游戲好港,特別是RPG類型裁僧,基本都需要添加小地圖功能來輔助玩家铺坞。

實現(xiàn)小地圖需解決的問題:

  1. 小地圖(貼圖)從哪里來惯悠?
  2. 如何把場景中單位的坐標(biāo)轉(zhuǎn)換到小地圖上
  3. 小地圖視角怎么跟玩家視角一致

思路:

  1. 讓美術(shù)垂直90°方向以正交視角俯視整個場景,然后截取場景輸出成圖片捉邢,截取的大小讓美術(shù)設(shè)置脯丝,一般不超過2048*2048
  2. 保存截圖時的矩陣
  3. 通過第2點保存的矩陣,在游戲運行時把場景中單位的世界坐標(biāo)轉(zhuǎn)換到小地圖下的局部坐標(biāo)

實現(xiàn):

  1. 根據(jù)設(shè)置(這里寫死了800*600)伏伐,設(shè)定截圖窗口的大小宠进,同時Camera視角校準(zhǔn)為玩家視角,我這里是直接使用Scene窗口
if (GUILayout.Button("調(diào)整截圖窗口大小"))
{   
    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的大小為圖片寬高,并預(yù)先算出此時的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是用于保存數(shù)據(jù)組件堤器,掛載在場景的一個空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. 根據(jù)第2點保存的兩個矩陣和圖片大小,通過以下接口(Lua實現(xiàn))即可完成坐標(biāo)轉(zhuǎn)換末贾,里面涉及的數(shù)學(xué)知識請自行查閱闸溃。
-- 世界坐標(biāo)轉(zhuǎn)圖片的局部坐標(biāo)
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

-- 圖片的局部坐標(biāo)轉(zhuǎn)世界坐標(biāo)
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事件拱撵,根據(jù)點擊的坐標(biāo)點轉(zhuǎn)換成世界坐標(biāo)點辉川,然后從在一點(當(dāng)然是上移到場景上空)通過射線往下檢測,得到與路面(路面需要設(shè)置特定Layer)的交點拴测,這個交點就是目標(biāo)點乓旗,接下來就是UnityEngine.AI.NavMeshAgent的事情了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末集索,一起剝皮案震驚了整個濱河市屿愚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌务荆,老刑警劉巖妆距,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異函匕,居然都是意外死亡毅厚,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進店門浦箱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吸耿,“玉大人,你說我怎么就攤上這事酷窥⊙拾玻” “怎么了?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵蓬推,是天一觀的道長妆棒。 經(jīng)常有香客問我,道長沸伏,這世上最難降的妖魔是什么糕珊? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮毅糟,結(jié)果婚禮上红选,老公的妹妹穿的比我還像新娘。我一直安慰自己姆另,他們只是感情好喇肋,可當(dāng)我...
    茶點故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著迹辐,像睡著了一般蝶防。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上明吩,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天间学,我揣著相機與錄音,去河邊找鬼印荔。 笑死低葫,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的躏鱼。 我是一名探鬼主播氮采,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼染苛!你這毒婦竟也來了鹊漠?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤茶行,失蹤者是張志新(化名)和其女友劉穎躯概,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體畔师,經(jīng)...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡娶靡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了看锉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姿锭。...
    茶點故事閱讀 40,861評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡塔鳍,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出呻此,到底是詐尸還是另有隱情轮纫,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布焚鲜,位于F島的核電站掌唾,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏忿磅。R本人自食惡果不足惜糯彬,卻給世界環(huán)境...
    茶點故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望葱她。 院中可真熱鬧撩扒,春花似錦、人聲如沸览效。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽锤灿。三九已至挽拔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間但校,已是汗流浹背螃诅。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留状囱,地道東北人术裸。 一個月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像亭枷,于是被迫代替她去往敵國和親袭艺。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,860評論 2 361