first commit
This commit is contained in:
@@ -0,0 +1,313 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
[RequireComponent(typeof(SphereCollider))]
|
||||
public class CaptureZone : MonoBehaviour
|
||||
{
|
||||
public enum Owner
|
||||
{
|
||||
Neutral,
|
||||
Player,
|
||||
Enemy
|
||||
}
|
||||
|
||||
public enum CaptureState
|
||||
{
|
||||
Neutral,
|
||||
CapturingByPlayer,
|
||||
CapturedByPlayer,
|
||||
CapturingByEnemy,
|
||||
CapturedByEnemy,
|
||||
Contested
|
||||
}
|
||||
|
||||
[Header("Identity")]
|
||||
public string zoneName = "Zone";
|
||||
|
||||
[Header("Capture")]
|
||||
public Owner currentOwner = Owner.Neutral;
|
||||
[Range(0f, 1f)] public float captureProgress = 0.5f;
|
||||
public float captureTime = 5f;
|
||||
public int playersInside;
|
||||
public int enemiesInside;
|
||||
public int pointsPerSecond = 5;
|
||||
|
||||
[Header("Visuals")]
|
||||
public Renderer zoneRenderer;
|
||||
public Color neutralColor = new Color(0.55f, 0.55f, 0.55f, 0.45f);
|
||||
public Color playerColor = new Color(0.1f, 0.35f, 1f, 0.55f);
|
||||
public Color enemyColor = new Color(1f, 0.12f, 0.08f, 0.55f);
|
||||
public Color contestedColor = new Color(1f, 0.82f, 0.05f, 0.65f);
|
||||
|
||||
public event Action<CaptureZone> onCapturedByPlayer;
|
||||
public event Action<CaptureZone> onCapturedByEnemy;
|
||||
|
||||
private Owner lastNotifiedOwner;
|
||||
private Vector3 baseScale;
|
||||
private float pulseTimer;
|
||||
private float scoreTimer;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
SphereCollider trigger = GetComponent<SphereCollider>();
|
||||
trigger.isTrigger = true;
|
||||
|
||||
lastNotifiedOwner = currentOwner;
|
||||
baseScale = transform.localScale;
|
||||
ApplyOwnerProgress(currentOwner);
|
||||
UpdateVisual();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
UpdateCaptureProgress();
|
||||
TickScoreIncome();
|
||||
UpdateVisual();
|
||||
UpdateCapturePulse();
|
||||
}
|
||||
|
||||
private void OnTriggerEnter(Collider other)
|
||||
{
|
||||
if (other.CompareTag("Player"))
|
||||
{
|
||||
playersInside++;
|
||||
}
|
||||
else if (other.CompareTag("Enemy"))
|
||||
{
|
||||
enemiesInside++;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTriggerExit(Collider other)
|
||||
{
|
||||
if (other.CompareTag("Player"))
|
||||
{
|
||||
playersInside = Mathf.Max(0, playersInside - 1);
|
||||
}
|
||||
else if (other.CompareTag("Enemy"))
|
||||
{
|
||||
enemiesInside = Mathf.Max(0, enemiesInside - 1);
|
||||
}
|
||||
}
|
||||
|
||||
public float GetProgress()
|
||||
{
|
||||
return captureProgress;
|
||||
}
|
||||
|
||||
public Owner GetOwner()
|
||||
{
|
||||
return currentOwner;
|
||||
}
|
||||
|
||||
public string GetStateLabel()
|
||||
{
|
||||
switch (GetCaptureState())
|
||||
{
|
||||
case CaptureState.CapturingByPlayer:
|
||||
return "Capturing by Player";
|
||||
case CaptureState.CapturedByPlayer:
|
||||
return "Player";
|
||||
case CaptureState.CapturingByEnemy:
|
||||
return "Capturing by Enemy";
|
||||
case CaptureState.CapturedByEnemy:
|
||||
return "Enemy";
|
||||
case CaptureState.Contested:
|
||||
return "Contested";
|
||||
default:
|
||||
return "Neutral";
|
||||
}
|
||||
}
|
||||
|
||||
public CaptureState GetCaptureState()
|
||||
{
|
||||
bool hasPlayer = playersInside > 0;
|
||||
bool hasEnemy = enemiesInside > 0;
|
||||
|
||||
if (hasPlayer && hasEnemy)
|
||||
{
|
||||
return CaptureState.Contested;
|
||||
}
|
||||
|
||||
if (hasPlayer && currentOwner != Owner.Player)
|
||||
{
|
||||
return CaptureState.CapturingByPlayer;
|
||||
}
|
||||
|
||||
if (hasEnemy && currentOwner != Owner.Enemy)
|
||||
{
|
||||
return CaptureState.CapturingByEnemy;
|
||||
}
|
||||
|
||||
if (currentOwner == Owner.Player)
|
||||
{
|
||||
return CaptureState.CapturedByPlayer;
|
||||
}
|
||||
|
||||
if (currentOwner == Owner.Enemy)
|
||||
{
|
||||
return CaptureState.CapturedByEnemy;
|
||||
}
|
||||
|
||||
return CaptureState.Neutral;
|
||||
}
|
||||
|
||||
public void ForceSetOwner(Owner owner)
|
||||
{
|
||||
SetOwner(owner, true);
|
||||
}
|
||||
|
||||
private void UpdateCaptureProgress()
|
||||
{
|
||||
bool hasPlayer = playersInside > 0;
|
||||
bool hasEnemy = enemiesInside > 0;
|
||||
|
||||
// Спорная зона замораживает прогресс, чтобы игрок видел механику contest.
|
||||
if (hasPlayer == hasEnemy)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float step = Time.deltaTime / Mathf.Max(0.1f, captureTime);
|
||||
|
||||
if (hasPlayer)
|
||||
{
|
||||
captureProgress = Mathf.MoveTowards(captureProgress, 1f, step);
|
||||
if (Mathf.Approximately(captureProgress, 1f))
|
||||
{
|
||||
SetOwner(Owner.Player, false);
|
||||
}
|
||||
}
|
||||
else if (hasEnemy)
|
||||
{
|
||||
captureProgress = Mathf.MoveTowards(captureProgress, 0f, step);
|
||||
if (Mathf.Approximately(captureProgress, 0f))
|
||||
{
|
||||
SetOwner(Owner.Enemy, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TickScoreIncome()
|
||||
{
|
||||
if (currentOwner == Owner.Neutral || ResourceManager.Instance == null)
|
||||
{
|
||||
scoreTimer = 0f;
|
||||
return;
|
||||
}
|
||||
|
||||
scoreTimer += Time.deltaTime;
|
||||
if (scoreTimer < 1f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int ticks = Mathf.FloorToInt(scoreTimer);
|
||||
scoreTimer -= ticks;
|
||||
int amount = pointsPerSecond * ticks;
|
||||
|
||||
if (currentOwner == Owner.Player)
|
||||
{
|
||||
ResourceManager.Instance.AddPlayerPoints(amount);
|
||||
}
|
||||
else if (currentOwner == Owner.Enemy)
|
||||
{
|
||||
ResourceManager.Instance.AddEnemyPoints(amount);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetOwner(Owner owner, bool forceNotify)
|
||||
{
|
||||
if (currentOwner == owner && !forceNotify)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Owner previousOwner = currentOwner;
|
||||
currentOwner = owner;
|
||||
ApplyOwnerProgress(owner);
|
||||
pulseTimer = 0.25f;
|
||||
|
||||
if (previousOwner == owner && !forceNotify)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastNotifiedOwner != currentOwner || forceNotify)
|
||||
{
|
||||
lastNotifiedOwner = currentOwner;
|
||||
|
||||
if (currentOwner == Owner.Player)
|
||||
{
|
||||
onCapturedByPlayer?.Invoke(this);
|
||||
}
|
||||
else if (currentOwner == Owner.Enemy)
|
||||
{
|
||||
onCapturedByEnemy?.Invoke(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyOwnerProgress(Owner owner)
|
||||
{
|
||||
if (owner == Owner.Player)
|
||||
{
|
||||
captureProgress = 1f;
|
||||
}
|
||||
else if (owner == Owner.Enemy)
|
||||
{
|
||||
captureProgress = 0f;
|
||||
}
|
||||
else if (Mathf.Approximately(captureProgress, 0f) || Mathf.Approximately(captureProgress, 1f))
|
||||
{
|
||||
captureProgress = 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateVisual()
|
||||
{
|
||||
if (zoneRenderer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Color color = GetVisualColor();
|
||||
zoneRenderer.material.color = color;
|
||||
}
|
||||
|
||||
private Color GetVisualColor()
|
||||
{
|
||||
CaptureState state = GetCaptureState();
|
||||
if (state == CaptureState.Contested || state == CaptureState.CapturingByPlayer || state == CaptureState.CapturingByEnemy)
|
||||
{
|
||||
float pulse = Mathf.Lerp(0.75f, 1f, Mathf.PingPong(Time.time * 3f, 1f));
|
||||
return contestedColor * pulse;
|
||||
}
|
||||
|
||||
if (currentOwner == Owner.Player)
|
||||
{
|
||||
return playerColor;
|
||||
}
|
||||
|
||||
if (currentOwner == Owner.Enemy)
|
||||
{
|
||||
return enemyColor;
|
||||
}
|
||||
|
||||
return neutralColor;
|
||||
}
|
||||
|
||||
private void UpdateCapturePulse()
|
||||
{
|
||||
if (pulseTimer <= 0f)
|
||||
{
|
||||
transform.localScale = baseScale;
|
||||
return;
|
||||
}
|
||||
|
||||
pulseTimer -= Time.deltaTime;
|
||||
float t = Mathf.Clamp01(pulseTimer / 0.25f);
|
||||
float scale = 1f + Mathf.Sin(t * Mathf.PI) * 0.12f;
|
||||
transform.localScale = baseScale * scale;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user