using System; using System.Collections.Generic; using Godot; using NodeWar.scripts; namespace NodeWar; public enum NoduleType { Base, Connector, } [SceneTree] public partial class Nodule : Area2D { private const float GrowthFactor = 0.01f; private bool _growAreaInside; private bool _holdInsideGrowArea; private Vector2 _lastPosition; private bool _freezeMove; [Export] private NoduleType _noduleType; private float _maxRadius; [Export] public bool BuildMode { get; set; } = false; [Export] public float Age { get; set; } = 0; [Export] public PackedScene RootScene { get; set; } public List ConnectedNodules { get; } = []; public Nodule ParentNoduleWhileBuilding; public Nodule ChildNoduleWhileBuilding; [Signal] public delegate void NoduleBuiltEventHandler(); [Signal] public delegate void BuildingCanceledEventHandler(); public override void _Ready() { _maxRadius = _.ConnectionArea.GetRadius(); _.ConnectionArea.NoduleEntered += HandleNoduleEntered; _.ConnectionArea.NoduleExited += HandleNoduleExited; switch (_noduleType) { case NoduleType.Base: Modulate = Colors.Red; _.Gfx.Get().Scale = new Vector2(2, 2); BuildNode(); break; case NoduleType.Connector: break; default: throw new ArgumentOutOfRangeException(); } QueueRedraw(); } public override void _Process(double delta) { // TODO: StateMachine? if (BuildMode) { var distanceToParent = GetGlobalMousePosition() - ParentNoduleWhileBuilding.GlobalPosition; if (distanceToParent.Length() > _maxRadius) { GlobalPosition = ParentNoduleWhileBuilding.GlobalPosition + distanceToParent.Normalized() * _maxRadius; } else { GlobalPosition = GetGlobalMousePosition(); } if (Input.IsActionJustReleased(Scripts.Globals.MyInput.MouseLeft)) { BuildNode(); } if (Input.IsMouseButtonPressed(MouseButton.Right)) { EmitSignalBuildingCanceled(); BuildMode = false; BuildManager.Instance.IsBuilding = false; QueueFree(); } } else { if (Input.IsActionJustPressed(Scripts.Globals.MyInput.MouseLeft) && _growAreaInside) { _holdInsideGrowArea = true; } if (Input.IsActionJustReleased(Scripts.Globals.MyInput.MouseLeft) && _growAreaInside) { _holdInsideGrowArea = false; } Age += GrowthFactor * delta.ToFloat(); Age = MathF.Min(Age, 1); QueueRedraw(); } // TODO: replace with line2d? QueueRedraw(); _lastPosition = GlobalPosition; } public override void _Draw() { if (BuildMode) { foreach (var nodule in ConnectedNodules) { DrawDashedLine( Vector2.Zero, nodule.GlobalPosition - GlobalPosition, Colors.White, 2f, dash: 4f, antialiased: true ); } } } private void HandleNoduleEntered(Nodule nodule) { ConnectedNodules.Add(nodule); } private void HandleNoduleExited(Nodule nodule) { ConnectedNodules.Remove(nodule); } private void BuildNode() { EmitSignalNoduleBuilt(); BuildMode = false; ChildNoduleWhileBuilding = null; // Weird architecture... BuildManager.Instance.IsBuilding = false; // try connecting built nodule to connected ones foreach (var connectedNodule in ConnectedNodules) { BuildManager.Instance.RegisterConnection(this, connectedNodule); } _.GrowArea.Get().MouseEntered += () => { _growAreaInside = true; }; _.GrowArea.Get().MouseExited += () => { if (_holdInsideGrowArea) { StartBuilding(); _holdInsideGrowArea = false; } _growAreaInside = false; }; } private void StartBuilding() { GD.Print("START BUILDING"); if (BuildManager.Instance.IsBuilding) return; BuildManager.Instance.IsBuilding = true; var newNodule = Instantiator.Instantiate(); GetParent().AddChild(newNodule); newNodule.BuildMode = true; newNodule.GlobalPosition = GlobalPosition; newNodule.ParentNoduleWhileBuilding = this; ChildNoduleWhileBuilding = newNodule; } }