From 0600a7360f1c3d9b4a2c04ac7142e7a6c14d490d Mon Sep 17 00:00:00 2001 From: Fernando Cortez Date: Fri, 10 Mar 2023 11:09:15 -0500 Subject: [PATCH] fix: Invaders hit fx not replicated on player & enemy bullets (#113) * player and enemy bullet send client rpcs to spawn hit FX * redundant server side checks removed, spawn/despawn method usage parity * formatting --- Basic/Invaders/Assets/Scripts/EnemyBullet.cs | 59 ++++++++++++++----- Basic/Invaders/Assets/Scripts/PlayerBullet.cs | 49 +++++++++------ 2 files changed, 75 insertions(+), 33 deletions(-) diff --git a/Basic/Invaders/Assets/Scripts/EnemyBullet.cs b/Basic/Invaders/Assets/Scripts/EnemyBullet.cs index 66e37fff..61059e3e 100644 --- a/Basic/Invaders/Assets/Scripts/EnemyBullet.cs +++ b/Basic/Invaders/Assets/Scripts/EnemyBullet.cs @@ -1,9 +1,9 @@ -using Unity.Mathematics; +using System; using Unity.Netcode; using UnityEngine; using UnityEngine.Assertions; -public class EnemyBullet : MonoBehaviour +public class EnemyBullet : NetworkBehaviour { private const float k_YBoundary = -4.0f; @@ -12,59 +12,86 @@ public class EnemyBullet : MonoBehaviour [SerializeField] [Tooltip("The constant speed at which the Bullet travels")] private float m_TravelSpeed = 3.0f; - + [SerializeField] ParticleSystem m_ShieldExplosionParticle; - private void Start() + void Awake() { - Assert.IsTrue(InvadersGame.Singleton); - Assert.IsTrue(NetworkManager.Singleton); + enabled = false; + } - if(InvadersGame.Singleton) + public override void OnNetworkSpawn() + { + enabled = IsServer; + + if (!IsServer) + { + return; + } + + Assert.IsTrue(InvadersGame.Singleton); + + if (InvadersGame.Singleton) + { InvadersGame.Singleton.isGameOver.OnValueChanged += OnGameOver; + } } private void Update() { - if (!NetworkManager.Singleton.IsServer) return; transform.Translate(0, -m_TravelSpeed * Time.deltaTime, 0); - if (transform.position.y < k_YBoundary) Destroy(gameObject); + if (transform.position.y < k_YBoundary) + { + NetworkObject.Despawn(); + } } - private void OnDestroy() + public override void OnNetworkDespawn() { - if (InvadersGame.Singleton) InvadersGame.Singleton.isGameOver.OnValueChanged -= OnGameOver; + if (InvadersGame.Singleton) + { + InvadersGame.Singleton.isGameOver.OnValueChanged -= OnGameOver; + } } private void OnTriggerEnter2D(Collider2D collider) { - if (!NetworkManager.Singleton.IsServer) + // several OnTriggerEnter2D calls may be invoked in the same frame (for different Colliders), so we check if + // we're spawned to make sure we don't trigger hits for already despawned bullets + if (!IsServer || !IsSpawned) return; var hitPlayer = collider.gameObject.GetComponent(); if (hitPlayer != null) { + NetworkObject.Despawn(); hitPlayer.HitByBullet(); - Destroy(gameObject); return; } var hitShield = collider.gameObject.GetComponent(); if (hitShield != null) { + SpawnExplosionVFXClientRpc(transform.position, Quaternion.identity); + Destroy(hitShield.gameObject); - Destroy(gameObject); - Instantiate(m_ShieldExplosionParticle, transform.position, quaternion.identity); + NetworkObject.Despawn(); } } + [ClientRpc] + void SpawnExplosionVFXClientRpc(Vector3 spawnPosition, Quaternion spawnRotation) + { + Instantiate(m_ShieldExplosionParticle, spawnPosition, spawnRotation); + } + private void OnGameOver(bool oldValue, bool newValue) { enabled = false; // On game over destroy the bullets - if (NetworkManager.Singleton.IsServer) Destroy(gameObject); + NetworkObject.Despawn(); } } diff --git a/Basic/Invaders/Assets/Scripts/PlayerBullet.cs b/Basic/Invaders/Assets/Scripts/PlayerBullet.cs index 25a2e76f..021559c4 100644 --- a/Basic/Invaders/Assets/Scripts/PlayerBullet.cs +++ b/Basic/Invaders/Assets/Scripts/PlayerBullet.cs @@ -1,8 +1,8 @@ -using Unity.Mathematics; +using System; using Unity.Netcode; using UnityEngine; -public class PlayerBullet : MonoBehaviour +public class PlayerBullet : NetworkBehaviour { private const float k_YBoundary = 15.0f; public PlayerControl owner; @@ -15,20 +15,31 @@ public class PlayerBullet : MonoBehaviour [SerializeField] ParticleSystem m_EnemyExplosionParticle; + void Awake() + { + enabled = false; + } + + public override void OnNetworkSpawn() + { + enabled = IsServer; + } + private void Update() { - if (!NetworkManager.Singleton.IsServer) return; - transform.Translate(0, m_TravelSpeed * Time.deltaTime, 0); if (transform.position.y > k_YBoundary) - if (NetworkManager.Singleton.IsServer) - Destroy(gameObject); + { + NetworkObject.Despawn(); + } } private void OnTriggerEnter2D(Collider2D collider) { - if (!NetworkManager.Singleton.IsServer) + // several OnTriggerEnter2D calls may be invoked in the same frame (for different Colliders), so we check if + // we're spawned to make sure we don't trigger hits for already despawned bullets + if (!IsServer || !IsSpawned) return; var hitEnemy = collider.gameObject.GetComponent(); @@ -36,17 +47,13 @@ public class PlayerBullet : MonoBehaviour { owner.IncreasePlayerScore(hitEnemy.score); - if (NetworkManager.Singleton.IsServer) - { - // Only the server can despawn a NetworkObject - hitEnemy.NetworkObject.Despawn(); - } + // Only the server can despawn a NetworkObject + hitEnemy.NetworkObject.Despawn(); - Destroy(gameObject); + SpawnExplosionVFXClientRPC(transform.position, Quaternion.identity); + + NetworkObject.Despawn(); - // this instantiates at the position of the bullet, there is an offset in the Y axis on the - // particle systems in the prefab so it looks like it spawns in the middle of the enemy - Instantiate(m_EnemyExplosionParticle, transform.position, quaternion.identity); return; } @@ -54,7 +61,15 @@ public class PlayerBullet : MonoBehaviour if (hitShield != null) { Destroy(hitShield.gameObject); - Destroy(gameObject); + NetworkObject.Despawn(); } } + + [ClientRpc] + void SpawnExplosionVFXClientRPC(Vector3 spawnPosition, Quaternion spawnRotation) + { + // this instantiates at the position of the bullet, there is an offset in the Y axis on the + // particle systems in the prefab so it looks like it spawns in the middle of the enemy + Instantiate(m_EnemyExplosionParticle, spawnPosition, spawnRotation); + } }