Unity帶來的
 新型遊戲開發方式
如何用Component導向設計進行
   Rapid Prototyping
     講師 : 石川 將光
       @lucifuges
      aka Unity仙人
以往的遊戲程式設計法
以往的遊戲程式設計法
■物件導向的繼承結構
只要功能有點不同,就會出現很多類似的
Class
GameActor
 GameActor     Enemy
                Enemy      FlyingEnemy
                            FlyingEnemy
                           SwimingEnemy
                            SwimingEnemy
EnemyBase
 EnemyBase
                Boss
                 Boss       JeffsEnemy
                             JeffsEnemy


             FlyingBoss
              FlyingBoss    JeffsBoss
                             JeffsBoss

                                           3/49
以往的遊戲程式設計法
■物件導向的繼承結構
只要功能有點不同,就會出現很多類似的
Class      What's
                        different?
GameActor
 GameActor     Enemy
                Enemy                FlyingEnemy
                                      FlyingEnemy
                                     SwimingEnemy
                                      SwimingEnemy
EnemyBase
 EnemyBase
                Boss
                 Boss                 JeffsEnemy
                                       JeffsEnemy
                            WHO?

             FlyingBoss
              FlyingBoss              JeffsBoss
                                       JeffsBoss

                                                     4/49
以往的遊戲程式設計法
■物件導向的繼承結構
想在部份Class追加功能的時候,不知道該加
在哪裡
 GameActor
  GameActor      Enemy
                  Enemy      FlyingEnemy
                              FlyingEnemy
                             SwimingEnemy
                              SwimingEnemy
 EnemyBase
  EnemyBase
                  Boss
                   Boss       JeffsEnemy
                               JeffsEnemy
加在EnemyBase裡
然後沒用到的Class不
呼叫就好?          FlyingBoss     JeffsBoss
                FlyingBoss     JeffsBoss
還是乾脆個別貼上?

                                             5/49
以往的遊戲程式設計法
■物件導向的繼承結構
例如下面的例子,想要作一隻會飛又會游泳
的敵人該怎麼辦?重新設計繼承結構嗎?
GameActor
 GameActor     Enemy
                Enemy      FlyingEnemy
                            FlyingEnemy
                           SwimingEnemy
                            SwimingEnemy
EnemyBase
 EnemyBase
                Boss
                 Boss       JeffsEnemy
                             JeffsEnemy


             FlyingBoss
              FlyingBoss    JeffsBoss
                             JeffsBoss

                                           6/49
以往的遊戲程式設計法

 物件導向
擴張性很高?




             7/49
以往的遊戲程式設計法

 物件導向
擴張性很高?

 有設計過的
  物件導向
 擴張性才高
             8/49
以往的遊戲程式設計法
■遊戲開發的變化性很高
・常常會更改規格
 →難道要每次都改繼承結構?
 →不仔細分析繼承關係的話很難分辨什麼
  能作什麼不能作




                      9/49
Unity的遊戲程式設計法




                10/49
Unity的遊戲程式設計法
■Component導向
把每個功能用Class化的Component組合起
來,定義整體的Behaviour

    EnemyObject
     EnemyObject       PlayerObject
                        PlayerObject
        Transform           Transform
      MeshRenderer       MeshRenderer
     CapsuleCollider    CapsuleCollider
     DamageAcceptor     DamageAcceptor
        AIControl        PlayerControl
                                          11/49
Unity的遊戲程式設計法
■Component=有實作的Interface
用SendMessage丟出訊息,只要有同名的
Method就會執行

                   PlayerObject
                    PlayerObject
BulletObject
 BulletObject
                        Transform
  DamageProvider
                     MeshRenderer
                    CapsuleCollider
                                      有!
  有TakeDamage       DamageAcceptor
  這個Method的話
     就執行             PlayerControl

                                       12/49
Unity的遊戲程式設計法
■Component=有實作的Interface
用GetComponent確認是否有Component,
然後再呼叫Method

                    PlayerObject
                     PlayerObject
BulletObject
 BulletObject
                         Transform
  DamageProvider
                      MeshRenderer
                     CapsuleCollider
   DamageAcceptor
                     DamageAcceptor
   存在的話就呼叫
    TakeDamage        PlayerControl
     這個Method
                                       13/49
Unity的遊戲程式設計法
■Component=有實作的Interface
沒有Component的話什麼也不做


