Unity 快速入門 (一) 簡介

用途

Unity 起初是作為遊戲引擎(Game Engine),可以橫跨多個平台建置遊戲。現今則作為創作引擎(Creation Engine)角色,可用於遊戲、建築、工業、模擬、動畫、電影等領域的編輯引擎,支援極多樣化的輸出平台: Windows、MacOS、Linux桌面平台,iOS、Android、Windows Store、AR、VR、WebGL、Facebook Gameroom….等,基本上大多數的遊戲平台皆可使用Unity開發,部分特殊平台如各式家用主機等等需要則額外處理才可用。

下圖為Unity官方的建制目標總覽。

gdc-keynote-blog-section-headers-03

概觀

用最簡單的一句話來描述Unity是什麼的話,可以用如下敘述:

用來控制與呈現,場景中各式物件間互動行為與感官特效的跨平台運行環境。

Unity是一個運行環境,Unity Editor則是基於這個環境的編輯器,用來定義物件本身的行為與和其他物件互動的行為,通常說Unity的各項功能都是指Unity Editor的功能,因為我們會使用Editor來控制Unity呈現的內容。

Unity本身對於初級素材創作(如3D建模、繪圖、編曲等)比較不在行,動畫製作雖然可於Unity中作成,但使用其他的專業引擎會具有更好的效率與功能。Unity 2018會整合ProBuilder到Editor當中,讓簡單建模也可以很方便的在Unity中完成,相關資訊可以看官方Blog,目前已可於Asset Store中免費使用。

Unity支援多種形態的素材,將素材導入Unity後進行組合。Unity官方的Asset Store更是一個集合各種素材的自由販賣平台,可以購買其他人上架的素材包(也有包含程式庫),與進行販賣。

Unity內建有許多功能,會在"功能分類"段落列舉,而Unity最主要的工作是建立場景與其中的遊戲物件設置。

Unity中所有的遊戲物件(GameObject)都必須擺放在場景當中,而編輯器可以一次開啟多個場景,並可以進行合併,在場景中的物件都有其Transform資料(主要包含3維位置、角度、縮放量),並可進行樹狀組合堆疊(一個物件下可以再包含數個子物件,當物件被操控時,底下的子物件也會被操控,並且子物件的座標系統以物件作為原點)。物件上可以裝置多個元件(Component),Component通常是內建的元件或是玩家自定義的腳本程式(Script),用來讓遊戲物件根據設定的程式執行對應的行為。

現況

以下列使用Unity引擎製作的特別知名遊戲:

神魔之塔 (2013)

爐石戰記:魔獸英雄傳 (2014)

紀念碑谷 Monument Vally (2014)

王者榮耀 (2015)

精靈寶可夢GO (2016)

等等,其中手機遊戲市場又以Unity開發的遊戲佔據了很大一塊,在最頂尖的1000個免費遊戲中有34%的數量使用Unity製作 (可視為各家免費手機遊戲競爭的頂點)。而在其下的整體數量又更加龐大,在其他平台的數量也相當可觀,VR領域更是有最大的市佔率。

Unity最大的優勢在於上手快,基本功能健全,對於遊戲初學者、獨立開發者或小型工作室來說非常好用,若要加大規模也有足夠的擴展性,雖然無法直接修改核心的程式碼,但在大部分的狀況下都可以用其他手段處理,除非在效能或是效果上有很高的要求,否則已完全足夠使用。

(下圖來自Unity官網)

Unity Mobile Market top 1000 free 34%

UnityMarket

價格

主要有三大類型,可以參考官網

Personal:免費使用,包含所有Unity核心功能,限年收或募資金額10萬美金以下使用。

Plus:每月35美金,基於Personal,增加Unity 遊戲開發課程 + Bolt Visual Scripting Tool ($214 美金價值)、Asset Store訂閱者優惠折扣、客製化啟動畫面、效能報表、更好的Unity分析數據、整合的遊戲內付費功能等,最重要的為可供20萬美元年收或募資金額以下使用。

