1.Animator

为了在游戏对象上有动画,需要添加一个组件Animator。

在工程窗口中,双击Robot  预制体。

unity animation 有时候不播 unity animation在哪_游戏

如图所示,添加Animator组件。

2.Creating a New Controller

在工程窗口Animator文件夹中,右击新建Robot脚本,并应用到Animator上。

unity animation 有时候不播 unity animation在哪_游戏_02

点右上角保存按钮。

3.动画Animations

为了在Unity Editor中建立动画,可以使用Animation window,在预制体中选择Robot ,点Window > Animation > Animation。

unity animation 有时候不播 unity animation在哪_游戏_03

出现“To begin animating [Prefab/GameObject name], create an Animation Clip”, 点Create。

在Animations 文件夹中,建立RobotLeft.anim动画片段。

unity animation 有时候不播 unity animation在哪_游戏_04

如上图,左边为动画属性,右边为动画 的关键帧。

4.修改精灵Changing a Sprite

在Art > Sprites > Characters中,可以找到MrClockworkSheet 。在单个图片中可以找到多个精灵。

按住shift键不放,选择MrClockworkWalkSides1,MrClockworkWalkSides2,MrClockworkWalkSides3,MrClockworkWalkSides4。将这些拖到动画窗口中。

点play看下效果。

设置Samples 为4,以使精灵运行正常。

5.建立一个动画 Creating an Animation

在上图左边点击Create New Clip,名为Right_Run,选择Animation 文件夹。

重新创建Left animation,并将四个精灵拖上去,并设置Samples 为4。点增加属性,从Sprite Renderer找到Flip X。

勾选上属性选项,

重复操作建立running up和running down。

6.建立一个脚本  Building the Controller

在工程窗口中,选中Robot预制体,点Windows > Animation > Animator。

unity animation 有时候不播 unity animation在哪_游戏_05

上图左边中的层用于3D动画,参数用于向脚本传递信息。

动画状态机是动画的所有状态图,可以从一种状态转到另一个状态。

另一种方式是混合树,可以通过参数从一种状态转到另一种状态。可以通过方向参数来控制动画。

7.使用混合树 Using a Blend Tree

删除所有动画,右击Create State > From New Blend Tree,创建Blend Tree。

双击Blend Tree,点Blend Tree结点,打开如下图。

unity animation 有时候不播 unity animation在哪_unity3d_06

修改Blend Type类型为2D Simple Directional。

8.Parameters Move X and Move Y

在动画窗口中,点击参数。

unity animation 有时候不播 unity animation在哪_c#_07

点float类型Move X,和Move Y。点混合树视图,显示如下:

unity animation 有时候不播 unity animation在哪_ci_08

点右上角的加号,点Add Motion Field ,增加4个点,并调整它们的位置。

  • Left : Pos X = -0.5 Pos Y = 0,Right: Pos X = 0.5 Pos Y = 0,Up: Pos X = 0 Pos Y = 0.5,Down: Pos X = 0 Pos Y = -0.5

unity animation 有时候不播 unity animation在哪_游戏_09

调整后的图为

unity animation 有时候不播 unity animation在哪_游戏_10

图像代表着混合,每个点代表一个片断,红点代表参数所给的位置前、后、左、右。

9.将参数发送给Animator脚本 Sending parameters to the Animator Controller

打开EnemyController 脚本,增加

Animator animator;

通过

animator.SetFloat("Move X", 0);
animator.SetFloat("Move Y", direction);

给Animator 传送方向。

10.设置主要脚色的动画  Setting Animation for the Main Character

在Ruby预制体中,增加Animator 组件,并指定Animation 文件夹中的动画Animator 组件的动画。现在Ruby的动画类似于下图。

unity animation 有时候不播 unity animation在哪_c#_11

在图上,精灵有三种状态:移动Moving、静止Idle、和其他物体有冲突时Hit。白色的代表了状态的转换。双击白线,可以看到如下的状态转换图。

unity animation 有时候不播 unity animation在哪_ci_12

上图中的Has Exit Time不有被选中。这意味着移动动画不会等到完成状态机变为空闲动画之前,它会立即更改。

最重要的最下面的Conditions 。如果没有它的话,转变将会在动画的最后发生。

11.修改代码如下Modifying the RubyController Script

1 增加Animator变量

2增加Vector2 变量 lookDirection 并初始化为 (1,0),里面有两个方向参数Look X 和a Look Y。

3 通过animator.SetTrigger("Hit");触发点击动画。

12.完整的脚本如下 Check Your Scripts

public class RubyController : MonoBehaviour
{
    public float speed = 3.0f;
    
    public int maxHealth = 5;
    public float timeInvincible = 2.0f;

    public int health { get { return currentHealth; }}
    int currentHealth;
    
    bool isInvincible;
    float invincibleTimer;
    
    Rigidbody2D rigidbody2d;
    float horizontal;
    float vertical;
    
    Animator animator;
    Vector2 lookDirection = new Vector2(1,0);
    
    // Start is called before the first frame update
    void Start()
    {
        rigidbody2d = GetComponent<Rigidbody2D>();
        animator = GetComponent<Animator>();
        
        currentHealth = maxHealth;
    }

    // Update is called once per frame
    void Update()
    {
        horizontal = Input.GetAxis("Horizontal");
        vertical = Input.GetAxis("Vertical");
        
        Vector2 move = new Vector2(horizontal, vertical);
        
        if(!Mathf.Approximately(move.x, 0.0f) || !Mathf.Approximately(move.y, 0.0f))
        {
            lookDirection.Set(move.x, move.y);
            lookDirection.Normalize();
        }
        
        animator.SetFloat("Look X", lookDirection.x);
        animator.SetFloat("Look Y", lookDirection.y);
        animator.SetFloat("Speed", move.magnitude);
        
        if (isInvincible)
        {
            invincibleTimer -= Time.deltaTime;
            if (invincibleTimer < 0)
                isInvincible = false;
        }
    }
    
    void FixedUpdate()
    {
        Vector2 position = rigidbody2d.position;
        position.x = position.x + speed * horizontal * Time.deltaTime;
        position.y = position.y + speed * vertical * Time.deltaTime;

        rigidbody2d.MovePosition(position);
    }

    public void ChangeHealth(int amount)
    {
        if (amount < 0)
        {
            animator.SetTrigger("Hit");
            if (isInvincible)
                return;
            
            isInvincible = true;
            invincibleTimer = timeInvincible;
        }
        
        currentHealth = Mathf.Clamp(currentHealth + amount, 0, maxHealth);
        Debug.Log(currentHealth + "/" + maxHealth);
    }
}

动画片段是进行动画的部分。通过状态机来表示动画之间的关联。通过Animator 来在控制器中进行动画的演示。下一章将进行发射炮弹的演示。