学习总结-2020年12月16日

昨天把动画系统大致过了一遍,今天主要学习案例巩固,案例学习未完成,还是把一些操作总结以下。

  一.lerp的使用

  使用插值运算能够使得变化平滑,但是lerp插值的运算结果是无限趋近,无法到达,可以在插值后进行判断,插值结果和目标结果足够接近的化直接设置为目标结果。 

siren.GetComponent<AudioSource>().volume = Mathf.Lerp(siren.GetComponent<AudioSource>().volume,0,Time.deltaTime * intensityChangeSpeed);

这是一段控制声音的代码,将音量设置为现有音量和0之间的插值,插值百分比为帧时间乘以每秒变化速度,可以将音量逐渐降为0,但是最后的结果无限趋近于0。可以作判断,如果当前音量和0的差小于0.01,则直接将音量设置为0,否则进行插值运算。

插值除了上面的线性插值外,还可以使用球形插值Slerp。线性插值和球形插值使用方法相同,达到的效果相似,但是底层的运算方法不同,球形插值会运算角度和向量长度。

  二.pingpong的使用 

  使用pingpong方法能够使值在0和目标值之间来回变化,就像乒乓球一样。

alarmLight.intensity = Mathf.PingPong(Time.time * intensityChangeSpeed, 0.5f);

这是一段控制灯光强度的代码,使灯光强度在0和0.5之间来回变化,第一个参数为自递增的值,使用游戏运行时间。

  三.单例模式

  管理游戏进程和UI界面显示的脚本可以命名为GameManager(见下图,这个类名称为官方的类ID参考中的9号名称,将脚本修改为此名称脚本图标也会变成齿轮,谨慎使用)或者GameController等(随你乐意),这个类中的参数和方法等往往会被其他脚本设置或者调用,因此最好采用单例模式。

public static GameManager _instance;

    void Start()
    {
        _instance = this;
    }

见上面代码,在类中提供公开的静态的这个类的实例属性(一般可以命名为_instance),然后在初始化时将这个实例属性赋值,最好将构造方法私有化,这样在外部不能实例化这个类,而这个类自己提供了唯一的实例,因为是静态的,也可以在外部通过类名调用这个唯一实例。

  四.标签类Tags

  在游戏中,大量的游戏对象往往通过标签进行查找,在查找游戏对象时为了防止写错标签名,可以提供标签类Tags。

public class Tags : MonoBehaviour
{
    public const string player = "Player";
    public const string siren = "Siren";
    public const string enemy = "Enemy";
}

标签类中使用const关键字修饰标签名称,可以在外部直接通过类名.属性名调用这个字符串(const是指静态且不可修改的变量),但是不能在外部修改属性的值。这里也可以使用枚举enum类,但是enum类的值是整数,这种方式更合适。

  五.角色的动画和移动

  角色的移动可以使用改变位移的方式,但是动画中也可以改变位移量(动画可以理解为在一定帧范围内,如0-60帧,游戏物体的位置、旋转、颜色等属性进行改变的过程),因此一般将位移直接做到动画中,播放动画人物模型也会相应的移动旋转等。

  下面使用2D混合树控制角色的移动。

 横轴的值代表角色的转向,纵轴的值代表角色的向前位移。从上到下四排分别对应跑、走、下蹲慢走、停止四种向前的状态,纵轴值对应1、0.5、0.25、0四种。从左到右三列对应向左转、没有方向改变、向右转,横轴值对应为-1、0、1三种。如走路并向左转为(-1,0.5),原地右转为(1,0)。接下来通过代码设置横轴和纵轴的值。

