Unity筆記 《Unity遊戲設計與實現》

這書不錯,學習以下設計思路很好。

第零章
介紹了一些Unity基礎。
camera控制:alt、ctrl + alt、F按鍵 的使用。
一個小例子不斷polish的過程。
物理控制的經驗:
1)避免漂浮感,調整物體大小(rigidbody 1.0 = 1米)或在PhysicsManager中提高Gravity的Y的絕對值(例子中爲-20)。
2)固定高度的跳躍

float   y_speed = Mathf.Sqrt(2.0f*Mathf.Abs(Physics.gravity.y)*this.JumpHeight);

v = sqrt( 2 g h )

第一章
捲動背景,移動攻擊。
記下可以做成遊戲的構思,說不定什麼時候會用到。

無限循環背景,處理跟隨物體移動過快問題。
根據攝像機位置找到n(整體背景的位置),直接用乘法來計算位置,無論多快的移動用這個算法3塊背景就足夠了!
這裏討論了兩種四折五入的做法,對於負數結果是不同的。
Mathf.RoundToInt( vf );
Mathf.FloorToInt( vf +0.5f );

關於碰撞形狀的選擇。球和方形擠在一起時會發生位移,而方形和方形擠在一起時卻確難的多發生位移。
球碰撞在側視圖中往往會有誤差,認爲能打到敵人的卻沒有打到。

加入高風險高回報的機制提高有趣性。這裏用的是攻擊距離,實際實現用的是發起攻擊到傷害的時間。

“預判斷”(碰撞體存在比動作稍長)機制讓遊戲更容易上手。

製作“攻擊反饋”。先搞清player面向x正,y是上,z向裏對應Vector3.right Vector3.up Vector3.forward。
按照一個軸旋轉的Quaternion:

blowout_xz = Quaternion.AngleAxis(y_angle, Vector3.up)*blowout_xz;

=============================================================
Find References In Scene可以找到一個腳本在哪個gameobject上。
這個常見,do{ … }while(false)是一種goto,可以在裏面寫break。
2個scene,titlescene和gamescene。注意自己打開的是哪個。

AnimatedTextureExtendedUV利用texture的scale和offset實現幀動畫,用於刀光的實現。

AttackColliderControl刀的碰撞球。
OnTriggerEnter和OnTriggerStay的區別。

CameraControl和玩家一起移動。
this.transform.position = new Vector3(player.transform.position.x + this.offset.x, this.transform.position.y, this.transform.position.z);

FadeControl動態加入的component算法,使用一個1x1紋理用於全屏淡出。
fader = gameObject.AddComponent();

FloorControl作者得意的無限背景。

GUIControl加入SceneControl處理gui部分,這個ui的弄法較老。

LevelControl生成怪物,這樣的方式來初始化。這個類並不是繼承monobehaviour所以不會做爲組件使用。
this.level_control = new LevelControl();
this.level_control.scene_control = this;
this.level_control.player = this.player;
this.level_control.OniGroupPrefab = this.OniGroupPrefab;
this.level_control.create();

OniControl單個怪物控制。

OniEmitterControl最後結算時的怪物塔,就是簡單的綁定了sphere的一些oni隨機位置落下。

OniGroupControl怪物方陣控制。

OniStillBodyControl最後結算時的怪物塔。

PlayerControl控制玩家

ResultControl用於結算數據,這個在SceneControl裏直接new出使用。
this.result_control = new ResultControl();

SceneControl場景控制模塊,放在場景裏的empty gameobject上。可以說是主模塊。
除了主要的prefab(玩家、oni),還有一個遊戲狀態的維護(STEP)。

ScoreControl分數顯示

SimpleSpriteGUI分數顯示用到顯示文字

TitleSceneControl,ScoreControl的簡化版本,Application.LoadLevel(“GameScene”);裝載場景。

第二章
拼圖。
點擊,2d到3d,碎塊的任意位置拖動,要考慮到點擊時的偏移量就可以做到了。
移動不移動到鼠標位置,這是個手感問題,作者應該是推崇考慮偏移量。

碼放打亂的碎片,建立一個網格放入元素再進行一些變換。

“可控隨機數”,這裏使用一組週期性變換的數值(指旋轉90)效果也不錯。

介紹gameobject和component。
render、collider、audio等都是GetComponent的縮寫。

以下3中一個意思:
this.rigibody 直接從別的組件訪問另外組件。
this.gameObject.rigibody 回到gameObject在訪問另外組件。
this.gameObject.GetComponent() 也不使用縮寫,原生態的寫法。

