Unity类银河恶魔城学习记录7-8 P74 Pierce sword源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释,可供学习Alex教程的人参考

此代码仅为较上一P有所改变的代码

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

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

public enum SwordType
{
    Regular,
    Bounce,
    Pierce,
    Spin
}

public class Sword_Skill : Skill
{
    public SwordType swordType = SwordType.Regular;//创建应一个enum列表,后面用来判断切换状态

    [Header("Bounce Info")]
    [SerializeField] private int bounceAmount;
    [SerializeField] private float bounceGravity;

    [Header("Pierce info")]
    [SerializeField] private int pierceAmount;
    [SerializeField] private float pierceGravity;

    [Header("Skill Info")]
    [SerializeField] private GameObject swordPrefab;//sword预制体
    [SerializeField] private Vector2 launchForce;//发射力度
    [SerializeField] private float swordGravity;//发射体的重力

    private Vector2 finalDir;//发射方向

    [Header("Aim dots")]
    [SerializeField] private int numberOfDots;//需要的点的数量
    [SerializeField] private float spaceBetweenDots;//相隔的距离
    [SerializeField] private GameObject dotPrefab;//dot预制体
    [SerializeField] private Transform dotsParent;//不是很懂

    private GameObject[] dots;//dot组

    protected override void Start()
    {
        base.Start();

        GenerateDots();//生成点函数

        SetupGravity();
    }

    private void SetupGravity()//每个剑的状态都对应了不同的剑重力
    {
        if(swordType == SwordType.Pierce)
        {
            swordGravity = pierceGravity;
        }
        if(swordType == SwordType.Bounce)
        {
            swordGravity = bounceGravity;
        }
    }

    protected override void Update()
    {
        base.Update();
        if (Input.GetKeyUp(KeyCode.Mouse1))
        {
            finalDir = new Vector2(AimDirection().normalized.x * launchForce.x, AimDirection().normalized.y * launchForce.y);
            //将位移量改为单位向量分别与力度的x,y相乘作为finalDir
        }

        if (Input.GetKey(KeyCode.Mouse1))
        {
            for (int i = 0; i < dots.Length; i++)
            {
                dots[i].transform.position = DotsPosition(i * spaceBetweenDots);//用循环为每个点以返回值赋值(传入值为每个点的顺序i*点间距
            }
        }
    }
    public void CreateSword()
    {
        GameObject newSword = Instantiate(swordPrefab, player.transform.position, transform.rotation);//创造实例,初始位置为此时player的位置
        Sword_Skill_Controller newSwordScript = newSword.GetComponent<Sword_Skill_Controller>();//获得Controller
        
        if(swordType == SwordType.Bounce)
        {
            newSwordScript.SetupBounce(true, bounceAmount);
        }
        else if(swordType == SwordType.Pierce)
        {
            newSwordScript.SetupPierce(pierceAmount);
        }


        
        newSwordScript.SetupSword(finalDir, swordGravity, player);//调用Controller里的SetupSword函数,给予其速度和重力和player实例

        player.AssignNewSword(newSword);//调用在player中保存通过此方法创造出的sword实例
        DotsActive(false);//关闭点的显示
    }
    #region Aim region
    public Vector2 AimDirection()
    {
        Vector2 playerPosition = player.transform.position;//拿到玩家此时的位置
        Vector2 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);//https://docs.unity3d.com/cn/current/ScriptReference/Camera.ScreenToWorldPoint.html
                                                                                    //大概就是返回屏幕上括号里的参数的位置,这里返回了鼠标的位置
                                                                                    //拿到此时鼠标的位置
        Vector2 direction = mousePosition - playerPosition;//获得距离的绝对向量

