Merge branch 'main' of https://scoveria.ddns.net/scove/BABA_YAGA
This commit is contained in:
205
Assets/Scripts/Baba_yaga/Trap/TrapBase.cs
Normal file
205
Assets/Scripts/Baba_yaga/Trap/TrapBase.cs
Normal file
@@ -0,0 +1,205 @@
|
||||
using Fusion;
|
||||
using UnityEngine;
|
||||
|
||||
public enum TrapState
|
||||
{
|
||||
Arming, // Newly placed, arming delay active
|
||||
Armed, // Active and scanning for targets
|
||||
Triggered, // Tripped by a target, applying effects
|
||||
Despawning // Mark for cleanup/destruction
|
||||
}
|
||||
|
||||
[RequireComponent(typeof(NetworkObject))]
|
||||
public abstract class TrapBase : NetworkBehaviour
|
||||
{
|
||||
[Header("Trap Config")]
|
||||
[SerializeField] protected TrapDataSO trapData;
|
||||
|
||||
[Networked] public PlayerRef Owner { get; set; }
|
||||
[Networked, OnChangedRender(nameof(OnStateChanged))] public TrapState State { get; set; }
|
||||
[Networked] protected TickTimer ArmingTimer { get; set; }
|
||||
[Networked] protected TickTimer LifetimeTimer { get; set; }
|
||||
|
||||
protected Collider trapCollider;
|
||||
protected Animator animator;
|
||||
protected AudioSource audioSource;
|
||||
|
||||
public override void Spawned()
|
||||
{
|
||||
trapCollider = GetComponent<Collider>();
|
||||
animator = GetComponentInChildren<Animator>();
|
||||
audioSource = GetComponent<AudioSource>();
|
||||
|
||||
if (Object.HasStateAuthority)
|
||||
{
|
||||
State = TrapState.Arming;
|
||||
ArmingTimer = TickTimer.CreateFromSeconds(Runner, trapData.ArmingDelay);
|
||||
LifetimeTimer = TickTimer.CreateFromSeconds(Runner, trapData.Lifetime);
|
||||
}
|
||||
|
||||
ConfigureVisibility();
|
||||
}
|
||||
|
||||
public override void FixedUpdateNetwork()
|
||||
{
|
||||
if (!Object.HasStateAuthority) return;
|
||||
|
||||
// Count down the arming delay
|
||||
if (State == TrapState.Arming && ArmingTimer.Expired(Runner))
|
||||
{
|
||||
State = TrapState.Armed;
|
||||
}
|
||||
|
||||
// Auto-despawn when lifetime timer expires
|
||||
if (LifetimeTimer.Expired(Runner))
|
||||
{
|
||||
DespawnTrap();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnTriggerEnter(Collider other)
|
||||
{
|
||||
// Physics collision triggers are only processed on Server/Host (State Authority)
|
||||
if (!Object.HasStateAuthority) return;
|
||||
if (State != TrapState.Armed) return;
|
||||
|
||||
if (IsTargetValid(other.gameObject))
|
||||
{
|
||||
TriggerTrap(other.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
protected bool IsTargetValid(GameObject target)
|
||||
{
|
||||
// Verify target has a NetworkObject and check role through PlayerData
|
||||
var netObj = target.GetComponent<NetworkObject>();
|
||||
if (netObj != null)
|
||||
{
|
||||
var playerData = target.GetComponent<PlayerData>();
|
||||
if (playerData != null && playerData.PlayerRole == _Role.Seeker)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void TriggerTrap(GameObject victim)
|
||||
{
|
||||
State = TrapState.Triggered;
|
||||
OnTriggered(victim);
|
||||
}
|
||||
|
||||
// Abstract methods to be implemented by specific traps
|
||||
protected abstract void OnTriggered(GameObject victim);
|
||||
|
||||
protected virtual void ConfigureVisibility()
|
||||
{
|
||||
var localPlayer = Runner.LocalPlayer;
|
||||
PlayerDataManager pdm = PlayerDataManager.Instance;
|
||||
|
||||
if (pdm != null && pdm.TryGetPlayerMetaData(localPlayer, out var meta))
|
||||
{
|
||||
if (meta.Role == _Role.Trapper)
|
||||
{
|
||||
// Trapper sees their traps clearly
|
||||
gameObject.layer = LayerMask.NameToLayer("Default");
|
||||
SetTrapAlpha(0.8f);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Seeker: place in stealth layer if exists, otherwise disable MeshRenderers as fallback
|
||||
int stealthLayer = LayerMask.NameToLayer("StealthTrap");
|
||||
if (stealthLayer != -1)
|
||||
{
|
||||
SetLayerRecursively(gameObject, stealthLayer);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetRenderersEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetLayerRecursively(GameObject obj, int newLayer)
|
||||
{
|
||||
if (obj == null) return;
|
||||
obj.layer = newLayer;
|
||||
foreach (Transform child in obj.transform)
|
||||
{
|
||||
SetLayerRecursively(child.gameObject, newLayer);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetTrapAlpha(float alpha)
|
||||
{
|
||||
Renderer[] renderers = GetComponentsInChildren<Renderer>();
|
||||
foreach (var r in renderers)
|
||||
{
|
||||
foreach (var mat in r.materials)
|
||||
{
|
||||
Color col = mat.color;
|
||||
col.a = alpha;
|
||||
mat.color = col;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetRenderersEnabled(bool isEnabled)
|
||||
{
|
||||
Renderer[] renderers = GetComponentsInChildren<Renderer>();
|
||||
foreach (var r in renderers)
|
||||
{
|
||||
r.enabled = isEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnStateChanged()
|
||||
{
|
||||
HandleStateVisuals();
|
||||
}
|
||||
|
||||
protected virtual void HandleStateVisuals()
|
||||
{
|
||||
switch (State)
|
||||
{
|
||||
case TrapState.Arming:
|
||||
// Play placement sound effect or visual cue locally
|
||||
if (audioSource != null && trapData.PlaceSFX != null)
|
||||
{
|
||||
audioSource.PlayOneShot(trapData.PlaceSFX);
|
||||
}
|
||||
break;
|
||||
case TrapState.Armed:
|
||||
// Visual indicators of trap active state (e.g. flashing light)
|
||||
break;
|
||||
case TrapState.Triggered:
|
||||
// When triggered, reveal the trap mesh to everyone
|
||||
SetRenderersEnabled(true);
|
||||
|
||||
if (animator != null)
|
||||
{
|
||||
animator.SetTrigger("Trigger");
|
||||
}
|
||||
if (audioSource != null && trapData.TriggerSFX != null)
|
||||
{
|
||||
audioSource.PlayOneShot(trapData.TriggerSFX);
|
||||
}
|
||||
if (trapData.TriggerVFX != null)
|
||||
{
|
||||
Instantiate(trapData.TriggerVFX, transform.position, Quaternion.identity);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected void DespawnTrap()
|
||||
{
|
||||
if (Object != null && Object.IsValid && Object.HasStateAuthority)
|
||||
{
|
||||
State = TrapState.Despawning;
|
||||
Runner.Despawn(Object);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user