這個作業(yè)屬于哪個課程 | 軟件工程2022年春-F班 |
---|---|
這個作業(yè)要求在哪里 | 軟件工程實(shí)踐總結(jié)&個人技術(shù)博客 |
這個作業(yè)的目標(biāo) | 課程回顧、個人技術(shù)總結(jié) |
其他參考文獻(xiàn) | 《構(gòu)建之法》 |
一、技術(shù)概述
1.1 技術(shù)使用場景
??你不滿足于別人提供的現(xiàn)成的地圖,想要利用原有的素材來將你自己的想法實(shí)現(xiàn)嗎?或者你不知道如何獲取素材,不知道如何使用素材?在此發(fā)揮你天馬行空的想象力,用你的鼠標(biāo)和鍵盤來繪制自己的王國吧!
1.2 技術(shù)難點(diǎn)
??隨機(jī)資源生成算法的實(shí)現(xiàn)。(注:本人unity版本為2021.3.2f1c1,不同版本可能組件位置有所不同)
二、技術(shù)詳述
2.1 素材導(dǎo)入
??在項(xiàng)目中,點(diǎn)擊左上角菜單欄的window,可以看到子選項(xiàng)中有一個Asset Store。
??點(diǎn)擊它我們可以來到Unity資源商店尋找我們想要的資源,包括地圖、角色、道具、材質(zhì)等等,你幾乎可以在這里找到所想要的東西。
??點(diǎn)擊左上角的2D,并勾選上“環(huán)境”、“免費(fèi)資源”(能不花錢就不花錢啊喂),我們來挑選一張心儀的地圖,進(jìn)入資源詳情頁后,點(diǎn)擊“添加至我的資源”后選擇“在unity中打開”即可。
??選擇import,等待資源導(dǎo)入。
??可以看到左下角的項(xiàng)目文件已經(jīng)把素材導(dǎo)入進(jìn)來,現(xiàn)在我們可以開始創(chuàng)作了!
2.2 編輯素材
??首先我們更改一下素材的配置,主要要更改一下素材每單位的像素點(diǎn)。我們可以看到我們的Scene界面有很多網(wǎng)格,一個格子就是一個Unit,這個Pixels Per Unit就是指一個格子中的像素點(diǎn),當(dāng)這個值過大,會讓每個單位格里面的東西變得很小,個人習(xí)慣將這個值調(diào)至16,當(dāng)然你可以自由選擇。Sprite Mode更改成Multiple,這會有利于我們后續(xù)對素材的切割和制作。更改后,記得點(diǎn)擊Apply應(yīng)用。
2.3 繪制地圖
??繪制地圖我們需要一個載體,右鍵左部空白位置,點(diǎn)擊2D Object -> Tilemap ->Rectangular ,生成一個Tilemap,供我們在上面制作地圖。
??我們還需要一個畫板,就跟畫家的調(diào)色板一樣,他們會在上面放上各種顏料,而我們需要在上面放上我們的素材,我們的畫板就是Tile Palette。點(diǎn)擊左上角的window -> 2D -> Tile Paletee,這時候我們彈出了一個窗口,這個就是我們的畫板,將素材(顏料)放在上面,我們才可以進(jìn)行我們的創(chuàng)作。
??我們可以看到這個素材包里面有現(xiàn)成的幫我們“調(diào)制”好的顏料,不過呢有的素材包是沒有的,為了能夠掌握地圖繪制的步驟,我們來重新“調(diào)制”一遍!點(diǎn)擊畫板中的Create New Palette,將新畫板的名字重命名,然后點(diǎn)擊Create,這時候會彈窗讓我們選擇一個保存位置,我們可以新建一個文件夾,隨便命名一下(我這里命名為Map),選擇該文件夾將該畫板保存到這個位置。
??不過現(xiàn)在你可以看到,我們的畫板上沒有任何的東西,我們現(xiàn)在需要將我們的素材切割好并導(dǎo)入,也就是調(diào)制我們的顏料。在素材詳情頁面點(diǎn)擊Sprite Editor,進(jìn)入素材編輯界面,點(diǎn)擊Type更改切割類型,選擇Grid By Cell Size,更改Pixel Size中x和y使之和我們之前定義的Pixels Per Unit數(shù)值一致,之后點(diǎn)擊slice,最后記得點(diǎn)擊右上角的Apply保存。
??這時我們可以使用素材中每個單元格來進(jìn)行地圖的繪制了!將素材拖入我們的Tile Palette中,選擇一個保存的文件夾(我們還是選擇放在Map文件夾中),等待導(dǎo)入,之后我們就會發(fā)現(xiàn),我們現(xiàn)在畫板上就已經(jīng)有了素材,而且它已經(jīng)被劃分成了一小格一小格的單位,這時候,我們便可以拿起我們的畫筆,正式開始創(chuàng)作!
??讓我們用流程圖總結(jié)一下簡單地圖制作的過程!
2.4 關(guān)于圖層
??圖層問題是一個需要長篇幅來敘述的功能,你可以利用圖層決定角色、水域、草地等元素的顯示優(yōu)先級以及碰撞等等一些細(xì)節(jié)的體現(xiàn),本博客止于地圖的簡單創(chuàng)建,接下來隨機(jī)生成物體的內(nèi)容需要你對諸如Tilemap的創(chuàng)建、預(yù)制體的創(chuàng)建等內(nèi)容有所了解,如果想對這些部分進(jìn)行學(xué)習(xí),可以查看本博客的參考內(nèi)容中的教程。
2.5 簡單的隨機(jī)資源生成
??我們首先創(chuàng)建一張地圖,將可生成資源的地塊劃分到一個圖層,剩下的劃分到另一個圖層。例如我這里將不可生成資源的地塊劃分到了unrandomground,可生成資源的地塊在randomground中。我們還需要準(zhǔn)備一些預(yù)制體,將這些預(yù)制體作為生成的資源。
??新建一個腳本,開始編寫代碼。思路如下流程圖所示:
??首先做好前期準(zhǔn)備,保存我們需要隨機(jī)的資源:
//需要隨機(jī)的資源
public List<GameObject> resourceGrass = new List<GameObject>(); // 草
public List<GameObject> resourceGravel = new List<GameObject>(); // 石頭
public List<GameObject> resourceTree = new List<GameObject>(); // 樹木、灌木
public List<GameObject> resourceWoodenConstruction = new List<GameObject>(); // 木制結(jié)構(gòu)
public List<GameObject> resourceLithicalConstruction = new List<GameObject>(); // 石制結(jié)構(gòu)
private Tilemap tilemap;
private List<Vector3> randomGroundTileWorldPos = new List<Vector3>(); // 獲取可隨機(jī)的地塊
private bool[] randomGroundTileHasEmptySlot; // 判斷地塊是否已占用,需要初始化
private int randomGroundTileCount; // 隨機(jī)地塊數(shù)量
private int resourcesGrassCount; // 草 數(shù)量
private int resourcesGravelCount; // 碎石 數(shù)量
private int resourcesTreeCount; // 樹木、灌木
private int resourcesWoodConstructionCount; // 木制結(jié)構(gòu)數(shù)量
private int resourcesLithicalConstructionCount; // 石制結(jié)構(gòu)數(shù)量
??初始化函數(shù),由于我們可以將腳本掛接在randomground下,因此保存所有地塊就相當(dāng)于保存了所有可隨機(jī)地塊:
void InitializeTileMap() // 保存地圖的所有地塊
{
tilemap = GetComponent<Tilemap>();
Vector3Int tmOrg = tilemap.origin;
Vector3Int tmSz = tilemap.size;
for (int x = tmOrg.x; x < tmSz.x; x++)
{
for (int y = tmOrg.y; y < tmSz.y; y++)
{
if (tilemap.GetTile(new Vector3Int(x, y, 0)) != null)
{
Vector3 cellToWorldPos = tilemap.GetCellCenterWorld(new Vector3Int(x, y, 0));
randomGroundTileWorldPos.Add(cellToWorldPos);
}
}
}
}
??接著就開始生成資源,這里舉例生成草的函數(shù):
void GenerateGrass(System.Random rm) // 生成草
{
int aRandomTile;
for (int i = 0; i < 150; i++)
{
while(!randomGroundTileHasEmptySlot[aRandomTile])
{
aRandomTile= rm.Next(0, randomGroundTileCount);
}
Vector3 spawnPos = randomGroundTileWorldPos[aRandomTile];
int aRandomRes = rm.Next(0,resourcesGrassCount);
GameObject spawnRes = resourceGrass[aRandomRes];
Instantiate(spawnRes, spawnPos, Quaternion.identity);
randomGroundTileHasEmptySlot[aRandomTile] = false;
}
}
??編寫完代碼后,將腳本掛在randomground下,將需要生成的資源以預(yù)制體的形式拖入,點(diǎn)擊運(yùn)行,就可以得到我們想要的效果
??不過我們發(fā)現(xiàn),當(dāng)物體較多時,生成的速率會變慢,這是因?yàn)槲覀冇靡粋€數(shù)組去存儲地塊的生成資源情況會使得在地塊稀少時尋找可利用地塊耗時增加,我們可以改進(jìn)一下,將生成過資源的地塊直接從我們保存地塊的列表之中移出,代碼如下:
void GenerateTree(System.Random rm) // 生成樹木、灌木
{
for (int i = 0; i < 100; i++) // 生成樹木和灌木
{
randomGroundTileCount = randomGroundTileWorldPos.Count; // 隨機(jī)地塊數(shù)量
int aRandomTile = rm.Next(0, randomGroundTileCount);
Vector3 spawnPos = randomGroundTileWorldPos[aRandomTile];
int aRandomRes = rm.Next(0, resourcesTreeCount);
GameObject spawnRes = resourceTree[aRandomRes];
Instantiate(spawnRes, spawnPos, Quaternion.identity);
randomGroundTileWorldPos.Remove(spawnPos);
}
}
??可以發(fā)現(xiàn)效率較上一種方法高的多。
三、可能遇到的問題以及解決方案
3.1 素材問題
Q:Unity商店里有我很喜歡的素材,但是賣的很貴怎么辦?
A:
??如果只是新手練手使用,可以由tb或者pdd等渠道獲取,但如果要用于商業(yè),必須由本人在版權(quán)方所提供的渠道購買(Unity商店),否則會有侵權(quán)的問題。不過Unity商店提供的素材經(jīng)常有大力度的打折,你可以收藏下你喜歡的素材等打折時購買。這里推薦一個B站Up主Lee哥的游戲開發(fā)加油站,他經(jīng)常發(fā)一些優(yōu)質(zhì)且有很大折扣的Unity素材,可供參考。
Q:我在切割素材時,有些按Grid By Cell Size類型切割并不能得到我想要的效果?
A:
??可以嘗試著選擇其他類型的切割方式,或者是調(diào)整一下每個單元格的像素量,素材質(zhì)量有高有低,有時還需要自己微調(diào)。
3.2 地圖制作問題
Q:我明明給地圖某些部分添加了碰撞體積,但是子彈能穿過去?
A:
??地圖的碰撞體積一般由如下圖三部分構(gòu)成,選擇Composite Collider 2D中的Geometry Type(指定復(fù)合碰撞體生成的幾何體的類型),將其設(shè)為Polygons(設(shè)置符合碰撞體,以便為由凸多邊形組成的合并碰撞體集合體生成封閉輪廓),然后在子彈的碰撞體積中,設(shè)置Rigidbody 2D的Collision Detection為Continuous(連續(xù)檢測,防止對象穿過所有靜態(tài)碰撞體)
??可參考Unity-Rigidbody組件、Unity官方文檔-GeometryType。
3.3 隨機(jī)生成資源問題
Q:生成的物體位置與我設(shè)想的不一致?
?? 正常情況下樹木如果在它腳下這塊石板上生成,應(yīng)該會是如下圖所示,但實(shí)際會往下偏移
A: 這是預(yù)制體的錨點(diǎn)問題,在sprite Editor中將對應(yīng)物體的錨點(diǎn)往下移動即可。
Q:生成的物體圖層有問題,例如樹木后面的物體應(yīng)該是被遮蔽的,事實(shí)卻不是如此?
A:
??點(diǎn)擊Edit選擇ProjectSettings,在Graphics中選擇Transparency Sort Mode,將其置為Custom Axis,此時在同一圖層上,物體會根據(jù)所處的Y值排序,即Y值越高,顯示優(yōu)先級越靠后,便解決了該問題
四、總結(jié)
??Unity的地圖制作是新手入門Unity的必學(xué)操作之一,其難度并不高,主要依靠學(xué)者的細(xì)心和耐心。關(guān)于資源的隨機(jī)生成本博客只是提供了一個簡單的辦法,實(shí)際上關(guān)于隨機(jī)地圖的生成有其他更深入的研究,包括限制資源生成范圍、地形的生成,甚至可以做到地圖全隨機(jī)而不用自己先搭建出一個框架,涉及到了各種模型分析和數(shù)值計算。學(xué)無止境,不可止步于此。文章來源:http://www.zghlxwxcb.cn/news/detail-401436.html
五、參考內(nèi)容
1、如何在Tilemap上隨機(jī)生成資源——bilibili
2、Unity2018教程2D入門——bilibili
3、Unity官方用戶手冊文章來源地址http://www.zghlxwxcb.cn/news/detail-401436.html
到了這里,關(guān)于在Unity中簡單地制作一張2D地圖并隨機(jī)生成資源的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!