銷燬:
Destory(this); 銷燬腳本自己
Destory(this.gameObject) 銷燬整個gameObject

[RequireComponent(typeof(MeshCollider))]
public class PieceControl:MonoBehaviour{
這樣就會一併添加MeshCollider

PazzleControl通過代碼添加組件和MeshCollider

逐漸變慢的滑動插值動畫,也可以考慮使用動畫插件:

case STEP.SNAPPING:
{
    // 朝目標位置移動
    Vector3 next_position, distance, move;

    // 按Easing方式運動
    distance = this.snap_target - this.transform.position;

    // 下一處位置=當前位置和目標位置的中間點
    distance *= 0.25f*(60.0f*Time.deltaTime);

    next_position = this.transform.position + distance;

    move = next_position - this.transform.position;

    float   snap_speed_min = PieceControl.SNAP_SPEED_MIN*Time.deltaTime;
    float   snap_speed_max = PieceControl.SNAP_SPEED_MAX*Time.deltaTime;

    if(move.magnitude < snap_speed_min) {

        // 移動量小於一定值則結束
        // 快速向目標位置移動
        // 結束判斷在狀態遷移檢測過程中進行,這裏只調整其位置
        // 
        this.transform.position = this.snap_target;

    } else {

        // 如果移動速度過快則進行調整
        if(move.magnitude > snap_speed_max) {

            move *= snap_speed_max/move.magnitude;

            next_position = this.transform.position + move;
        }

        this.transform.position = next_position;
    }
}
break;

第三章
吃豆類遊戲規則介紹,整數處理grid形式,可以提前按下方向到T形路口改變方向。
所謂的“操作輔助”,改善操作困難的情況。

文本編輯地形。使用CSV(逗號分割的文本),很好的string處理的例子。

自定義了一個editor按鈕來生成。

using UnityEngine;
using System.Collections;
using UnityEditor;

[CustomEditor(typeof(Map))]
public class MapModelCreator : Editor {
    public override void OnInspectorGUI() {
        DrawDefaultInspector ();
        if (GUILayout.Button("Create Map Model")) {
            Map map = target as Map;
            map.CreateModel();
        }
    }
}

動畫2技巧:
1)動畫混合mix,握劍和揮劍下半身混合行走。

// 開始合成動畫的結點
        Transform mixTransform = transform.Find("root/hip/mune");

        // 揮動寶劍
        animation["up_sword_action"].layer = 1;
        animation["up_sword_action"].AddMixingTransform(mixTransform);      

        // 把劍舉到胸前
        animation["up_sword"].layer = 1;
        animation["up_sword"].AddMixingTransform(mixTransform);         

2)聲音事件,用腳本添加事件的例子。

protected virtual void InitializeAnimations()
    {
        animation["run"].speed = 2.0f;

        // 腳步聲事件
        AnimationEvent ev = new AnimationEvent();
        ev.time = 0.0f;
        ev.functionName = "PlayStepSound";
        ev.floatParameter = 1.0f;
        animation["run"].clip.AddEvent(ev);

        AnimationEvent ev2 = new AnimationEvent();
        ev2.time = animation["run"].clip.length / 2.0f;
        ev2.functionName = "PlayStepSound";
        ev2.floatParameter = 1.06f;
        animation["run"].clip.AddEvent(ev2);        
    }
// 播放腳步聲
    public void PlayStepSound(AnimationEvent ev)
    {
        (FindObjectOfType(typeof(AudioChannels)) as AudioChannels).PlayOneShot(m_stepSE,1.0f,0.0f,ev.floatParameter);

    }

幽靈AI:
設計4種不同性格的幽靈。

第四章
潛水艇。
3D聲音,設置距離衰減。設置Volume rolloff 爲custrom rolloff

強行中斷聲音的播放會有時會出現噪音,所以採用fadeout的方法,書中例子使用了coroutine。

private IEnumerator Fadeout(float duration)
{
     // 淡出
     float currentTime = 0.0f;
     float waitTime = 0.02f;
     float firstVol = audio.volume;
     while (duration > currentTime)
     {
         audio.volume = Mathf.Lerp(firstVol, 0.0f, currentTime / duration);
         yield return new WaitForSeconds(waitTime);
         currentTime += waitTime;
     }

     // 淡出處理完全結束後銷燬對象
     if (hitEffector)
     {
         while (hitEffector.IsPlaying())
         {
             yield return new WaitForSeconds(waitTime);
         }
     }
     // 發送銷燬對象消息
     transform.parent.gameObject.SendMessage("OnDestroyLicense");
 }

