Unity教程(三)角色跳跃的实现

Unity开发2D类银河恶魔城游戏学习笔记

Unity教程(零)Unity和VS的使用相关内容
Unity教程(一)开始学习状态机
Unity教程(二)角色移动的实现
Unity教程(三)角色跳跃的实现
Unity教程(四)碰撞检测
Unity教程(五)角色冲刺的实现
Unity教程(六)角色滑墙的实现
Unity教程(七)角色蹬墙跳的实现
Unity教程(八)角色攻击的基本实现
Unity教程(九)角色攻击的改进

Unity教程(十)Tile Palette搭建平台关卡
Unity教程(十一)相机
Unity教程(十二)视差背景

Unity教程(十三)敌人状态机
Unity教程(十四)敌人空闲和移动的实现
Unity教程(十五)敌人战斗状态的实现
Unity教程(十六)敌人攻击状态的实现
Unity教程(十七)敌人战斗状态的完善

Unity教程(十八)战斗系统 攻击逻辑
Unity教程(十九)战斗系统 受击反馈
Unity教程(二十)战斗系统 角色反击

Unity教程(二十一)技能系统 基础部分
Unity教程(二十二)技能系统 分身技能
Unity教程(二十三)技能系统 掷剑技能(上)基础实现
Unity教程(二十四)技能系统 掷剑技能(中)技能变种实现


如果你更习惯用知乎
Unity开发2D类银河恶魔城游戏学习笔记目录



前言

本文为Udemy课程The Ultimate Guide to Creating an RPG Game in Unity学习笔记,如有错误,欢迎指正。

本节进行角色跳跃的实现。

Udemy课程地址

对应视频:
Jump with State Machine

精灵表素材。
素材链接:https://pan.baidu.com/s/1PnN2t7xOcNpPDLteLm4EJw?pwd=7pec。
提取码: 7pec


一、概述

本节实现角色跳跃需要创建超级状态PlayerGroundedState接地状态和PlayerAirState空中状态。

超级状态是一种用来分层控制的状态,它之下可以有很多简单状态,能对简单状态进行控制。举例说明,比如接地状态下角色可以是移动和闲置的,符合某种条件时可以从接地状态转换成另一个超级状态空中状态,这时角色不能再移动和闲置,但可以在空中状态下转换状态。通过这种方式创建分层状态机,就是状态机中又嵌套了一个状态机,通过分离来减少过渡条件,减少状态机的复杂度。我参照了文章

状态转换条件如下:
在这里插入图片描述

可以看到转换到跳跃状态是在超级状态接地状态中进行的,这保证了无论角色处于闲置还是移动状态时都能进行跳跃。如果没有接地状态的控制可能会出现这种情况,角色可以在空中不断继续跳跃升天。

在实现时我们需要添见PlayerJumpState跳跃状态和两个超级状态PlayerGroundedState接地状态和PlayerAirState空中状态,它们都继承自状态基类PlayerState。同时我们需要修改PlayerIdleState空闲状态和PlayerMoveState移动状态让它们继承自PlayerGroundedState接地状态。具体如图:
在这里插入图片描述

二、创建超级状态

创建两个超级状态PlayerGroundedState接地状态和PlayerAirState空中状态。
在这里插入图片描述
把它们继承的类改为状态基类PlayerState,并生成构造函数、生成重写。基本操作具体讲解见
Unity教程(零)Unity和VS的使用相关内容
在这里插入图片描述

修改PlayerIdleState空闲状态和PlayerMoveState移动状态让它们继承自PlayerGroundedState接地状态
在这里插入图片描述
在这里插入图片描述


三、创建跳跃状态的混合树动画

层次面板中选中Animator,在Animation面板中创建两个动画playerJump跳跃动画和playerFall下落动画
playerJump精灵表标号41-43,采样率改为10
playerFall精灵表标号46-48,采样率改为10
具体讲解见Unity教程(零)Unity和VS的使用相关内容
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

你会看到动画师中多出两个状态
在这里插入图片描述


删掉palyerJump和playerFall这两个块,创建混合树动画,命名为Jump/Fall
右键->Create State->From New Blend Tree
在这里插入图片描述在这里插入图片描述
把混合树参数重命名为yVelocity,到时候我们需要动画按照角色y方向速度混合。

