Unity类银河战士恶魔城学习总结(P178 Archer s arrow 弓箭手的箭)

【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili

教程源地址:https://www.udemy.com/course/2d-rpg-alexdev/

本章节制作了一个弓箭手的箭

Arrow_Controller.cs

1.OnTriggerEnter2D方法

  • 功能:检测箭矢与其他对象的碰撞。
  • 逻辑
    • 如果碰撞对象的层级与targetLayerName匹配
      • 获取碰撞对象的CharacterStats组件并调用TakeDamage(damage)方法,造成伤害。
      • 调用StuckInto(collision)方法,使箭矢嵌入碰撞对象。
    • 如果碰撞对象的层级为"Ground"
      • 直接调用StuckInto(collision)方法,使箭矢嵌入地面。

2.StuckInto方法

  • 功能:处理箭矢嵌入目标后的状态变化。
  • 步骤
    1. 停止粒子系统 :停止箭矢子对象中的ParticleSystem,例如拖尾效果。
    2. 禁用碰撞体 :禁用箭矢的Collider2D,防止进一步的碰撞检测。
    3. 停止移动 :将canMove设为false,阻止在Update中继续移动。
    4. 设置刚体为运动学 :将rb.isKinematic设为true,使箭矢不再受物理引擎影响。
    5. 冻结所有刚体约束 :通过rb.constraints = RigidbodyConstraints2D.FreezeAll冻结箭矢的所有移动和旋转,确保其在嵌入后不再移动。
    6. 设置父对象 :将箭矢的transform设置为碰撞对象的子对象,使其随碰撞对象一起移动。
    7. 销毁箭矢 :在5到7秒后销毁箭矢对象,使用Random.Range(5,7)生成销毁延迟时间。

3.FlipArrow()方法

功能:翻转箭矢的方向,使其朝相反方向移动,并更改目标层级。

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//2024.12.11
public class Arrow_Controller : MonoBehaviour
{
    [SerializeField] private int damage;//箭矢造成的伤害值
    [SerializeField] private string targetLayerName = "Player";//箭矢的目标层

    [SerializeField] private float xVelocity;
    [SerializeField] private Rigidbody2D rb;

    [SerializeField] private bool canMove;
    [SerializeField] private bool flipped;


    private void Update()
    {
        if(canMove)
            rb.velocity = new Vector2(xVelocity, rb.velocity.y);
    }



    private void OnTriggerEnter2D(Collider2D collision)
    {
        if(collision.gameObject.layer == LayerMask.NameToLayer(targetLayerName))
        {
            collision.GetComponent<CharacterStats>().TakeDamage(damage);
            StuckInto(collision);

        }
        else if (collision.gameObject.layer == LayerMask.NameToLayer("Ground"))
        {
            StuckInto(collision);
        }

    }


    private void StuckInto(Collider2D collision)//射中目标
    {
        GetComponentInChildren<ParticleSystem>().Stop();//停止粒子系统
        GetComponent<Collider2D>().enabled = false;
        canMove = false;
        rb.isKinematic = true;//刚体为运动
        rb.constraints = RigidbodyConstraints2D.FreezeAll;
        transform.parent = collision.transform;//箭矢的父物体为碰撞物体

        Destroy(gameObject, Random.Range(5,7));
    }


    public void FlipArrow()
    {
        if (flipped)
            return;


        xVelocity = xVelocity * -1;
        flipped = true;
        transform.Rotate(0,180,0);
        targetLayerName = "Enemy";

    }
}

PlayerCounterAttackState.cs

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerCounterAttackState : PlayerState
{
    private bool canCreateClone;

    public PlayerCounterAttackState(Player _player, PlayerStateMachine _stateMachine, string _animBoolName) : base(_player, _stateMachine, _animBoolName)
    {
    }

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

        canCreateClone = true;
        stateTimer = player.counterAttackDuration;
        player.anim.SetBool("SuccessfulCounterAttack", false);

    }

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

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

        player.SetZeroVelocity();

        Collider2D[] colliders = Physics2D.OverlapCircleAll(player.attackCheck.position, player.attackCheckRadius);


        foreach (var hit in colliders)
        {
            if(hit.GetComponent<Arrow_Controller>()!= null)
            {
                hit.GetComponent<Arrow_Controller>().FlipArrow();
                SuccesfulCounterAttack();
            }


            if (hit.GetComponent<Enemy>() != null)
            {
                if (hit.GetComponent<Enemy>().CanBeStunned())
                    {
                        SuccesfulCounterAttack();

                        player.skill.parry.UseSkill();


                        if (canCreateClone)
                        {
                            canCreateClone = false;
                            player.skill.parry.MakeMirageOnParry(hit.transform);
                        }
                    }
                }
        }

        if (stateTimer < 0 || triggerCalled)
            stateMachine.ChangeState(player.idleState);

    }

    private void SuccesfulCounterAttack()
    {
        stateTimer = 10;//大于1的数,保证不会进入idle状态
        player.anim.SetBool("SuccessfulCounterAttack", true);
    }
}
相关推荐
向阳花开_miemie17 小时前
Android音频学习(二十二)——音频接口
学习·音视频
胡萝卜3.017 小时前
深入理解string底层:手写高效字符串类
开发语言·c++·学习·学习笔记·string类·string模拟实现
fanstering17 小时前
腾讯混元P3-SAM: Native 3D Part Segmentation
笔记·学习·3d·点云
im_AMBER18 小时前
数据结构 05 栈和队列
数据结构·笔记·学习
云草桑18 小时前
.net AI MCP 入门 适用于模型上下文协议的 C# SDK 简介(MCP)
ai·c#·.net·mcp
报错小能手19 小时前
linux学习笔记(31)网络编程——TCP time_wait机制
linux·笔记·学习
Yupureki19 小时前
从零开始的C++学习生活 7:vector的入门使用
c语言·c++·学习·visual studio
i学长的猫19 小时前
Ruby小白学习路线
开发语言·学习·ruby
送秋三十五19 小时前
Docker 构建教程:学习上下文、架构和性能优化技术
学习·docker·架构
思成不止于此19 小时前
软考中级软件设计师备考指南(四):I/O 技术、安全与可靠性 —— 综合应用篇
网络·笔记·学习·信息安全·总线系统·i/o 技术·可靠性计算