# 简介
Unity 来实现脚印功能的话,实际上并不是很难,只要知道了方法,代码也就那么一点的事。因为既然是脚印,那么必然是与角色的移动的动画息息相关的,所以触发这个 “脚印” 事件,我就选择放在了动画本身的事件之上,这大约也算是实现脚印与动画本身同步率比较高的一种方式了。
# 创建预制体
首先是寻找脚印,需要两张图片:一只右脚、一只左脚。这个脚印本身图片的话,稍微百度一下就是一大堆了,所以我就随便选择了一张,然后用 PS 处理了一下,将其分割成两张,并导出为 PNG 格式:
然后,在 Unity 中创建两个 Quad,将这两张图片赋给两个 Quad 的材质,如图所示。
# 详情
接下来就是脚本了。
新建一个脚本,这儿我就命名为 “PlayFootEffect”,在最前边定义两个 GameObject 变量,以接收外部的两个 “脚印” 物体的引用。
public GameObject m_leftFoot; | |
public GameObject m_rightFoot; |
层级,再定义一个地面层级,以判断地面。作为脚印,当然是只能在踩到地卖弄才出现吧。
private LayerMask m_groundLayer = 1 << LayerMask.NameToLayer("Ground"); |
接着,定义一个方法 “Play”。这个方法就是用于动画事件进行调用的,接收一个 String 参数,以判断是左脚还是右脚。
public void Play(string foot) | |
{ | |
GameObject obj; | |
// 判断左脚还是右脚,以实例化相应的脚印 | |
if (foot == "Left") | |
{ | |
obj = GameObject.Instantiate<GameObject>(m_leftFoot); | |
} | |
else | |
{ | |
obj = GameObject.Instantiate<GameObject>(m_rightFoot); | |
} | |
// 设置到专门存放脚印的物体之下 | |
SetToRoot(obj); | |
// 检测地面 | |
CheckToGround(obj); | |
// 销毁脚印 | |
Destroy(obj, 5); | |
// 播放音效 | |
AudioPlayer.GetInstance.PlayEffect(40000); | |
} |
设置专门存放脚印的方法:
private GameObject m_FootManager; | |
// 为了整洁,将所有实例化出来的脚印,都放置于同一个用于管理的空物体之下 | |
private void SetToRoot(GameObject obj) | |
{ | |
if (m_FootManager == null) | |
{ | |
m_FootManager = new GameObject("[FootManager]"); | |
m_FootManager.transform.SetParent(Pathea.TransRoot.self.transform); | |
} | |
obj.transform.SetParent(m_FootManager.transform); | |
} |
检测地面应该算是最简单,也是最令人麻烦的地方了。关于将脚印结结实实地 “贴到 “地面,因为作为脚印,肯定不能直接放在角色位置处,那样必定是浮空的,显得非常虚假、难看。当初我做的时候,思考了无数方式,最终竟然非常简单:一个 LookAt 就可以了!将脚印的方向朝向玩家前方,并且贴在地面。
// 检查地面,并设置脚印朝向等 | |
private void CheckToGround(GameObject obj) | |
{ | |
RaycastHit hit; | |
Ray ray = new Ray(transform.position + Vector3.up * 0.5f, Vector3.down); | |
if (Physics.Raycast(ray, out hit, 0.7f, m_groundLayer)) | |
{ | |
obj.transform.position = hit.point; | |
obj.transform.LookAt(hit.point + hit.normal, transform.forward); | |
} | |
} |
# 设置动画事件
在编辑器中,选择模型 -> 动画,然后拖到最下边,打开 Events。然后根据动画落脚的那一帧进行事件的添加。如图所示。
添加完成后,将 PlayFootEffect 这个脚本挂载于角色身上,当播放相应添加了事件的动画时,就会触发其中的”Play“方法。
# 效果
不过随便找的脚印效果.... 也太差强人意了。还是用项目的结果看看吧:
# 完整代码
/********************************************************** | |
*Author: CWHISME | |
*Date: 2015.12.4 | |
*Func: | |
**********************************************************/ | |
using UnityEngine; | |
using Pathea.AudioNs; | |
public class PlayFootEffect : MonoBehaviour | |
{ | |
public GameObject m_leftFoot; | |
public GameObject m_rightFoot; | |
private LayerMask m_groundLayer = 1 << LayerMask.NameToLayer("Ground"); | |
public void Play(string foot) | |
{ | |
GameObject obj; | |
// 判断左脚还是右脚,以实例化相应的脚印 | |
if (foot == "Left") | |
{ | |
obj = GameObject.Instantiate<GameObject>(m_leftFoot); | |
} | |
else | |
{ | |
obj = GameObject.Instantiate<GameObject>(m_rightFoot); | |
} | |
// 设置到专门存放脚印的物体之下 | |
SetToRoot(obj); | |
// 检测地面 | |
CheckToGround(obj); | |
// 销毁脚印 | |
Destroy(obj, 5); | |
// 播放音效 | |
AudioPlayer.GetInstance.PlayEffect(40000); | |
} | |
private GameObject m_FootManager; | |
// 为了整洁,将所有实例化出来的脚印,都放置于同一个用于管理的空物体之下 | |
private void SetToRoot(GameObject obj) | |
{ | |
if (m_FootManager == null) | |
{ | |
m_FootManager = new GameObject("[FootManager]"); | |
m_FootManager.transform.SetParent(Pathea.TransRoot.self.transform); | |
} | |
obj.transform.SetParent(m_FootManager.transform); | |
} | |
// 检查地面,并设置脚印朝向等 | |
private void CheckToGround(GameObject obj) | |
{ | |
RaycastHit hit; | |
Ray ray = new Ray(transform.position + Vector3.up * 0.5f, Vector3.down); | |
if (Physics.Raycast(ray, out hit, 0.7f, m_groundLayer)) | |
{ | |
obj.transform.position = hit.point; | |
obj.transform.LookAt(hit.point + hit.normal, transform.forward); | |
} | |
} | |
} |