using System; using Unity.BossRoom.Gameplay.GameplayObjects; using Unity.BossRoom.Gameplay.GameplayObjects.Character; using Unity.BossRoom.Infrastructure; using Unity.Netcode; using UnityEngine; namespace Unity.BossRoom.Gameplay.Actions { /// /// Action responsible for creating a projectile object. /// [CreateAssetMenu(menuName = "BossRoom/Actions/Launch Projectile Action")] public class LaunchProjectileAction : Action { private bool m_Launched = false; public override bool OnStart(ServerCharacter serverCharacter) { //snap to face the direction we're firing, and then broadcast the animation, which we do immediately. serverCharacter.physicsWrapper.Transform.forward = Data.Direction; serverCharacter.serverAnimationHandler.NetworkAnimator.SetTrigger(Config.Anim); serverCharacter.clientCharacter.ClientPlayActionRpc(Data); return true; } public override void Reset() { m_Launched = false; base.Reset(); } public override bool OnUpdate(ServerCharacter clientCharacter) { if (TimeRunning >= Config.ExecTimeSeconds && !m_Launched) { LaunchProjectile(clientCharacter); } return true; } /// /// Looks through the ProjectileInfo list and finds the appropriate one to instantiate. /// For the base class, this is always just the first entry with a valid prefab in it! /// /// thrown if no Projectiles are valid protected virtual ProjectileInfo GetProjectileInfo() { foreach (var projectileInfo in Config.Projectiles) { if (projectileInfo.ProjectilePrefab && projectileInfo.ProjectilePrefab.GetComponent()) return projectileInfo; } throw new System.Exception($"Action {name} has no usable Projectiles!"); } /// /// Instantiates and configures the arrow. Repeatedly calling this does nothing. /// /// /// This calls GetProjectilePrefab() to find the prefab it should instantiate. /// protected void LaunchProjectile(ServerCharacter parent) { if (!m_Launched) { m_Launched = true; var projectileInfo = GetProjectileInfo(); NetworkObject no = NetworkObjectPool.Singleton.GetNetworkObject(projectileInfo.ProjectilePrefab, projectileInfo.ProjectilePrefab.transform.position, projectileInfo.ProjectilePrefab.transform.rotation); // point the projectile the same way we're facing no.transform.forward = parent.physicsWrapper.Transform.forward; //this way, you just need to "place" the arrow by moving it in the prefab, and that will control //where it appears next to the player. no.transform.position = parent.physicsWrapper.Transform.localToWorldMatrix.MultiplyPoint(no.transform.position); no.GetComponent().Initialize(parent.NetworkObjectId, projectileInfo); no.Spawn(true); } } public override void End(ServerCharacter serverCharacter) { //make sure this happens. LaunchProjectile(serverCharacter); } public override void Cancel(ServerCharacter serverCharacter) { if (!string.IsNullOrEmpty(Config.Anim2)) { serverCharacter.serverAnimationHandler.NetworkAnimator.SetTrigger(Config.Anim2); } } public override bool OnUpdateClient(ClientCharacter clientCharacter) { return ActionConclusion.Continue; } } }