BulletObject
 BulletObject      BackgroundObject
                    BackgroundObject
  DamageProvider        Transform
                     MeshRenderer
                     CubeCollider
     因為沒有
  DamageAcceptor
    直接消失不見

                                       14/49
Unity的遊戲程式設計法
■容易增減功能
只要追加Component就可以增加功能


BulletObject
 BulletObject      BackgroundObject
                    BackgroundObject
  DamageProvider       Transform
                     MeshRenderer
                     CubeCollider
    背景物件                               追加!
  也可以破壞比較好          DamageAcceptor


                                        15/49
Unity的遊戲程式設計法
■暫時改變行為也很簡單
只要以Component為單位開關功能就好


                  PlayerObject
                   PlayerObject
EventObject
 EventObject
                       Transform
   EventTrigger
                    MeshRenderer
                   CapsuleCollider
   事件進行中           DamageAcceptor
  停止控制輸入和
    傷害計算            PlayerControl

                                     16/49
Unity的遊戲程式設計法

Component導向
 擴張性很高?




                17/49
Unity的遊戲程式設計法

Component導向
 擴張性很高?

  有設計過的
Component導向
  擴張性才高
                18/49
Unity的遊戲程式設計法
■功能拆解失敗的話就會出錯
・The All-in-one Component
 →想在一個Component裡解決所有事情

                                  PlayerObject
                                   PlayerObject
ObjectBehaviour   IControllable
+ModelData        +Controller       PlayerBehaviour
+Collider                           +ModelData
                                    +Collider
                                    +CharStatus
CharBehaviour                       +Controller
+CharStatus       結果跟物件導向
                   一模一樣…
                                                  19/49
Unity的遊戲程式設計法
■功能拆解失敗的話就會出錯
・Spaghetti Components
 →Component之間的相依關係過於複雜

                     PlayerObject
                      PlayerObject
  BulletObject
   BulletObject
                          Transform
      Transform
                       MeshRenderer
   ParticleSystem
                      CapsuleCollider
   CapsuleCollider
                      DamageAcceptor
   DamageProvider
                       PlayerControl
                                        20/49
Unity的遊戲程式設計法
■功能拆解失敗的話就會出錯
・Tons of Components
 →定義一個Behaviour要用到大量的
  Component
PlayerObject
 PlayerObject
     Transform     MeshFilter        HP
  MeshRenderer    AudioSource        MP
 CapsuleCollider ParticleSystem   Strength
 DamageAcceptor   TrailRenderer   Intellect
  PlayerControl    Animation      Dexterity
                                              21/49
Component導向的範例




                 22/49
Component導向的範例




EZ GUI vs NGUI


                  23/49
Component導向的範例
■EZ GUI
物件導向的Library。Asset Store上最早出現
的GUI Library,也有很多人用…




                           24/49
Component導向的範例
■EZ GUI
按鈕Component的
Inspector畫面




                     25/49
Component導向的範例
■EZ GUI
       指定位置及大小
              顏色調整
       Render相關設定
          Label相關設定
    Drag&Drop相關設定
           事件相關設定
           音效相關設定
          Sprite相關設定
     Animation相關設定
      Material相關設定
                       26/49
Component導向的範例
■EZ GUI
典型的All-in-one Component。很難理解每
個功能被放在哪裡。而且也很難開關個別功
能。

利用擴充編輯器和Foldout的話倒是可以讓他
變好看一點。

It's NOT easy!

                           27/49
Component導向的範例




    NGUI


                 28/49
Component導向的範例
■NGUI
Component導向的Library。佔有晚出的優
勢,設計上非常適合Unity使用。




                         29/49
Component導向的範例
■NGUI
按鈕Component的
Inspector畫面




                     30/49
Component導向的範例
■NGUI
                       按鈕圖示
 Mouseover及
 Mouseclick時的
 顏色變化及管理               按鈕文字

 縮放Animation

 座標Animation

 Sound Effect

                        31/49
Component導向的範例
■NGUI

Sprite物件的話只會
Attach跟Sprite相關
的Component




                      32/49
Component導向的範例
■NGUI
如果要停止按鈕的縮放動畫,只要刪除或是
Disable UIButtonScale Component就好。
而且每個功能被Component化之後很容易理
解。

