Unity2D 角色生命系统及UI控制脚本编写之四(学习自用)

最后一步是设置角色被击飞动画。

这里只编写角色被击飞,也就是当角色碰到尖刺后角色向运动方向的反方向运动,同时角色沿y轴蹦起。

声明三个变量,跟之前一样,一个是击飞计时器,一个是击飞长度,还有一个是击飞力度,当然击飞计时器是私有变量,因为它是会变化的。

public float knockBackLength, knockBackForce;  // 声明玩家被击打后的长度和力度
private float knockBackCounter;                // 声明玩家被击打计时器

这里需要注意的是,如果不设置角色的移动为0,那么角色在碰到尖刺后持续的往前走,因为当计时器大于0后,角色会因为惯性往前走,所以必须要设定玩家放弃按钮后,角色的x轴速度为0,y轴往上被击飞。

编写击飞函数,当碰到尖刺时,赋予击飞计时器击飞长度,角色的移动的y轴为向上移动,x轴不动,同时给角色击飞动画。

    public void KnockBack(){
        knockBackCounter = knockBackLength;
        theRB.velocity = new Vector2(0f, knockBackForce);
        anim.SetTrigger("hurt");
    }

之后设置角色往x轴反方向移动,计时器是会变换的,当计时器等于0时是不受击飞限制,当计时器大于0时,它会慢慢变小。

knockBackCounter -= Time.deltaTime;

// 如果玩家没有翻转,向左移动,反之向右
if(!theSR.flipX){
    theRB.velocity = new Vector2(-knockBackForce, theRB.velocity.y);
}
else{
    theRB.velocity = new Vector2(knockBackForce, theRB.velocity.y);
}

这里要设置if函数,如果计时器小于0时,角色由玩家控制,大于0时会被击飞。

        if(knockBackCounter < 0)
        {
            // 控制玩家移动
            theRB.velocity = new Vector2(moveSpeed * Input.GetAxisRaw("Horizontal"), theRB.velocity.y);
            
            // 绘制半圆,检测圆心是否接触地面
            isGrounded = Physics2D.OverlapCircle(groundCheckPoint.position, .2f, whatIsGround);
            // 声明在地面时可以两段跳,不在地面时不能两段跳
            if(isGrounded){
                canDoubleJump = true;
            }

            // 设置跳跃
            if(Input.GetButtonDown("Jump")){
                if(isGrounded){
                    theRB.velocity = new Vector2(theRB.velocity.x, jumpForce);
                }
                else{
                    if(canDoubleJump){
                        theRB.velocity = new Vector2(theRB.velocity.x, jumpForce);
                        canDoubleJump  = false;
                    }
                }
            }

            // 控制人物左右方向翻转
            if(theRB.velocity.x < 0){
                theSR.flipX = true;     // flip按钮时unity界面上的按钮
            }
            else if(theRB.velocity.x > 0){
                theSR.flipX = false;
            }
        }
        else
        {
            knockBackCounter -= Time.deltaTime;
            // 如果玩家没有翻转,向左移动,反之向右
            if(!theSR.flipX){
                theRB.velocity = new Vector2(-knockBackForce, theRB.velocity.y);
            }
            else{
                theRB.velocity = new Vector2(knockBackForce, theRB.velocity.y);
            }
        }

        // 获取动画组组件的MoveSpeed,将主角的移动速度赋予给它
        anim.SetFloat("MoveSpeed", Mathf.Abs(theRB.velocity.x)); // math.Abs是取绝对值
        anim.SetBool("isGrounded", isGrounded);
    }

在PlayerHealthController中调用KnockBack函数

PlayerCont.instance.KnockBack();

同时调用ui界面函数

// 调用静态变量函数
UIController.instance.UpdateHealthDisplay();

完整函数代码如下

    public void DealDamage(){
        
        if(invincibleCounter <= 0)
        {
        
            currentHealth --;
            
            // 当生命值为0时,玩家消失
            if(currentHealth <= 0){
                gameObject.SetActive(false);
            }
            else{
                invincibleCounter = invincibleLenght;
                theSR.color = new Color(theSR.color.r, theSR.color.g, theSR.color.b, 0.5f);

                PlayerCont.instance.KnockBack();
            }

            // 调用静态变量函数
            UIController.instance.UpdateHealthDisplay();
        }
    }

基于此,角色的ui系统和生命系统已经全部显示完毕,以下展示四个脚本的代码:

DamgePlayer脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DamgePlayer : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    void OnTriggerEnter2D(Collider2D other)
    {
        if(other.tag == "Player"){
            
            /* Debug.Log("Hit"); // 测试阶段,检测角色是否触碰到陷阱
            // 调用PlayerHealthController中的DealDamage函数
            FindObjectOfType<PlayerHealthController>().DealDamage(); */

            PlayerHealthController.instance.DealDamage(); // 调用PlayerHealthController中在DealDamage的静态变量
        }
        
    }
}