双击Jump/Fall混合树进入混合树的进一步编辑
在这里插入图片描述
在右侧面板添加两个动画
"+"号->Add Motion Field->拖入动画
在这里插入图片描述
在这里插入图片描述
结果如下:
在这里插入图片描述
在这里插入图片描述
勾掉Automate Threshholds,将PlayerFall的Threshhold改为-1
在这里插入图片描述
关于Threshold阈值的理解
参照博客Unity动画系统详解5:BlendTree混合树是什么?官方手册 混合树1D混合
在此混合树中我们使用的是1D混合,Threshold代表的是混合树参数在等于阈值时完全使用这个动画。
在这里插入图片描述
顺带一提,这个钟表图标Time Scale可以调节动画的播放速度,比如你想让动画播放速度变为原来的2倍,可以把它设置为2。
在这里插入图片描述
在这里可以检查混合树的效果
将右下Blend Tree这一小条向上拖
在这里插入图片描述
在这里插入图片描述
拖动Blend Tree的参数滑动条查看不同参数时的动画
在这里插入图片描述
可以看到动画随参数变化
在这里插入图片描述


连接状态机,并添加过渡条件Jump,并修改过渡设置
如需更详细过程讲解,见Unity教程(零)Unity和VS的使用相关内容
添加条件变量
在这里插入图片描述
连接过渡
在这里插入图片描述

进入Jump/Fall的过渡
在这里插入图片描述
退出Jump/Fall的过渡
在这里插入图片描述


四、跳跃的实现

跳跃的实现要经过这样一个过程:
在角色处于接地状态PlayerGroundedState时接收到跳跃键按下的输入,转换到跳跃状态PlayerJumpState,在跳跃状态中设置跳跃速度。然后当跳跃至顶点时角色开始下落,在y方向的速度开始为负,这时切换到空中状态PlayerAirState。在落到地面时,y方向速度为0,角色切换为闲置状态。

在这里插入图片描述
创建脚本PlayerJumpState,继承于PlayerState,生成构造函数和重写。

在Player添加PlayerJumpState和PlayerAirState两个状态,在Awake函数中创建这两个状态,它们都通过条件变量Jump去控制动画。

    #region 状态
    public PlayerStateMachine StateMachine { get; private set; }
    public PlayerIdleState idleState { get; private set; }
    public PlayerMoveState moveState { get; private set; }
    public PlayerJumpState jumpState { get; private set; }
    public PlayerAirState airState { get; private set; }
    #endregion

    //创建对象
    private void Awake()
    {
        StateMachine = new PlayerStateMachine();

        idleState = new PlayerIdleState(StateMachine, this, "Idle");
        moveState = new PlayerMoveState(StateMachine, this, "Move");
        jumpState = new PlayerJumpState(StateMachine, this, "Jump");
        airState = new PlayerAirState(StateMachine, this, "Jump");

        anim = GetComponentInChildren<Animator>();
        rb = GetComponent<Rigidbody2D>();

    }

完善PlayerJumpState实现设置跳跃和切换状态,实现大致如下:
在这里插入图片描述

在player中添加变量jumpForce用以设置跳跃

    public float jumpForce = 12f;

顺带Gravity Scale改为3.5
在这里插入图片描述

接下来在PlayerJumpState中进行完善。
在进入Jump状态时设置y方向速度实现跳跃。

    public override void Enter()
    {
        base.Enter();

        rb.velocity = new Vector2(rb.velocity.x, player.jumpForce);
    }

在y方向速度开始小于0时,角色下落切换到空中状态

    public override void Update()
    {
        base.Update();

        if(rb.velocity.y < 0)
            stateMachine.ChangeState(player.airState);
    }

完善PlayerGroundedState,按下空格时切换到跳跃状态
    //更新
    public override void Update()
    {
        base.Update();

        if (Input.GetKeyDown(KeyCode.Space))
            stateMachine.ChangeState(player.jumpState);
    }

完善PlayerAirState,实现落地后切换为闲置状态
    public override void Update()
    {
        base.Update();

        if(rb.velocity.y == 0)
            stateMachine.ChangeState(player.idleState);
    }

完成后运行,效果如下:
在这里插入图片描述


你会发现还有一个小问题,下落的时候并没有切换到下落的动画,依旧是向上跳跃时的,因为我们还没有设置混合树的参数。
我们在PlayerState中设置,确保它在跳跃和空中状态都可用。

    //更新状态
    public virtual void Update()
    {
        xInput = Input.GetAxisRaw("Horizontal");
        player.anim.SetFloat("yVelocity", rb.velocity .y);
    }

这样我们就实现了跳跃和下落动画的混合
在这里插入图片描述


总结 完整代码

Player.cs

添加创建跳跃状态和空中状态,定义跳跃力度

