這書不錯,學習以下設計思路很好。
第零章
介紹了一些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空間中的拾取問題。
按照間隔生成路徑。
基於路徑生成多邊形。
扭曲隧道模型。
道路兩邊的點綴的樹木,開始稀少中間茂密最後稀少。