using System; using System.Collections; using System.Collections.Generic; using FMOD.Studio; using FMODUnity; using HurricaneVR.Framework.Components; using HurricaneVR.Framework.Core; using HurricaneVR.Framework.Core.Grabbers; using HurricaneVR.Framework.Core.Utils; using HurricaneVR.Framework.Weapons; using UnityEngine; using STOP_MODE = FMOD.Studio.STOP_MODE; public class GrenadeWeapon : MonoBehaviour { [Header("Grenade")] [SerializeField] private float delayToDamage = 0.2f; [SerializeField] private LayerMask mask; [SerializeField] private float radius; [SerializeField] private float upDistance = 1f; [SerializeField] private float delayToExplosion; [SerializeField] private HVRDamageProvider damageProvider; [SerializeField] private List toCheckColliders; [Header("Sound")] [SerializeField] private EventReference soundRef; [SerializeField] private AnimationCurve soundCurve; private EventInstance soundInstance; [Header("Setup")] [SerializeField] private HVRGrabbable grabbable; [SerializeField] private GrenadeActivator activator; [SerializeField] private GameObject explosionFx; [SerializeField] private HVRGunSounds sounds; [SerializeField] private Renderer buttonRender; [SerializeField] private Material buttonMaterial; [SerializeField] private float offset; [SerializeField] private Color emissionColor; [SerializeField] private bool isDebug; private static readonly int emissionColorId = Shader.PropertyToID("_EmissionColor"); private bool isReady; private void Start() { soundInstance = RuntimeManager.CreateInstance(soundRef); RuntimeManager.AttachInstanceToGameObject(soundInstance, gameObject.transform); buttonMaterial = buttonRender.material; activator.OnReady += OnReady; grabbable.HandGrabbed.AddListener(Grab); grabbable.HandReleased.AddListener(Release); } private void OnDestroy() { activator.OnReady -= OnReady; grabbable.HandGrabbed.RemoveListener(Grab); grabbable.HandReleased.RemoveListener(Release); } private void Grab(HVRHandGrabber arg0, HVRGrabbable hvrGrabbable) { } private void Release(HVRGrabberBase arg0, HVRGrabbable hvrGrabbable) { if(isReady) { OnActivator(); isReady = false; } } private void OnReady() { sounds.PlaySlideForward(); StartCoroutine(Ready()); } IEnumerator Ready() { activator.OnReady -= OnReady; isReady = true; soundInstance.stop(STOP_MODE.IMMEDIATE); soundInstance.start(); var t = 0f; var inverse = false; while(t >= 0f) { if(!inverse) t += Time.deltaTime; if(inverse) t -= Time.deltaTime; if(t >= 1f) { t = 1f; inverse = true; } t = Mathf.Clamp01(t); var c = emissionColor * t; buttonMaterial.SetVector(emissionColorId, c); yield return null; } soundInstance.stop(STOP_MODE.IMMEDIATE); } private void OnActivator() { StartCoroutine(WaitAndExplosion()); } private IEnumerator WaitAndExplosion() { var t = 0f; var soundActivate = false; while(t <= delayToExplosion) { t += Time.deltaTime; var ev = soundCurve.Evaluate(t); if(ev > 0.9f && !soundActivate) { soundActivate = true; soundInstance.stop(STOP_MODE.IMMEDIATE); soundInstance.start(); } else if(ev < 0.8 && soundActivate) { soundActivate = false; } var c = emissionColor * ev; buttonMaterial.SetVector(emissionColorId, c); yield return null; } soundInstance.stop(STOP_MODE.IMMEDIATE); soundInstance.release(); IEnumerator DelayHit() { yield return new WaitForSeconds(delayToDamage); var hits = PhysicsExtension.SphereCastAll(transform.position, radius, Vector3.up, upDistance, mask, QueryTriggerInteraction.Ignore); foreach(var raycastHit in hits) { var handler = raycastHit.collider.GetComponent(); if(handler) { var position = transform.position; var dir = (position - raycastHit.point).normalized; var ray = new Ray(raycastHit.point + dir * offset, dir); var isRay = Physics.Raycast(ray, out var rayHit, Mathf.Infinity, mask, QueryTriggerInteraction.Ignore); if(isRay) { if(toCheckColliders.Contains(rayHit.collider)) { handler.HandleRayCastHit(damageProvider, raycastHit); handler.HandleDamageProvider(damageProvider, raycastHit.point, dir.normalized); } } } } Destroy(gameObject); } StartCoroutine(DelayHit()); var expInstantiate = Instantiate(explosionFx, transform.position, Quaternion.identity); Destroy(expInstantiate, 2f); } private void OnDrawGizmos() { if (!isDebug) return; var color = Gizmos.color; Gizmos.DrawWireSphere(transform.position, radius); var hits = PhysicsExtension.SphereCastAll(transform.position, radius, Vector3.up, upDistance, mask, QueryTriggerInteraction.Ignore); foreach(var raycastHit in hits) { var handler = raycastHit.collider.GetComponent(); if(handler) { var position = transform.position; var dir = (position - raycastHit.point).normalized; var ray = new Ray(raycastHit.point + dir * offset, dir); Gizmos.color = Color.yellow; Gizmos.DrawWireSphere(raycastHit.point, 0.05f); var isRay = Physics.Raycast(ray, out var rayHit, Mathf.Infinity, mask, QueryTriggerInteraction.Ignore); if(isRay) { if(toCheckColliders.Contains(rayHit.collider)) { Debug.DrawLine(raycastHit.point, rayHit.point); } else { Gizmos.color = Color.red; Gizmos.DrawWireSphere(rayHit.point, 0.05f); Debug.DrawLine(raycastHit.point, rayHit.point); } } } } Gizmos.color = color; } }