/// <summary>
    /// 获取键盘输入,并存储为h值和v值,以便update函数中用于设置animator的参数,使用插值运算使运动平滑
    /// </summary>
    private void GetInputInfo()
    {
        //左shift键和向前键,下蹲慢走
        if (Input.GetKey(KeyCode.LeftShift) && (Input.GetAxis("Vertical") > 0.1f))
        {
            h = Mathf.Lerp(h,0f,acceleratedSpeed * Time.deltaTime);v = Mathf.Lerp(v, 0.25f, acceleratedSpeed * Time.deltaTime);
        }
        //向前向左和空格键,向左跑
        else if(Input.GetAxis("Vertical") > 0.1f && Input.GetAxis("Horizontal") < -0.1f && Input.GetKey(KeyCode.Space))
        {
            h = Mathf.Lerp(h, -1f, acceleratedSpeed * Time.deltaTime); v = Mathf.Lerp(v, 1f, acceleratedSpeed * Time.deltaTime);
        }
        //向前向右键和空格键,向右跑
        else if (Input.GetAxis("Vertical") > 0.1f && Input.GetAxis("Horizontal") > 0.1f && Input.GetKey(KeyCode.Space))
        {
            h = Mathf.Lerp(h, 1f, acceleratedSpeed * Time.deltaTime); v = Mathf.Lerp(v, 1f, acceleratedSpeed * Time.deltaTime);
        }
        //向前键和空格键,向前跑
        else if (Input.GetAxis("Vertical") > 0.1f && Input.GetKey(KeyCode.Space))
        {
            h = Mathf.Lerp(h, 0f, acceleratedSpeed * Time.deltaTime); v = Mathf.Lerp(v, 1f, acceleratedSpeed * Time.deltaTime);
        }
        //向前向左键,向前走
        else if (Input.GetAxis("Vertical") > 0.1f && Input.GetAxis("Horizontal") < -0.1f)
        {
            h = Mathf.Lerp(h, -1f, acceleratedSpeed * Time.deltaTime); v = Mathf.Lerp(v, 0.5f, acceleratedSpeed * Time.deltaTime);
        }
        //向前向右键,向右走
        else if (Input.GetAxis("Vertical") > 0.1f && Input.GetAxis("Horizontal") > 0.1f)
        {
            h = Mathf.Lerp(h, 1f, acceleratedSpeed * Time.deltaTime); v = Mathf.Lerp(v, 0.5f, acceleratedSpeed * Time.deltaTime);
        }
        //向左键,原地左转
        else if (Input.GetAxis("Horizontal") < -0.1f)
        {
            h = Mathf.Lerp(h, -1f, acceleratedSpeed * Time.deltaTime); v = Mathf.Lerp(v, 0f, acceleratedSpeed * Time.deltaTime);
        }
        //=向右键,原地右转
        else if (Input.GetAxis("Horizontal") > 0.1f)
        {
            h = Mathf.Lerp(h, 1f, acceleratedSpeed * Time.deltaTime); v = Mathf.Lerp(v, 0f, acceleratedSpeed * Time.deltaTime);
        }
        //向前键,向前走
        else if (Input.GetAxis("Vertical") > 0.1f)
        {
            h = Mathf.Lerp(h, 0f, acceleratedSpeed * Time.deltaTime); v = Mathf.Lerp(v, 0.5f, acceleratedSpeed * Time.deltaTime);
        }
        //idle状态
        else
        {
            h = Mathf.Lerp(h, 0f, acceleratedSpeed * Time.deltaTime); v = Mathf.Lerp(v, 0f, acceleratedSpeed * Time.deltaTime);
        }
    }

在update函数中调用这个函数,设置好h和v值后将animator组件中的horizontal参数和vertical参数的值同步为h和v值。这里使用了线性插值使运动状态的变化不会太突兀,也可以直接设置h和v值,这样动画播放切换的时候会有一些生硬。

void Update()
    {
        GetInputInfo();
        anim.SetFloat("Vertical", v);
        anim.SetFloat("Horizontal", h);
    }

可以看到,这里并没有向后运动的动画,如果有可以继续添加,纵轴的值设置为负值即可,如有向右后方运动的动画设置坐标为(1,-1),再通过代码获取相应按键后设置h和v值即可。

ps:这种按键控制方式感觉对第一人称游戏的主角运动较为适用,而且一般主角运动默认都是跑步的,这里默认运动为走,不过也懒得修改了。

原文地址:https://www.cnblogs.com/movin2333/p/14147506.html