Files
Cielonos/Assets/Scripts/MainGame/AttackArea/Submodules/BoomerangMoveSubmodule.cs
SoulliesOfficial 9a9e48f8a5
2026-06-27 12:52:03 -04:00

213 lines
8.1 KiB
C#

using System;
using Cielonos.MainGame.Characters;
using UnityEngine;
namespace Cielonos.MainGame
{
public class BoomerangMoveSubmodule : MoveSubmoduleBase
{
public Transform projectile => owner.topParent;
public CharacterBase target;
public float moveSpeed;
public float moveAcceleration;
public float angularSpeed;
public float angularAcceleration;
public bool isReturning;
public float catchRadius;
public float autoReturnTime; // Time in seconds after which it automatically returns if not triggered manually
public bool autoConnect;
public float detectRadius;
public bool keepFlat;
public bool straightThrowInitially;
public float straightThrowDuration;
public Action onCatchAction;
private float _timer;
private float deltaTime => owner.creator.selfTimeSm.DeltaTime;
private float projectileSpeedMultiplier => owner.creator.attributeSm[CharacterAttribute.ProjectileSpeedMultiplier];
public BoomerangMoveSubmodule(AttackAreaBase attackArea, CharacterBase target,
float moveSpeed, float moveAcceleration, float angularSpeed, float angularAcceleration, Vector3 initialDirection,
float autoReturnTime = float.MaxValue, float catchRadius = 1.5f, bool autoConnect = true, float detectRadius = 20f,
bool keepFlat = true, bool straightThrowInitially = false, float straightThrowDuration = 1f, bool stopWhenHit = false)
: base(attackArea, stopWhenHit)
{
this.target = target;
this.moveSpeed = moveSpeed;
this.moveAcceleration = moveAcceleration;
this.angularSpeed = angularSpeed;
this.angularAcceleration = angularAcceleration;
this.autoReturnTime = autoReturnTime;
this.catchRadius = catchRadius;
this.autoConnect = autoConnect;
this.detectRadius = detectRadius;
this.keepFlat = keepFlat;
this.straightThrowInitially = straightThrowInitially;
this.straightThrowDuration = straightThrowDuration;
this.isReturning = false;
projectile.forward = initialDirection;
}
public BoomerangMoveSubmodule(AttackAreaBase attackArea, CharacterBase target,
float moveSpeed, float angularSpeed, Vector3 initialDirection)
: this(attackArea, target, moveSpeed, 0f, angularSpeed, 0f, initialDirection)
{
}
public BoomerangMoveSubmodule WithAcceleration(float moveAcceleration, float angularAcceleration)
{
this.moveAcceleration = moveAcceleration;
this.angularAcceleration = angularAcceleration;
return this;
}
public BoomerangMoveSubmodule WithAutoReturn(float autoReturnTime)
{
this.autoReturnTime = autoReturnTime;
return this;
}
public BoomerangMoveSubmodule WithCatch(float catchRadius, Action onCatchAction = null)
{
this.catchRadius = catchRadius;
if (onCatchAction != null)
{
this.onCatchAction = onCatchAction;
}
return this;
}
public BoomerangMoveSubmodule WithTargeting(bool autoConnect, float detectRadius = 20f)
{
this.autoConnect = autoConnect;
this.detectRadius = detectRadius;
return this;
}
public BoomerangMoveSubmodule WithKeepFlat(bool keepFlat)
{
this.keepFlat = keepFlat;
return this;
}
public BoomerangMoveSubmodule WithStraightThrow(bool straightThrowInitially, float straightThrowDuration = 1f)
{
this.straightThrowInitially = straightThrowInitially;
this.straightThrowDuration = straightThrowDuration;
return this;
}
public BoomerangMoveSubmodule WithStopWhenHit(bool stopWhenHit)
{
this.stopWhenHit = stopWhenHit;
return this;
}
public BoomerangMoveSubmodule WithTimeScale(float timeScaleCoefficient)
{
this.timeScaleCoefficient = timeScaleCoefficient;
return this;
}
public void TriggerReturn(float moveSpeed = -1f, float moveAcceleration = -1f, float angularSpeed = -1f, float angularAcceleration = -1f)
{
if (isReturning || !canMove) return;
isReturning = true;
target = owner.creator; // Start tracing the player/creator
if (moveSpeed >= 0f) this.moveSpeed = moveSpeed;
if (moveAcceleration >= 0f) this.moveAcceleration = moveAcceleration;
if (angularSpeed >= 0f) this.angularSpeed = angularSpeed;
if (angularAcceleration >= 0f) this.angularAcceleration = angularAcceleration;
autoConnect = false;
}
public override void Update()
{
if (!canMove) return;
float speedMultiplier = projectileSpeedMultiplier;
_timer += deltaTime;
// Check auto-return condition
if (!isReturning && _timer >= autoReturnTime)
{
TriggerReturn();
}
// Check catch distance
if (isReturning && target != null && target.CenterPoint != null)
{
float distanceToCreator = Vector3.Distance(projectile.position, target.CenterPoint.position);
if (distanceToCreator <= catchRadius)
{
isReturning = false;
canMove = false;
owner.isEnabling = false;
owner.canTriggerHitEvent = false;
if (owner.timeSm != null)
{
owner.timeSm.isEnabling = false; // Stop the lifetime timer
}
if (onCatchAction != null)
{
onCatchAction.Invoke();
}
else if (owner.timeSm != null)
{
owner.timeSm.timeOutAction?.Invoke();
}
return;
}
}
// Update speed & angular speed
moveSpeed += moveAcceleration * deltaTime;
moveSpeed = Mathf.Max(moveSpeed, 0f);
angularSpeed += angularAcceleration * deltaTime;
angularSpeed = Mathf.Max(angularSpeed, 0f);
// Handle target selection if target is dead/missing (and not returning)
if (!isReturning && !straightThrowInitially && (target == null || target.statusSm.isDead))
{
if (autoConnect && owner.creator == MainGameManager.Player)
{
CharacterBase detectEnemy = CombatManager.EnemySm.GetBestEnemy(detectRadius, owner.transform);
if (detectEnemy != null)
{
target = detectEnemy;
}
}
}
// Calculate movement direction
bool shouldTrack = isReturning || !straightThrowInitially || (_timer >= straightThrowDuration);
if (shouldTrack && target != null && !target.statusSm.isDead && target.CenterPoint != null)
{
Vector3 direction = target.CenterPoint.position - projectile.position;
if (keepFlat)
{
direction.y = 0f;
}
if (direction != Vector3.zero)
{
Quaternion targetRotation = Quaternion.LookRotation(direction);
projectile.rotation = Quaternion.RotateTowards(projectile.rotation, targetRotation, angularSpeed * speedMultiplier * deltaTime);
}
}
// Translate position
unscaledVelocity = projectile.forward * (moveSpeed * speedMultiplier);
scaledVelocity = unscaledVelocity * timeScaleCoefficient;
projectile.position += scaledVelocity * deltaTime;
}
}
}