using System.Collections.Generic; using System.Diagnostics; using Godot; using GodotComponentTest.components; using GodotComponentTest.entities; using GodotComponentTest.utils; public class Player : Entity, IInteractionInterface { // public members [Export] public NodePath WorldNode; public int WoodCount; public int GoldCount; public bool HasAxe; public TaskQueueComponent TaskQueueComponent; public NavigationComponent NavigationComponent { get; private set; } public InteractionComponent InteractionComponent { get; set; } [Signal] private delegate void WoodCountChanged(int woodCount); [Signal] private delegate void GoldCountChanged(int goldCount); // private members private WorldInfoComponent _worldInfo; private readonly List _attractedItemList = new(); private AnimationTree _animationTree; private DebugGeometry _debugGeometry; private GroundMotionComponent _groundMotion; private Area _itemAttractorArea; private Area _itemPickupArea; private AnimationPlayer _playerAnimationPlayer; private BoneAttachment _toolAttachement; // Called when the node enters the scene tree for the first time. public override void _Ready() { _groundMotion = new GroundMotionComponent(); _worldInfo = (WorldInfoComponent)FindNode("WorldInfo", false); NavigationComponent = (NavigationComponent)FindNode("Navigation", false); NavigationComponent.World = GetNode(WorldNode); TaskQueueComponent = new TaskQueueComponent(); _itemAttractorArea = (Area)FindNode("ItemAttractorArea", false); if (_itemAttractorArea == null) { GD.PushWarning("No ItemAttractorArea node found for " + GetClass()); } else { _itemAttractorArea.Connect("body_entered", this, nameof(OnItemAttractorBodyEntered)); _itemAttractorArea.Connect("body_exited", this, nameof(OnItemAttractorBodyExited)); } _itemPickupArea = (Area)FindNode("ItemPickupArea", false); if (_itemPickupArea == null) { GD.PushWarning("No ItemPickupArea node found for " + GetClass()); } else { _itemPickupArea.Connect("body_entered", this, nameof(OnItemPickupAreaBodyEntered)); } _animationTree = GetNode("Geometry/AnimationTree"); Debug.Assert(_animationTree != null); AnimationNodeStateMachinePlayback stateMachine = (AnimationNodeStateMachinePlayback)_animationTree.Get("parameters/playback"); stateMachine.Start("Idle"); _toolAttachement = (BoneAttachment)FindNode("ToolAttachement"); if (_toolAttachement == null) { GD.PushWarning("No ToolAttachement found!"); } _debugGeometry = (DebugGeometry)FindNode("DebugGeometry"); } public override void _PhysicsProcess(float delta) { base._PhysicsProcess(delta); if (NavigationComponent == null) { return; } if (TaskQueueComponent != null && TaskQueueComponent.Queue.Count > 0) { TaskQueueComponent.Process(this, delta); if (TaskQueueComponent.Queue.Count > 0) { TaskQueueComponent.Task currentTask = TaskQueueComponent.Queue.Peek(); TaskQueueComponent.NavigationTask navigationTask = currentTask as TaskQueueComponent.NavigationTask; if (navigationTask != null && navigationTask.PlanningComplete == false) { // _navigationComponent.PlanGridPath(this, GlobalTransform, navigationTask.NavigationPoint); NavigationComponent.PlanSmoothedPath(this, GlobalTransform, navigationTask.NavigationPoint); NavigationComponent.ActivatePlannedPath(); navigationTask.PlanningComplete = true; } NavigationComponent.UpdateCurrentGoal(GlobalTransform); _groundMotion.PhysicsProcess(delta, this, NavigationComponent.CurrentGoalPositionWorld, NavigationComponent.CurrentGoalAngleWorld, _worldInfo.World); if (NavigationComponent.IsGoalReached()) { navigationTask.NavigationPoint = new NavigationPoint(GlobalTransform); } } } } public override void _Process(float delta) { if (NavigationComponent != null) { NavigationComponent.UpdateCurrentGoal(GlobalTransform); } foreach (Node node in _attractedItemList) { Entity entity = node as Entity; if (entity != null) { CollectibleComponent collectibleComponent = entity.GetCollectibleComponent(); if (collectibleComponent != null) { collectibleComponent.SetTarget(GlobalTransform.origin); } } } UpdateDebugGeometry(); } public void UpdateDebugGeometry() { if (_debugGeometry == null || _debugGeometry.Visible == false) { return; } _debugGeometry.Clear(); _debugGeometry.GlobalTransform = Transform.Identity; if (NavigationComponent != null) { NavigationComponent.DebugDraw(this, _debugGeometry); } } public void OnItemAttractorBodyEntered(Node node) { _attractedItemList.Add(node); } public void OnItemAttractorBodyExited(Node node) { Entity entity = node as Entity; if (entity != null) { CollectibleComponent collectibleComponent = entity.GetCollectibleComponent(); if (collectibleComponent != null) { collectibleComponent.UnsetTarget(); } } _attractedItemList.Remove(node); } public void OnItemPickupAreaBodyEntered(Node body) { GD.Print("Picking up item: " + body.Name); if (body is Axe) { SetActiveTool("Axe"); } if (body is GoldBar) { GoldCount++; EmitSignal("GoldCountChanged", GoldCount); } else if (body is Wood) { WoodCount++; EmitSignal("WoodCountChanged", WoodCount); } body.QueueFree(); } public void SetActiveTool(string toolName) { Debug.Assert(_toolAttachement != null); if (toolName == "Axe") { _toolAttachement.Visible = true; HasAxe = true; } else if (toolName == "") { _toolAttachement.Visible = false; HasAxe = false; } } public void OnInteractionStart() { AnimationNodeStateMachinePlayback stateMachine = (AnimationNodeStateMachinePlayback)_animationTree.Get("parameters/playback"); Debug.Assert(stateMachine != null); if (InteractionComponent.TargetEntity is Chest) { GD.Print("Player Opening Box"); stateMachine.Travel("Interaction"); } else if (InteractionComponent.TargetEntity is Tree) { if (!HasAxe) { GD.Print("Not chopping tree, player has no Axe!"); InteractionComponent.EndInteraction(); stateMachine.Travel("Shrug-loop"); return; } GD.Print("Player Chopping Tree"); stateMachine.Travel("Hit"); } } public void OnInteractionEnd() { GD.Print("Player Stopping Interaction"); AnimationNodeStateMachinePlayback stateMachine = (AnimationNodeStateMachinePlayback)_animationTree.Get("parameters/playback"); Debug.Assert(stateMachine != null); stateMachine.Travel("Idle"); } }