潛艇的控制:
attenuate-衰減。
Mathf.SmoothStep有speed up和slow down的插值。
margin-幅度。

使用不同的攝像機繪製雷達和主畫面,通過culling mask來控制外觀。通過視口設置來製作畫中畫(注意這裏並沒有用到render target)。

============
這個項目管理方式和前面幾個不同。
打開root scene

SceneSelector
這個腳本附着在Root上,設置了DontDestroyOnLoad(gameObject);所以是全局存在的。
有2個子(也是全局存在的):
Intermission,過場插頁,實際切換髮生在IntermissionEffector的Finish裏。
RootCamera,clear flag depth only,是個疊加攝像機。

之後用協程加載了title這個場景。
包括的gameobject
Adapter,stage也有一個

 // 場景結束後調用
 void OnSceneEnd()
 {
     // 開始Stage
     if (root) root.SendMessage("OnStartStage");
 }

Field
裏面有terrain和submarine,用於title背景。
UI
unity 5之前的ui做法。

GameObject.BroadcastMessage(調用gameobject自身和子的函數)
一個遊戲中使用通常是一組對象的集合,用這個可以分別處理。

可以這樣用狀態機的形式管理整體遊戲
root scene:
gameobject gamephasemanager singleton.
setgamephase

gamephase(One scene has N phase) array in manager.
phase 0 phase0begin phase0work phase0end
phase 1
phase 2 …

第五章
節拍遊戲。

每個打點過了,就屬於下個打點了。
對應打點到屏幕像素。
點擊準確程度分成3個等級。這裏作者提出了重複判斷的情況,不要提前判斷後面的節奏。
事件系統,根據音樂產生各種事件。

建立turn around環境。
閥值,某些數字的範圍。這裏用一個可以調整的誤差來控制遊戲的難易。
定位音樂的位置,MusicManager

AudioSource m_audioSource;
public void Seek(float beatCount){
        m_audioSource.time =  beatCount / m_currentSongInfo.beatPerSecond;
        m_beatCountFromStart = m_previousBeatCountFromStart = beatCount;
    }

===============================
這個項目只有一個scene。

PhaseManager對應的gameobject在場景裏,管理遊戲狀態。

第六章
飛機遊戲。
生成用於鎖定的碰撞區域,用扇形區域來避免幀間跳過,而不用效率低的continuous檢查方式。

meshFilter.mesh = mesh;

// mesh 發生變化後如果不執行 false -> true 則不會得到反映
meshCollider.enabled = false;
meshCollider.enabled = true;

不連續鎖定,這裏使用了實例的唯一id。
int targetId = collider.gameObject.GetInstanceID();

制導,軌跡trailrender
圓弧軌跡,每次移動都會增加偏移角度,避免圍繞敵人一直無法攻擊的情況。也用在AI等地方。

消息窗口:
逐字顯示效果。
=========================
打開opening場景
maincamera上有個clicktogamestart會裝載game場景

第七章
消除遊戲。
遞歸檢測相鄰方塊,這裏需要添加一個已經處理過的標誌避免重複處理。爲求萬全,作者加了遞歸最大調用次數。
初始的方塊碼放,作者下了一定的功夫處理這個,根據需求生成了,只有1個4,多個3的隨機初始方塊。
爲搞清除同時上下滑動和替換的動畫情況,有個子動畫的測試項目。
本來是數組安排的方塊,如何處理方塊的移動。數組的索引是立即變化的,同時設計偏移距離值,偏移值會插值到0產生動畫。
=========================
GlobalParam 提供了singleton的方式
titlecontrol loadlevel gamescene
debugprint singleton的寫屏調試方式
用trigger反彈:

Vector3 v = this.rigidbody.velocity;
v.z *= -0.5f;
this.rigidbody.velocity = v;

第八章
貓竄。
試用狀態機來管理animation
可以控制的跳躍高度,注意處理2此和下落過程的處理。
碰撞的處理,記錄所用的碰撞,然後處理。窗戶框的碰撞模型和模型外觀不同,有利於模型滑動。
碰撞後的回彈,直接操作rigidbody速度。
基於物理+特殊處理的方式。

第九章
RPG。
Action,使用2維數組記錄各種action。
Actor基類來實現各種event。
Event執行,其中有個wait input的處理等待玩家輸入。
Message處理特殊情況,通用的再加入到event。

第十章
賽車。
3d空間中的拾取問題。
按照間隔生成路徑。
基於路徑生成多邊形。
扭曲隧道模型。
道路兩邊的點綴的樹木,開始稀少中間茂密最後稀少。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章