// Update is called once per frame void Update() { if (target == null) { Debug.LogWarning("this laser has no target"); return; } // Read gradient for laser intensity float time = (Time.time % patternDuration) / patternDuration; float laserIntensity = pattern.getAlpha(time); // Override linerenderer alpha keys for (int i = 0; i < tempAlphaKeys.Length; i++) { tempAlphaKeys[i].alpha = laserIntensity; } tempGradient.SetKeys(tempGradient.colorKeys, tempAlphaKeys); lineRenderer.colorGradient = tempGradient; // Combine masks LayerMask collisionMask = waterSurfaceMask | obstacleMask; Vector2 thisPos = transform.position; Vector2 targetPos = target.position; Vector2 directionDelta = targetPos - thisPos; Vector2 direction = directionDelta.normalized; // Raycast distance float laserDistanceCast = directionDelta.magnitude; // Test water & terrain bool hitWater = false; Vector2 waterCollisionPos = Vector3.zero; bool hitObstacle = false; Vector2 obstaclePos = Vector3.zero; int waterSurfaceLayer = waterSurfaceMask.LayerMaskToLayer(); RaycastHit2D[] hits = Physics2D.RaycastAll(thisPos, direction, laserDistanceCast, collisionMask); foreach (RaycastHit2D hit in hits) { // Extend through water surface if (hit.collider.gameObject.layer == waterSurfaceLayer) { hitWater = true; prevTouchedWater = true; waterCollisionPos = hit.point; lastDetectedWaterCollider = hit.collider; lastDetectedWaterY = waterCollisionPos.y; } // Terrain or body, stop extending else { hitObstacle = true; obstaclePos = hit.point; // Reduce health if has health Health targetHealth = hit.collider.GetComponent <Health>(); if (targetHealth != null) { float damage = laserDamage * laserIntensity * Time.deltaTime; if (damage > 0.0f) { targetHealth.damage(damage); } } break; } } // Laser end point Vector2 laserEndPos = Vector2.zero; if (hitObstacle) { laserEndPos = obstaclePos; } else { laserEndPos = thisPos + direction * laserDistanceCast; } // Set line renderer lineRenderer.SetPosition(0, Vector2.zero); lineRenderer.SetPosition(1, laserEndPos - thisPos); // Evaluate if laser shoots into water or out of water // or completely submerged pr completely above water if (!hitWater) { // Never touched water OR previously touched water surface went below if ((!prevTouchedWater && lastDetectedWaterCollider == null) || (lastDetectedWaterCollider != null && thisPos.y >= lastDetectedWaterCollider.transform.position.y)) { state = aquaMode.aboveWater; } else { state = aquaMode.belowWater; } } else { if (direction.y < 0.0f) { state = aquaMode.intoWater; } else { state = aquaMode.outtaWater; } } // Emit bubbles from submerged laser segment if (state != aquaMode.aboveWater && laserIntensity > 0.0f) { laserParticle.keepOn(); } else { laserParticle.keepOff(); } Vector2 waterBubbleStartPos = Vector2.zero; Vector2 waterBubbleEndPos = Vector2.zero; switch (state) { case aquaMode.aboveWater: break; case aquaMode.belowWater: waterBubbleStartPos = thisPos; waterBubbleEndPos = laserEndPos; break; case aquaMode.intoWater: waterBubbleStartPos = waterCollisionPos; waterBubbleEndPos = laserEndPos; break; case aquaMode.outtaWater: waterBubbleStartPos = thisPos; waterBubbleEndPos = waterCollisionPos; break; } ParticleSystem.ShapeModule laserParticleShape = laserParticle.shape; float directionAngle = Mathf.Atan2(direction.y, direction.x) * 180.0f / 3.14f; laserParticleShape.rotation = Vector3.forward * directionAngle; laserParticleShape.radius = Vector2.Distance(waterBubbleStartPos, waterBubbleEndPos) / 2.0f; laserParticleShape.position = (waterBubbleStartPos + waterBubbleEndPos) / 2.0f - thisPos; }