新人求教关于unity中ios layer 层级层级的设置问题

程序写累了,就来玩玩酷跑小游戏吧,嘿嘿。
雨松MOMO送你一首歌曲,嘿嘿。
Unity3D研究院之脚本自动添加tag和Layer
Unity3D研究院之脚本自动添加tag和Layer
围观21193次
编辑日期: 字体:
有朋友问我他做了一个unity游戏插件,但是它的插件里面自定义了自己的tag和layer。这样用户在导入他的unitypackage的时候如果项目里没有写入它的tag或者layer那么就会有错误,所以他希望在导入unitypackage的时候自定把它的tag或者layer写进用户的项目里。
把下面这条脚本,随着你的资源一起打包,这样当你的unitypackage被别人导入的时候,程序就会调用AddTag和AddLayer来添加。因为有可能你的项目里已经添加了这个tag或者layer所以在添加之前我做了一个判断,判断项目是否已经存在了这个tag。
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
using System;using System.Collections;using System.Reflection;using UnityEditor;using UnityEngine;&public class NewBehaviourScript :AssetPostprocessor{& static void OnPostprocessAllAssets (string[] importedAssets, string[] deletedAssets,string[] movedAssets, string[] movedFromAssetPaths)
foreach(string s in importedAssets)
if (s.Equals("Assets/NewBehaviourScript.cs"))
//增加一个叫momo的tag
AddTag("momo");
//增加一个叫ruoruo的layer
AddLayer("ruoruo");
}& static void AddTag(string tag) {
if(!isHasTag(tag))
SerializedObject tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]);
SerializedProperty it = tagManager.GetIterator();
while (it.NextVisible(true))
if(it.name == "tags")
for (int i = 0; i & it.arraySize; i++)
SerializedProperty dataPoint = it.GetArrayElementAtIndex(i);
if(string.IsNullOrEmpty(dataPoint.stringValue)){
dataPoint.stringValue = tag;
tagManager.ApplyModifiedProperties();
} }& static void AddLayer(string layer) {
if(!isHasLayer(layer))
SerializedObject tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]);
SerializedProperty it = tagManager.GetIterator();
while (it.NextVisible(true))
if(it.name.StartsWith("User Layer"))
if(it.type == "string" )
if(string.IsNullOrEmpty(it.stringValue)){
it.stringValue&&= layer;
tagManager.ApplyModifiedProperties();
} }& static bool isHasTag(string tag) {
for (int i = 0; i & UnityEditorInternal.InternalEditorUtility.tags.Length; i++) {
if (UnityEditorInternal.InternalEditorUtility.tags[i].Contains(tag))
return true;
return false; }& static bool isHasLayer(string layer) {
for (int i = 0; i & UnityEditorInternal.InternalEditorUtility.layers.Length; i++) {
if (UnityEditorInternal.InternalEditorUtility.layers[i].Contains(layer))
return true;
return false; }}
OK然后就是导入你的unitypackage
倒入完毕后,新增加的tag和layer就都保存进去了。
代码其实不难,如果你想同时导入多个tag或者layer,简单的拓展一下方法传入不固定参数即可。最近MOMO好累呀!希望痛苦的日子赶快过去。。
本文固定链接:
转载请注明:
雨松MOMO提醒您:亲,如果您觉得本文不错,快快将这篇文章分享出去吧 。另外请点击网站顶部彩色广告或者捐赠支持本站发展,谢谢!
作者:雨松MOMO
专注移动互联网,Unity3D游戏开发
如果您愿意花10块钱请我喝一杯咖啡的话,请用手机扫描二维码即可通过支付宝直接向我捐款哦。
您可能还会对这些文章感兴趣!最近连续遇到了几个绘制图像之间相互遮挡关系不正确的问题,网上查找的信息比较凌乱,所以这里就把自己解决问题中总结的经验记录下来。
Unity中的渲染顺序自上而下大致分为三层。 最高层为Camera层,可以在Camera的depth那里设置,设置之后,图形的渲染顺序就是先绘制depth低的相机下的物体,再绘制depth高的相机下的物体,也就是说,depth高的相机会覆盖depth低的相机(具体的覆盖关系有don&t clear, solid color等等几种)
比Camera层稍低一层的是sorting layer层, 随便找一个可以设置sorting layer的地方,选择sorting layer,点添加按钮,就可以看到当前所有的sorting layer,并且可以更改sorting layer的顺序,排位靠后的sorting layer会覆盖排位靠前的sorting layer。
设置好sorting layer的相互关系之后,就可以给任何一个继承于Renderer类,或者有renderer的子类作为field的对象设置sorting layer了。
注意这些sorting layer的遮挡关系是在同一个camera的层级下的。
不同camera下的renderer渲染顺序以camera的depth为准。
有的component的sorting layer可以直接在unity editor里面设置,比如Sprite Renderer。
有的则需要用代码来设置,比如设置Particle system的sorting layer, 就需要在代码中取到 ParticleSystem.Renderer.SortingLayer 来进行设置。
比sorting layer再低一层的是sorting order, 这个数字指代的是在同一个sorting layer下的渲染顺序,用法很明显就不赘述了。
需要注意不要混淆的是gameobject的layer,和renderer的sorting layer。
gameObject的layer个人理解是一个逻辑上的分层,用于camera的culling mask等。
而renderer的sorting layer则用于渲染。只有继承与renderer或者有renderer作为filed的component才需要设置sorting layer。
另外需要指出的是,常用的NGUI的widget depth其本质也是一个sorting layer下的sorting order。
NGUI好像用的是一个叫做&UI&的sorting layer。 由此大家如果有需要,也可以自己取Hack NGUI的代码,把NGUI的sorting layer暴露出来供自己定制。
简单总结一下,决定Unity渲染关系的层级顺序是:
sorting layer
sorting order
好了,本篇unity3d教程到此结束,下篇我们再会!
猜你喜欢:
简介:& && && && &
& & & & 随着互联网信息爆炸式增长,用户浏览单个网页时,并不像我们想象的如阅读文章般从左到右、从上倒下逐一查看,那么朋友们和丝路教育一起了解如何在设计中建立良好的视觉层级!
& & & & 一、 视觉层级为什么重要
& & & & ...
&/&0&评论&&&&&&&&&&06-10
简介:& && && && &
& & & & 今天我们来看一下Ahmed Fathi的VRay分层渲染并在ps中合成的教程。这个教程发布后引起了很多人的响应。所以,如果你错过了第一次,这次为什么不细细研读呢?
& & & & 在这篇教程里将演示如何将渲染的图层通过P...
&/&0&评论&&&&&&&&&&06-10
觉得不错?顶一下!
复制本文地址
本栏目最新:
更新时间:
更新时间:
更新时间:
所属栏目:[]
所属栏目:[]
所属栏目:[]
所属栏目:[]
所属栏目:[]
所属栏目:[]
所属栏目:[]
所属栏目:[]
本页全部评论共计()条&&&&
您的昵称:(10个汉字以内)
&&&&&&&&&&&&&&&&&&&&
评论中不要带有网址,并且不要发布违禁词汇。字数限制在300汉字以内。
&&&&&&&&&&
验证码:(注意大小写)
网友最新评论:&&&&&&&&&&
114PS教程网()发布的所有教程信息版权归原作者所有,由本站转载的内容仅为提供更多信息,并不代表本站同意其观点。
所有图片信息均来自网络,本站仅作学习使用,若无意冒犯,请联系本站。
Copyright &給Unity新手的第三人稱遊戲系統教學
Unity 是由 Unity Technologies 所開發的 3D 遊戲引擎,他以入門門檻低、跨平台支援以及開發成本相對低的優點,受到遊戲業界的歡迎,而 Unity 作為遊戲、3D互動原型開發也相當適合,因此也在我們人機互動的研究中所使用。
最近我請教了我的遊戲開發者朋友-許多關於 Unity 的技術,並將部分重新整理成一份完整的新手教學文章,這篇文章的誕生都要感謝王瀚宇的無私分享,他曾經開發過
並獲得了數個該年度遊戲競賽的大獎,同時也在人機互動領域中專注研究遊戲的各種可能性,是一位相當厲害的遊戲開發者。
這篇文章將會分享如何從零開始製作一個第三人稱視角的基礎遊戲系統,包含讓一個角色在 3D 場景中:
透過鍵盤或搖桿移動角色,並且攝影機在角色後上方觀看,並且以適當距離追隨主角。
按下左右鍵角色以攝影機為圓心左右旋轉前進,如果角色撞到場景障礙物而不能前進時,則由攝影機旋轉直到角色可以繼續前進。
按下後退鍵角色面向攝影機前進,並且如果攝影機碰撞到場景障礙物時,向上移動從上方觀看角色。
同時垂直(前後)與水平(左右)移動,可以進行 45 度角移動。
完成預覽影片:
(以下教學在 Unity 4.5.4版本完成,並推薦有基本程式基礎的人但沒有 Unity 經驗的人閱讀)
新建 Unity 專案
從 Unity 官方網站並安裝 Unity 開發工具,打開後選擇 File & New Project ,新增一個 Unity 專案在你喜歡的地方。
從 Asset Store 下載素材
Unity 官方提供了一個遊戲素材交易分享平台-Asset Store,你可以在上面找到來自全世界遊戲設計師所設計的遊戲素材,包含 3D 模型場景、特效、音效……等等,你可以從菜單上的 Window & Asset Store打開他,然而要下載上面的素材得需要一個 Asset Store 帳號,請你先註冊一個帳號。
註冊完以後便可以在上面下載免費素材了,請搜尋我們這次需要的角色模型 Unity Chan,並選擇下載並 Import 到我們的專案中。題外話,Unity Chan 是 Unity Technologies Japan 所設計的官方 Unity 角色,目的是在日本推廣 Unity 引擎,並且完全 Open Source 其角色模型與語音素材,真是十分有日本特色的推廣方式啊!
場景模型則請搜尋 Make Your Fantasy Game Lite,同樣地下載後選擇 Import 置入專案。
建立場景與角色
打開剛剛下載的場景,位置是 Asset & L_G_Assets_pack_Lite & Demo 。
打開後選擇 File & Save Scene As 另存為場景為 main,之後我們將在 main 上開發我們的遊戲。
再來從我們底下的 Assets & UnityChan & Models 找到我們的角色模型,並把它拖曳到我們的場景裡。
完成後你可以在 Scene 中看到我們的角色已經被放到場景中了。
置入攝影機與角色調整
設置攝影機
在左邊的 Hierarchy 中選擇 Create & Camera,將攝影機放到場景中。
由於我們需要設計角色向後移動時,攝影機撞到障礙物時垂直向上移的效果,所以我們預先建立一個用來偵測攝影機碰撞的遊戲物件。從菜單選擇 GameObject & Create Empty 後,把新增的 Game Object 更名為 CollisionBox 並把 Camera 放到 CollisionBox 底下。
在左邊的 Hierarchy 點選 Camera ,把右邊 Inspector 中的 Position 全部設為 0,讓 Camera 與 CollisionBox 位置重合。接下來我們要讓攝影機視角看向主角,此時我們要為攝影機掛上腳本,讓攝影機一直看著主角。
請選擇 Inspector & Add Component & New Script 加入 CameraScript。
並且雙擊 CameraScript 打開程式編輯器, 貼上以下程式碼。
using UnityE
using System.C
public class CameraScript : MonoBehaviour {
public Transform lookAtO
// Update is called once per frame
void Update () {
// look at player
transform.LookAt(lookAtObj);
在 Unity 中腳本的 Update function 會每一個 frame 被呼叫一次,也就是畫面每刷新一次都會呼叫 Update function,通常會把處理遊戲 Input 與 Output 的程式碼放在 Update function ,讓它每個 frame 都去即時接收遊戲的輸入與刷新遊戲物件的反饋。
這段程式碼的功能是,讓 Camera 每次刷新時都叫他旋轉自己面向 lookAtObj,稍後我們會把 lookAtObj 變數設為我們的 Unity Chan ,這樣 Camera 就會一直注視著我們的主角了。
lookAtObj 是一個 public 變數,在 Unity 中 public 變數會出現在 Unity 的 GUI 面板上,可以直接用拖拉的方式給值,並且在遊戲進行中(run time)檢視更改,是 Unity 十分強大的功能。
在這裡,我們直接在 Hierarchy 面板中拖想要指定的物件到 Inspector 面板上的 lookAtObj,就可以指定 lookAtObj 變數的值。為了要讓攝影機盯著角色的頭看,我們要建立一個 Game Object 叫做 LookHere 放在 Unity Chan 的頭上,並讓攝影機盯著他看。
建立 LookHere 的方法跟剛剛 CollisionBox 一樣,建立完之後將他放到 unitychan 之下,並且調整右邊 Inspector 面板的 position 讓 LookHere 放到主角約為頭的位置。
最後拖曳 LookHere 到 CameraScript 的 lookAtObj上。
此時你可以稍微把整個 CollisionBox 往後拉到主角的背後上方合適的位置,你可以直接在 Scene 中拉動 CollisionBox 或是在 Inspector 中調整 Position 的X、Y、Z,然後點選播放鍵檢視遊戲。
設置 skybox
這時候發現我們的天空是一片灰藍,非常地單調無趣,我們可以去設置 Skybox 的材質來讓場景更為豐富。
首先先匯入 Skybox 素材。
接下來選菜單上的 Edit & Render Setting,設置 Skybox Material 為 MoonShine Skybox,將天空設為月夜背景。
調整燈光與模型反光
現在整個畫面看起來非常的暗,這是因為這個場景並沒有什麼燈光,我們得自己加一個燈在攝影機上,就像專業攝影會打燈一樣。 請點選 Hierarchy & Create & Point light,並把新增的 Point light 放到 Camera 之下,同時在右邊 Inspector 設置光的 Range 為 100。
這個時候會發現視野周邊的場景有變亮了,但是主角身上仍然非常地暗,這是因為 Unity Chan 模型身上材質反光(著色運算)設定的問題,我們得在底下的 Asset & UnityChan & Models & Materials 找到 Unity Chan 的材質貼圖,並把除了臉頰紅暈 mat_cheek 外的貼圖選起來。
更改右邊的 Shader 為 Diffuse(漫射),點擊 Main Color 開啟顏色選單如下圖調整顏色,讓反光看起來自然一點。
而剛剛沒有調整到的 mat_cheek ,重複剛剛類似的步驟更改右邊的 Shader 為 Transparent/Diffuse,並調整一下透明度。
設置第三人稱視角控制器
從菜單選擇 GameObject & Create Empty 後,把新增的 Game Object 叫做 ThirdPersonController 並把 unitychan 與 CollisionBox 都放到他之下,接下來我們會把控制角色與攝影機的程式放在這個物件上。
給主角加上物理性質
在 3D 遊戲中,角色會有物理碰撞性質,以免有穿牆等不合理的現象發生。我們的主角也需要在 Unity 中設置物理碰撞,請選擇 unitychan 並且點選 Inspector & Add Component & Rigid body 來增加主角的物理性質,包含重力、碰撞運算等等,新增完後打開 Rigid body 底下的 Constrain 把 Freeze Rotation 中的 X、Y、Z 都勾起來,避免主角撞到障礙物反彈時,會亂彈旋轉甚至倒地。
有了物理性質,還需要設置主角模型的碰撞邊界,也就是主角實際與其他物體碰撞的判定位置,增加的方式為點選 Inspector & Add Component & Capsule Collider,完成後你會發現角色腳下多了個綠色框線的物體,那就是碰撞判定的區塊,調整 Capsule Collider 的參數,讓它貼近角色的模型大小,參數大約是 Radius 為 0.2、Height 為 1.57、Y 為 0.82。
設置完之後,角色碰到牆或是其他障礙物就不會穿過去了。
基礎前進與後退
在 ThirdPersonController 上點 Add Component & New Script 加入名為 ThirdPersonController 的新腳本,並一樣雙擊 ThirdPersonController 腳本,來打開程式編輯器。
首先先加入我們想要在 Inspector 上可以直接調整設定的 public 變數:
//指定主角物件
public GameO
//指定攝影機物件
public GameObject mainC
//指定攝影機碰撞物件
public GameObject cameraCollisionB
//攝影機與主角的距離
public float M
//主角的移動速度
public float moveS
然後使用一樣拖曳的方式,將這些 public 變數設置好。
在 Update Function 中則寫上以下的程式:
void Update () {
// GET INPUT AXIS
float vertical = Input.GetAxis ("Vertical");
float horizontal = Input.GetAxis ("Horizontal");
// GET DIRECTION
Vector3 forward = mainCamera.transform.
//Calibrate Y AXIS
forward.y = 0;
// GET DIRECTION UNIT VECTOR
forward.Normalize ();
Vector3 distance = (mainCamera.transform.position - player.transform.position);
distance.y = 0;
if (vertical & 0) {
player.rigidbody.velocity = forward * moveS
//Camera chases the player
if (distance.magnitude & Maxdistance) {
float originY = cameraCollisionBox.transform.position.y;
Vector3 newPosition = player.transform.position + distance.normalized * M
newPosition.y = originY;
cameraCollisionBox.transform.position = newP
} else if (vertical & 0) {
player.rigidbody.velocity = -forward * moveS
//Camera chases the player
float originY = cameraCollisionBox.transform.position.y;
Vector3 newPosition = player.transform.position + distance.normalized * M
newPosition.y = originY;
cameraCollisionBox.transform.position = newP
player.rigidbody.velocity = Vector3.
現在我們就可以控制角色前後移動了。
這段程式碼的邏輯可以拆成兩段來看,一個是角色的移動,另一個則是攝影機的移動。
角色的移動很單純,接受到哪個方向的輸入,就給角色對應方向的速度,如果沒有輸入就將速度設為零。
攝影機的移動則是當往前時,角色與攝影機距離超過 Maxdistance 時,攝影機就移到與角色保持 Maxdistance 的位置;而往後方向時,暫時先寫為一直保持 Maxdistance 距離。
以下為詳細的程式碼分析:
Input.GetAxis() 是讀取遊戲輸入中方向的值,也就是鍵盤的上下左右、WASD 或是搖桿的方向鍵,Input.GetAxis() 把不同裝置的方向 input 給封裝起來,並回傳 -1~1 之間的浮點數表示方樣,讓開發者統一讀取。舉例來說,鍵盤向前是回傳 1.0f、向後是回傳 -1.0f,而搖桿方向鍵則有輕重之分,向前按輕一點會出現像是 0.5f 這種介於 1~0 之間的數值。
Input.GetAxis ("Vertical")是指讀取前後方向輸入的值,而Input.GetAxis ("Horizontal")是指讀取左右方向輸入的值,相關輸入按鍵的設定可以在 Edit & Project Settings & Input 中找到。
記住! Unity 的座標系是 Y 向天空,XZ平面表示水平面。
角色移動程式碼:
Vector3 forward = mainCamera.transform.
forward.y = 0;
forward.Normalize (); //取得單位向量
player.rigidbody.velocity = forward * moveS
角色的移動是藉由設置速度來完成的,也就是給 player.rigidbody.velocity 設一個速度,速度是一個向量,有其方向與值。我們已經有了 moveSpeed 這個由我們自己給的速率值,但是我們還沒有移動方向,那麼我們要怎麼知道移動方向呢? 由於攝影機會一直看著角色,所以攝影機的前方就是角色的前方,我們藉由 mainCamera.transform.forward 取得攝影機正前方的方向向量,但攝影機是在空中的,也就是有 Y 軸的向量,但是角色是在 XZ 平面移動,為了要獲取只有 XZ 平面的向量,所以我們把 Y 值設為零,來得到我們要的向量。
計算攝影機與角色距離程式碼:
Vector3 distance = (mainCamera.transform.position - player.transform.position);
distance.y = 0;
if (distance.magnitude & Maxdistance) {
攝影機與角色距離計算方式為將攝影機與角色的座標相減得到兩點之間的向量,並且與之前一樣不算 Y 軸只算 XZ 平面的兩點距離,因此將 Y 設為零,而 Unity 的向量有
方法可以直接取得向量長度,也就是距離。
攝影機移動程式碼:
Vector3 distance = (mainCamera.transform.position - player.transform.position);
float originY = cameraCollisionBox.transform.position.y;
Vector3 newPosition = player.transform.position + distance.normalized * M
newPosition.y = originY;
cameraCollisionBox.transform.position = newP
攝影機的移動則是永遠保持自己 Y 軸的高度,但 XZ 平面的座標會根據角色的位置重新計算。計算的方式為從角色的座標往攝影機方向移動 Maxdistance 距離,所以先將兩點之間的向量
,取得往攝影機方向的單位向量再乘上 Maxdistance 距離,得到從角色座標出發到攝影機目標位置的向量。
處理攝影機後退碰撞
這裡的邏輯是當角色向後攝影機碰撞到牆時,我們的攝影機垂直沿 y 軸向上移動,角色往牆面移動多少,攝影機便向上移動多少。同時為了避免攝影機向上移動超過牆的高度時,系統就認為沒有碰撞事件,我們讓 CollisionBox 停在原本的高度,只讓攝影機向上移。
處理碰撞之前,要先給 CollisionBox 上物理碰撞性質。所以與之前為 Unity Chan 設置物裡性質的方式一樣,點Inspector & Add Component & Rigid body,這次我們不需要 Use Gravity 但需要勾選 Is Kinematic,並且點擊 Inspector & Add Component & Box Collider 加入碰撞器,並且勾選 is Trigger,最後調整整個 box 的 Size 為 0.2。
為什麼要勾選 Is Trigger 跟 Is Kinematie 呢?
那是因為 CollisionBox 撞到障礙物不需要被卡住而是要觸發事件讓程式知道現在攝影機撞到障礙物了,勾選 Is Kinematie 會讓這個物件與其他人碰撞不會有物理反應;勾選 Is Trigger 則會讓碰撞發生 OnTrigger 事件,讓程式可以知道這個物體碰撞了。
接下來為 CollisionBox 增加一個新的腳本,取名為 CollisionCounter ,其程式碼如下:
using UnityE
using System.C
public class CollisionCounter : MonoBehaviour {
// Use this for initialization
void Start(){
counter = 0;
void OnTriggerEnter(Collider other) {
counter++;
void OnTriggerExit(Collider other) {
counter--;
當我們有勾選 Is Trigger 就可以用 OnTriggerEnter 知道碰撞發生; OnTriggerExit 知道碰撞結束,如此以來,我們可以從 CollisionCounter 裡頭的 counter 知道現在 Camera 碰撞到多少障礙物了。
回到我們 ThirdPersonController.cs 加上以下兩個變數,並且一樣在 Unity 的介面上拖曳來設置這兩個 public 變數:
public CollisionCounter cameraP //Camera 碰撞探測器
public float verticalR //Camera 垂直向上移動的比例
此時我們可以藉由 cameraProbe.counter == 0 來判斷攝影機有沒有碰到障礙物,如果有碰到障礙物時,我們就呼叫 CalculateHeight 重新計算攝影機高度,CalculateHeight 內容如下:
void CalculateHeight(){
// Camera 在世界座標的位置
Vector3 originVector = mainCamera.transform.
// Camera 相對 CollisonBox 座標的位置
Vector3 localVector = mainCamera.transform.localP
// REMOVE Y to caculate XZ magnitude
originVector.y = player.transform.position.y;
float y = Maxdistance - (originVector - player.transform.position).
localVector.y=y;
mainCamera.transform.localPosition = localVector*verticalR
Maxdistance - (originVector - player.transform.position).magnitude 計算了攝影機撞牆以後,角色還移動了多少,我們把這段移動的距離設為 Camera 相對 CollisionBox 的高度。
如果有問題,你可以參考到這裡目前的 ThirdPersonController.cs [完整程式碼]。()
左右移動旋轉
左右移動時,角色以攝影機為圓心向左右轉,然而如果旋轉過程中撞牆無法前進時,轉為讓攝影機以角色為圓心反轉,直到角色可以繼續旋轉。
所以我們第一步,要在角色前面加裝一個碰撞偵測器,讓角色碰撞事件來切換角色/攝影機旋轉,請照著下圖的操作,增加一個 Front Collider,並且也掛上我們剛剛寫好的 CollisionCounter。
接下來為了讓 ThirdPersonController.cs 可以讀到角色的碰撞事件,請在 ThirdPersonController.cs 加上:
public CollisionC
並且一樣拖曳 Front Collider 到我們的 probe 上。
從上圖可以發現,我們的 Front Collider 跟角色撞在一起了,但是我們並不想讓碰撞偵測器會對 player 有反應,我們只想讓碰撞偵測器對環境有反應就好,這時候我們需要設定一下物理圖層之間的關係,讓碰撞偵測器對 player 不會有反應。
首先我們要新建兩個 layer : player、CollsionSensor,分別掛到主角以及碰撞器上。
接下來,我們設定一下 player 和 CollsionSensor 的碰撞關係,從菜單選 Edit & Project Settings & Physics 打開 Physics Manager ,把 player 和 CollsionSensor 之間的勾選取消,這樣他們兩個之間就不會有碰撞了。
到這裡,我們可以開始著手寫程式碼,來讓角色旋轉了,首先先在 ThirdPersonController 的 Update 加上
Vector3 right = mainCamera.transform.
right.y = 0;
right.Normalize ();
由於讓角色旋轉的方法是一直給角色切線向量,由於攝影機會一直盯著角色看,攝影機的水平方向向量剛剛好就是切線向量,所以我們先把攝影機在 XZ 平面的右向量先存起來。
再來加上水平方向控制:
if (horizontal & 0){
if( probe.counter & 0 ){
cameraCollisionBox.transform.position += -right*moveSpeed*Time.deltaT
player.rigidbody.velocity = right*moveS
}else if (horizontal & 0){
if( probe.counter & 0 ){
cameraCollisionBox.transform.position += right*moveSpeed*Time.deltaT
player.rigidbody.velocity = -right*moveS
這段程式的邏輯是如果有角色碰撞,就讓攝影機去不斷以反方向旋轉,而角色持續向切線方向的前進。
現在角色已經會左右旋轉了,但是角色的臉不會面向前進方向,所以我們接下來需要去旋轉角色自己來面向前進方向:
if( vertical!=0 || horizontal!=0 ){
float rotate = Mathf.Atan2 (player.rigidbody.velocity.x, player.rigidbody.velocity.z);
player.transform.rotation = Quaternion.Euler (0, rotate / Mathf.PI * 180, 0);
player.rigidbody.velocity = Vector3.
這段程式的邏輯是如果有任何移動的指令,就利用角色前進方向的水平速度分量來回推目前前進的角度是什麼,由於角色是在 XZ 平面上移動,因此我們會有 X 軸與 Z 軸的分量,藉由這兩個分量我們可以做 tan(θ) 的反運算求得 θ,
並且把求得的角度換算回弧度 (2π rad= 360°) ,帶入到 Quaternion 座標中。
如果有問題,你可以參考到這裡目前的 ThirdPersonController.cs
45度角移動
接下來我們要修改程式碼,同時可以接受兩軸方向的輸入,並把把兩軸移動同時表現出來,也就是可以 45 度角移動前進。
為了要方便程式撰寫,我們把程式拆成兩塊,一塊先專心處理 input ,先把所有輸入記下來,另一塊處理 output ,把所有輸出疊合運算出最終結果,一起呈現在角色與攝影機上。在這裡我們把處理輸出的部份寫到 Draw() 裡。
我們在ThirdPersonController.cs新增以下四個變數,來記錄有沒有水平、垂直移動以及分別的速度為多少。
private bool isHoriM
private bool isVertiM
private Vector3 horiV
private Vector3 vertiV
修改原本 if (vertical > 0) {...} 以及 if (horizontal > 0){...} 中所有的給主角速度值 player.rigidbody.velocity = ... 改成先存在 horiVelocity、 vertiVelocity 中,並且一旦有移動就把對應方向的 horiVelocity、 vertiVelocity 設為 true,改完以後你的 Update 部分程式碼應該長成這樣:
if (vertical & 0) {
this.vertiVelocity = forward*moveS
//Camera chases the player
if( distance.magnitude & Maxdistance ){
float originY = cameraCollisionBox.transform.position.y;
Vector3 newPosition = player.transform.position + distance.normalized * M
newPosition.y = originY;
cameraCollisionBox.transform.position = newP
CalculateHeight();
isVertiMove =
}else if( vertical & 0){
this.vertiVelocity = -forward*moveS
if( cameraProbe.counter &= 0 ){
//Camera chases the player
float originY = cameraCollisionBox.transform.position.y;
Vector3 newPosition = player.transform.position + distance.normalized * M
newPosition.y = originY;
cameraCollisionBox.transform.position = newP
//Camera move higher to see the player
CalculateHeight();
isVertiMove =
if (horizontal & 0){
if( probe.counter & 0 ){
cameraCollisionBox.transform.position += -right*moveSpeed*Time.deltaT
this.horiVelocity = right*moveS
isHoriMove =
}else if (horizontal & 0){
if( probe.counter & 0 ){
cameraCollisionBox.transform.position += right*moveSpeed*Time.deltaT
this.horiVelocity = -right*moveS
isHoriMove =
// perform the result on charactor
最後把輸出結果的程式,寫到 Draw function 裡:
void Draw(){
if( this.isHoriMove && this.isVertiMove ){
player.rigidbody.velocity = this.horiVelocity + this.vertiV
}else if( this.isHoriMove ){
player.rigidbody.velocity = this.horiV
}else if( this.isVertiMove ){
player.rigidbody.velocity = this.vertiV
if (this.isHoriMove || this.isVertiMove) {
// Caculate the player's degree from velocity
float rotate = Mathf.Atan2 (player.rigidbody.velocity.x, player.rigidbody.velocity.z);
player.transform.rotation = Quaternion.Euler (0, rotate / Mathf.PI * 180, 0);
player.rigidbody.velocity = Vector3.
如果有問題,你可以參考到這裡目前的 ThirdPersonController.cs
設置行走動畫
最後我們要讓 Unity Chan 移動過程中,播放模型的跑步動畫,閒置時則播放等待動畫。
在 Unity 中設定動畫是藉由 Animator 來操作,Animator 是個 Finite State Machine ,裡頭有不同的動作狀態,例如走路、跳躍、閒置、出拳……等等,每個狀態表示一個完整的動作動畫,而這些動作之前的切換是藉由滿足不同的條件舉例來說,我們的案例十分單純,只有閒置與跑步兩個狀態,而從閒置轉移到跑步的條件是我們的角色有移動速度,反之從跑步移到閒置狀態,則是滿足角色沒有移動速度。
首先,我們先在底下 Asset 按下滑鼠右鍵,選擇 Create & Animation Controller ,新增一個動畫控制器取名為 PlayerAnimator。
在 Animator 中按下右鍵,Create State & Empty 來新增一個動畫狀態,在右邊的 Inspector 中命名這個狀態為 idle 並選擇 Motion 來設定主角的閒置動畫,請選擇一個你喜歡的動作,我這邊使用 WAIT01 。
同樣在生成一個新的狀態,命名為 run 並把它 Motion 設定為 RUN00_F。
完成狀態生成後,我們要來新增動畫狀態切換條件,首先先在左下方的Parameters加入一個 float 變數velocity`。
然後在 idle 上點右鍵選 Make Transition 連結到 run 上,同樣也從 run 加入一條 transition 到 idle 上,並點擊 idle 到 run 的 transition 在右邊的 Inspector 選擇 Conditions ,設定為 velocity greater 0.01,反之設定 run 到 idle 的 transition 為 velocity less `0.01,到這裡我們就設定完我們的 Animator 了。
接下來是要讓我們的狀態機條件能被程式觸發,所以切到 unitychan 選擇 Add Component & New Script,新增一個 AnimatorController ,並順手把剛剛做好的 Animator 掛上我們的主角上,再把 Apply Root Motion 取消。
有了 AnimatorController 我們就可以寫一些程式,讓角色的速度真正地影響到角色的動畫狀態!請把以下的程式碼寫進 AnimatorController中。
using UnityE
using System.C
public class AnimatorController : MonoBehaviour {
void Start () {
animator = gameObject.GetComponent&Animator& ();
void Update () {
// 把角色的速度值傳給 animator 中的 velocity
animator.SetFloat ("velocity", this.rigidbody.velocity.magnitude);
到這裡,我們的角色移動時也會有跑步的動畫了,離最終的成品也只差一小步!
最後修正兩個小問題
角色垂直浮空問題
從上圖可以看到,當角色經過比較高的地形後,會浮在空中緩慢地掉下來,那是因為我們的程式一旦沒有方向輸入時,就把所有的速度歸零,這同時也把 Y 軸掉落的速度給歸零了,所以我們的程式要稍微修改一下,把 Y 軸的速度加回去。
詳細作法可以看。
左右、前後反方向切換不順暢
同樣地,由於我們的動畫是由角色速度來驅動的,當左右方向切換時,會有一瞬間速度為零,此時動畫變成閒置動畫,而不是連續的跑步動畫,所以程式要修改為,沒有按鍵後需等一下下再把速度歸零,具體做法為新增一個計時器,如果這計時器倒數完,還是沒有輸入,才把速度歸零。
詳細作法可以看。
完整原始碼
你可以直接下載完成的專案來練習:
Cover image from
official website
About the author
Believe computers can change your life for the better.

我要回帖

更多关于 ios layer 层级 的文章

 

随机推荐