P19- P21跟Alex Dev老师的课程利用unity从零开始学习做横版2D游戏的学习笔记----包含原代码部分和个人见解

补上之前缺的,都放在这一章

冲刺冷却时间的设置:

[SerializeField] private float dashCooldown;
private float dashCooldownTimer;

      dashCooldownTimer -= Time.deltaTime;

        if (Input.GetKeyDown(KeyCode.LeftShift))
        {
            DashAbility();
        }

    }

    private void DashAbility()
    {
        if (dashCooldownTimer < 0)
        {
            dashCooldownTimer = dashCooldown;

            dashTime = dashDuration;
        }

    private void Movement()
    // 移动由 x 输入 和 移动速度控制
    {
        if (dashTime > 0)
        {
            rb.velocity = new Vector2(xInput * dashSpeed, 0);
        }
        else
        {
            rb.velocity = new Vector2(xInput * moveSpeed, rb.velocity.y);
        }
    }

Attacking animation

人物的攻击动作分为1 2 3,通过素材的拖拽将其设置为合理的值,加入新的动画器参数isattacjing,combocounter  并设置合理的连接状态,但是人物的动作结束将有一个退出时间。

    [Header("Attack info")]
    private bool isAttacking;
    private int comboCounter;

    public void AttackingOver()
    {
        isAttacking = false;
    }

    private void AnimatorControllers()
    // 动画控制器控制动画的播出
    {

        bool isMoving = rb.velocity.x != 0;

        anim.SetFloat("yVelocity", rb.velocity.y);

        anim.SetBool("isMoving", isMoving);
        // 1.调用 Animator = anim 组件中的 SetBool 方法,将 isMoving 参数的值设置到 Animator 组件中
        // 2.后面的 isMoving 这个变量的值将被传递给 SetBool 方法,用于设置 "isMoving" 参数的值
        // 要求:player或者其子对象Animitor中必须有一个 Animator 的组件,并且Animator Controller中必须有一个名为 isMoving 的布尔参数

        anim.SetBool("isGrounded", isGrounded);

        anim.SetBool("isDashing", dashTime > 0);

        anim.SetBool("isAttacking", isAttacking);

        anim.SetInteger("comnoCounter", comboCounter);

    }

创建一个C#脚本,放置于Animitor之中,并在攻击动画的最后一帧之中加入一个事件,这个事件将调用我们刚刚创建的C#脚本之中的函数,以便我们在动作结束之后能够使得 isAttacking 变为flase,停止继续重复播放这个动作。

以下为C#脚本脚本之中的函数:

public class playerAnimEvents : MonoBehaviour
{
    private player player;

    
    void Start()
    {
        player = GetComponentInParent<player>();
    }

    private void AnimationTrigger() 
    {
        player.AttackingOver();
    
    }

这里我们需要注意:

1.public class player : MonoBehaviour  这行代码表明 player 继承自 MonoBehaviour 类。


2.private player player;   声明一个 后player 变量,为 前player 类型,那么 后player 这个变量能够引用和操作 前Player 类的实例。


3.player = GetComponentInParent<player>();

使用 GetComponentInParent<player>() 时,Unity会从当前GameObject开始,向上遍历其父级,直到找到一个包含 player 类型组件的GameObject。

一旦找到,它就返回这个组件的引用,你可以使用这个引用的返回值来访问 player 类中定义的属性和方法,如下:

player.AttackingOver();

P21 16.Attack combo

添加新的变量:↓

    [Header("Attack info")]
    [SerializeField] private float comboTime = .3f;
    private float comboTimeWindow;
    private bool isAttacking;
    private int comboCounter;

每秒更新:↓

        comboTimeWindow -= Time.deltaTime;

对AttackingOver()函数进行更新:↓

    public void AttackingOver()
    {
        isAttacking = false;

        comboCounter++;

        if (comboCounter > 2) 
        {
            comboCounter = 0;        
        }   

    }

对检查输入进行更新:↓

    private void CheckInput()
    {
        xInput = Input.GetAxisRaw("Horizontal");
        // 设置 x 的输入,获得移动的机会

        if (Input.GetKeyDown(KeyCode.J))
        {
            StartAttackEvent();
        }

并且创建新的函数:↓

    private void StartAttackEvent()
    {
        if (comboTimeWindow < 0)
        {
            comboCounter = 0;
        }

        isAttacking = true;

        comboTimeWindow = comboTime;
    }

对移动函数进行更新:↓

    private void Movement()
    // 移动由 x 输入 和 移动速度控制
    {


        if (isAttacking)
        {
            rb.velocity = new Vector2(0, 0);   
        }
        else if (dashTime > 0)
        {
            rb.velocity = new Vector2(facingDirection * dashSpeed, 0);
        }
        else
        {
            rb.velocity = new Vector2(xInput * moveSpeed, rb.velocity.y);
        }
    }

攻击动作的代码进行更新:↓

   private void StartAttackEvent()
   {
       if (!isGrounded) 
           return;
        

更新动画控制函数:↓并且需要再attack2 attack3动画的最后一帧添加函数

    private void AnimatorControllers()

        anim.SetInteger("comboCounter", comboCounter);

这是这一部分总的代码总结,接下来我们将会通过状态机进行代码调试。

public class player : MonoBehaviour
{
    private Rigidbody2D rb;
    // rb目前处于未被初始化的状态,值为null,不能被调用,不指向任何对象。

    private Animator anim;

    [SerializeField] private float moveSpeed;

    [SerializeField] private float jumpForce;

    [Header("Dash info")]
    [SerializeField] private float dashSpeed;
    [SerializeField] private float dashDuration;
    private float dashTime;

    [SerializeField] private float dashCooldown;
    private float dashCooldownTimer;

    [Header("Attack info")]
    [SerializeField] private float comboTime = .3f;
    private float comboTimeWindow;
    private bool isAttacking;
    private int comboCounter;

    private float xInput;

    private int facingDirection = 1;
    private bool facingRight = true;


    [Header("Collision info")]
    [SerializeField] private float groundCheckDistance;
    [SerializeField] private LayerMask whatIsground;
    private bool isGrounded;


    void Start()
    {
        rb = GetComponent<Rigidbody2D>();

        anim = GetComponentInChildren<Animator>();
    }


    void Update()
    {
        Movement();

        CheckInput();

        CollisionCheck();

        dashTime -= Time.deltaTime;

        dashCooldownTimer -= Time.deltaTime;

        comboTimeWindow -= Time.deltaTime;

        FlipController();

        AnimatorControllers();

    }

    public void AttackingOver()
    {
        isAttacking = false;

        comboCounter++;

        if (comboCounter > 2) 
        {
            comboCounter = 0;        
        }   

    }

    private void CollisionCheck()
    // 如果 groundCheckDistance 碰到地面就是true,没有碰到地面是 flase
    {
        isGrounded = Physics2D.Raycast(transform.position, Vector2.down, groundCheckDistance, whatIsground);
    }

    private void CheckInput()
    {
        xInput = Input.GetAxisRaw("Horizontal");
        // 设置 x 的输入,获得移动的机会

        if (Input.GetKeyDown(KeyCode.J))
        {
            StartAttackEvent();
        }

        if (Input.GetKeyDown(KeyCode.K))
        // 如果输入 空格 就会进行跳跃
        {
            Jump();
        }

        if (Input.GetKeyDown(KeyCode.LeftShift))
        {
            DashAbility();
        }

    }

    private void StartAttackEvent()
    {
        if (!isGrounded)
            return;
        
        if (comboTimeWindow < 0)
        {
            comboCounter = 0;
        }

        isAttacking = true;

        comboTimeWindow = comboTime;
    }

    private void DashAbility()
    {
        if (dashCooldownTimer < 0 && !isAttacking)
        {
            dashCooldownTimer = dashCooldown;

            dashTime = dashDuration;
        }

    }

    private void Movement()
    // 移动由 x 输入 和 移动速度控制
    {


        if (isAttacking)
        {
            rb.velocity = new Vector2(0, 0);   
        }
        else if (dashTime > 0)
        {
            rb.velocity = new Vector2(facingDirection * dashSpeed, 0);
        }
        else
        {
            rb.velocity = new Vector2(xInput * moveSpeed, rb.velocity.y);
        }
    }

    private void Jump()
    // 跳跃由跳跃强度控制
    {
        if (isGrounded)
        {
            rb.velocity = new Vector2(rb.velocity.x, jumpForce);
        }
    }

    private void AnimatorControllers()
    // 动画控制器控制动画的播出
    {

        bool isMoving = rb.velocity.x != 0;

        anim.SetFloat("yVelocity", rb.velocity.y);

        anim.SetBool("isMoving", isMoving);
        // 1.调用 Animator = anim 组件中的 SetBool 方法,将 isMoving 参数的值设置到 Animator 组件中
        // 2.后面的 isMoving 这个变量的值将被传递给 SetBool 方法,用于设置 "isMoving" 参数的值
        // 要求:player或者其子对象Animitor中必须有一个 Animator 的组件,并且Animator Controller中必须有一个名为 isMoving 的布尔参数

        anim.SetBool("isGrounded", isGrounded);

        anim.SetBool("isDashing", dashTime > 0);

        anim.SetBool("isAttacking", isAttacking);

        anim.SetInteger("comboCounter", comboCounter);

    }

    private void Flip()
    // 进行角色翻转
    {
        facingDirection = facingDirection * -1;

        facingRight = !facingRight;

        transform.Rotate(0, 180, 0);

    }

    private void FlipController()
    // 角色翻转控制器
    {
        if (rb.velocity.x > 0 && !facingRight)
        {
            Flip();
        }
        else if (rb.velocity.x < 0 && facingRight)
        {
            Flip();
        }

    }

    private void OnDrawGizmos()
    {
        Gizmos.DrawLine(transform.position, new Vector3(transform.position.x, transform.position.y - groundCheckDistance));
    }


}

子体脚本如下:

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

public class playerAnimEvents : MonoBehaviour
{
    private player player;

    
    void Start()
    {
        player = GetComponentInParent<player>();
    }

    private void AnimationTrigger() 
    {
        player.AttackingOver();
    
    }
  
}
// public class player : MonoBehaviour  这行代码表明 player 继承自 MonoBehaviour 类。
// private player player;   声明一个 后player 变量,为 前player 类型,那么 后player 这个变量能够引用和操作 前Player 类的实例
// player = GetComponentInParent<player>();
// 使用 GetComponentInParent<player>() 时,Unity会从当前GameObject开始,向上遍历其父级,直到找到一个包含 player 类型组件的GameObject。
// 一旦找到,它就返回这个组件的引用,你可以使用这个引用的返回值来访问 player 类中定义的属性和方法,如下:
// player.AttackingOver();

  • 25
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值