using System; using System.Diagnostics; using Godot; public partial class Flashlight : Node { [Signal] public delegate void EnergyOutEventHandler(); [Signal] public delegate void ChargedEventHandler(); [Export] public Player Player; [Export] public GameCamera Camera; [Export] public Node2D Circle; [Export] public Node2D PlayerCircle; [Export] public Polygon2D Polygon; [Export] public CollisionShape2D CollisionCircle; [Export] public CollisionShape2D CollisionPlayerCircle; [Export] public CollisionPolygon2D CollisionPolygon; [Export] public CanvasGroup FlashlightGroup; [Export] public Curve BrightnessCurve; [Export] public AudioStreamPlayer CrankSoundPlayer; private float FlashlightRadius = Constants.MaxFlashlightRadius; private float FlashlightEnergy = 0; private float FlashlightChargeTimeout = 1; private bool _isDischarged = true; public override void _Ready() { base._Ready(); if (CollisionCircle.Shape is not CircleShape2D) throw new Exception("Invalid collision shape on the circle"); if (CollisionPlayerCircle.Shape is not CircleShape2D) throw new Exception("Invalid collision shape on the player circle"); } public override void _PhysicsProcess(double delta) { var playerScreenCenterPosition = Player.Position - Camera.Position; var flashlightScreenCenterPosition = Camera.FlashlightPosition - Camera.Position; var playerScreenPosition = playerScreenCenterPosition + Constants.HalfScreenSize; PlayerCircle.Position = playerScreenPosition; CollisionPlayerCircle.Position = playerScreenPosition; var d = Camera.FlashlightPosition.DistanceTo(Player.Position); FlashlightRadius = Mathf.Lerp(Constants.MinFlashlightRadius, Constants.MaxFlashlightRadius, Mathf.Clamp(d - Constants.MinFlashlightDistance, 0, Constants.MaxFlashlightDistance - Constants.MinFlashlightDistance) / Constants.MaxFlashlightDistance); var flashlightScreenPosition = flashlightScreenCenterPosition + Constants.HalfScreenSize; var flashlightScale = FlashlightRadius / Constants.MaxFlashlightRadius; Circle.Position = flashlightScreenPosition; Circle.Scale = new Vector2(flashlightScale, flashlightScale); CollisionCircle.Position = flashlightScreenPosition; ((CircleShape2D)CollisionCircle.Shape).Radius = FlashlightRadius; if (d <= FlashlightRadius) Polygon.Visible = false; else { Polygon.Visible = true; var a = Mathf.Sqrt(d * d - FlashlightRadius * FlashlightRadius); var xy2 = Camera.FlashlightPosition - Player.Position; var angle = xy2.Angle(); var arcsinRd = Mathf.Asin(FlashlightRadius / d); var dslkhjdsflkhjsdfhlkjdfsjlk = angle + arcsinRd; var xy3 = a * new Vector2(Mathf.Cos(dslkhjdsflkhjsdfhlkjdfsjlk), Mathf.Sin(dslkhjdsflkhjsdfhlkjdfsjlk)); var dslkhjdsflkhjsdfhlkjdfsjlk2 = angle - arcsinRd; var xy4 = a * new Vector2(Mathf.Cos(dslkhjdsflkhjsdfhlkjdfsjlk2), Mathf.Sin(dslkhjdsflkhjsdfhlkjdfsjlk2)); var polygon = new[] { playerScreenPosition, playerScreenPosition + xy3, playerScreenPosition + xy4 }; Polygon.Polygon = polygon; CollisionPolygon.Polygon = polygon; } FlashlightChargeTimeout = Mathf.Clamp(FlashlightChargeTimeout - (float)delta, 0, 1); if (Input.IsActionJustPressed("flashlight_charge") && FlashlightChargeTimeout <= 0) { EmitSignal(SignalName.Charged); _isDischarged = false; FlashlightChargeTimeout = 1; FlashlightEnergy += Constants.FlashlightEnergyPerCharge; var rng = new RandomNumberGenerator(); CrankSoundPlayer.PitchScale = rng.RandfRange(1f, 1.15f); CrankSoundPlayer.Play(); } FlashlightEnergy = Mathf.Clamp(FlashlightEnergy - (float)delta * Constants.FlashlightDischargeModifier, 0, Constants.MaxFlashlightEnergy); FlashlightGroup.Modulate = new Color(BrightnessCurve.Sample(FlashlightEnergy / Constants.MaxFlashlightEnergy), 1, 1, 1); CollisionCircle.Disabled = CollisionPlayerCircle.Disabled = CollisionPolygon.Disabled = FlashlightEnergy < 10; if (!_isDischarged && FlashlightEnergy < 5) { EmitSignal(SignalName.EnergyOut); _isDischarged = true; } } }