        return direction;//返回距离向量
    }

    public void DotsActive(bool _isActive)
    {
        for (int i = 0; i < dots.Length; i++)
        {
            dots[i].SetActive(_isActive);//设置每个点是否显示函数
        }
    }
    private void GenerateDots()//生成点函数
    {
        dots = new GameObject[numberOfDots];//为dot赋予实例数量
        for (int i = 0; i < numberOfDots; i++)
        {
            dots[i] = Instantiate(dotPrefab, player.transform.position, Quaternion.identity, dotsParent);//对象与世界轴或父轴完全对齐
            //https://docs.unity3d.com/cn/current/ScriptReference/Quaternion-identity.html
            dots[i].SetActive(false);//关闭dot
        }
    }

    private Vector2 DotsPosition(float t)//传入顺序相关的点间距
    {
        Vector2 position = (Vector2)player.transform.position +
            new Vector2
            (AimDirection().normalized.x * launchForce.x,
             AimDirection().normalized.y * launchForce.y) * t  //基本间距
             + .5f * (Physics2D.gravity * swordGravity) * (t * t)//重力影响
             ;
        //t是控制之间点间距的
        return position;//返回位置
    }//设置点间距函数
    #endregion
}
Sword_Skill_Controller.cs
cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Sword_Skill_Controller : MonoBehaviour
{
    [SerializeField] private float returnSpeed = 12;
    private bool isReturning;

    private Animator anim;
    private Rigidbody2D rb;
    private CircleCollider2D cd;
    private Player player;

    private bool canRotate = true;
    [Header("Piece info")]
    [SerializeField] float pierceAmount;

    [Header("Bounce info")]
    [SerializeField]private float bounceSpeed;//设置弹跳速度
    private bool isBouncing;//判断是否可以弹跳
    private int bounceAmount;//弹跳的次数
    public List<Transform> enemyTargets;//保存所有在剑范围内的敌人的列表
    private int targetIndex;//设置targetIndex作为敌人计数器

    private void Awake()
    {
        anim = GetComponentInChildren<Animator>();
        rb = GetComponent<Rigidbody2D>();
        cd = GetComponent<CircleCollider2D>();
    }
    public void ReturnSword()
    {
        rb.constraints = RigidbodyConstraints2D.FreezeAll;//修复剑只要不触碰到物体就无法收回的bug
        //rb.isKinematic = false;
        transform.parent = null;
        isReturning = true;
    }
    public void SetupSword(Vector2 _dir,float _gravityScale,Player _player)
    {
        player = _player;
        rb.velocity = _dir;
        rb.gravityScale = _gravityScale;
        if(pierceAmount < 0)
          anim.SetBool("Rotation", true); //其次在pierceAmount > 0时不启动旋转动画
    }

    public void SetupBounce(bool _isBouncing,int _bounceAmount)
    {
        isBouncing = _isBouncing;
        bounceAmount = _bounceAmount;
    }

    public void SetupPierce(int _pierceAomunt)
    {
        pierceAmount = _pierceAomunt;
    }

    private void Update()
    {
        if (canRotate)
            transform.right = rb.velocity;//使武器随着速度而改变朝向

        if (isReturning)
        {
            transform.position = Vector2.MoveTowards(transform.position, player.transform.position, returnSpeed * Time.deltaTime);//从原来的位置返回到player的位置
                                                                                                                                  //并且随着时间增加而增加速度
            if (Vector2.Distance(transform.position, player.transform.position) < 1)//当剑与player的距离小于一定距离,清除剑
            {
                player.CatchTheSword();
            }
        }

        BounceLogic();
    }

    private void BounceLogic()
    {
        if (isBouncing && enemyTargets.Count > 0)
        {

            transform.position = Vector2.MoveTowards(transform.position, enemyTargets[targetIndex].position, bounceSpeed * Time.deltaTime);
            //3.当可以弹跳且列表内数量大于0,调用ToWords,这将使剑能够跳到敌人身上
            if (Vector2.Distance(transform.position, enemyTargets[targetIndex].position) < .1f)
            {
                targetIndex++;
                bounceAmount--;//设置弹跳次数
                if (bounceAmount <= 0)
                {
                    isBouncing = false;
                    isReturning = true;
                }//这样会使当弹跳次数为0时,返回到角色手中
                if (targetIndex >= enemyTargets.Count)
                {
                    targetIndex = 0;
                }
            }//利用与目标距离的判断,使剑接近目标距离时切换到下一个目标。
             //且如果所有目标都跳完了,切回第一个
        }
    }

    private void OnTriggerEnter2D(Collider2D collision)//传入碰到的物体的碰撞器
    {
        if (isReturning)
        {
            return;
        }//修复在返回时扔出时没有碰到任何物体,但返回时碰到了物体导致剑的一些性质发生改变的问题,及回来的时候调用了OnTriggerEnter2D

        collision.GetComponent<Enemy>()?.Damage();//设置一下敌人受击动画

        if (collision.GetComponent<Enemy>() != null)//首先得碰到敌人,只有碰到敌人才会跳
        {
            if (isBouncing && enemyTargets.Count <= 0)
            {
                Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, 10);
                foreach (var hit in colliders)
                {
                    if (hit.GetComponent<Enemy>() != null)
                    {
                        enemyTargets.Add(hit.transform);
                    }
                }
            }
        }

        StuckInto(collision);
    }//打开IsTrigger时才可使用该函数
    //https://docs.unity3d.com/cn/current/ScriptReference/Collider2D.OnTriggerEnter2D.html

    private void StuckInto(Collider2D collision)
    {
        if(pierceAmount > 0 && collision.GetComponent<Enemy>()!= null)//本质就是能穿过敌人,在amount>0时不执行能让剑卡在敌人里的语句就行
        {
            pierceAmount--;
            return;
        }

        canRotate = false;
        cd.enabled = false;//相当于关闭碰撞后触发函数。//https://docs.unity3d.com/cn/current/ScriptReference/Collision2D-enabled.html

        rb.isKinematic = true;//开启物理学反应 https://docs.unity3d.com/cn/current/ScriptReference/Rigidbody2D-isKinematic.html
        rb.constraints = RigidbodyConstraints2D.FreezeAll;//冻结所有移动

        if (isBouncing&&enemyTargets.Count>0)//修复剑卡不到墙上的bug
            return;
        //终止对动画的改变和终止附在敌人上
        transform.parent = collision.transform;//设置sword的父组件为碰撞到的物体
        anim.SetBool("Rotation", false);
    }
    
}
相关推荐
anlog29 分钟前
C#在自定义事件里传递数据
开发语言·c#·自定义事件
奶香臭豆腐42 分钟前
C++ —— 模板类具体化
开发语言·c++·学习
波音彬要多做1 小时前
41 stack类与queue类
开发语言·数据结构·c++·学习·算法
ue星空2 小时前
虚幻引擎结构之UWorld
游戏引擎·虚幻
ue星空2 小时前
虚幻引擎结构之ULevel
游戏引擎·虚幻
向宇it2 小时前
【从零开始入门unity游戏开发之——unity篇01】unity6基础入门开篇——游戏引擎是什么、主流的游戏引擎、为什么选择Unity
开发语言·unity·c#·游戏引擎
m0_748256782 小时前
WebGIS实战开源项目:智慧机场三维可视化(学习笔记)
笔记·学习·开源
仰望大佬0072 小时前
Avalonia实例实战五:Carousel自动轮播图
数据库·microsoft·c#
糖朝3 小时前
c#读取json
c#·json
南七澄江4 小时前
各种网站(学习资源及其他)
开发语言·网络·python·深度学习·学习·机器学习·ai