Improved interactions.

- Interactions can now be stopped by both participating Entities.
- Player animation now controlled by AnimationTree.
WorldChunkRefactoring
Martin Felis 2023-06-26 22:34:48 +02:00
parent 22ad86319d
commit 2e7f30e214
9 changed files with 148 additions and 27 deletions

View File

@ -1,11 +1,47 @@
[gd_scene load_steps=3 format=2] [gd_scene load_steps=12 format=2]
[ext_resource path="res://assets/Characters/Pirate.glb" type="PackedScene" id=1] [ext_resource path="res://assets/Characters/Pirate.glb" type="PackedScene" id=1]
[ext_resource path="res://assets/Objects/toolAxe.tscn" type="PackedScene" id=2] [ext_resource path="res://assets/Objects/toolAxe.tscn" type="PackedScene" id=2]
[sub_resource type="AnimationNodeAnimation" id=1]
animation = "Hit-loop"
[sub_resource type="AnimationNodeAnimation" id=2]
animation = "Idle-loop"
[sub_resource type="AnimationNodeAnimation" id=3]
animation = "Interaction-loop"
[sub_resource type="AnimationNodeStateMachineTransition" id=4]
[sub_resource type="AnimationNodeStateMachineTransition" id=5]
switch_mode = 2
xfade_time = 0.2
[sub_resource type="AnimationNodeStateMachineTransition" id=6]
[sub_resource type="AnimationNodeStateMachineTransition" id=7]
switch_mode = 2
xfade_time = 0.2
[sub_resource type="AnimationNodeStateMachine" id=8]
states/Hit/node = SubResource( 1 )
states/Hit/position = Vector2( 415, 45 )
states/Idle/node = SubResource( 2 )
states/Idle/position = Vector2( 149, 39 )
states/Interaction/node = SubResource( 3 )
states/Interaction/position = Vector2( 176, 157 )
transitions = [ "Idle", "Hit", SubResource( 4 ), "Hit", "Idle", SubResource( 5 ), "Idle", "Interaction", SubResource( 6 ), "Interaction", "Idle", SubResource( 7 ) ]
start_node = "Idle"
[sub_resource type="AnimationNodeStateMachinePlayback" id=9]
[node name="Pirate" instance=ExtResource( 1 )] [node name="Pirate" instance=ExtResource( 1 )]
transform = Transform( 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0 ) transform = Transform( 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0 )
[node name="Skeleton" parent="Armature" index="0"]
bones/4/bound_children = [ NodePath("ToolAttachement") ]
[node name="ToolAttachement" type="BoneAttachment" parent="Armature/Skeleton" index="5"] [node name="ToolAttachement" type="BoneAttachment" parent="Armature/Skeleton" index="5"]
transform = Transform( 1, 8.68458e-08, -1.04308e-07, 1.74623e-07, -1, -1.30385e-07, 1.41561e-07, 1.50874e-07, -1, -0.72, 0.45, 3.28113e-08 ) transform = Transform( 1, 8.68458e-08, -1.04308e-07, 1.74623e-07, -1, -1.30385e-07, 1.41561e-07, 1.50874e-07, -1, -0.72, 0.45, 3.28113e-08 )
visible = false visible = false
@ -15,3 +51,9 @@ bone_name = "HandTip.R"
transform = Transform( -1.12419e-14, 8.74228e-08, -2, 2, -8.74228e-08, -1.39841e-13, -8.74228e-08, -2, -8.74228e-08, 2.38419e-07, -0.151768, 0.615043 ) transform = Transform( -1.12419e-14, 8.74228e-08, -2, 2, -8.74228e-08, -1.39841e-13, -8.74228e-08, -2, -8.74228e-08, 2.38419e-07, -0.151768, 0.615043 )
[node name="toolAxe" parent="Armature/Skeleton/ToolAttachement/Tool" index="0" instance=ExtResource( 2 )] [node name="toolAxe" parent="Armature/Skeleton/ToolAttachement/Tool" index="0" instance=ExtResource( 2 )]
[node name="AnimationTree" type="AnimationTree" parent="." index="2"]
tree_root = SubResource( 8 )
anim_player = NodePath("../AnimationPlayer")
active = true
parameters/playback = SubResource( 9 )

View File

@ -0,0 +1,15 @@
using Godot;
namespace GodotComponentTest.components;
public class InteractionComponent: Component
{
[Signal]
delegate void InteractionStart(Entity owningEntity, Entity targetEntity);
[Signal]
delegate void InteractionEnd(Entity owningEntity, Entity targetEntity);
public Entity OwningEntity;
public Entity TargetEntity;
}

View File

