# 简介

Unity 来实现脚印功能的话,实际上并不是很难,只要知道了方法,代码也就那么一点的事。因为既然是脚印,那么必然是与角色的移动的动画息息相关的,所以触发这个 “脚印” 事件,我就选择放在了动画本身的事件之上,这大约也算是实现脚印与动画本身同步率比较高的一种方式了。

# 创建预制体

首先是寻找脚印,需要两张图片:一只右脚、一只左脚。这个脚印本身图片的话,稍微百度一下就是一大堆了,所以我就随便选择了一张,然后用 PS 处理了一下,将其分割成两张,并导出为 PNG 格式:
FootPrint
然后,在 Unity 中创建两个 Quad,将这两张图片赋给两个 Quad 的材质,如图所示。
FootPrint

# 详情

接下来就是脚本了。
新建一个脚本,这儿我就命名为 “PlayFootEffect”,在最前边定义两个 GameObject 变量,以接收外部的两个 “脚印” 物体的引用。

s
public GameObject m_leftFoot;
    public GameObject m_rightFoot;

层级,再定义一个地面层级,以判断地面。作为脚印,当然是只能在踩到地卖弄才出现吧。

s
private LayerMask m_groundLayer = 1 << LayerMask.NameToLayer("Ground");

接着,定义一个方法 “Play”。这个方法就是用于动画事件进行调用的,接收一个 String 参数,以判断是左脚还是右脚。

s
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);
    }

设置专门存放脚印的方法:

s
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 就可以了!将脚印的方向朝向玩家前方,并且贴在地面。

s
// 检查地面,并设置脚印朝向等
    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。然后根据动画落脚的那一帧进行事件的添加。如图所示。
FootPrint_Settting

添加完成后,将 PlayFootEffect 这个脚本挂载于角色身上,当播放相应添加了事件的动画时,就会触发其中的”Play“方法。

# 效果

FootPrint_Result
不过随便找的脚印效果.... 也太差强人意了。还是用项目的结果看看吧:
FootPrint_Result

# 完整代码

s
/**********************************************************
*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);
        }
    }
}