法杖,武器切换
This commit is contained in:
@@ -14,7 +14,7 @@ using Random = UnityEngine.Random;
|
||||
|
||||
namespace Cielonos.MainGame
|
||||
{
|
||||
public abstract partial class AttackAreaBase : MonoBehaviour
|
||||
public abstract partial class AttackAreaBase : SerializedMonoBehaviour
|
||||
{
|
||||
private static Dictionary<string, int> areaNameCountDictionary = new Dictionary<string, int>();
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace Cielonos.MainGame
|
||||
public Action updateAction;
|
||||
|
||||
[Title("Submodules")]
|
||||
[HideInEditorMode] public TransformSubmodule transformSm;
|
||||
[HideInEditorMode] public AttackSubmodule attackSm;
|
||||
[HideInEditorMode] public TimeSubmodule timeSm;
|
||||
[HideInEditorMode] public HitSubmodule hitSm;
|
||||
@@ -96,12 +97,19 @@ namespace Cielonos.MainGame
|
||||
}
|
||||
|
||||
this.SetReactionSubmodule<T>();
|
||||
|
||||
BattleManager.AttackAreaSm.Register(this);
|
||||
topParent.GetComponent<VFXObject>().onDespawnAction = () =>
|
||||
{
|
||||
BattleManager.AttackAreaSm.Unregister(this);
|
||||
};
|
||||
|
||||
return this as T;
|
||||
}
|
||||
|
||||
protected virtual void Update()
|
||||
{
|
||||
transformSm?.Update();
|
||||
raycastSm?.Update();
|
||||
updateAction?.Invoke();
|
||||
hitSm?.Update();
|
||||
@@ -112,6 +120,16 @@ namespace Cielonos.MainGame
|
||||
|
||||
public partial class AttackAreaBase
|
||||
{
|
||||
#region TransformSubmodule
|
||||
|
||||
public T SetTransformSubmodule<T>(Transform target = null, float delay = 0) where T : AttackAreaBase
|
||||
{
|
||||
transformSm = new TransformSubmodule(this, target, delay);
|
||||
return this as T;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region AttackSubmodule
|
||||
public T SetAttackSubmodule<T>(AttackUnit attackUnit, GameObject hitVFX = null) where T : AttackAreaBase
|
||||
{
|
||||
@@ -163,10 +181,41 @@ namespace Cielonos.MainGame
|
||||
|
||||
#region TraceMoveModule
|
||||
|
||||
public T SetTraceMoveModule<T>(CharacterBase target, float moveSpeed, float moveAcceleration,
|
||||
/// <summary>
|
||||
/// 设置自适应追踪移动子模块,根据和目标的距离自动连接和断开追踪
|
||||
/// 断开追踪后,自动选择范围内最近的目标进行追踪
|
||||
/// </summary>
|
||||
public T SetAdaptiveTraceMoveModule<T>(CharacterBase target, float moveSpeed, float moveAcceleration,
|
||||
float angularSpeed, float angularAcceleration, Vector3 initialDirection,
|
||||
bool autoConnect = true, bool autoDisconnect = true, float detectRadius = 10f, bool stopWhenHit = true) where T : AttackAreaBase
|
||||
{
|
||||
moveSm = new TraceMoveSubmodule(this, target, moveSpeed, moveAcceleration, angularSpeed,
|
||||
angularAcceleration, initialDirection, autoConnect, autoDisconnect, detectRadius, stopWhenHit);
|
||||
return this as T;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置不可更改目标的追踪移动子模块
|
||||
/// 永远追踪指定目标,不会断开
|
||||
/// </summary>
|
||||
public T SetUnchangeableTraceMoveModule<T>(CharacterBase target, float moveSpeed, float moveAcceleration,
|
||||
float angularSpeed, float angularAcceleration, Vector3 initialDirection, bool stopWhenHit = true) where T : AttackAreaBase
|
||||
{
|
||||
moveSm = new TraceMoveSubmodule(this, target, moveSpeed, moveAcceleration, angularSpeed, angularAcceleration, initialDirection, stopWhenHit);
|
||||
moveSm = new TraceMoveSubmodule(this, target, moveSpeed, moveAcceleration, angularSpeed,
|
||||
angularAcceleration, initialDirection, false, false, 0, stopWhenHit);
|
||||
return this as T;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置可分离目标的追踪移动子模块
|
||||
/// 一旦目标超出检测范围则断开追踪,断开后不再追踪其他目标
|
||||
/// </summary>
|
||||
public T SeDetachableTraceMoveModule<T>(CharacterBase target, float moveSpeed, float moveAcceleration,
|
||||
float angularSpeed, float angularAcceleration, Vector3 initialDirection,
|
||||
float detectRadius = 10f, bool stopWhenHit = true) where T : AttackAreaBase
|
||||
{
|
||||
moveSm = new TraceMoveSubmodule(this, target, moveSpeed, moveAcceleration, angularSpeed,
|
||||
angularAcceleration, initialDirection, false, true, detectRadius, stopWhenHit);
|
||||
return this as T;
|
||||
}
|
||||
|
||||
|
||||
@@ -96,8 +96,13 @@ namespace Cielonos.MainGame
|
||||
}
|
||||
}
|
||||
|
||||
public void Explode(Vector3 hitPosition)
|
||||
public void Explode(Vector3 hitPosition = default)
|
||||
{
|
||||
if (hitPosition == default)
|
||||
{
|
||||
hitPosition = transform.position;
|
||||
}
|
||||
|
||||
GenerateHitEffect(hitPosition);
|
||||
PlaySoundFX(hitPosition);
|
||||
LeanPool.Despawn(topParent.gameObject);
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Cielonos.MainGame
|
||||
Vector3 point1 = owner.transform.position - rayDirection.normalized * capsuleHeight;
|
||||
Collider[] hitColliders = new Collider[8];
|
||||
int size = Physics.OverlapCapsuleNonAlloc(point0, point1, capsuleRadius, hitColliders,
|
||||
LayerMask.GetMask("Player", "Enemy", "Default", "FadableEnvironment", "UnfadableEnvironment", "Wall", "Ground"));
|
||||
LayerMask.GetMask("HurtBox", "Default", "FadableEnvironment", "UnfadableEnvironment", "Wall", "Ground"));
|
||||
if (size >= 1)
|
||||
{
|
||||
Debug.Log("RaycastSubmodule detected colliders: " + size);
|
||||
@@ -74,7 +74,7 @@ namespace Cielonos.MainGame
|
||||
else
|
||||
{
|
||||
if (Physics.Raycast(ray, out RaycastHit hit, rayLength,
|
||||
LayerMask.GetMask("Player", "Enemy", "Default", "FadableEnvironment", "UnfadableEnvironment", "Wall", "Ground")))
|
||||
LayerMask.GetMask("HurtBox", "Default", "FadableEnvironment", "UnfadableEnvironment", "Wall", "Ground")))
|
||||
{
|
||||
onHit?.Invoke(hit.collider, hit.point);
|
||||
}
|
||||
|
||||
@@ -3,26 +3,34 @@ using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame
|
||||
{
|
||||
public class TraceMoveSubmodule : MoveSubmoduleBase
|
||||
public partial class TraceMoveSubmodule : MoveSubmoduleBase
|
||||
{
|
||||
public Transform projectile => owner.topParent;
|
||||
public CharacterBase target;
|
||||
public Transform targetTransform;
|
||||
public float angularSpeed;
|
||||
public float angularAcceleration;
|
||||
public float moveSpeed;
|
||||
public float moveAcceleration;
|
||||
|
||||
public bool autoConnect;
|
||||
public bool autoDisconnect;
|
||||
public float detectRadius;
|
||||
|
||||
private float deltaTime => owner.creator.selfTimeSm.DeltaTime;
|
||||
private Vector3 step;
|
||||
|
||||
public TraceMoveSubmodule(AttackAreaBase attackArea, CharacterBase target, float moveSpeed, float moveAcceleration,
|
||||
float angularSpeed, float angularAcceleration, Vector3 initialDirection, bool stopWhenHit) : base(attackArea, stopWhenHit)
|
||||
public TraceMoveSubmodule(AttackAreaBase attackArea, CharacterBase target,
|
||||
float moveSpeed, float moveAcceleration, float angularSpeed, float angularAcceleration, Vector3 initialDirection,
|
||||
bool autoConnect, bool autoDisconnect, float detectRadius, bool stopWhenHit) : base(attackArea, stopWhenHit)
|
||||
{
|
||||
this.target = target;
|
||||
this.targetTransform = target != null ? target.transform : null;
|
||||
this.angularSpeed = angularSpeed;
|
||||
this.angularAcceleration = angularAcceleration;
|
||||
this.moveSpeed = moveSpeed;
|
||||
this.moveAcceleration = moveAcceleration;
|
||||
this.autoConnect = autoConnect;
|
||||
this.autoDisconnect = autoDisconnect;
|
||||
this.detectRadius = detectRadius;
|
||||
projectile.forward = initialDirection;
|
||||
}
|
||||
|
||||
@@ -30,16 +38,29 @@ namespace Cielonos.MainGame
|
||||
{
|
||||
if (target == null || target.statusSm.isDead)
|
||||
{
|
||||
moveSpeed += moveAcceleration * Time.deltaTime;
|
||||
moveSpeed += moveAcceleration * deltaTime;
|
||||
moveSpeed = Mathf.Max(moveSpeed, 0f);
|
||||
unscaledVelocity = projectile.forward * moveSpeed;
|
||||
scaledVelocity = unscaledVelocity * timeScaleCoefficient; //attackArea.creator.selfTimeModule
|
||||
projectile.position += scaledVelocity * Time.deltaTime;
|
||||
scaledVelocity = timeScaleCoefficient * unscaledVelocity;
|
||||
projectile.position += scaledVelocity * deltaTime;
|
||||
|
||||
if (autoConnect)
|
||||
{
|
||||
if (owner.creator == MainGameManager.Player)
|
||||
{
|
||||
CharacterBase detectEnemy = BattleManager.EnemySm.GetNearestEnemy(detectRadius, owner.transform);
|
||||
if (detectEnemy != null)
|
||||
{
|
||||
target = detectEnemy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
angularSpeed += angularAcceleration * Time.deltaTime;
|
||||
moveSpeed += moveAcceleration * Time.deltaTime;
|
||||
angularSpeed += angularAcceleration * deltaTime;
|
||||
moveSpeed += moveAcceleration * deltaTime;
|
||||
angularSpeed = Mathf.Max(angularSpeed, 0f);
|
||||
moveSpeed = Mathf.Max(moveSpeed, 0f);
|
||||
|
||||
@@ -48,12 +69,21 @@ namespace Cielonos.MainGame
|
||||
{
|
||||
Quaternion targetRotation = Quaternion.LookRotation(direction);
|
||||
// RotateTowards 保证恒定转速,不会因为角度小而变慢
|
||||
projectile.rotation = Quaternion.RotateTowards(projectile.rotation, targetRotation, angularSpeed * Time.deltaTime);
|
||||
projectile.rotation = Quaternion.RotateTowards(projectile.rotation, targetRotation, angularSpeed * deltaTime);
|
||||
}
|
||||
|
||||
unscaledVelocity = projectile.forward * moveSpeed;
|
||||
scaledVelocity = unscaledVelocity * timeScaleCoefficient; //attackArea.creator.selfTimeModule.EntityDeltaTime);
|
||||
projectile.position += scaledVelocity * Time.deltaTime;
|
||||
scaledVelocity = unscaledVelocity * timeScaleCoefficient;
|
||||
projectile.position += scaledVelocity * deltaTime;
|
||||
|
||||
if (autoDisconnect)
|
||||
{
|
||||
float distanceToTarget = Vector3.Distance(projectile.position, target.flexibleCenterPoint.position);
|
||||
if (distanceToTarget > detectRadius)
|
||||
{
|
||||
target = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
using SLSFramework.General;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame
|
||||
{
|
||||
public partial class TransformSubmodule : AttackAreaSubmoduleBase
|
||||
{
|
||||
public Transform targetTransform;
|
||||
public float delay;
|
||||
public float timer;
|
||||
|
||||
public bool applyPosition;
|
||||
public float positionMoveDuration;
|
||||
public EaseType positionEaseType;
|
||||
public Vector3 startPosition;
|
||||
public Vector3 endPosition;
|
||||
private AnimationCurve positionCurve;
|
||||
|
||||
public bool applyRotation;
|
||||
public float rotationMoveDuration;
|
||||
public EaseType rotationEaseType;
|
||||
public Vector3 startEulerAngles;
|
||||
public Vector3 endEulerAngles;
|
||||
private AnimationCurve rotationCurve;
|
||||
|
||||
public bool applyScale;
|
||||
public float scaleMoveDuration;
|
||||
public EaseType scaleEaseType;
|
||||
public Vector3 startScale;
|
||||
public Vector3 endScale;
|
||||
private AnimationCurve scaleCurve;
|
||||
|
||||
public TransformSubmodule(AttackAreaBase attackArea, Transform targetTransform = null, float delay = 0f) : base(attackArea)
|
||||
{
|
||||
this.targetTransform = targetTransform ?? attackArea.topParent.transform;
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
public AttackAreaBase ApplyPositionMove(Vector3 startPosition, Vector3 endPosition, float duration, EaseType easeType = EaseType.Linear)
|
||||
{
|
||||
this.applyPosition = true;
|
||||
this.startPosition = startPosition;
|
||||
this.endPosition = endPosition;
|
||||
this.positionMoveDuration = duration;
|
||||
this.positionEaseType = easeType;
|
||||
this.positionCurve = Ease.GetCurve(easeType);
|
||||
return attackArea;
|
||||
}
|
||||
|
||||
public AttackAreaBase ApplyRotationMove(Vector3 startEulerAngles, Vector3 endEulerAngles, float duration, EaseType easeType = EaseType.Linear)
|
||||
{
|
||||
this.applyRotation = true;
|
||||
this.startEulerAngles = startEulerAngles;
|
||||
this.endEulerAngles = endEulerAngles;
|
||||
this.rotationMoveDuration = duration;
|
||||
this.rotationEaseType = easeType;
|
||||
this.rotationCurve = Ease.GetCurve(easeType);
|
||||
return attackArea;
|
||||
}
|
||||
|
||||
public AttackAreaBase ApplyScaleMove(Vector3 startScale, Vector3 endScale, float duration, EaseType easeType = EaseType.Linear)
|
||||
{
|
||||
this.applyScale = true;
|
||||
this.startScale = startScale;
|
||||
this.endScale = endScale;
|
||||
this.scaleMoveDuration = duration;
|
||||
this.scaleEaseType = easeType;
|
||||
this.scaleCurve = Ease.GetCurve(easeType);
|
||||
return attackArea;
|
||||
}
|
||||
}
|
||||
|
||||
public partial class TransformSubmodule
|
||||
{
|
||||
public virtual void Update()
|
||||
{
|
||||
if(timer > Mathf.Max(positionMoveDuration, rotationMoveDuration, scaleMoveDuration))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float deltaTime = attackArea.creator != null ? attackArea.creator.selfTimeSm.DeltaTime : Time.deltaTime;
|
||||
if (delay > 0f)
|
||||
{
|
||||
delay -= deltaTime;
|
||||
return;
|
||||
}
|
||||
|
||||
timer += deltaTime;
|
||||
|
||||
if (applyPosition)
|
||||
{
|
||||
float t = Mathf.Clamp01(timer / positionMoveDuration);
|
||||
t = positionCurve.Evaluate(t);
|
||||
attackArea.topParent.transform.localPosition = Vector3.LerpUnclamped(startPosition, endPosition, t);
|
||||
}
|
||||
|
||||
if (applyRotation)
|
||||
{
|
||||
float t = Mathf.Clamp01(timer / rotationMoveDuration);
|
||||
t = rotationCurve.Evaluate(t);
|
||||
Vector3 currentEulerAngles = Vector3.LerpUnclamped(startEulerAngles, endEulerAngles, t);
|
||||
attackArea.topParent.transform.localRotation = Quaternion.Euler(currentEulerAngles);
|
||||
}
|
||||
|
||||
if (applyScale)
|
||||
{
|
||||
float t = Mathf.Clamp01(timer / scaleMoveDuration);
|
||||
t = scaleCurve.Evaluate(t);
|
||||
attackArea.topParent.transform.localScale = Vector3.LerpUnclamped(startScale, endScale, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3fab41e279f53e64581303af20901fbd
|
||||
@@ -211,7 +211,7 @@ namespace Cielonos.MainGame.Characters
|
||||
.SetAttackSubmodule<Projectile>(attackData["ShockwaveMissile"])
|
||||
.SetTimeSubmodule<Projectile>(5f)
|
||||
.SetHitSubmodule<Projectile>()
|
||||
.SetTraceMoveModule<Projectile>(player, 20f, -2f, 60f, -10f, bulletSpawnerTransform.forward, false)
|
||||
.SeDetachableTraceMoveModule<Projectile>(player, 20f, -2f, 60f, -10f, bulletSpawnerTransform.forward)
|
||||
.SetRaycastSubmodule<Projectile>(default, 0.1f, 0.2f)
|
||||
.SetForceSubmodule<Projectile>(1f)
|
||||
.SetReactionSubmodule<Projectile>(false, false, false, true, false, false);
|
||||
|
||||
@@ -32,8 +32,9 @@ namespace Cielonos.MainGame.Characters
|
||||
public void EquipMainWeapon(MainWeaponBase newWeapon)
|
||||
{
|
||||
currentMainWeapon = newWeapon;
|
||||
currentMainWeapon.OnEquipped();
|
||||
currentMainWeapon.RegisterFullBodyFuncAnims();
|
||||
currentMainWeapon.OnEquipped();
|
||||
|
||||
|
||||
PlayerCanvas.Instance.mainWeaponUIArea.Initialize(currentMainWeapon);
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@ namespace Cielonos.MainGame.Inventory
|
||||
public List<FuncAnimData> fullBodyFuncAnims = new List<FuncAnimData>();
|
||||
[HideInInspector]
|
||||
private List<string> registeredFunctionNames = new List<string>();
|
||||
|
||||
[FormerlySerializedAs("objectData")]
|
||||
public ViewObjectData viewObjectData;
|
||||
public VFXData vfxData;
|
||||
public ComboData comboData;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using Cielonos.MainGame.Characters;
|
||||
using SLSFramework.General;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame.Inventory
|
||||
@@ -9,7 +11,9 @@ namespace Cielonos.MainGame.Inventory
|
||||
public override void OnEquipped()
|
||||
{
|
||||
base.OnEquipped();
|
||||
RegisterFunctionsToAnimSc(SwingForward, SwingDown, LightAttack0, LightAttack1_0, LightAttack1_1, LightAttack2, LightAttack3, HeavyAttack);
|
||||
RegisterFunctionsToAnimSc(SwingForward, SwingDown, LightAttack0, LightAttack1_0, LightAttack1_1,
|
||||
LightAttack2, LightAttack3, HeavyAttack, ReleaseAura);
|
||||
PlayTargetedAnimation("Equip");
|
||||
}
|
||||
|
||||
public override void OnPrimaryPress()
|
||||
@@ -25,7 +29,7 @@ namespace Cielonos.MainGame.Inventory
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayTargetedAnimation("LightAttack" + comboSm.GetCurrentNodeName(), null, 5f);
|
||||
PlayTargetedAnimation("LightAttack" + comboSm.GetCurrentNodeName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,6 +61,7 @@ namespace Cielonos.MainGame.Inventory
|
||||
private void LightAttack2() => GenerateProjectile("NormalProjectile", currentTarget, 10f);
|
||||
private void LightAttack3() => GenerateProjectile("HeavyProjectile", currentTarget, 10f);
|
||||
private void HeavyAttack() => GenerateGroundArea("GroundArea");
|
||||
private void ReleaseAura() => GenerateSquareExpandingAura("SquareExpandingAura");
|
||||
}
|
||||
|
||||
public partial class FutureWand : MainWeaponBase
|
||||
@@ -69,7 +74,6 @@ namespace Cielonos.MainGame.Inventory
|
||||
private void SwingForward()
|
||||
{
|
||||
Swing("Swing", "Swing", Vector3.forward * 0.2f);
|
||||
Debug.Log("SwingForward executed");
|
||||
}
|
||||
|
||||
private void SwingDown() => Swing("Swing", "Swing", Vector3.down * 0.3f);
|
||||
@@ -93,8 +97,8 @@ namespace Cielonos.MainGame.Inventory
|
||||
.SetAttackSubmodule<Projectile>(attackUnit)
|
||||
.SetTimeSubmodule<Projectile>(10f)
|
||||
.SetHitSubmodule<Projectile>()
|
||||
.SetTraceMoveModule<Projectile>(currentTarget, speed, 5f, 20f, 20f, direction)
|
||||
.SetRaycastSubmodule<Projectile>()
|
||||
.SetAdaptiveTraceMoveModule<Projectile>(currentTarget, speed, 5f, 20f, 20f, direction)
|
||||
.SetRaycastSubmodule<Projectile>(default, 0.25f, 0.5f)
|
||||
.SetForceSubmodule<Projectile>(5f);
|
||||
|
||||
audioContainer.PlaySoundFX(vfxName + "Release", projectile.gameObject, true);
|
||||
@@ -113,7 +117,7 @@ namespace Cielonos.MainGame.Inventory
|
||||
|
||||
area.Initialize<NormalArea>(player, this, Fraction.Enemy)
|
||||
.SetAttackSubmodule<NormalArea>(attackUnit)
|
||||
.SetTimeSubmodule<NormalArea>(1f, 0.8f, 0.2f)
|
||||
.SetTimeSubmodule<NormalArea>(1f, 0.2f, 0.8f)
|
||||
.SetHitSubmodule<NormalArea>(0.1f, 5)
|
||||
.SetForceSubmodule<NormalArea>(5f, false);
|
||||
|
||||
@@ -122,5 +126,44 @@ namespace Cielonos.MainGame.Inventory
|
||||
area.hitSm.AddHitSound("NormalHit")
|
||||
.AddHitEvent((enemy, hitPosition) => feedbackSc["Hit"].Play());
|
||||
}
|
||||
|
||||
private void GenerateSquareExpandingAura(string vfxName)
|
||||
{
|
||||
vfxData.SpawnMuzzleVFX(vfxName, muzzle);
|
||||
NormalArea area = vfxData.SpawnVFX(vfxName).GetComponentInChildren<NormalArea>();
|
||||
|
||||
AttackUnit attackUnit = attackData["LightAttack"].Clone();
|
||||
attackUnit.hitVFX = vfxData.Get(vfxName).hitVFX;
|
||||
|
||||
area.Initialize<NormalArea>(player, this, Fraction.Enemy)
|
||||
.SetAttackSubmodule<NormalArea>(attackUnit)
|
||||
.SetTimeSubmodule<NormalArea>(4f, 0.2f, 2.8f)
|
||||
.SetHitSubmodule<NormalArea>()
|
||||
.SetTransformSubmodule<NormalArea>();
|
||||
|
||||
area.transformSm.ApplyScaleMove(Vector3.one, Vector3.one * 50, 1f, EaseType.OutQuart);
|
||||
area.updateAction = () =>
|
||||
{
|
||||
if (area.timeSm.enablingTime > 3f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<Projectile> toBeRemoved = new List<Projectile>();
|
||||
|
||||
foreach (Projectile projectile in BattleManager.AttackAreaSm.enemyAttackAreas.activeProjectiles)
|
||||
{
|
||||
if (area.areaCollider.IsPointInside(projectile.topParent.transform.position))
|
||||
{
|
||||
toBeRemoved.Add(projectile);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Projectile projectile in toBeRemoved)
|
||||
{
|
||||
projectile.Explode();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace Cielonos.MainGame.Inventory
|
||||
{
|
||||
public partial class Polychrome : MainWeaponBase
|
||||
{
|
||||
public BlockData equipBlockData;
|
||||
public float perfectBlockedTimer;
|
||||
|
||||
protected override void Update()
|
||||
@@ -26,8 +27,11 @@ namespace Cielonos.MainGame.Inventory
|
||||
LightAttack0, LightAttack1, LightAttack2, LightAttack3,
|
||||
TripleAttack_0, TripleAttack_1, TripleAttack_2,
|
||||
DisruptAttack, HeavyAttack, RunAttack, ParryAttack, StayBlocking);
|
||||
|
||||
SetBlock(equipBlockData);
|
||||
}
|
||||
|
||||
|
||||
public override void OnPrimaryPress()
|
||||
{
|
||||
if (player.inputSc.IsHoldingSpecialA && functionSm["TripleAttack"].IsAvailable() && fullBodyFuncAnimSm.CheckPlayability())
|
||||
@@ -296,8 +300,9 @@ namespace Cielonos.MainGame.Inventory
|
||||
|
||||
string parryAnimName = "ParryL";
|
||||
|
||||
private void SetBlock()
|
||||
private void SetBlock(BlockData blockData = null)
|
||||
{
|
||||
blockData ??= this.blockData;
|
||||
BlockSource blockSource = blockData.CreateBlockSource(player, this);
|
||||
blockSource.onNormalBlock = (attackArea) =>
|
||||
{
|
||||
|
||||
8
Assets/Scripts/MainGame/Managers/BattleManager.meta
Normal file
8
Assets/Scripts/MainGame/Managers/BattleManager.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 227a01888e283184ca2c520daf8ac212
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,89 @@
|
||||
using System.Collections.Generic;
|
||||
using Cielonos.MainGame.Characters;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame
|
||||
{
|
||||
public partial class BattleManager
|
||||
{
|
||||
public class AttackAreaSubmodule : SubmoduleBase<BattleManager>
|
||||
{
|
||||
public AttackAreaCollection playerAttackAreas;
|
||||
public AttackAreaCollection enemyAttackAreas;
|
||||
|
||||
public AttackAreaSubmodule(BattleManager owner) : base(owner)
|
||||
{
|
||||
playerAttackAreas = new AttackAreaCollection();
|
||||
enemyAttackAreas = new AttackAreaCollection();
|
||||
}
|
||||
|
||||
public void Register(AttackAreaBase attackArea)
|
||||
{
|
||||
if (attackArea.creator.fraction == Fraction.Player)
|
||||
{
|
||||
Debug.Log($"Registered AttackArea: {attackArea.areaName}");
|
||||
playerAttackAreas.Add(attackArea);
|
||||
}
|
||||
else if (attackArea.creator.fraction == Fraction.Enemy)
|
||||
{
|
||||
enemyAttackAreas.Add(attackArea);
|
||||
}
|
||||
}
|
||||
|
||||
public void Unregister(AttackAreaBase attackArea)
|
||||
{
|
||||
if (attackArea.creator.fraction == Fraction.Player)
|
||||
{
|
||||
Debug.Log($"Unregistered AttackArea: {attackArea.areaName}");
|
||||
playerAttackAreas.Remove(attackArea);
|
||||
}
|
||||
else if (attackArea.creator.fraction == Fraction.Enemy)
|
||||
{
|
||||
enemyAttackAreas.Remove(attackArea);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class AttackAreaCollection
|
||||
{
|
||||
public List<AttackAreaBase> activeAttackAreas;
|
||||
public List<NormalArea> activeNormalAreas;
|
||||
public List<Projectile> activeProjectiles;
|
||||
|
||||
public AttackAreaCollection()
|
||||
{
|
||||
activeAttackAreas = new List<AttackAreaBase>();
|
||||
activeNormalAreas = new List<NormalArea>();
|
||||
activeProjectiles = new List<Projectile>();
|
||||
}
|
||||
|
||||
public void Add(AttackAreaBase attackArea)
|
||||
{
|
||||
activeAttackAreas.Add(attackArea);
|
||||
|
||||
if (attackArea is NormalArea normalArea)
|
||||
{
|
||||
activeNormalAreas.Add(normalArea);
|
||||
}
|
||||
else if (attackArea is Projectile projectile)
|
||||
{
|
||||
activeProjectiles.Add(projectile);
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove(AttackAreaBase attackArea)
|
||||
{
|
||||
activeAttackAreas.Remove(attackArea);
|
||||
|
||||
if (attackArea is NormalArea normalArea)
|
||||
{
|
||||
activeNormalAreas.Remove(normalArea);
|
||||
}
|
||||
else if (attackArea is Projectile projectile)
|
||||
{
|
||||
activeProjectiles.Remove(projectile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e21e9325e65fefa42924ff1f8880d266
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Cielonos.MainGame.Characters;
|
||||
using Sirenix.OdinInspector;
|
||||
using SLSFramework.General;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame
|
||||
{
|
||||
public partial class BattleManager : Singleton<BattleManager>
|
||||
{
|
||||
private static Player Player => MainGameManager.Player;
|
||||
|
||||
[ShowInInspector]
|
||||
private EnemySubmodule enemySm;
|
||||
|
||||
[ShowInInspector]
|
||||
private AttackAreaSubmodule attackAreaSm;
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
enemySm ??= new EnemySubmodule(this);
|
||||
attackAreaSm ??= new AttackAreaSubmodule(this);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class BattleManager
|
||||
{
|
||||
public static EnemySubmodule EnemySm => Instance.enemySm;
|
||||
public static AttackAreaSubmodule AttackAreaSm => Instance.attackAreaSm;
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Cielonos.MainGame.Characters;
|
||||
using Sirenix.OdinInspector;
|
||||
using SLSFramework.General;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame
|
||||
{
|
||||
public partial class BattleManager : Singleton<BattleManager>
|
||||
{
|
||||
private static Player Player => MainGameManager.Player;
|
||||
|
||||
[ShowInInspector]
|
||||
private EnemySubmodule enemySm;
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
enemySm ??= new EnemySubmodule(this);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class BattleManager
|
||||
{
|
||||
public static EnemySubmodule EnemySm => Instance.enemySm;
|
||||
}
|
||||
|
||||
public partial class BattleManager
|
||||
{
|
||||
public class EnemySubmodule : SubmoduleBase<BattleManager>
|
||||
@@ -98,4 +76,4 @@ namespace Cielonos.MainGame
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cfa83226b5985464ebb62c8b756c514d
|
||||
85
Assets/Scripts/SLSFramework/General/ColliderExtensions.cs
Normal file
85
Assets/Scripts/SLSFramework/General/ColliderExtensions.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace SLSFramework.General
|
||||
{
|
||||
public static class ColliderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 判断一个世界坐标点是否在 BoxCollider 内部(支持旋转和缩放)
|
||||
/// </summary>
|
||||
public static bool IsPointInside(this BoxCollider box, Vector3 worldPoint)
|
||||
{
|
||||
// 1. 将世界坐标转为该 Collider 的本地坐标(处理了旋转和位置)
|
||||
Vector3 localPoint = box.transform.InverseTransformPoint(worldPoint);
|
||||
|
||||
// 2. 减去中心偏移
|
||||
localPoint -= box.center;
|
||||
|
||||
// 3. 计算实际的半长宽高(考虑 LossyScale 缩放)
|
||||
// 注意:BoxCollider 的 size 已经包含了本地缩放,InverseTransformPoint 已经处理了缩放的影响
|
||||
Vector3 halfSize = box.size * 0.5f;
|
||||
|
||||
// 4. AABB 判定
|
||||
return Mathf.Abs(localPoint.x) <= halfSize.x &&
|
||||
Mathf.Abs(localPoint.y) <= halfSize.y &&
|
||||
Mathf.Abs(localPoint.z) <= halfSize.z;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断一个世界坐标点是否在 SphereCollider 内部
|
||||
/// </summary>
|
||||
public static bool IsPointInside(this SphereCollider sphere, Vector3 worldPoint)
|
||||
{
|
||||
// 考虑中心偏移的世界坐标中心点
|
||||
Vector3 center = sphere.transform.TransformPoint(sphere.center);
|
||||
|
||||
// 计算缩放后的实际半径(Unity 以三个轴中缩放最大的为准)
|
||||
Vector3 lossyScale = sphere.transform.lossyScale;
|
||||
float maxScale = Mathf.Max(lossyScale.x, Mathf.Max(lossyScale.y, lossyScale.z));
|
||||
float scaledRadius = sphere.radius * maxScale;
|
||||
|
||||
// 距离平方判定,性能最高
|
||||
float sqrDistance = (worldPoint - center).sqrMagnitude;
|
||||
return sqrDistance <= (scaledRadius * scaledRadius);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断一个世界坐标点是否在 CapsuleCollider 内部
|
||||
/// </summary>
|
||||
public static bool IsPointInside(this CapsuleCollider capsule, Vector3 worldPoint)
|
||||
{
|
||||
// 转为本地坐标
|
||||
Vector3 localPoint = capsule.transform.InverseTransformPoint(worldPoint);
|
||||
localPoint -= capsule.center;
|
||||
|
||||
// 计算胶囊体内部中心轴线的半高度(不含两头的半圆)
|
||||
float radius = capsule.radius;
|
||||
float halfHeight = Mathf.Max(0f, (capsule.height * 0.5f) - radius);
|
||||
|
||||
// 根据方向计算点到中心线段的最短距离
|
||||
// direction: 0 = X, 1 = Y, 2 = Z
|
||||
Vector3 closestPointOnAxis = Vector3.zero;
|
||||
switch (capsule.direction)
|
||||
{
|
||||
case 0: closestPointOnAxis.x = Mathf.Clamp(localPoint.x, -halfHeight, halfHeight); break;
|
||||
case 1: closestPointOnAxis.y = Mathf.Clamp(localPoint.y, -halfHeight, halfHeight); break;
|
||||
case 2: closestPointOnAxis.z = Mathf.Clamp(localPoint.z, -halfHeight, halfHeight); break;
|
||||
}
|
||||
|
||||
return (localPoint - closestPointOnAxis).sqrMagnitude <= (radius * radius);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通用入口:根据 Collider 类型自动选择检测方法
|
||||
/// </summary>
|
||||
public static bool IsPointInside(this Collider collider, Vector3 worldPoint)
|
||||
{
|
||||
if (collider is BoxCollider box) return box.IsPointInside(worldPoint);
|
||||
if (collider is SphereCollider sphere) return sphere.IsPointInside(worldPoint);
|
||||
if (collider is CapsuleCollider capsule) return capsule.IsPointInside(worldPoint);
|
||||
|
||||
// 如果是 MeshCollider 等复杂形状,回退到 Bounds 粗略检测
|
||||
return collider.bounds.Contains(worldPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bbfbb5726f87a7241b8f73b6201de57d
|
||||
@@ -21,6 +21,9 @@ namespace SLSFramework.LeanPoolAssistance
|
||||
|
||||
protected bool spawnExecuted = false;
|
||||
|
||||
public Action onSpawnAction;
|
||||
public Action onDespawnAction;
|
||||
|
||||
public virtual void OnSpawn()
|
||||
{
|
||||
if (spawnExecuted)
|
||||
@@ -30,6 +33,7 @@ namespace SLSFramework.LeanPoolAssistance
|
||||
|
||||
spawnExecuted = true;
|
||||
despawnTimer = 0;
|
||||
onSpawnAction?.Invoke();
|
||||
|
||||
children = GetComponentsInChildren<IPoolable>().ToList();
|
||||
children.Remove(this);
|
||||
@@ -56,9 +60,10 @@ namespace SLSFramework.LeanPoolAssistance
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDespawn()
|
||||
public virtual void OnDespawn()
|
||||
{
|
||||
spawnExecuted = false;
|
||||
onDespawnAction?.Invoke();
|
||||
children.ForEach(child => child.OnDespawn());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user