@ -1,6 +1,7 @@
using Godot; using Godot;
using System; using System;
using System.Linq; using System.Linq;
using GodotComponentTest.components;
using GodotComponentTest.entities; using GodotComponentTest.entities;
public class Chest : Entity, IInteractionInterface public class Chest : Entity, IInteractionInterface
@ -20,6 +21,13 @@ public class Chest : Entity, IInteractionInterface
private MeshInstance _mesh; private MeshInstance _mesh;
private AnimationPlayer _animationPlayer; private AnimationPlayer _animationPlayer;
private InteractionComponent _interactionComponent;
public InteractionComponent InteractionComponent
{
get => _interactionComponent;
set => _interactionComponent = value;
}
[Signal] [Signal]
delegate void EntityClicked(Entity entity); delegate void EntityClicked(Entity entity);
@ -105,5 +113,10 @@ public class Chest : Entity, IInteractionInterface
); );
GetParent().AddChild(bar); GetParent().AddChild(bar);
} }
if (_interactionComponent != null)
{
_interactionComponent.EmitSignal("InteractionEnd");
}
} }
} }

View File

@ -65,11 +65,14 @@ tracks/2/loop_wrap = true
tracks/2/imported = false tracks/2/imported = false
tracks/2/enabled = true tracks/2/enabled = true
tracks/2/keys = { tracks/2/keys = {
"times": PoolRealArray( 0.3 ), "times": PoolRealArray( 0.3, 1 ),
"transitions": PoolRealArray( 1 ), "transitions": PoolRealArray( 1, 1 ),
"values": [ { "values": [ {
"args": [ ], "args": [ ],
"method": "OnChestOpened" "method": "OnChestOpened"
}, {
"args": [ ],
"method": "OnChestOpened"
} ] } ]
} }

View File

@ -1,7 +1,15 @@
using GodotComponentTest.components;
namespace GodotComponentTest.entities; namespace GodotComponentTest.entities;
public interface IInteractionInterface public interface IInteractionInterface
{ {
void OnInteractionStart(); void OnInteractionStart();
void OnInteractionEnd(); void OnInteractionEnd();
InteractionComponent InteractionComponent
{
get;
set;
}
} }

View File

@ -3,6 +3,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using GodotComponentTest.components;
using GodotComponentTest.entities; using GodotComponentTest.entities;
public class Player : Entity, IInteractionInterface public class Player : Entity, IInteractionInterface
@ -30,6 +31,13 @@ public class Player : Entity, IInteractionInterface
private List<Node> _attractedItemList = new List<Node>(); private List<Node> _attractedItemList = new List<Node>();
private BoneAttachment _toolAttachement; private BoneAttachment _toolAttachement;
private AnimationPlayer _playerAnimationPlayer; private AnimationPlayer _playerAnimationPlayer;
private AnimationTree _animationTree;
private InteractionComponent _interactionComponent;
public InteractionComponent InteractionComponent
{
get => _interactionComponent;
set => _interactionComponent = value;
}
// Called when the node enters the scene tree for the first time. // Called when the node enters the scene tree for the first time.
public override void _Ready() public override void _Ready()
@ -61,8 +69,12 @@ public class Player : Entity, IInteractionInterface
_itemPickupArea.Connect("body_entered", this, nameof(OnItemPickupAreaBodyEntered)); _itemPickupArea.Connect("body_entered", this, nameof(OnItemPickupAreaBodyEntered));
} }
_playerAnimationPlayer = (AnimationPlayer)GetNode<AnimationPlayer>("Geometry/AnimationPlayer"); _playerAnimationPlayer = GetNode<AnimationPlayer>("Geometry/AnimationPlayer");
Debug.Assert(_playerAnimationPlayer != null); Debug.Assert(_playerAnimationPlayer != null);
_animationTree = GetNode<AnimationTree>("Geometry/AnimationTree");
Debug.Assert(_animationTree != null);
AnimationNodeStateMachinePlayback stateMachine = (AnimationNodeStateMachinePlayback)_animationTree.Get("parameters/playback");
stateMachine.Start("Idle");
_toolAttachement = (BoneAttachment)FindNode("ToolAttachement"); _toolAttachement = (BoneAttachment)FindNode("ToolAttachement");
if (_toolAttachement == null) if (_toolAttachement == null)
@ -168,14 +180,25 @@ public class Player : Entity, IInteractionInterface
public void OnInteractionStart() public void OnInteractionStart()
{ {
GD.Print("Player Starting Interaction"); AnimationNodeStateMachinePlayback stateMachine = (AnimationNodeStateMachinePlayback)_animationTree.Get("parameters/playback");
_playerAnimationPlayer.CurrentAnimation = "Hit-loop"; Debug.Assert(stateMachine != null);
_playerAnimationPlayer.Play();
if (_interactionComponent.TargetEntity is Chest)
{
GD.Print("Player Opening Box");
stateMachine.Travel("Interaction");
} else if (_interactionComponent.TargetEntity is Tree)
{
GD.Print("Player Chopping Tree");
stateMachine.Travel("Hit");
}
} }
public void OnInteractionEnd() public void OnInteractionEnd()
{ {
GD.Print("Player Stopping Interaction"); GD.Print("Player Stopping Interaction");
_playerAnimationPlayer.CurrentAnimation = "Idle-loop"; AnimationNodeStateMachinePlayback stateMachine = (AnimationNodeStateMachinePlayback)_animationTree.Get("parameters/playback");
Debug.Assert(stateMachine != null);
stateMachine.Travel("Idle");
} }
} }