//Player:玩家
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{

    [Header("Move Info")]
    public float moveSpeed = 8f;
    public int facingDir { get; private set; } = 1;
    private bool facingRight = true;

    public float jumpForce = 12f;


    #region 组件
    public Animator anim { get; private set; }
    public Rigidbody2D rb { get; private set; }
    #endregion


    #region 状态
    public PlayerStateMachine StateMachine { get; private set; }
    public PlayerIdleState idleState { get; private set; }
    public PlayerMoveState moveState { get; private set; }
    public PlayerJumpState jumpState { get; private set; }
    public PlayerAirState airState { get; private set; }
    #endregion

    //创建对象
    private void Awake()
    {
        StateMachine = new PlayerStateMachine();

        idleState = new PlayerIdleState(StateMachine, this, "Idle");
        moveState = new PlayerMoveState(StateMachine, this, "Move");
        jumpState = new PlayerJumpState(StateMachine, this, "Jump");
        airState = new PlayerAirState(StateMachine, this, "Jump");

        anim = GetComponentInChildren<Animator>();
        rb = GetComponent<Rigidbody2D>();

    }

    // 设置初始状态
    private void Start()
    {
        StateMachine.Initialize(idleState);
    }

    // 更新
    private void Update()
    {
        StateMachine.currentState.Update();
    }

    //设置速度
    public void SetVelocity(float _xVelocity, float _yVelocity)
    {
        rb.velocity = new Vector2(_xVelocity, _yVelocity);
        FlipController(_xVelocity);
    }

    //翻转实现
    public void Flip()
    {
        facingDir = -1 * facingDir;
        facingRight = !facingRight;
        transform.Rotate(0, 180, 0);
    }
    //翻转控制
    public void FlipController(float _x)
    {
        if (_x > 0 && !facingRight)
            Flip();
        else if(_x < 0 && facingRight)
            Flip();
    }
}

PlayerGroundedState.cs

实现接地状态切换到跳跃,并且被PlayerIdleState,PlayerMoveState继承

//超级状态PlayerGroundedState:接地状态
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerGroundedState : PlayerState
{
    //构造函数
    public PlayerGroundedState(PlayerStateMachine _stateMachine, Player _player, string _animBoolName) : base(_stateMachine, _player, _animBoolName)
    {
    }

    //进入
    public override void Enter()
    {
        base.Enter();
    }

    //退出
    public override void Exit()
    {
        base.Exit();
    }

    //更新
    public override void Update()
    {
        base.Update();

        if (Input.GetKeyDown(KeyCode.Space))
            stateMachine.ChangeState(player.jumpState);
    }
}

PlayerJumpState.cs

实现设置跳跃速度,实现切换到PlayerAirState空中状态

//PlayJumpState:跳跃状态
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerJumpState : PlayerState
{
    public PlayerJumpState(PlayerStateMachine _stateMachine, Player _player, string _animBoolName) : base(_stateMachine, _player, _animBoolName)
    {
    }

    public override void Enter()
    {
        base.Enter();

        rb.velocity = new Vector2(rb.velocity.x, player.jumpForce);
    }

    public override void Exit()
    {
        base.Exit();
    }

    public override void Update()
    {
        base.Update();

        if(rb.velocity.y < 0)
            stateMachine.ChangeState(player.airState);
    }
}

PlayerAirState.cs

实现切换到闲置状态

//超级状态PlayerAirState:空中状态
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerAirState : PlayerState
{
    //构造函数
    public PlayerAirState(PlayerStateMachine _stateMachine, Player _player, string _animBoolName) : base(_stateMachine, _player, _animBoolName)
    {
    }

    //进入
    public override void Enter()
    {
        base.Enter();
    }

    //退出
    public override void Exit()
    {
        base.Exit();
    }

    //更新
    public override void Update()
    {
        base.Update();

        if(rb.velocity.y == 0)
            stateMachine.ChangeState(player.idleState);
    }
}

PlayerState.cs

实现混合树参数的设置

//PlayerState:状态基类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerState
{

    protected PlayerStateMachine stateMachine;
    protected Player player;

    protected Rigidbody2D rb;

    protected float xInput;
    private string animBoolName;

    //构造函数
    public PlayerState(PlayerStateMachine _stateMachine, Player _player, string _animBoolName)
    {
        this.stateMachine = _stateMachine;
        this.player = _player;
        this.animBoolName = _animBoolName;
    }

    //进入状态
    public virtual void Enter()
    {
        //进入动画播放条件变量设置
        player.anim.SetBool(animBoolName, true);

        //获取刚体
        rb = player.rb;
    }

    //更新状态
    public virtual void Update()
    {
        xInput = Input.GetAxisRaw("Horizontal");
        player.anim.SetFloat("yVelocity", rb.velocity .y);
    }

    //退出状态
    public virtual void Exit()
    {
        //退出动画播放条件变量设置
        player.anim.SetBool(animBoolName, false);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值