using System; using System.Collections; using System.Collections.Generic; using UnityEngine; public class BeamTower : AimTower { [SerializeField] private int maxBounces = 4; [SerializeField, Range(0f, 50f)] private float damage = 5f; [SerializeField] private LayerMask beamMask; private const float k_maxBeamDist = 100f; [SerializeField] private LineRenderer beam; [SerializeField, Range(0.01f, 20f)] private float attackSecondsDelay = 1f; protected override void Awake() { base.Awake(); horizontalArc.Value.AddListener(UpdateBeam); verticalArc.Value.AddListener(UpdateBeam); StartCoroutine(AttackLoop()); } private IEnumerator AttackLoop() { do { Vector3 origin = barrel.Tip.position; Vector3 rayDir = barrel.transform.forward; List hitPoints = new(); hitPoints.Add(origin); for (int i = 0; i < maxBounces; i++) { Debug.DrawRay(origin, rayDir.normalized * k_maxBeamDist, Color.red, 5f); RaycastHit hit; if (!Physics.Raycast(origin, rayDir, out hit, k_maxBeamDist, beamMask)) break; // Is damagable? HealthComponent healthComp = hit.collider.gameObject.GetComponent(); if (healthComp != null) { Debug.Log($"hitting {healthComp.name} {i}"); healthComp.TakeDamage(damage); break; } hitPoints.Add(hit.point); rayDir = Vector3.Reflect(rayDir, hit.normal); origin = hit.point; } beam.positionCount = hitPoints.Count; beam.SetPositions(hitPoints.ToArray()); yield return new WaitForSeconds(attackSecondsDelay); } while (true); } private void UpdateBeam(float unused) => UpdateBeam(); private void UpdateBeam() { Vector3 origin = barrel.Tip.position; Vector3 rayDir = barrel.transform.forward; List hitPoints = new(); hitPoints.Add(origin); for (int i = 0; i < maxBounces; i++) { Debug.DrawRay(origin, rayDir.normalized * k_maxBeamDist, Color.red, 5f); RaycastHit hit; if (!Physics.Raycast(origin, rayDir, out hit, k_maxBeamDist, beamMask)) break; hitPoints.Add(hit.point); rayDir = Vector3.Reflect(rayDir, hit.normal); origin = hit.point; } beam.positionCount = hitPoints.Count; beam.SetPositions(hitPoints.ToArray()); } }