View File

@ -1,17 +1,25 @@
using Godot; using Godot;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using GodotComponentTest.components;
using GodotComponentTest.entities; using GodotComponentTest.entities;
public class Tree : StaticBody, IInteractionInterface public class Tree : Entity, IInteractionInterface
{ {
[Export] public float ChopDuration = 2; [Export] public float ChopDuration = 2;
public bool IsMouseOver = false; public bool IsMouseOver;
private MeshInstance _geometry; private MeshInstance _geometry;
private AnimationPlayer _animationPlayer; private AnimationPlayer _animationPlayer;
private float _health = 100; private float _health = 100;
private bool _isBeingChopped = false; private bool _isBeingChopped;
private InteractionComponent _interactionComponent;
public InteractionComponent InteractionComponent
{
get => _interactionComponent;
set => _interactionComponent = value;
}
[Signal] [Signal]
delegate void EntityClicked(Entity entity); delegate void EntityClicked(Entity entity);

View File

@ -50,7 +50,7 @@ tracks/0/imported = false
tracks/0/enabled = true tracks/0/enabled = true
tracks/0/keys = PoolRealArray( 0, 1, 0, 0, 0, 0, 0, 0, 1, 1.5, 1, 1.5, 0.5, 1, 0, 0, 0, 0, 0, 0, 1, 1.5, 0.6, 1.5, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1.5, 1, 1.5 ) tracks/0/keys = PoolRealArray( 0, 1, 0, 0, 0, 0, 0, 0, 1, 1.5, 1, 1.5, 0.5, 1, 0, 0, 0, 0, 0, 0, 1, 1.5, 0.6, 1.5, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1.5, 1, 1.5 )
[node name="Tree" type="StaticBody"] [node name="Tree" type="KinematicBody"]
script = ExtResource( 3 ) script = ExtResource( 3 )
[node name="Geometry" type="MeshInstance" parent="."] [node name="Geometry" type="MeshInstance" parent="."]

View File

@ -2,6 +2,7 @@ using Godot;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Godot.Collections; using Godot.Collections;
using GodotComponentTest.components;
using GodotComponentTest.entities; using GodotComponentTest.entities;
using Array = System.Array; using Array = System.Array;
using NodePair = System.Tuple<Godot.Node, Godot.Node>; using NodePair = System.Tuple<Godot.Node, Godot.Node>;
@ -38,6 +39,7 @@ public class InteractionSystem : Node
if (interactableB != null) if (interactableB != null)
{ {
interactableB.OnInteractionEnd(); interactableB.OnInteractionEnd();
interactableB.InteractionComponent = null;
} }
} }
@ -47,10 +49,9 @@ public class InteractionSystem : Node
if (interactableA != null) if (interactableA != null)
{ {
interactableA.OnInteractionEnd(); interactableA.OnInteractionEnd();
interactableA.InteractionComponent = null;
} }
} }
} }
foreach (NodePair pair in invalidInteractionPairs) foreach (NodePair pair in invalidInteractionPairs)
@ -59,21 +60,29 @@ public class InteractionSystem : Node
} }
} }
public void OnStartInteraction(Node nodeA, Node nodeB) public void OnStartInteraction(Entity owningEntity, Entity targetEntity)
{ {
IInteractionInterface interactableA = nodeA as IInteractionInterface; InteractionComponent interactionComponent = new InteractionComponent();
if (interactableA != null) interactionComponent.OwningEntity = owningEntity;
{ interactionComponent.TargetEntity = targetEntity;
interactableA.OnInteractionStart();
} ConnectInteractionSignals(owningEntity, interactionComponent);
ConnectInteractionSignals(targetEntity, interactionComponent);
interactionComponent.EmitSignal("InteractionStart");
IInteractionInterface interactableB = nodeB as IInteractionInterface; NodePair pair = new NodePair(owningEntity, targetEntity);
if (interactableB != null) _interactionPairs.Add(new NodePair(owningEntity, targetEntity));
{ }
interactableB.OnInteractionStart();
}
NodePair pair = new NodePair(nodeA, nodeB); private static void ConnectInteractionSignals(Entity entity, InteractionComponent interactionComponent)
_interactionPairs.Add(new NodePair(nodeA, nodeB)); {
IInteractionInterface interactable = entity as IInteractionInterface;
if (interactable != null)
{
interactable.InteractionComponent = interactionComponent;
interactionComponent.Connect("InteractionStart", entity, nameof(interactable.OnInteractionStart));
interactionComponent.Connect("InteractionEnd", entity, nameof(interactable.OnInteractionEnd));
}
} }
} }