using Photon.Pun; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; public class NetworkedProjectile : MonoBehaviour { [Header("Visuals")] [SerializeField] private GameObject hitParticlesPrefab; [SerializeField] private GameObject visuals; [Header("Set by code")] public PhotonView photonView; public PhotonView owner; public Taggable ownerTag; public ProjectileAbility ability; public float speed; public float lifeSpan; public bool canPierce; public bool canHitSelf; private PhotonView possibleTarget; private Taggable target; private bool waitingForDestroy = false; public UnityEvent onTargetHit = new UnityEvent(); private List hitSpawnedVFXs = new List(); private GameObject hitSpawnedVFX; private Vector3 hitPositionCorrected; protected List processedTargets = new List(); NetworkedAntiProjectile possibleBlock; private void Awake() { photonView = GetComponent(); onTargetHit.AddListener(SpawnHitParticleVFX); } public void Init() { waitingForDestroy = false; if (photonView.IsMine) { photonView.RPC(nameof(RPC_RemoteInit), RpcTarget.Others, AbilityIndexer.Instance.Abilities.IndexOf(ability)); StartCoroutine(SelfDestruct()); } } [PunRPC] private void RPC_RemoteInit(int abilityIndex) { ability = (ProjectileAbility)AbilityIndexer.Instance.Abilities[abilityIndex]; } [PunRPC] private void RPC_DisableVisuals() { visuals.SetActive(false); } private void SpawnHitParticleVFX(Vector3 position) { if (hitParticlesPrefab == null) return; hitSpawnedVFX = Instantiate(hitParticlesPrefab, position, this.transform.rotation); //hitSpawnedVFX.transform.localScale = visuals.transform.localScale; hitSpawnedVFXs.Add(hitSpawnedVFX); } private void Update() { if (!photonView.IsMine) return; if (waitingForDestroy) return; this.transform.position += this.transform.forward * speed * Time.deltaTime; } private void OnTriggerEnter(Collider other) { if (waitingForDestroy) return; possibleTarget = other.GetComponentInParent(); if (possibleTarget != null) { if (!canHitSelf) if (possibleTarget == owner) return; } target = other.GetComponentInParent(); if (target == null) return; if (!target.IsValidTarget(ability.targettingTags)) return; if (processedTargets.Contains(target)) return; processedTargets.Add(target); hitPositionCorrected = target.transform.position; hitPositionCorrected.y = this.transform.position.y; onTargetHit.Invoke(hitPositionCorrected); if (!photonView.IsMine) return; possibleBlock = target.GetComponentInParent(); if (possibleBlock != null) { waitingForDestroy = true; possibleBlock.SendBlockNotice(); StartCoroutine(DelayedDestroy()); return; } foreach (BaseEffect effect in ability.abilityEffects) { effect.ApplyEffect(ownerTag, new List { target }); } if (!canPierce) { waitingForDestroy = true; StartCoroutine(DelayedDestroy()); } } IEnumerator SelfDestruct() { yield return new WaitForSeconds(lifeSpan); waitingForDestroy = true; StartCoroutine(DelayedDestroy()); } IEnumerator DelayedDestroy() { visuals.SetActive(false); photonView.RPC(nameof(RPC_DisableVisuals), RpcTarget.Others); yield return new WaitForSeconds(1.5f); for (int i = hitSpawnedVFXs.Count - 1; i >= 0; i--) { if (hitSpawnedVFXs[i] != null) { Destroy(hitSpawnedVFXs[i]); } } yield return new WaitForSeconds(1f); PhotonNetwork.Destroy(photonView); } }