Unity类银河战士恶魔城学习总结(P118 Thunder Strike On Ability 制作一把带有雷电效果的项链)
【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili
教程源地址:https://www.udemy.com/course/2d-rpg-alexdev/
本节实现了一个能给武器和水晶爆炸技能附魔的项链,取名为风暴之心
都是在造成伤害函数的部分加上了触发特殊效果的代码
Sword_Skill_Controller.cs
修改部分
private void SwordSkillDamage(Enemy enemy)
{
//enemy.DamageEffect();
player.stats.DoDamage(enemy.GetComponent<CharacterStats>());
enemy.StartCoroutine("FreezeTimerFor", freezeTimeDUration);
ItemData_Equipment equipedAmulet = Inventory.instance.GetEquipment(EquipmentType.Amulet);//获取护身符
if (equipedAmulet != null)
equipedAmulet.Effect(enemy.transform);//如果有护身符,就对敌人造成额外伤害
}
using System.Collections.Generic;
using Unity.Burst.CompilerServices;
using UnityEngine;
public class Sword_Skill_Controller : MonoBehaviour
{
private Animator anim;
private Rigidbody2D rb;
private CircleCollider2D cd;
private Player player;
private bool canRotate = true;
private bool isReturning;
private float freezeTimeDUration;
private float returnSpeed = 12;
[Header("Pierce info")]
[SerializeField] private int pierceAmount;
[Header("Bounce info")]
private float bounceSpeed;// 想通过函数传递删除SerializeField
private bool isBouncing; // 是否可以反弹
private int bounceAmount;// 反弹次数
private List<Transform> enemyTarget;//敌人目标
private int targetIndex = 0;//目标索引
[Header("Spin info")]
private float maxTravelDistance;//最大旋转距离
private float spinDuration;//旋转持续时间
private float spinTimer;//旋转计时器
private bool wasStopped;//是否停止
private bool isSpinning;//是否旋转
private float hitTimer;
private float hitCooldown;
private float spinDirection;//旋转方向
//Awake在脚本实例化时立即调用。它在所有对象的Awake方法都被调用完毕后,才会开始调用Start方法。而Start在第一次更新循环之前调用。
private void Awake()
{
anim = GetComponentInChildren<Animator>();
rb = GetComponent<Rigidbody2D>();
cd = GetComponent<CircleCollider2D>();
}
private void DestroyMe()
{
Destroy(gameObject);
}
//以下四个函数都是把局部变量传递给全局变量
public void SetupSword(Vector2 _dir, float _gravityScale, Player _player, float _freezeTimeDUration, float _returnSpeed) //设置飞行物体
{
player = _player;
freezeTimeDUration = _freezeTimeDUration;
returnSpeed = _returnSpeed;
rb.velocity = _dir;
rb.gravityScale = _gravityScale;
if (pierceAmount <= 0)
anim.SetBool("Rotation", true);
spinDirection = Mathf.Clamp(rb.velocity.x, -1, 1);//限制旋转方向在-1到1之间
Invoke("DestroyMe", 7);//Invoke 是 Unity 中 MonoBehaviour 类的一部分,用于在指定的延迟时间后调用某个方法
}
public void SetupBounce(bool _isBouncing, int _amountOfBounces, float _bounceSpeed)//设置反弹
{
isBouncing = _isBouncing;
bounceAmount = _amountOfBounces;
bounceSpeed = _bounceSpeed;
enemyTarget = new List<Transform>();//当把上面的public改成private时,系统就不会创建一个空的列表
}
public void SetupPierce(int _pierceAmount)//int _pierceAmoun:方法参数
{
pierceAmount = _pierceAmount;
}
public void SetupSpin(bool _isSpinning, float _maxTravelDistance, float _spinDuration, float _hitCooldown)//设置旋转
{
isSpinning = _isSpinning;
maxTravelDistance = _maxTravelDistance;
spinDuration = _spinDuration;//,_spinDuration 是一个形式参数
hitCooldown = _hitCooldown;
}
public void ReturnSword()
{
rb.constraints = RigidbodyConstraints2D.FreezeAll;// 冻结刚体的所有约束
//rb.isKinematic = false;
transform.parent = null;
isReturning = true;
}
private void Update()
{
if (canRotate)//如果可以旋转
transform.right = rb.velocity;//设置旋转方向
if (isReturning)
{
transform.position = Vector2.MoveTowards(transform.position, player.transform.position, returnSpeed * Time.deltaTime);//返回到玩家手上
if (Vector2.Distance(transform.position, player.transform.position) < 1)
player.CatchTheSword();
}
BounceLogic();//反弹逻辑
SpinLogic();//旋转逻辑
}
private void SpinLogic()
{
if (isSpinning)
{
if (Vector2.Distance(transform.position, player.transform.position) > maxTravelDistance && !wasStopped)//如果距离大于最大旋转距离并且没有停止
{
StopWhenSpinning();
}
if (wasStopped)//如果停止
{
spinTimer -= Time.deltaTime;//计时器减去时间
//transform.position = Vector2.MoveTowards(transform.position,
// new Vector2(transform.position.x + spinDirection, transform.position.y), 1.5f * Time.deltaTime);//移动到旋转方向
if (spinTimer < 0)
{
isReturning = true;
isSpinning = false;
}
hitTimer -= Time.deltaTime;
if (hitTimer < 0)
{
hitTimer = hitCooldown;
Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, 1);
foreach (var hit in colliders)
{
if (hit.GetComponent<Enemy>() != null)
{
SwordSkillDamage(hit.GetComponent<Enemy>());
}
}
}
}
}
}
private void StopWhenSpinning()//旋转时候停止
{
wasStopped = true;
rb.constraints = RigidbodyConstraints2D.FreezeAll;
spinTimer = spinDuration;//旋转计时器
}
private void BounceLogic()
{
if (isBouncing && enemyTarget.Count > 0)//如果可以反弹并且敌人目标数量大于0
{
transform.position = Vector2.MoveTowards(transform.position, enemyTarget[targetIndex].position, bounceSpeed * Time.deltaTime);//移动到敌人
if (Vector2.Distance(transform.position, enemyTarget[targetIndex].position) < 0.1f)//如果距离小于0.1
{
SwordSkillDamage(enemyTarget[targetIndex].GetComponent<Enemy>());//敌人受到伤害
//enemyTarget[targetIndex].GetComponent<Enemy>().Damage();
//enemyTarget[targetIndex].GetComponent<Enemy>().StartCoroutine("FreezeTimerFor", freezeTimeDUration);
targetIndex++; //敌人目标的索引,攻击了这个敌人就攻击下一个敌人
bounceAmount--;
if (bounceAmount <= 0)
{
isBouncing = false;
isReturning = true;
}
if (targetIndex >= enemyTarget.Count) //如果目标索引大于等于敌人目标数量
{
targetIndex = 0;
}
}
}
}
private void OnTriggerEnter2D(Collider2D collision)//Sword碰到敌人时候的处理
{
if (isReturning)
return;//后面的就不会再触发,sword可以返回时候攻击到敌人,并且返回到手上
if (collision.GetComponent<Enemy>() != null)//如果碰到敌人
{
Enemy enemy = collision.GetComponent<Enemy>();//获取敌人
SwordSkillDamage(enemy);
}
SetupTargetsForBounce(collision);
StuckInto(collision);
}
private void SwordSkillDamage(Enemy enemy)
{
//enemy.DamageEffect();
player.stats.DoDamage(enemy.GetComponent<CharacterStats>());
enemy.StartCoroutine("FreezeTimerFor", freezeTimeDUration);
ItemData_Equipment equipedAmulet = Inventory.instance.GetEquipment(EquipmentType.Amulet);//获取护身符
if (equipedAmulet != null)
equipedAmulet.Effect(enemy.transform);//如果有护身符,就对敌人造成额外伤害
}
private void SetupTargetsForBounce(Collider2D collision)
{
if (collision.GetComponent<Enemy>() != null)//碰到敌人
{
if (isBouncing && enemyTarget.Count <= 0)//如果可以反弹并且敌人目标数量小于等于0
{
Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, 10);//获取周围敌人的碰撞体
foreach (var hit in colliders)//遍历周围敌人的碰撞体
{
if (hit.GetComponent<Enemy>() != null)//如果碰到的是敌人
{
enemyTarget.Add(hit.transform);//添加到敌人目标
}
}
}
}
}
private void StuckInto(Collider2D collision)//碰撞时候的处理
{
if (pierceAmount > 0 && collision.GetComponent<Enemy>() != null)//如果可以穿透并且碰到敌人
{
pierceAmount--;
return;
}
if (isSpinning)
{
StopWhenSpinning();//注释掉经过敌人不会停止
return;
}
canRotate = false; // 停止旋转
cd.enabled = false;// 禁用碰撞体
rb.isKinematic = true;// 设置刚体为运动学模式
rb.constraints = RigidbodyConstraints2D.FreezeAll;// 冻结刚体的所有约束
if (isBouncing && enemyTarget.Count > 0) // 如果可以反弹并且敌人目标数量大于0
return;
anim.SetBool("Rotation", false);
transform.parent = collision.transform;// 将当前物体设为碰撞对象的子对象,即粘在敌人身上
}
}
Crystal_Skill_Controller.cs
修改部分
private void AnimationExplodeEvent()//可以放在动画触发器里面
{
Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, cd.radius);//从克隆控制器粘贴上的
foreach (var hit in colliders)
{
if (hit.GetComponent<Enemy>() != null)
player.stats.DoMagicDamage(hit.GetComponent<CharacterStats>());//加上魔法伤害
ItemData_Equipment equipedAmulet = Inventory.instance.GetEquipment(EquipmentType.Amulet) ;//获取护身符
if (equipedAmulet != null)
equipedAmulet.Effect(hit.transform);//如果有护身符,就对敌人造成额外伤害
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Crystal_Skill_Controller : MonoBehaviour //放在水晶得预制件里面
{
private Animator anim => GetComponent<Animator>(); //引用是为了在更新中使用SetTrigger
private CircleCollider2D cd => GetComponent<CircleCollider2D>();//为了完成爆炸伤害
private Player player;// 2024年10月30日,给技能加上伤害
private float crystalExistTimer;//消失计时器
private bool canExplode ;//是否可以爆炸
private bool canMove;
private float moveSpeed;
private bool canGrow;
private float growSpeed = 5;
private Transform closetTarget;
[SerializeField] private LayerMask whatIsEnemy;
public void SetupCrystal(float _crystalDuration,bool _canExplode,bool _canMove,float _moveSpeed,Transform _closetTarget,Player _player)
{
player = _player;
crystalExistTimer = _crystalDuration;//放置水晶,然后开始计时
canExplode = _canExplode;
canMove = _canMove;
moveSpeed = _moveSpeed;
closetTarget=_closetTarget;
}
public void ChooseRandomEnemy()
{
float radius = SkillManager.instance.blackhole.GetBlackholeRadius();//从黑洞控制器中获取黑洞半径
Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, radius, whatIsEnemy);//选取周围所有的碰撞体
if(colliders.Length > 0)
closetTarget = colliders[Random.Range(0, colliders.Length)].transform;//随机选取一个敌人
}
private void Update()
{
crystalExistTimer -= Time.deltaTime;//控制器起码能控制时间吧
if (crystalExistTimer < 0)
{
//Destroy(gameObject); 新增的功能,水晶消失后可以爆炸,所以检查是否可以爆炸
FinishCrystal();
}
if (canMove)//移动到敌人的逻辑函数
{
if (closetTarget == null)
return;//防止拾取物品时候出现bug
transform.position = Vector2.MoveTowards(transform.position, closetTarget.position, moveSpeed * Time.deltaTime);//水晶移动到敌人位置(这里是最近敌人位置)
if (Vector2.Distance(transform.position, closetTarget.position) < .5f)//如果水晶到达敌人位置
{
FinishCrystal();
canMove = false;
}
}
if (canGrow)//和上面函数优先级?
transform.localScale = Vector2.Lerp(transform.localScale, new Vector2(3,3), growSpeed * Time.deltaTime);//水晶变大
}
private void AnimationExplodeEvent()//可以放在动画触发器里面
{
Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, cd.radius);//从克隆控制器粘贴上的
foreach (var hit in colliders)
{
if (hit.GetComponent<Enemy>() != null)
player.stats.DoMagicDamage(hit.GetComponent<CharacterStats>());//加上魔法伤害
ItemData_Equipment equipedAmulet = Inventory.instance.GetEquipment(EquipmentType.Amulet) ;//获取护身符
if (equipedAmulet != null)
equipedAmulet.Effect(hit.transform);//如果有护身符,就对敌人造成额外伤害
}
}
public void FinishCrystal()
{
if (canExplode)
{
canGrow = true;
anim.SetTrigger("Explode");
}
else
SelfDestroy();
}
public void SelfDestroy() => Destroy(gameObject);
}