不過控制Render順序之類的部份還是不太容
易理解。


                                33/49
Component導向的範例




Component化的指標


                  34/49
Component導向的範例
■Component化的指標
・把物件的特性Component化

  Sword
   Sword               可以裝備
       Equipment
                       可以造成傷害
   DamageProvider


    Shield
     Shield
                       可以裝備
        Equipment
                       可以吸收傷害
      DamageAbsorber
                                35/49
Component導向的範例
■Component化的指標
・把暫時的狀態Component化
                    因為無敵Component,
                    暫時失效
 PlayerObject
  PlayerObject
   DamageAcceptor
                    玩家無敵期間會Attach上去
   Invulnerable     (一段時間後消失)
    BlinkModel
                    因為無敵Component追加
                    的模型閃爍Component
                    (一段時間後消失)
                                     36/49
Component導向的範例
■Component化的指標
・把可更換的功能Component化
                     朝指定的方向移動,控制相關
  PlayerObject
   PlayerObject      Animation的Component
       Character
   ControllerInput     從控制器輸入指令,
                       移動角色
    EnemyObject
     EnemyObject
        Character      從AI輸入指令,
         AIInput       移動角色
                                      37/49
Component導向的範例
■Component化的指標
・把可更換的功能Component化

  PlayerObject
   PlayerObject
       Character
       AIInput

                       在Enemy身上加上
    EnemyObject
     EnemyObject       ControllerInput
        Character      就可以控制敵人
     ControllerInput
                                         38/49
Component導向的範例
■Component化的指標
・把可更換的功能Component化

  PlayerObject
   PlayerObject
       Character
     EventActor


    EnemyObject      事件中就根據
     EnemyObject
        Character    事件的指令移動
        EventActor
                               39/49
Component導向的範例




Component化的注意事項


                   40/49
Component導向的範例
■Component化的注意事項
・不要集中在1個Component上
GameManager
 GameManager
  TransLevel(next)
                              一邊降低BGM音量
  {
     while (e < t)            一邊把畫面變暗,
     {                        結束之後再切換場景。
        bgm.volume = 1 - e;
        fade.alpha = e;
        yield return;
     }
     LoadLevel(next);
  }
                                       41/49
Component導向的範例
■Component化的注意事項
・不要集中在1個Component上
GameManager
 GameManager
  TransLevel(next)
                              不要在1個Component
  {
     while (e < t)            上存取大量的其他
     {                        Component
        bgm.volume = 1 - e;
        fade.alpha = e;       不要用1個Component
        yield return;
                              做完所有事情
     }
     LoadLevel(next);
  }
                                          42/49
Component導向的範例
■Component化的注意事項
・不要集中在1個Component上
GameManager
 GameManager                      製作必要的
 TransLevel(next)                 Component,
 {                                一段時間後切換場景
   AddComponent<BGMFade>( );
   AddComponent<ScreenFade>( );
   WaitForSeconds(1);
   LoadLevel(next);               逐漸降低BGM音量的
 }                                Component

    BGMFade                       把畫面逐漸變暗的
   ScreenFade                     Component
                                              43/49
Component導向的範例
■Component化的注意事項
・避免Component間的相互參照

BulletObject
 BulletObject      PlayerObject
                    PlayerObject
  DamageProvider       Character
                    ControllerInput
                    DamageAcceptor    彼此相依的
                                      Component
                                      是個惡夢
盡量避免相互監視的
Component

                                             44/49
Component導向的範例
■Component化的注意事項
・適度的將物件階層化
PlayerObject
 PlayerObject      負責輸入和碰撞判定的物件
    Character
 ControllerInput   PlayerModel
                    PlayerModel    負責Render模型的
                      MeshFilter   物件
                    MeshRenderer
                      Animation
                                   HitEffect
                                    HitEffect
                                    ParticleSystem
                   負責Effect的物件
                                                 45/49
Component導向的範例
■Component化的注意事項
・活用Prefab以及編輯器擴充功能
 →每次都要設定一堆Component很累人,
  盡可能把常用的組合Prefab化,然後透
  過編輯器擴充功能從選單直接產生。




                      46/49
如何以Unity快速製作Prototype




                    47/49
如何以Unity快速製作Prototype




  實際Demo

                    48/49
謝謝!
我愛台灣!
        49/49

Unity帶來的新型遊戲開發方式