Pro:每月125美金,基於Plus,增加官方支援(可觸及原始碼),沒有商業金額限制。

關於更多的細節請參閱官網。

操作介面

啟動Unity後的專案畫面,登入Unity帳號後即可瀏覽自己的專案,這個介面除了開啟新專案、打開專案(選擇專案資料夾)外,還可以進入學習視窗,進入官方的入門教學。

Unity專案畫面

打開專案後,會進入Unity主視窗。

Unity操作介面

Unity的所有操作視窗都可以任意拉動,配置位置。若不小心關掉了,可於上方工作列Window再打開。

常用的幾個視窗:

Hierarchy:顯示場景(可同時開啟多個場景)與其中的遊戲物件,所有一開始就出現在場景中的遊戲物件都可以在這裡找到,點選物件後可於Scene或Inspector視窗中調整物件的數值(調整位置與角度很方便)。另外也可以直接在這裡點選右鍵建立一些基本物件。也可以將script直接拉到物件上。

Scene:可以看見場景中的各項物件,進行拖拉、旋轉、縮放等,用滑鼠操作的預設調整畫面技巧

  1. 滾輪:拉近拉遠畫面
  2. 滑鼠中鍵:拖曳視角
  3. 滑鼠右鍵:旋轉視角

Inspector:顯示各項數值設定,點選Add Component可以直接在選擇的物件上附加新元件。經常會需要拖曳東西到元件上(script是一種元件),來給予物件初始值(或是可以視作綁定物件間的關係,建立溝通橋梁)。

Game:在Editor中快速執行遊戲的畫面,可以按Maximize On Play執行時放大,也可以按下Stats觀察效能,特別注意有時候在Editor當中執行的結果會和建置出來的不一樣(除了畫面、有時候某些功能可能會不支援),測試遊戲一定要實際建置實行看看。你可以在執行的時候控制其他視窗與改變數值。

Project:顯示整個Project內容的目錄瀏覽器,和檔案總管有點像,底下通常會有多個資料夾,某些檔案須要放在特定資料夾下才可以使用,會在之後的章節介紹。可以直接在其中建立資料夾與腳本,打開腳本的預設IDE/Editor為Visual Studio,可於Edit/Preferences設定自訂的工具。點兩下檔案可以更名(右鍵沒有這項功能,注意繼承Monobehavior的script要拖到物件上,檔名需要與類別名相同)。

Console:Editor的Log視窗,可以看錯誤與警告,或是用Script中的Debug下的多種method印出訊息,只有在Editor中很方便查看,若需要在實際建置中查看可能另外建立一個UI會比較方便。只有在沒有紅色錯誤訊息的狀況下才可以建置或是執行。

主要功能分類

深度:☆ – ☆☆☆☆☆ (1~5)

  • Unity Editor控制 ☆ – ☆☆☆☆☆
    • 包含自訂Unity Editor功能
  • 資源管理 ☆ – ☆☆☆
  • 場景與物件控制 ☆ – ☆☆
  • UI ☆ – ☆☆☆☆
  • 燈光 ☆ – ☆☆☆
  • 攝影機與渲染 ☆ – ☆☆☆☆
  • 音效 ☆ – ☆☆
  • 粒子系統 ☆☆ – ☆☆☆☆
  • 碰撞與物理 ☆☆ – ☆☆☆☆
  • 導航系統 ☆☆
  • 腳本系統 ☆ – ☆☆☆☆☆
  • 外掛插件 ☆☆ – ☆☆☆☆☆
  • Shader ☆☆☆ – ☆☆☆☆☆
  • 內建多人連線系統 ☆☆☆ – ☆☆☆☆
  • TileMap ?還沒用過
  • 地形與種樹 ☆ – ☆☆

Unity 平行化探討 – C# Job System

前言

