using UnityEngine; using System.Collections; namespace FORGE3D { [RequireComponent(typeof(LineRenderer))] public class F3DBeam : MonoBehaviour { public LayerMask layerMask; [Tooltip("The amount of damage this projectil inflicts generally.")] public float Damage = 1f; [Tooltip("The magnitude of the blast when hitting something.")] public float BlastMagnitude = 0.1f; [HideInInspector] public int OwnerId = 0; public WeaponEffect fxType; // Weapon type public bool OneShot; // Constant or single beam? public Texture[] BeamFrames; // Animation frame sequence public float FrameStep; // Animation time public float beamScale; // Default beam scale to be kept over distance public float MaxBeamLength; // Maximum beam length public bool AnimateUV; // UV Animation public float UVTime; // UV Animation speed public Transform rayImpact; // Impact transform public Transform rayMuzzle; // Muzzle flash transform LineRenderer lineRenderer; // Line rendered component RaycastHit hitPoint; // Raycast structure RaycastHit2D hitPoint2D; // Raycasthit in 2d int frameNo; // Frame counter int FrameTimerID; // Frame timer reference float beamLength; // Current beam length float initialBeamOffset; // Initial UV offset public float fxOffset; // Fx offset from bullet's touch point void Awake() { // Get line renderer component lineRenderer = GetComponent(); // Assign first frame texture if (!AnimateUV && BeamFrames.Length > 0) lineRenderer.material.mainTexture = BeamFrames[0]; // Randomize uv offset initialBeamOffset = Random.Range(0f, 5f); } // OnSpawned called by pool manager void OnSpawned() { // Do one time raycast in case of one shot flag if (OneShot) Raycast(); // Start animation sequence if beam frames array has more than 2 elements if (BeamFrames.Length > 1) Animate(); } // OnDespawned called by pool manager void OnDespawned() { // Reset frame counter frameNo = 0; // Clear timer if (FrameTimerID != -1) { F3DTime.time.RemoveTimer(FrameTimerID); FrameTimerID = -1; } } // Hit point calculation void Raycast() { // Prepare structure and create ray hitPoint = new RaycastHit(); Ray ray = new Ray(transform.position, transform.forward); // Calculate default beam proportion multiplier based on default scale and maximum length float propMult = MaxBeamLength * (beamScale / 10f); // Raycast if (Physics.Raycast(ray, out hitPoint, MaxBeamLength, layerMask) && DetectorCollision(hitPoint) != OwnerId) { // Get current beam length and update line renderer accordingly beamLength = Vector3.Distance(transform.position, hitPoint.point); lineRenderer.SetPosition(1, new Vector3(0f, 0f, beamLength)); // Calculate default beam proportion multiplier based on default scale and current length propMult = beamLength * (beamScale / 10f); // Spawn prefabs and apply force switch (fxType) { case WeaponEffect.Sniper: F3DFXController.instance.SniperImpact(hitPoint.point + hitPoint.normal * fxOffset); break; case WeaponEffect.RailGun: F3DFXController.instance.RailgunImpact(hitPoint.point + hitPoint.normal * fxOffset); break; case WeaponEffect.PlasmaBeam: break; case WeaponEffect.PlasmaBeamHeavy: break; } // Adjust impact effect position if (rayImpact) rayImpact.position = hitPoint.point - transform.forward * 0.5f; } else { // Set beam to maximum length beamLength = MaxBeamLength; lineRenderer.SetPosition(1, new Vector3(0f, 0f, beamLength)); // Adjust impact effect position if (rayImpact) rayImpact.position = transform.position + transform.forward * beamLength; } // Adjust muzzle position if (rayMuzzle) rayMuzzle.position = transform.position + transform.forward * 0.1f; // Set beam scaling according to its length lineRenderer.material.SetTextureScale("_BaseMap", new Vector2(propMult, 1f)); } /// /// Checks if a HitDetector was hit and registers a hit /// on it if so. /// /// /// OwnerId of the hit detector (-1 on none) int DetectorCollision(RaycastHit hitPoint) { if (hitPoint.collider.gameObject.TryGetComponent(out HitDetection detector)) { // Check if the one firing was hit if (detector.OwnerId == OwnerId) { return OwnerId; } ProjectileDamage inflictling = new() { DamageValue = Damage, ImpactMagnitude = BlastMagnitude, ImpactPoint = hitPoint.point, ImpactDirection = transform.forward }; detector.RegisterHit(inflictling); return detector.OwnerId; } return -1; } // Advance texture frame void OnFrameStep() { // Set current texture frame based on frame counter lineRenderer.material.mainTexture = BeamFrames[frameNo]; frameNo++; // Reset frame counter if (frameNo == BeamFrames.Length) frameNo = 0; } // Initialize frame animation void Animate() { if (BeamFrames.Length > 1) { // Set current frame frameNo = 0; lineRenderer.material.mainTexture = BeamFrames[frameNo]; // Add timer FrameTimerID = F3DTime.time.AddTimer(FrameStep, BeamFrames.Length - 1, OnFrameStep); frameNo = 1; } } // Apply force to last hit object void ApplyForce(float force) { if (hitPoint.rigidbody != null) hitPoint.rigidbody.AddForceAtPosition(transform.forward * force, hitPoint.point, ForceMode.VelocityChange); } // Set offset of impact public void SetOffset(float offset) { fxOffset = offset; } private float animateUVTime; void Update() { // Animate texture UV if (AnimateUV) { animateUVTime += Time.deltaTime; if (animateUVTime > 1.0f) animateUVTime = 0f; var v = animateUVTime * UVTime + initialBeamOffset; lineRenderer.material.SetVector("_Offset", new Vector2(v, 0)); } // Raycast for laser beams if (!OneShot) Raycast(); } } }