213 lines
8.1 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|