以現在遊戲用的電腦而言,有8個thread以上可以平行處理的CPU已經相當普遍,但是如果遊戲程式沒有使用到平行化技術,還是只能使用一個thread來執行,造成效能瓶頸。

在Unity當中,開發者所寫的程式如果沒有自行開啟新thread (在最新版的Unity中以可使用C#開新thread),那麼主程式都是由一個main thread在執行,雖然Unity內部會開一些thread來做渲染之類的工作,增加效能,但是開發者自定義的部分不會被平行到。

自己使用C#的thread會遇到很多問題,很多重要數值,尤其是與物理引擎有關的部分,像是transform的position, 剛體的velocity等等,都是只能在main thread寫入的,因此我們需要使用Unity提供的一些平行化方式。

順道一提,Unity的協程(Coroutine)並沒有平行化的效果,依然是在main thread上執行。

概觀

C# Job System可以在Unity 2018.1 beta中使用,主要概念是將相同Component中Update()裡面的內容提取出來控制,光從這點上就能減少因大量Component產生的大量Update()呼叫帶來的效能損耗。

例如本來是很多Component在Update時,都讓transform根據速度移動一點。現在將移動的這段程式移到一個獨立的Component,原本的那些GameObject變成用一個陣列的形式來存取,每次這個獨立的Component做Update的時候,將陣列裡的GameObject掃過一遍,讓每個都依照他的速度動一點。

Job System中,會定義一些Job,這些Job會需要預先定義會使用到那些資料,並定義要怎麼使用這些資料。

例如

struct PositionUpdateJob : IJobParallelForTransform
{
    [ReadOnly]
    public NativeArray<Vector3> velocity; // the velocities from AccelerationJob
    public float deltaTime;

    public void Execute(int i, TransformAccess transform)
    {
        transform.position += velocity[i] * deltaTime;
    }
}

這是一個定義position更新的job,所有的job都會是struct,並根據需要繼承不同的interface,在這裡我們會需要更新transform的值,所以繼承IJobParallelForTransform。

在這job被建立的時候,我們需要給定一個velocity的array,而在job執行時,我們要給定一個受影響的Transform array,這個array當中的每個transform都會被傳遞到Execute方法中執行。

i表示現在執行array中的哪個index,TransformAccess transform表示現在存取到的那個transform。

我們透過一個官方範例來理解怎麼使用Job System。

範例

完整官方範例請參考 https://github.com/stella3d/job-system-cookbook

首先打開 https://github.com/stella3d/job-system-cookbook/blob/master/Assets/Scripts/AccelerationParallelFor.cs

使用Job System的時候要using Unity.Jobs與UnityEngine.Jobs (第3,4行)

BaseJobObjectExample是一個簡單的MonoBehavior類別,他提供快速建立一大堆物件與提供存取物件資料的陣列,你也可以根據自己的需要製作,不必使用他的類別。

看到Start(),首先先建立很多個遊戲物件,範例中預設建立10000個物件,並在這裡預先建立好需要使用的資料陣列。

接下來是定義兩個job,第一個PositionUpdateJob 是剛剛看到的,根據給定的速度來更新位置的job。第二個是AccelerationJob,用來計算速度的job。

我們需要先計算每個物件的速度,然後再根據這個速度更新每個物件。

Update()中,每次我們就新建這兩個job,並給定參考的陣列。

透過m_AccelJobHandle = m_AccelJob.Schedule(m_ObjectCount, 64);

規劃m_AccelJob,總共有m_ObjectCount個物件要計算速度,內部一個批次計算64個。

再來執行m_PositionJobHandle = m_Job.Schedule(m_TransformsAccessArray, m_AccelJobHandle);

這是讓更新的位置依賴於計算速度的位置,每個物件要計算位置時,速度要先算完。

在這邊建立好相依性後,job不會馬上完成,只是進行規劃。直到LateUpdate()中,m_PositionJobHandle.Complete(),這裡會等到job中的所有運算都完成後才會繼續執行下去。

 

整個Job System的觀念是定義好job所需的資料與job之間的相依性,然後同步執行job的內容。因為i是獨立的,所以可以分給很多個worker去運算。Job System會建立所有thread數-1個worker來執行job,可以在profiler中觀察到,像是有8個實體thread的話,除了main thread,會另外有7個worker來算job,使用的好的話可以大幅提升遊戲效能。

 

線上遊戲後端系統設計 – 目錄

一、課程簡介

本課程將會對開發線上遊戲的後端系統進行教學,內容為各種線上遊戲皆可以參考的核心骨架系統與各項開發線上遊戲後端程式所需的關鍵技術。 課程分成三階段:基礎、中階、進階,逐步深入。

基礎課程由建立專案開始,學習建立簡單線上遊戲會用到的各項技術,學習後可以著手開發一萬行C#以下的簡單線上遊戲程式。

中階課程會學習如何面對一萬行C#以上的遊戲專案,並提升程式設計的抽象化能力,避免程式出現冗餘的部分,並讓功能擴展性增加,以面對多樣化的遊戲需求。是開發小型遊戲以上的必備能力,並銜接進階課程的內容。中階課程依然以單伺服器為開發對象,目標為開發10萬行C#以內或同時在線1000人以下的線上遊戲。

 

進階課程以多伺服器後端環境切入,並探索專案的切割方式,將各項功能切成許多專案來開發,以供許多人同時進行專案開發,並介紹我的基本兩層式伺服器架構,由1+N個伺服器應用程式組成,可以服務1000人以上。

二、課程數值說明

重要性:

★☆☆☆☆:不會也沒關係

★★☆☆☆:最好要知道

★★★☆☆:最好要會使用

★★★★☆:常常會使用

★★★★★:必須知道

███████:可能致命

難度:

★☆☆☆☆:通識

★★☆☆☆:程式入門程度

★★★☆☆:會寫簡單的遊戲專案的程度

★★★★☆:已經學會設計模式的程度

★★★★★:高度抽象

███████:大概只有我自己知道

學會才能開發的專案規模:

★☆☆☆☆:練習小專案(1000行C#以下)

★★☆☆☆:課堂期末專題(5000行C#以下)

★★★☆☆:完整獨立小型遊戲專案(10000行C#以下)

★★★★☆:多專案分割,完整遊戲專案(100000行C#以下)

★★★★★:大型專案(100000行C#以上)

███████:把世界造出來

三、課程目錄

基礎

專案建立:學習如何建立Visual Studio與Unity遊戲專案。

GitHub使用指南:學習簡單的使用GitHub來做程式開發版本控制。

認識線上遊戲類型:認識線上遊戲類型,並辨識開發難度。

基本線上遊戲架構與伺服器環境:學習線上遊戲後端架構的基礎。

建立與伺服器的連線:學習如何在客戶端與伺服器間建立連線,並執行遊戲操作。

加入新功能到遊戲中:學習如何在已建構出的伺服器環境上加入新遊戲功能。

資料庫存取:學習使用資料庫來存取遊戲資料。

中階

架構切割與專案分離:學習將一個大的遊戲專案依照功能類型切成數個小專案。

抽象世界:學習使用抽象類別來描述遊戲邏輯。

泛型類別:學習使用泛型來減少相似類別內的重複宣告。

分離式通訊骨架:學習建構應用程式級的RMI系統,並消去物件之間的強烈耦合性。

抽象化伺服器環境:將伺服器邏輯與伺服器通訊設備分離,可適應多種伺服器套件。

物件參考分離:摧毀物件間的直接參考,以支援物件實體放在不同伺服器間的運作。

進階

線上遊戲多伺服器架構簡介:介紹大型線上遊戲的伺服器結構。

大型線上遊戲專案切割:介紹大型線上遊戲專案間的分割與繼承。

內部伺服器通訊設施:介紹如何建立多台伺服器間的通訊與使用。

跨伺服器運算:探討如何處理一個需要橫跨多台不同類型的伺服器才能完成的操作。

 

以上規模大小皆由我個人設想,不一定是真實情況。

線上遊戲實作技術-設定檔XML序列化

簡介

這篇教學文章主要介紹如何編寫一個設定檔,這個設定檔可以直接用文字編輯器打開與修改,這些設定可以在程式執行時讀取,相比直接把資料寫死在程式碼中,擁有較高的修改自由度與避免重要資訊公開。

設定檔

設定檔就是一些變數值,通常在程式執行期間都不會進行更改,在課程的線上遊戲當中,我會透過設定檔來儲存資料庫的位置與帳號密碼,如此一來,這些資訊就可以另外設定,不會因為放到GitHub上而被其他人看到,當我想要修改這些值的時候,也可以不需要重新建置我的程式。

XML

wikiExtensible Markup Language,簡稱:XML,就是使用一大堆<>標籤來表達資料結構的一種資料格式,C#中內建有XML格式的序列化工具,XML本身也具有可閱讀的特性,適合拿來快速實作設定檔。

序列化

序列化(Serialization),指的是將各種形式的資料轉換成一種可以被傳輸的中間表達形式,通常用來進行網路傳輸工作。當你需要透過網路傳送一個比較複雜的資料結構時,如果你不想將整個資料一一拆解成最簡單的資料型態,那麼你就需要使用這項技術才能把資料傳送過去。例如有一個複雜的類別,裡面儲存了很多不同型態的資料,其中還包刮了多型集合,要將這種複雜資料傳到另一個地方是有難度的,序列化可以將這些複雜的資料轉換成一些低階的資料格式,如string,byte[]之類的,這些就很容易被傳輸。在透過反序列化(Deserialization)將中間資料轉換成原來的資料。

中間資料有很多種格式,binary,json,xml等等,這裡我們會介紹C#中XML格式的序列化方式。

實例

參考https://github.com/NCTUGDC/HearthStone/blob/master/HearthStone/HearthStone.Server/Configurations/DatabaseConfiguration.cs

using System.IO;//使用讀寫檔案的部分
using System.Xml;//使用建立與讀取xml格式資料的部分
using System.Xml.Serialization;//使用xml序列化工具

在屬性或欄位上加上[XmlElement]標註,表示這個資料要被序列化與反序列化
XmlSerializer serializer = new XmlSerializer(typeof(DatabaseConfiguration));
告訴XmlSerializer這是要序列化哪一種類別
用XmlReader來反序列化資料(從檔案把資料讀出來成物件)
用XmlWriter來序列化資料(把資料寫入檔案)

參考上面的程式碼範例,當檔案存在時就讀取,當不存在時就新建一個空的,第一次使用的時候你可以靠這樣自動產生一個空的後再來修改。產生的檔案會長成這樣

<?xml version="1.0" encoding="utf-8"?><DatabaseConfiguration xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Hostname>not set</Hostname><Username>not set</Username><Password>not set</Password><Database>not set</Database></DatabaseConfiguration>

你需要手動的調整一下縮排

<?xml version="1.0" encoding="utf-8"?>
<DatabaseConfiguration xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Hostname>not set</Hostname>
    <Username>not set</Username>
    <Password>not set</Password>
    <Database>not set</Database>
</DatabaseConfiguration>

把標籤中的資料換成你想要的就可以很方便的使用了。

在伺服器啟動的時候把這些資料讀取進來使用即可。

DatabaseConfiguration config;
DatabaseConfiguration.Load(“config/test.config", out config)

你可以在你的伺服器程式執行資料夾(有bin和log的)中新加一個config資料夾,這樣比較容易找到設定檔,設定檔約定俗成的用.config當作附檔名,PhotonServer環境也會自動偵測到有.config檔案的改變會重開該伺服器程式。

讀取到資料後你就可以用這些資料來做事了。

如果你不想用MySQL資料庫,你也可以研究看看要怎麼用XML來做儲存資料的文件檔。