PlayerCont脚本代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerCont : MonoBehaviour
{
    public static PlayerCont instance;

    public float moveSpeed;     // 声明移动数值
    public Rigidbody2D theRB;   // 声明刚体部件
    public float jumpForce;     // 声明跳跃强度

    private bool isGrounded;            // 声明bool值:是否在地面?
    public Transform groundCheckPoint;  // 获取玩家触碰地面的点位置
    public LayerMask whatIsGround;      // 声明地面图层

    private bool canDoubleJump;         // 声明bool值:是否两段跳?

    private Animator anim;              // 声明动画交互
    private SpriteRenderer theSR;       // 声明精灵操作对象

    public float knockBackLength, knockBackForce;  // 声明玩家被击打后的长度和力度
    private float knockBackCounter;                // 声明玩家被击打计时器

    private void Awake()
    {
        instance = this;
    }

    void Start()
    {
        anim = GetComponent<Animator>();         // 获取动画组件
        theSR = GetComponent<SpriteRenderer>();  // 获取玩家精灵对象组件
    }

    void Update()
    {
        if(knockBackCounter < 0)
        {
            // 控制玩家移动
            theRB.velocity = new Vector2(moveSpeed * Input.GetAxisRaw("Horizontal"), theRB.velocity.y);
            
            // 绘制半圆,检测圆心是否接触地面
            isGrounded = Physics2D.OverlapCircle(groundCheckPoint.position, .2f, whatIsGround);
            // 声明在地面时可以两段跳,不在地面时不能两段跳
            if(isGrounded){
                canDoubleJump = true;
            }

            // 设置跳跃
            if(Input.GetButtonDown("Jump")){
                if(isGrounded){
                    theRB.velocity = new Vector2(theRB.velocity.x, jumpForce);
                }
                else{
                    if(canDoubleJump){
                        theRB.velocity = new Vector2(theRB.velocity.x, jumpForce);
                        canDoubleJump  = false;
                    }
                }
            }

            // 控制人物左右方向翻转
            if(theRB.velocity.x < 0){
                theSR.flipX = true;     // flip按钮时unity界面上的按钮
            }
            else if(theRB.velocity.x > 0){
                theSR.flipX = false;
            }
        }
        else
        {
            knockBackCounter -= Time.deltaTime;
            // 如果玩家没有翻转,向左移动,反之向右
            if(!theSR.flipX){
                theRB.velocity = new Vector2(-knockBackForce, theRB.velocity.y);
            }
            else{
                theRB.velocity = new Vector2(knockBackForce, theRB.velocity.y);
            }
        }

        // 获取动画组组件的MoveSpeed,将主角的移动速度赋予给它
        anim.SetFloat("MoveSpeed", Mathf.Abs(theRB.velocity.x)); // math.Abs是取绝对值
        anim.SetBool("isGrounded", isGrounded);
    }

    public void KnockBack(){
        knockBackCounter = knockBackLength;
        // theRB.velocity = new Vector2(0f, theRB.velocity.y);  // 玩家被击退时停止运动
        theRB.velocity = new Vector2(0f, knockBackForce);       // 给y值一个变量,玩家会出现向上蹦一下的效果

        anim.SetTrigger("hurt");
    }
}

PlayerHealthController脚本代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerHealthController : MonoBehaviour
{
    public static PlayerHealthController instance;   // 声明静态变量

    public int currentHealth, maxHealth;             // 声明当前生命和最大生命

    public  float invincibleLenght;                  // 声明玩家无敌时间变量
    private float invincibleCounter;                 // 声明玩家无敌计数器

    private SpriteRenderer theSR;                    // 声明玩家渲染变量

    private void Awake()
    {
        instance = this;
    }

    void Start()
    {
        currentHealth = maxHealth;

        theSR = GetComponent<SpriteRenderer>();
    }

    // Update is called once per frame
    void Update()
    {
        if(invincibleCounter > 0){
            invincibleCounter -= Time.deltaTime;

            if(invincibleCounter <= 0){
                theSR.color = new Color(theSR.color.r, theSR.color.g, theSR.color.b, 1f);
            }
        }
    }

    public void DealDamage(){
        
        if(invincibleCounter <= 0)
        {
        
            currentHealth --;
            
            // 当生命值为0时,玩家消失
            if(currentHealth <= 0){
                gameObject.SetActive(false);
            }
            else{
                invincibleCounter = invincibleLenght;
                theSR.color = new Color(theSR.color.r, theSR.color.g, theSR.color.b, 0.5f);

                PlayerCont.instance.KnockBack();
            }

            // 调用静态变量函数
            UIController.instance.UpdateHealthDisplay();
        }
    }
}

UIController脚本代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UIController : MonoBehaviour
{
    // 创建静态变量以访问其他脚本
    public static UIController instance ;

    public Image heart1, heart2, heart3;             // 声明图片变量

    public Sprite heartFull, heartHalf, heartEmpty;  // 声明精灵变量

    private void Awake(){
        instance = this;
    }
    
    void Start()
    {
        
    }

    void Update()
    {
        
    }

    // 声明角色收到伤害后数据更新
    public void UpdateHealthDisplay(){
        switch(PlayerHealthController.instance.currentHealth){
            case 6:
                heart1.sprite = heartFull;
                heart2.sprite = heartFull;
                heart3.sprite = heartFull;

                break;

            case 5:
                heart1.sprite = heartFull;
                heart2.sprite = heartFull;
                heart3.sprite = heartHalf;

                break;

            case 4:
                heart1.sprite = heartFull;
                heart2.sprite = heartFull;
                heart3.sprite = heartEmpty;
                
                break;

            case 3:
                heart1.sprite = heartFull;
                heart2.sprite = heartHalf;
                heart3.sprite = heartEmpty;
                
                break;
            
            case 2:
                heart1.sprite = heartFull;
                heart2.sprite = heartEmpty;
                heart3.sprite = heartEmpty;

                break;

            case 1:
                heart1.sprite = heartHalf;
                heart2.sprite = heartEmpty;
                heart3.sprite = heartEmpty;

                break;

            case 0:
                heart1.sprite = heartEmpty;
                heart2.sprite = heartEmpty;
                heart3.sprite = heartEmpty;

                break;

            default:
                heart1.sprite = heartEmpty;
                heart2.sprite = heartEmpty;
                heart3.sprite = heartEmpty;

                break;

        }
    }
}

以下为unity界面的操作:

全部演示完毕,这一章内容较多,花费三天时间写完,写笔记对理解游戏运行逻辑有很大帮助。

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值