30分鐘簡易復刻《元氣騎士》地圖生成系統
元氣騎士是由涼屋遊戲工作室研發的一款角色扮演類遊戲,於2017年2月17日釋出。 遊戲講述了外星生物奪走維持世界的魔法石的故事,玩家將扮演騎士、刺客等角色參與遊戲,奪回魔法石。
Unity Connect社群博主超級汽水藉助Unity對遊戲中的地圖生成系統進行了復刻。與各位分享在此。
地圖顯示方式
- 隨機大小的矩形房間。
- 隨機的房間數量。
- 通過走廊連線每個房間。
- 每個圖都有 倆個特殊房間:“出生房”、“傳送房”。
地圖生成思路梳理
因為在原版遊戲中房間並不是完全的正方形,所以我們在設計時要考慮到邊長的問題。
雖然遊戲中的房間數量是隨機的,但是也是有一個範圍的。所以需要按照生成地圖的最終面積來做一個約束。
走廊連線算是遊戲中的一個難點,因為走廊的長度是不確定的要在生成房間後根據房間的位置和大小來確定走廊的生成位置以及長度。
在遊戲中,每一個大關卡包含多個小關卡,每個小關卡中又包含了多張地圖,每個地圖中又有多個小房間。
這樣說可能有點不太好理解我畫了張圖來幫忙理解:
實現思路以及簡化
在之前博主已經發過兩篇文章介紹tilemap生成隨機地圖的方法,如果對tilemap不太瞭解可以點選【閱讀原文】關注博主,獲取往期教程。
整體的實現流程如下:
1、根據使用者定義建立一張足夠大的地圖 (這裡的地圖指每個小關所有房間所在的大地圖)。
2 、假設大地圖中所有位置佈滿大小相同的房間 (這裡的房間邊長一定要奇數,比較好操作),然後根據所需的房間總數來刪掉多餘的房間。
3 .根據規定的長寬比,來隨機修改每個房間的大小。
4 .生成過道連通所有房間,(這裡黃色的點是原先沒有改變大小時的正方形的中心點)
5 .確定特殊房間的位置。
Tilemap中單獨房間效果圖:
一個簡單的房間以及半個過道
長方形連線正方形房間,黃色方塊為中心點
Unity中詳細操作
1、建立一個普通的Tilemap。
2、建立一個空物體,用來掛載我們的地圖生成指令碼。
3、 建立所需要的變數
- <p>public class MapManager : MonoBehaviour</p><p>{</p><p> [Header("地圖種子")] public int seed = 123456;</p><p> [Header("每行房間數")] public int mapMaxW;</p><p> [Header("每列房間數")] public int mapMaxH;</p><p> [Header("總生成房間數")] public int mapCount;</p><p> [Header("最大房間寬")] public int roomMaxW;</p><p> [Header("最大房間高")] public int roomMaxH;</p><p> [Header("最小房間寬")] public int roomMinW;</p><p> [Header("最小房間高")] public int roomMinH;</p><p> [Header("房間的間隔距離")] public int distance;</p><p> [Header("地板")] public TileBase floor;</p><p> [Header("牆")] public TileBase wall;</p><p> [Header("地圖")] public Tilemap tilemap;</p><p> private int[,] _roomMap;</p><p> private List<Vector3Int> _centerPoint;</p><p> private Dictionary<Vector3Int,int> _mapPoint;</p><p>}</p>
4、列出所需函式
- <p>//畫出地圖</p><p>private void DrawMap(){}</p><p>//畫出房間</p><p>private void DrawRoom(int roomX,int roomY){}</p><p>//畫出路</p><p>private void DrawRoad(){}</p><p>//畫出地板和牆壁</p><p>private void DrawFloor(){}</p><p>//生成房間 (用二維 int 陣列表示)</p><p>private int[,] RandomRoom(int maxW, int maxH, int minW, int minH, out int width, out int height){}</p><p>//生成一個地圖 (用二維 int 陣列表示)</p><p>private int[,] GetRoomMap(int mapW, int mapH, int roomCount)</p><p>//獲取一個範圍內的隨機奇數</p><p>private int GetOddNumber(int min, int max){}</p><p>//獲取下一個房間的位置</p><p>private Vector2Int GetNextPoint(Vector2Int nowPoint, int maxW, int maxH)</p><p>
- </p>
5 、實現各個函式
程式碼已經放在文末的附件,這裡我講一下我的大體思路以及各個函式的作用。
首先是使用,我在 Update 函式中檢測按下 R 鍵重新生成地圖,生成很簡單隻要呼叫 DrawMap 函式就可以。
- <p>private void Update()</p><p>{</p><p> if (Input.GetKeyDown(KeyCode.R))</p><p> {</p><p> DrawMap();</p><p> }</p><p>}</p>
在 DrawMap 中 會呼叫 DrawRoad 和 DrawFloor 倆個函式來分別畫出道路和地板、牆壁。
部分函式解析:
- <p>//取一定範圍內的一個奇數</p><p>private int GetOddNumber(int min, int max)</p><p>{</p><p> while (true)</p><p> {</p><p> var temp = Random.Range(min, max);</p><p> if ((temp & 1) != 1) continue;</p><p> return temp;</p><p> }</p><p>}</p>
這個函式主要用來在房間生成的時候取一個隨機的奇數出來,因為我們的房間連線需要一箇中心點所以奇數更方便使用。
- <p>//生成一個房間,用二維 int 陣列表示</p><p>private int[,] RandomRoom(int maxW, int maxH, int minW, int minH, out int width, out int height)</p><p>{</p><p> width = GetOddNumber(minW, maxW);</p><p> height = GetOddNumber(minH, maxH); </p><p> var room = new int[width, height];</p><p> //方便以後擴充套件使用了二維陣列,這裡為了演示方便對房間內生成其他物體</p><p> for (var i = 0; i < width; i++)</p><p> {</p><p> for (var j = 0; j < height; j++)</p><p> {</p><p> room[i, j] = 1;</p><p> }</p><p> }</p><p> return room;</p><p>}</p>
這個函式主要用來生成一個房間,選用二維int陣列主要是為了擴充套件、儲存時方便。本案例中 普通地板為 1,牆壁為 0。同時為了後續步驟計算方便這裡把生成的房間的長寬也返回了。
- <p>private int[,] GetRoomMap(int mapW, int mapH, int roomCount)</p><p>{</p><p> //第一個房間的座標點</p><p> var nowPoint = Vector2Int.zero;</p><p> //當前生成的房間數</p><p> var mCount = 1;</p><p> //當前地圖</p><p> var map = new int[mapW, mapH];</p><p> //第一個格子總有房間,作為出生房間</p><p> map[nowPoint.x, nowPoint.y] = 1;</p><p>
- </p><p> while (mCount < roomCount)</p><p> {</p><p> nowPoint = GetNextPoint(nowPoint, mapW, mapH);</p><p> if (map[nowPoint.x, nowPoint.y] == 1) continue;</p><p> map[nowPoint.x, nowPoint.y] = 1;</p><p> mCount ++;</p><p> }</p><p> return map;</p><p>}</p>
這個函式用來生成總體的地圖,也就是用來檢視哪裡需要生成房間。需要生成房間的地方為 1 ,空白的地方為 0。與GetNextPoint 連用獲取下一個房間的座標點。因為房間總是相連所以不存在間隔。
- <p>private Vector2Int GetNextPoint(Vector2Int nowPoint, int maxW, int maxH)</p><p>{</p><p> while (true)</p><p> {</p><p> var mNowPoint = nowPoint;</p><p>
- </p><p> switch (Random.Range(0, 4))</p><p> {</p><p> case 0:</p><p> mNowPoint.x += 1;</p><p> break;</p><p> case 1:</p><p> mNowPoint.y += 1;</p><p> break;</p><p> case 2:</p><p> mNowPoint.x -= 1;</p><p> break;</p><p> default:</p><p> mNowPoint.y -= 1;</p><p> break;</p><p> }</p><p>
- </p><p> if (mNowPoint.x >= 0 && mNowPoint.y >= 0 && mNowPoint.x < maxW && mNowPoint.y < maxH)</p><p> {</p><p> return mNowPoint;</p><p> }</p><p> }</p><p>}</p>
這個函式大體的思想還是參照我前倆篇文章中講到的隨機遊走法的思路。
最終效果
1、生成房間
2 、新增橫向過道
3 、新增縱向過道
4 、新增牆壁
作者:超級汽水
來源:Unity官方平臺
原地址:https://mp.weixin.qq.com/s/OZggLLodTF9cownbt2FzGg
相關文章
- 拋棄「肉鴿」轉投「暗黑Like」,《元氣騎士新作》成色幾何?
- 元氣騎士蒼龍魔杖怎麼搭配-蒼龍魔杖搭配推薦
- 用Unity重現《空洞騎士》的苦痛之路(3)——地圖篇Unity地圖
- 攝像機?信標?深入解讀《元氣騎士》的視野機制
- 異界騎士鏈遊開發NFT系統技術
- 怎麼修復網站漏洞騎士cms的漏洞修復方案網站
- 簡易ATM系統
- 《鏟子騎士》:“復古遊戲”的集大成者遊戲
- 外星騎士NFT卡牌鏈遊系統技術開發詳情
- 復刻包包復刻包復刻包包是什麼意思
- abc145D 騎士走棋盤到達目的地的方案數
- 開放世界關卡設計:《空洞騎士》的奧祕,2D地圖如何實現探索感?地圖
- java生成簡易pdf文件Java
- jq的簡易模板生成
- 一個簡易停車場地圖製作軟體地圖
- 《空洞騎士》關卡設計解析
- 簡易進銷存CRM系統
- Python簡易學生管理系統Python
- Solidity技術丨外星騎士鏈遊系統程式設計開發丨DAPP丨NFTSolid程式設計APP
- 簡易地圖生成器,一個專業的地圖製作網站地圖網站
- go實現簡易分散式系統Go分散式
- 元氣先聲創客小程式系統開發
- 《狂暴騎士》“獎勵回收”:遊戲設計易放難收,收得不好就會爆炸遊戲設計
- 騎士放置 Page435 最大獨立集
- 《伊萬博士: 進化》利用三角剖分演算法復刻《超越光速》地圖機制演算法地圖
- Python實現簡易版選課系統Python
- SSM + easyUI 搭建簡易的人事管理系統 系統概要部分SSMUI
- win10系統下天氣磁貼不顯示當地天氣如何解決Win10
- 簡易流程圖繪圖軟體流程圖繪圖
- AMD首款銳龍游戲本上市 宏碁暗影騎士3銳龍版僅4999元
- 龍騎士們,空中集結!《世紀:灰燼紀元》現已免費登陸Steam!
- 復刻包是什麼意思復刻包包貨源哪裡來
- 死亡騎士形象是如何誕生和成型的
- 2020餓了麼藍騎士群體畫像
- 暴雪:一位屈服於時代的騎士
- web端作業控制系統簡易實現Web
- Windows系統安裝MySQL5.7簡易教程WindowsMySql
- 長志氣戒傲氣 必須時刻保持冷靜