2025-09-24 11:24:38 +05:00

214 lines
5.4 KiB
C#

using UnityEngine;
using Fusion;
using Fusion.Addons.KCC;
namespace TPSBR
{
public sealed class Airplane : ContextBehaviour
{
// PUBLIC MEMBERS
[Networked, HideInInspector]
public Vector3 NextTargetPosition { get; set; }
public bool DropEnabled { get { return _state.IsBitSet(0); } set { _state = _state.SetBitNoRef(0, value); } }
public bool DropFinished { get { return _state.IsBitSet(1); } set { _state = _state.SetBitNoRef(1, value); } }
public bool IsFlyingAway { get { return _state.IsBitSet(2); } set { _state = _state.SetBitNoRef(2, value); } }
public bool IsFinished { get { return _state.IsBitSet(3); } set { _state = _state.SetBitNoRef(3, value); } }
public Transform AgentPosition => _agentPosition;
public float OutZoneDistance => _outZoneDistance;
// PRIVATE MEMBERS
[SerializeField]
private GameObject _dropEnabledObject;
[SerializeField]
private GameObject _dropDisabledObject;
[SerializeField]
private Transform _agentPosition;
[SerializeField]
private float _maxSpeed = 8f;
[SerializeField]
private float _maxAcceleration = 8f;
[SerializeField]
private float _tiltSpeed = 8f;
[SerializeField]
private float _maxTilt = 60;
[SerializeField]
private float _minDistanceToTargetChange = 60f;
[SerializeField]
private float _outZoneDistance = 20f;
[SerializeField]
private float _inZoneDistance = 10f;
[Header("Sounds")]
[SerializeField]
private AudioEffect _audioEffect;
[SerializeField]
private AudioSetup _playerJumpedSound;
[Networked]
private byte _state { get; set; }
[Networked]
private Vector3 _velocity { get; set; }
[Networked]
private float _tilt { get; set; }
// PUBLIC METHODS
public void ActivateDropWindow()
{
if (HasStateAuthority == false)
return;
DropEnabled = true;
NextTargetPosition = Vector3.zero;
}
public void DeactivateDropWindow()
{
if (HasStateAuthority == false)
return;
DropEnabled = false;
DropFinished = true;
NextTargetPosition = Vector3.zero;
}
public void OnPlayerJumped(PlayerRef playerRef)
{
_audioEffect.Play(_playerJumpedSound);
}
// NetworkBehaviour INTERFACE
public override void Spawned()
{
if (HasStateAuthority == false)
return;
_velocity = transform.rotation * (Vector3.forward * _maxSpeed);
}
public override void FixedUpdateNetwork()
{
if (HasStateAuthority == false)
return;
if (IsFinished == true)
return;
if (NeedsNewTarget() == true)
{
if (IsFlyingAway == true)
{
// Plane is near fly away target, let's despawn
IsFinished = true;
return;
}
else if (DropEnabled == true)
{
NextTargetPosition = FindNewTargetInZone();
}
else if (DropFinished == false)
{
// Waiting for drop start
NextTargetPosition = FindNewTargetOutsideZone();
}
else
{
NextTargetPosition = FindFlyAwayTarget();
IsFlyingAway = true;
}
}
UpdatePosition();
}
public override void Render()
{
_dropEnabledObject.SetActive(DropEnabled);
_dropDisabledObject.SetActive(DropEnabled == false);
}
// PRIVATE METHODS
private bool NeedsNewTarget()
{
if (NextTargetPosition == Vector3.zero)
return true;
return Vector3.SqrMagnitude(transform.position - NextTargetPosition) < _minDistanceToTargetChange * _minDistanceToTargetChange;
}
private Vector3 FindNewTargetInZone()
{
var area = Context.GameplayMode.ShrinkingArea;
var dirToPlane = (transform.position - area.Center).OnlyXZ().normalized;
var nextDirection = -dirToPlane + _velocity.OnlyXZ().normalized * 0.3f;
if (nextDirection == Vector3.zero)
{
nextDirection = -dirToPlane;
nextDirection.x += 5;
}
var areaPoint = area.Center + nextDirection.normalized * (area.Radius - _inZoneDistance);
areaPoint.y = transform.position.y;
return areaPoint;
}
private Vector3 FindNewTargetOutsideZone()
{
var area = Context.GameplayMode.ShrinkingArea;
var dirOutOfArea = (transform.position + transform.forward * 60f - area.Center).OnlyXZ().normalized;
var areaPoint = area.Center + dirOutOfArea * (area.Radius + _outZoneDistance);
areaPoint.y = transform.position.y;
return areaPoint;
}
private Vector3 FindFlyAwayTarget()
{
var area = Context.GameplayMode.ShrinkingArea;
var dirOutOfArea = (transform.position + transform.forward * 60f - area.Center).OnlyXZ().normalized;
var areaPoint = area.Center + dirOutOfArea * (area.Radius + 300f);
areaPoint.y = transform.position.y + 50f;
return areaPoint;
}
private void UpdatePosition()
{
float deltaTime = Runner.DeltaTime;
transform.position = transform.position + _velocity * deltaTime;
var directionToTarget = NextTargetPosition - transform.position;
var lastLeft = -transform.right;
lastLeft.y = 0f;
float directionDot = Vector3.Dot(directionToTarget.normalized, lastLeft.normalized);
float targetTilt = MathUtility.Map(-1f, 1f, -_maxTilt, _maxTilt, directionDot);
_tilt = Mathf.Lerp(_tilt, targetTilt, _tiltSpeed * deltaTime);
var newRotation = Quaternion.LookRotation(_velocity, Vector3.up).eulerAngles;
newRotation.z = _tilt;
transform.rotation = Quaternion.Euler(newRotation);
_velocity += directionToTarget.normalized * _maxAcceleration * deltaTime;
float speed = _velocity.magnitude;
if (speed > _maxSpeed)
{
_velocity = (_velocity / speed) * _maxSpeed;
}
}
}
}