NavigationComponent can handle position and orientation targets.
parent
14e5d47d91
commit
716654a6fd
32
Game.gd
32
Game.gd
|
@ -1,32 +0,0 @@
|
||||||
extends Node2D
|
|
||||||
|
|
||||||
|
|
||||||
onready var SimpleEntity = preload("res://entities/SimpleEntity.tscn")
|
|
||||||
onready var WanderingEntity = preload("res://entities/WanderingEntity.tscn")
|
|
||||||
onready var player_movable_target_label = $UI/PlayerMovableTarget
|
|
||||||
onready var player = $PlayerEntity
|
|
||||||
onready var entities = $Entities
|
|
||||||
|
|
||||||
signal world_location_clicked
|
|
||||||
|
|
||||||
# Called when the node enters the scene tree for the first time.
|
|
||||||
func _ready():
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
func _process(delta):
|
|
||||||
player_movable_target_label.text = str(player.movable_component.target)
|
|
||||||
|
|
||||||
|
|
||||||
func _on_AddEntityButton_pressed():
|
|
||||||
var entity_instance = SimpleEntity.instance()
|
|
||||||
var viewport_rect = get_viewport_rect()
|
|
||||||
entity_instance.transform.origin = Vector2(randf() * viewport_rect.size[0], randf() * viewport_rect.size[1])
|
|
||||||
entities.add_child(entity_instance)
|
|
||||||
|
|
||||||
func _on_AddWanderingEntity_pressed():
|
|
||||||
var entity_instance = WanderingEntity.instance()
|
|
||||||
var viewport_rect = get_viewport_rect()
|
|
||||||
entity_instance.transform.origin = Vector2(randf() * viewport_rect.size[0], randf() * viewport_rect.size[1])
|
|
||||||
entities.add_child(entity_instance)
|
|
||||||
entity_instance.set_target(Vector2(randf() * viewport_rect.size[0], randf() * viewport_rect.size[1]))
|
|
131
Game.tscn
131
Game.tscn
|
@ -1,131 +0,0 @@
|
||||||
[gd_scene load_steps=10 format=2]
|
|
||||||
|
|
||||||
[ext_resource path="res://entities/SimpleEntity.tscn" type="PackedScene" id=1]
|
|
||||||
[ext_resource path="res://entities/PlayerEntity.tscn" type="PackedScene" id=2]
|
|
||||||
[ext_resource path="res://assets/white.png" type="Texture" id=3]
|
|
||||||
[ext_resource path="res://materials/PhysicsObjects.tres" type="Material" id=4]
|
|
||||||
[ext_resource path="res://utils/CollisionLine.gd" type="Script" id=5]
|
|
||||||
[ext_resource path="res://Game.gd" type="Script" id=6]
|
|
||||||
|
|
||||||
[sub_resource type="RectangleShape2D" id=1]
|
|
||||||
extents = Vector2( 57.5347, 51.5794 )
|
|
||||||
|
|
||||||
[sub_resource type="RectangleShape2D" id=2]
|
|
||||||
|
|
||||||
[sub_resource type="SegmentShape2D" id=3]
|
|
||||||
a = Vector2( 37, 302 )
|
|
||||||
b = Vector2( 34, 570 )
|
|
||||||
|
|
||||||
[node name="Game" type="Node2D"]
|
|
||||||
script = ExtResource( 6 )
|
|
||||||
|
|
||||||
[node name="Control" type="HBoxContainer" parent="."]
|
|
||||||
margin_left = 30.0
|
|
||||||
margin_top = 30.0
|
|
||||||
margin_right = 40.0
|
|
||||||
margin_bottom = 40.0
|
|
||||||
|
|
||||||
[node name="AddEntityButton" type="Button" parent="Control"]
|
|
||||||
margin_right = 77.0
|
|
||||||
margin_bottom = 20.0
|
|
||||||
text = "Add Entity"
|
|
||||||
__meta__ = {
|
|
||||||
"_edit_use_anchors_": false
|
|
||||||
}
|
|
||||||
|
|
||||||
[node name="AddWanderingEntity" type="Button" parent="Control"]
|
|
||||||
margin_left = 81.0
|
|
||||||
margin_right = 190.0
|
|
||||||
margin_bottom = 20.0
|
|
||||||
text = "Add Wandering"
|
|
||||||
__meta__ = {
|
|
||||||
"_edit_use_anchors_": false
|
|
||||||
}
|
|
||||||
|
|
||||||
[node name="Entities" type="Node2D" parent="."]
|
|
||||||
|
|
||||||
[node name="SimpleEntity" parent="Entities" instance=ExtResource( 1 )]
|
|
||||||
position = Vector2( 360, 118 )
|
|
||||||
|
|
||||||
[node name="SimpleEntity2" parent="Entities" instance=ExtResource( 1 )]
|
|
||||||
position = Vector2( 157, 306 )
|
|
||||||
|
|
||||||
[node name="PlayerEntity" parent="." instance=ExtResource( 2 )]
|
|
||||||
|
|
||||||
[node name="World" type="Node2D" parent="."]
|
|
||||||
|
|
||||||
[node name="Wall" type="KinematicBody2D" parent="World"]
|
|
||||||
position = Vector2( 582, 817 )
|
|
||||||
scale = Vector2( 7.56, 1 )
|
|
||||||
__meta__ = {
|
|
||||||
"_edit_group_": true
|
|
||||||
}
|
|
||||||
|
|
||||||
[node name="Sprite" type="Sprite" parent="World/Wall"]
|
|
||||||
material = ExtResource( 4 )
|
|
||||||
position = Vector2( 0.965286, 0.579379 )
|
|
||||||
scale = Vector2( 115, 104 )
|
|
||||||
texture = ExtResource( 3 )
|
|
||||||
|
|
||||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="World/Wall"]
|
|
||||||
position = Vector2( 0.465286, 0.57938 )
|
|
||||||
z_as_relative = false
|
|
||||||
shape = SubResource( 1 )
|
|
||||||
|
|
||||||
[node name="RigidBody2D" type="RigidBody2D" parent="World"]
|
|
||||||
position = Vector2( 649, 227 )
|
|
||||||
__meta__ = {
|
|
||||||
"_edit_group_": true
|
|
||||||
}
|
|
||||||
|
|
||||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="World/RigidBody2D"]
|
|
||||||
rotation = -0.432491
|
|
||||||
scale = Vector2( 11.5039, 4.3795 )
|
|
||||||
shape = SubResource( 2 )
|
|
||||||
|
|
||||||
[node name="Sprite" type="Sprite" parent="World/RigidBody2D/CollisionShape2D"]
|
|
||||||
material = ExtResource( 4 )
|
|
||||||
use_parent_material = true
|
|
||||||
scale = Vector2( 20.002, 19.4893 )
|
|
||||||
texture = ExtResource( 3 )
|
|
||||||
|
|
||||||
[node name="Wall2" type="KinematicBody2D" parent="World"]
|
|
||||||
position = Vector2( 896, 386 )
|
|
||||||
scale = Vector2( 7.56, 1 )
|
|
||||||
__meta__ = {
|
|
||||||
"_edit_group_": true
|
|
||||||
}
|
|
||||||
|
|
||||||
[node name="Sprite" type="Sprite" parent="World/Wall2"]
|
|
||||||
material = ExtResource( 4 )
|
|
||||||
position = Vector2( 0.965286, 0.579379 )
|
|
||||||
scale = Vector2( 115, 104 )
|
|
||||||
texture = ExtResource( 3 )
|
|
||||||
|
|
||||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="World/Wall2"]
|
|
||||||
position = Vector2( 0.465286, 0.57938 )
|
|
||||||
z_as_relative = false
|
|
||||||
shape = SubResource( 1 )
|
|
||||||
|
|
||||||
[node name="CollisionLine" type="KinematicBody2D" parent="World"]
|
|
||||||
position = Vector2( 221, 205 )
|
|
||||||
script = ExtResource( 5 )
|
|
||||||
|
|
||||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="World/CollisionLine"]
|
|
||||||
shape = SubResource( 3 )
|
|
||||||
|
|
||||||
[node name="UI" type="CanvasLayer" parent="."]
|
|
||||||
|
|
||||||
[node name="PlayerMovableTarget" type="Label" parent="UI"]
|
|
||||||
margin_right = 40.0
|
|
||||||
margin_bottom = 14.0
|
|
||||||
text = "Blaaa"
|
|
||||||
__meta__ = {
|
|
||||||
"_edit_use_anchors_": false
|
|
||||||
}
|
|
||||||
|
|
||||||
[connection signal="pressed" from="Control/AddEntityButton" to="." method="_on_AddEntityButton_pressed"]
|
|
||||||
[connection signal="pressed" from="Control/AddWanderingEntity" to="." method="_on_AddWanderingEntity_pressed"]
|
|
||||||
|
|
||||||
[editable path="Entities/SimpleEntity"]
|
|
||||||
[editable path="Entities/SimpleEntity2"]
|
|
|
@ -1,5 +1,9 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
public static class Globals
|
public static class Globals
|
||||||
{
|
{
|
||||||
public const float EpsPosition = 0.01f;
|
public const float EpsPosition = 0.01f;
|
||||||
public const float EpsPositionSquared = 0.01f * 0.01f;
|
public const float EpsPositionSquared = EpsPosition * EpsPosition;
|
||||||
|
public const float EpsRadians = 0.1f * Godot.Mathf.Pi / 180f;
|
||||||
|
public const float EpsRadiansSquared = EpsRadians * EpsRadians;
|
||||||
}
|
}
|
|
@ -13,4 +13,8 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Chickensoft.GoDotTest" Version="1.0.0" />
|
<PackageReference Include="Chickensoft.GoDotTest" Version="1.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="LocalSystems" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
public class Component : Node
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -6,12 +6,14 @@ using Vector3 = Godot.Vector3;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class GroundMotionComponent
|
public class GroundMotionComponent : Component
|
||||||
{
|
{
|
||||||
public float Accel = 50;
|
public float Accel = 50;
|
||||||
public float Damping = 0.2f;
|
public float Damping = 0.2f;
|
||||||
public float MaxSpeed = 8;
|
public float MaxSpeed = 8;
|
||||||
|
|
||||||
|
public float RotationSpeedRadPerSecond = 270 * Mathf.Pi / 180;
|
||||||
|
|
||||||
|
|
||||||
private void CalcPlaneVelocity(float delta, Entity entity, Vector3 targetPosition)
|
private void CalcPlaneVelocity(float delta, Entity entity, Vector3 targetPosition)
|
||||||
{
|
{
|
||||||
|
@ -19,13 +21,14 @@ public class GroundMotionComponent
|
||||||
targetPosition.z - entity.GlobalTranslation.z);
|
targetPosition.z - entity.GlobalTranslation.z);
|
||||||
float targetDistance = planeTargetVector.Length();
|
float targetDistance = planeTargetVector.Length();
|
||||||
Vector2 planeTargetDirection = planeTargetVector / targetDistance;
|
Vector2 planeTargetDirection = planeTargetVector / targetDistance;
|
||||||
|
Vector2 planeOrientation = new Vector2(entity.GlobalTransform.basis.z[0], entity.GlobalTransform.basis.z[2]);
|
||||||
|
|
||||||
Vector2 planeVelocity = new Vector2(entity.Velocity.x, entity.Velocity.z);
|
Vector2 planeVelocity = new Vector2(entity.Velocity.x, entity.Velocity.z);
|
||||||
// GD.Print("-- Step: distance: " + targetDistance + " dir: " + planeTargetDirection + " speed: " + planeVelocity.Length() + " vel dir: " + planeVelocity.Normalized());
|
// GD.Print("-- Step: distance: " + targetDistance + " dir: " + planeTargetDirection + " speed: " + planeVelocity.Length() + " vel dir: " + planeVelocity.Normalized());
|
||||||
planeVelocity -= planeVelocity * Damping;
|
planeVelocity -= planeVelocity * Damping;
|
||||||
// GD.Print(" damp : speed: " + planeVelocity.Length() + " vel dir: " + planeVelocity.Normalized());
|
// GD.Print(" damp : speed: " + planeVelocity.Length() + " vel dir: " + planeVelocity.Normalized());
|
||||||
|
|
||||||
if (targetDistance < 0.01)
|
if (targetDistance < 0.01 || planeOrientation.Dot(planeTargetDirection) < 0.9)
|
||||||
{
|
{
|
||||||
planeVelocity = Vector2.Zero;
|
planeVelocity = Vector2.Zero;
|
||||||
} else {
|
} else {
|
||||||
|
@ -79,15 +82,46 @@ public class GroundMotionComponent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void PhysicsProcess(float delta, Entity entity, Vector3 targetPosition, TileWorld tileWorld)
|
public void PhysicsProcess(float delta, Entity entity, Vector3 targetPosition, Quat targetOrientation, TileWorld tileWorld)
|
||||||
{
|
{
|
||||||
|
CalcAndApplyOrientation(delta, entity, targetPosition, targetOrientation);
|
||||||
CalcPlaneVelocity(delta, entity, targetPosition);
|
CalcPlaneVelocity(delta, entity, targetPosition);
|
||||||
|
|
||||||
CalcVerticalVelocity(delta, entity, tileWorld);
|
CalcVerticalVelocity(delta, entity, tileWorld);
|
||||||
|
|
||||||
Vector3 prePhysicsVelocity = entity.Velocity;
|
|
||||||
entity.Velocity = entity.MoveAndSlide(entity.Velocity);
|
entity.Velocity = entity.MoveAndSlide(entity.Velocity);
|
||||||
|
|
||||||
//GD.Print("Pre : speed: " + prePhysicsVelocity.Length() + " Velocity: " + prePhysicsVelocity);
|
//GD.Print("Pre : speed: " + prePhysicsVelocity.Length() + " Velocity: " + prePhysicsVelocity);
|
||||||
//GD.Print("Post: speed: " + entity.Velocity.Length() + " Velocity: " + entity.Velocity);
|
//GD.Print("Post: speed: " + entity.Velocity.Length() + " Velocity: " + entity.Velocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CalcAndApplyOrientation(float delta, Entity entity, Vector3 targetPosition, Quat targetOrientation)
|
||||||
|
{
|
||||||
|
Vector3 direction_to_target = targetPosition - entity.GlobalTranslation;
|
||||||
|
|
||||||
|
if (direction_to_target.LengthSquared() > Globals.EpsPositionSquared)
|
||||||
|
{
|
||||||
|
direction_to_target = direction_to_target.Normalized();
|
||||||
|
Vector3 localXAxis = Vector3.Up.Cross(direction_to_target);
|
||||||
|
targetOrientation = new Basis(localXAxis, Vector3.Up, direction_to_target).Quat().Normalized();
|
||||||
|
}
|
||||||
|
|
||||||
|
float orientationErrorRadians = entity.GlobalTransform.basis.Quat().AngleTo(targetOrientation);
|
||||||
|
if (orientationErrorRadians > 0)
|
||||||
|
{
|
||||||
|
Transform entityTransform = entity.Transform;
|
||||||
|
if (orientationErrorRadians < RotationSpeedRadPerSecond * delta)
|
||||||
|
{
|
||||||
|
entityTransform.basis = new Basis(targetOrientation);
|
||||||
|
}
|
||||||
|
else if (orientationErrorRadians > 0f)
|
||||||
|
{
|
||||||
|
Quat entityRotation = new Quat(entityTransform.basis);
|
||||||
|
float slerpWeight = RotationSpeedRadPerSecond / (orientationErrorRadians / delta);
|
||||||
|
entityRotation = entityRotation.Slerp(targetOrientation, slerpWeight);
|
||||||
|
entityTransform.basis = new Basis(entityRotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.Transform = entityTransform;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
using Godot;
|
using Godot;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
public class MovableComponent : Node
|
public class MovableComponent : Component
|
||||||
{
|
{
|
||||||
public Vector3 targetPosition = Vector3.Zero;
|
public Vector3 targetPosition = Vector3.Zero;
|
||||||
public Vector3 currentPosition = Vector3.Zero;
|
public Vector3 currentPosition = Vector3.Zero;
|
||||||
|
@ -58,7 +58,7 @@ public class MovableComponent : Node
|
||||||
currentAngle = springDamperResult.Item1;
|
currentAngle = springDamperResult.Item1;
|
||||||
currentAngularVelocity = springDamperResult.Item2;
|
currentAngularVelocity = springDamperResult.Item2;
|
||||||
|
|
||||||
EmitSignal("OrientationUpdated", this.currentAngle);
|
// EmitSignal("OrientationUpdated", this.currentAngle);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((Mathf.Abs(currentAngularVelocity) < 5 && Mathf.Abs(targetAngle - currentAngle) < 0.3)
|
if ((Mathf.Abs(currentAngularVelocity) < 5 && Mathf.Abs(targetAngle - currentAngle) < 0.3)
|
||||||
|
|
|
@ -12,22 +12,48 @@ using GoDotLog;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class NavigationComponent : Node
|
public class NavigationComponent : Node
|
||||||
{
|
{
|
||||||
|
public class NavigationPoint
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
public enum NavigationFlags
|
||||||
|
{
|
||||||
|
Position = 1,
|
||||||
|
Orientation = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 WorldPosition = Vector3.Zero;
|
||||||
|
public Quat WorldOrientation = Quat.Identity;
|
||||||
|
public NavigationFlags Flags = NavigationFlags.Position | NavigationFlags.Orientation;
|
||||||
|
|
||||||
|
public NavigationPoint(Vector3 worldPosition)
|
||||||
|
{
|
||||||
|
WorldPosition = worldPosition;
|
||||||
|
Flags = NavigationFlags.Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NavigationPoint(Quat worldOrientation)
|
||||||
|
{
|
||||||
|
WorldOrientation = worldOrientation;
|
||||||
|
Flags = NavigationFlags.Orientation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public TileWorld TileWorld { set; get; }
|
public TileWorld TileWorld { set; get; }
|
||||||
|
|
||||||
public Vector3 CurrentGoalWorld => _currentGoalWorld;
|
public Vector3 CurrentGoalPositionWorld => _currentGoalPositionWorld;
|
||||||
|
public Quat CurrentGoalOrientationWorld => _currentGoalOrientationWorld;
|
||||||
|
|
||||||
private Vector3 _currentGoalWorld = Vector3.Zero;
|
private NavigationPoint _currentGoal;
|
||||||
private Vector2 _currentGoalPlane = Vector2.Zero;
|
private Vector3 _currentGoalPositionWorld = Vector3.Zero;
|
||||||
private Vector2 _currentGoalOffset = Vector2.Zero;
|
private Quat _currentGoalOrientationWorld = Quat.Identity;
|
||||||
private Vector3 _currentPositionWorld = Vector3.Zero;
|
|
||||||
|
|
||||||
private List<Vector2> _pathOffsetCoords;
|
private List<NavigationPoint> _pathWorldNavigationPoints;
|
||||||
private HexCell[] _path;
|
private HexCell[] _path;
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
base._Ready();
|
base._Ready();
|
||||||
_pathOffsetCoords = new List<Vector2>();
|
_pathWorldNavigationPoints = new List<NavigationPoint>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _Process(float delta)
|
public override void _Process(float delta)
|
||||||
|
@ -50,39 +76,103 @@ public class NavigationComponent : Node
|
||||||
_path = fromCell.LineTo(toCell);
|
_path = fromCell.LineTo(toCell);
|
||||||
Debug.Assert(_path.Length > 0);
|
Debug.Assert(_path.Length > 0);
|
||||||
|
|
||||||
_pathOffsetCoords = new List<Vector2>();
|
_pathWorldNavigationPoints = new List<NavigationPoint>();
|
||||||
foreach (int index in Enumerable.Range(1, _path.Length - 1))
|
foreach (int index in Enumerable.Range(1, _path.Length - 1))
|
||||||
{
|
{
|
||||||
_pathOffsetCoords.Add(_path[index].OffsetCoords);
|
_pathWorldNavigationPoints.Add(
|
||||||
|
new NavigationPoint(TileWorld.GetTileWorldCenterFromOffset(_path[index].OffsetCoords)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((toPositionWorld - TileWorld.GetTileWorldCenterFromOffset(toCell.OffsetCoords)).LengthSquared() >
|
||||||
|
Globals.EpsPositionSquared)
|
||||||
|
{
|
||||||
|
_pathWorldNavigationPoints.Add(new NavigationPoint(toPositionWorld));
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateCurrentGoal();
|
UpdateCurrentGoal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Plan(Vector3 fromPositionWorld, Vector3 toPositionWorld, Quat toWorldOrientation)
|
||||||
|
{
|
||||||
|
Plan(fromPositionWorld, toPositionWorld);
|
||||||
|
|
||||||
|
_pathWorldNavigationPoints.Add(new NavigationPoint(toWorldOrientation));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void UpdateCurrentGoal()
|
private void UpdateCurrentGoal()
|
||||||
{
|
{
|
||||||
if (_pathOffsetCoords.Count == 0)
|
if (_pathWorldNavigationPoints.Count == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_currentGoalWorld = TileWorld.GetTileWorldCenterFromOffset(_pathOffsetCoords[0]);
|
_currentGoal = _pathWorldNavigationPoints[0];
|
||||||
|
|
||||||
GD.Print("Navigation: at " + _currentGoalWorld + " path length: " +
|
GD.Print("Navigation Goal: pos " + _currentGoal.WorldPosition + " " + " rot: " + _currentGoal.WorldOrientation +
|
||||||
_pathOffsetCoords.Count);
|
" flags: " + _currentGoal.Flags + " path length: " +
|
||||||
|
_pathWorldNavigationPoints.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void UpdateCurrentGoal(Vector3 currentPositionWorld)
|
public void UpdateCurrentGoal(Transform currentTransformWorld)
|
||||||
{
|
{
|
||||||
_currentPositionWorld = currentPositionWorld;
|
if (_pathWorldNavigationPoints.Count == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentGoal.Flags.HasFlag(NavigationPoint.NavigationFlags.Position))
|
||||||
|
{
|
||||||
|
_currentGoalPositionWorld = _pathWorldNavigationPoints[0].WorldPosition;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_currentGoalPositionWorld = currentTransformWorld.origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentGoal.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation))
|
||||||
|
{
|
||||||
|
_currentGoalOrientationWorld = _currentGoal.WorldOrientation;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_currentGoalOrientationWorld = currentTransformWorld.basis.Quat();
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 currentPositionWorld = currentTransformWorld.origin;
|
||||||
|
Quat currentOrientationWorld = currentTransformWorld.basis.Quat();
|
||||||
|
|
||||||
Vector2 currentPositionPlane = new Vector2(currentPositionWorld.x, currentPositionWorld.z);
|
Vector2 currentPositionPlane = new Vector2(currentPositionWorld.x, currentPositionWorld.z);
|
||||||
Vector2 currentGoalPlane = new Vector2(_currentGoalWorld.x, _currentGoalWorld.z);
|
Vector2 currentGoalPlane = new Vector2(_currentGoal.WorldPosition.x, _currentGoal.WorldPosition.z);
|
||||||
if (_pathOffsetCoords.Count > 0 &&
|
|
||||||
(currentPositionPlane - currentGoalPlane).LengthSquared() < Globals.EpsPositionSquared)
|
bool goalReached = false;
|
||||||
|
float positionErrorSquared = (currentPositionPlane - currentGoalPlane).LengthSquared();
|
||||||
|
float orientationError = _currentGoalOrientationWorld.AngleTo(currentOrientationWorld);
|
||||||
|
|
||||||
|
if (_currentGoal.Flags.HasFlag(NavigationPoint.NavigationFlags.Position)
|
||||||
|
&& _currentGoal.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation)
|
||||||
|
&& positionErrorSquared < Globals.EpsPositionSquared
|
||||||
|
&& orientationError < Globals.EpsRadians)
|
||||||
{
|
{
|
||||||
_pathOffsetCoords.RemoveAt(0);
|
goalReached = true;
|
||||||
|
}
|
||||||
|
else if (_currentGoal.Flags.HasFlag(NavigationPoint.NavigationFlags.Position) &&
|
||||||
|
positionErrorSquared < Globals.EpsPositionSquared)
|
||||||
|
{
|
||||||
|
goalReached = true;
|
||||||
|
}
|
||||||
|
else if (_currentGoal.Flags.HasFlag(NavigationPoint.NavigationFlags.Orientation) &&
|
||||||
|
orientationError < Globals.EpsRadians)
|
||||||
|
|
||||||
|
{
|
||||||
|
goalReached = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (goalReached)
|
||||||
|
{
|
||||||
|
_pathWorldNavigationPoints.RemoveAt(0);
|
||||||
UpdateCurrentGoal();
|
UpdateCurrentGoal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
using Godot;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
public class TaskQueueComponent : Component
|
||||||
|
{
|
||||||
|
public class Task
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NavigationTask : Task
|
||||||
|
{
|
||||||
|
[Flags] public enum Flags
|
||||||
|
{
|
||||||
|
Position = 1,
|
||||||
|
Orientation = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 TargetPositionWorld = Vector3.Zero;
|
||||||
|
public Quat TargetOrientationWorld = Quat.Identity;
|
||||||
|
public Flags NavigationFlags = Flags.Position | Flags.Orientation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class InteractionTask : Task
|
||||||
|
{
|
||||||
|
public Entity TargetEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Queue<Task> Queue;
|
||||||
|
|
||||||
|
public TaskQueueComponent()
|
||||||
|
{
|
||||||
|
Queue = new Queue<Task>();
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
Queue.Clear();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
using Godot;
|
using Godot;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
public class WorldInfoComponent : Node
|
public class WorldInfoComponent : Component
|
||||||
{
|
{
|
||||||
[Export] public NodePath World;
|
[Export] public NodePath World;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
@startuml
|
||||||
|
'https://plantuml.com/class-diagram
|
||||||
|
|
||||||
|
class Entity
|
||||||
|
Entity *-- Component
|
||||||
|
|
||||||
|
Entity : update()
|
||||||
|
Entity : Component[] mComponents
|
||||||
|
Entity : LocalSystem[] mSystems;
|
||||||
|
|
||||||
|
class Component3 {
|
||||||
|
void update()
|
||||||
|
int counter
|
||||||
|
}
|
||||||
|
note right of Entity::update
|
||||||
|
lel
|
||||||
|
end note
|
||||||
|
|
||||||
|
@enduml
|
|
@ -51,9 +51,4 @@ public class Chest : Entity
|
||||||
IsMouseOver = false;
|
IsMouseOver = false;
|
||||||
_mesh.MaterialOverride = null;
|
_mesh.MaterialOverride = null;
|
||||||
}
|
}
|
||||||
// // Called every frame. 'delta' is the elapsed time since the previous frame.
|
|
||||||
// public override void _Process(float delta)
|
|
||||||
// {
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
[gd_scene load_steps=3 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://assets/Objects/chest.glb" type="PackedScene" id=1]
|
||||||
|
[ext_resource path="res://entities/Chest.cs" type="Script" id=2]
|
||||||
|
|
||||||
|
[node name="Chest" instance=ExtResource( 1 )]
|
||||||
|
script = ExtResource( 2 )
|
||||||
|
|
||||||
|
[node name="Armature" parent="." index="2"]
|
||||||
|
transform = Transform( -0.259808, 0, 0.15, 0, 0.3, 0, -0.15, 0, -0.259808, 0, 0, 0 )
|
|
@ -0,0 +1,33 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Godot;
|
||||||
|
using Godot.Collections;
|
||||||
|
|
||||||
|
namespace GodotComponentTest.entities;
|
||||||
|
|
||||||
|
public class Flower : Entity
|
||||||
|
{
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
Array<Node> children = new Array<Node>();
|
||||||
|
GetAllChildren(this, ref children);
|
||||||
|
|
||||||
|
foreach (Node child in children)
|
||||||
|
{
|
||||||
|
if (child is ClickableComponent)
|
||||||
|
{
|
||||||
|
GD.Print("Found Clickable Component!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetAllChildren(Node childNode, ref Array<Node> childList)
|
||||||
|
{
|
||||||
|
var children = childNode.GetChildren();
|
||||||
|
foreach (Node child in children)
|
||||||
|
{
|
||||||
|
childList.Add(child);
|
||||||
|
GetAllChildren(child, ref childList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,8 @@ public class Player : Entity
|
||||||
// public members
|
// public members
|
||||||
public Vector3 TargetPosition = Vector3.Zero;
|
public Vector3 TargetPosition = Vector3.Zero;
|
||||||
|
|
||||||
|
public TaskQueueComponent TaskQueueComponent;
|
||||||
|
|
||||||
public NavigationComponent Navigation
|
public NavigationComponent Navigation
|
||||||
{
|
{
|
||||||
get { return _navigationComponent; }
|
get { return _navigationComponent; }
|
||||||
|
@ -15,7 +17,6 @@ public class Player : Entity
|
||||||
private MovableComponent _movable;
|
private MovableComponent _movable;
|
||||||
private Spatial _geometry;
|
private Spatial _geometry;
|
||||||
private WorldInfoComponent _worldInfo;
|
private WorldInfoComponent _worldInfo;
|
||||||
private Vector2 _offsetCoord = Vector2.Zero;
|
|
||||||
private GroundMotionComponent _groundMotion;
|
private GroundMotionComponent _groundMotion;
|
||||||
private NavigationComponent _navigationComponent;
|
private NavigationComponent _navigationComponent;
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ public class Player : Entity
|
||||||
_worldInfo = (WorldInfoComponent)FindNode("WorldInfo", false);
|
_worldInfo = (WorldInfoComponent)FindNode("WorldInfo", false);
|
||||||
_navigationComponent = (NavigationComponent)FindNode("Navigation", false);
|
_navigationComponent = (NavigationComponent)FindNode("Navigation", false);
|
||||||
_navigationComponent.TileWorld = _worldInfo.TileWorld;
|
_navigationComponent.TileWorld = _worldInfo.TileWorld;
|
||||||
|
TaskQueueComponent = new TaskQueueComponent();
|
||||||
|
|
||||||
_movable = (MovableComponent)FindNode("Movable", false);
|
_movable = (MovableComponent)FindNode("Movable", false);
|
||||||
if (_movable != null)
|
if (_movable != null)
|
||||||
|
@ -46,9 +48,18 @@ public class Player : Entity
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_navigationComponent.UpdateCurrentGoal(GlobalTranslation);
|
if (TaskQueueComponent != null && TaskQueueComponent.Queue.Count > 0)
|
||||||
|
{
|
||||||
|
var currentTask = TaskQueueComponent.Queue.Peek();
|
||||||
|
if (currentTask is TaskQueueComponent.NavigationTask)
|
||||||
|
{
|
||||||
|
TaskQueueComponent.NavigationTask navigationTask = (TaskQueueComponent.NavigationTask)TaskQueueComponent.Queue.Dequeue();
|
||||||
|
|
||||||
_groundMotion.PhysicsProcess(delta, this, _navigationComponent.CurrentGoalWorld, _worldInfo.TileWorld);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_navigationComponent.UpdateCurrentGoal(GlobalTransform);
|
||||||
|
_groundMotion.PhysicsProcess(delta, this, _navigationComponent.CurrentGoalPositionWorld, _navigationComponent.CurrentGoalOrientationWorld, _worldInfo.TileWorld);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -56,11 +67,12 @@ public class Player : Entity
|
||||||
{
|
{
|
||||||
if (_navigationComponent != null)
|
if (_navigationComponent != null)
|
||||||
{
|
{
|
||||||
_navigationComponent.UpdateCurrentGoal(GlobalTranslation);
|
_navigationComponent.UpdateCurrentGoal(GlobalTransform);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private void OnOrientationUpdated(float newOrientation)
|
private void OnOrientationUpdated(float newOrientation)
|
||||||
{
|
{
|
||||||
_geometry.Transform = new Transform(new Quat(Vector3.Up, newOrientation), Vector3.Zero);
|
_geometry.Transform = new Transform(new Quat(Vector3.Up, newOrientation), Vector3.Zero);
|
||||||
|
|
|
@ -75,7 +75,7 @@ _global_script_class_icons={
|
||||||
[application]
|
[application]
|
||||||
|
|
||||||
config/name="i3sc1 GodotComponentTest"
|
config/name="i3sc1 GodotComponentTest"
|
||||||
run/main_scene="res://scenes/AdaptiveWorldStream.tscn"
|
run/main_scene="res://scenes/Game.tscn"
|
||||||
config/icon="res://icon.png"
|
config/icon="res://icon.png"
|
||||||
|
|
||||||
[display]
|
[display]
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
[gd_scene load_steps=27 format=2]
|
[gd_scene load_steps=26 format=2]
|
||||||
|
|
||||||
[ext_resource path="res://scenes/AdaptiveWorldStream.cs" type="Script" id=1]
|
|
||||||
[ext_resource path="res://assets/CreatusPiratePack/characters/Pirate1final_0.01.glb" type="PackedScene" id=2]
|
[ext_resource path="res://assets/CreatusPiratePack/characters/Pirate1final_0.01.glb" type="PackedScene" id=2]
|
||||||
[ext_resource path="res://components/WorldInfoComponent.cs" type="Script" id=3]
|
[ext_resource path="res://components/WorldInfoComponent.cs" type="Script" id=3]
|
||||||
[ext_resource path="res://scenes/StreamContainer.cs" type="Script" id=4]
|
[ext_resource path="res://scenes/StreamContainer.cs" type="Script" id=4]
|
||||||
|
@ -104,7 +103,6 @@ tracks/1/keys = PoolRealArray( 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0.133333, 1,
|
||||||
extents = Vector3( 0.2, 0.2, 0.332224 )
|
extents = Vector3( 0.2, 0.2, 0.332224 )
|
||||||
|
|
||||||
[node name="AdaptiveWorldStream" type="Spatial"]
|
[node name="AdaptiveWorldStream" type="Spatial"]
|
||||||
script = ExtResource( 1 )
|
|
||||||
|
|
||||||
[node name="TileHighlight" parent="." instance=ExtResource( 7 )]
|
[node name="TileHighlight" parent="." instance=ExtResource( 7 )]
|
||||||
visible = false
|
visible = false
|
||||||
|
|
|
@ -6,7 +6,7 @@ using GoDotLog;
|
||||||
using Dictionary = Godot.Collections.Dictionary;
|
using Dictionary = Godot.Collections.Dictionary;
|
||||||
using Array = Godot.Collections.Array;
|
using Array = Godot.Collections.Array;
|
||||||
|
|
||||||
public class AdaptiveWorldStream : Spatial
|
public class Game : Spatial
|
||||||
{
|
{
|
||||||
// ui elements
|
// ui elements
|
||||||
private Label _framesPerSecondLabel;
|
private Label _framesPerSecondLabel;
|
||||||
|
@ -59,7 +59,7 @@ public class AdaptiveWorldStream : Spatial
|
||||||
_streamContainerArea = GetNode<Area>("StreamContainer/Area");
|
_streamContainerArea = GetNode<Area>("StreamContainer/Area");
|
||||||
_streamContainerActiveTiles = GetNode<Spatial>("StreamContainer/ActiveTiles");
|
_streamContainerActiveTiles = GetNode<Spatial>("StreamContainer/ActiveTiles");
|
||||||
_player = GetNode<Player>("Player");
|
_player = GetNode<Player>("Player");
|
||||||
_chest = GetNode<Chest>("Chest");
|
_chest = GetNode<Chest>("Entities/Chest");
|
||||||
_tileWorld = GetNode<TileWorld>("TileWorld");
|
_tileWorld = GetNode<TileWorld>("TileWorld");
|
||||||
|
|
||||||
Debug.Assert(_tileWorld != null);
|
Debug.Assert(_tileWorld != null);
|
||||||
|
@ -193,6 +193,13 @@ public class AdaptiveWorldStream : Spatial
|
||||||
public void OnEntityClicked(Entity entity)
|
public void OnEntityClicked(Entity entity)
|
||||||
{
|
{
|
||||||
GD.Print("Clicked on entity at " + entity.GlobalTranslation);
|
GD.Print("Clicked on entity at " + entity.GlobalTranslation);
|
||||||
|
|
||||||
|
Spatial mountPoint = (Spatial)entity.FindNode("MountPoint");
|
||||||
|
if (mountPoint != null)
|
||||||
|
{
|
||||||
|
GD.Print("Mount point!");
|
||||||
|
_player.Navigation.Plan(_player.GlobalTranslation, mountPoint.GlobalTranslation, mountPoint.GlobalTransform.basis.Quat());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,12 @@
|
||||||
|
public class LookupWorldSystem : IWorldSystemInterface
|
||||||
|
{
|
||||||
|
public void RegisterEntityComponent(Entity entity, Component component)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(float delta)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
public interface IWorldSystemInterface
|
||||||
|
{
|
||||||
|
void RegisterEntityComponent(Entity entity, Component component);
|
||||||
|
void Update(float delta);
|
||||||
|
}
|
Loading…
Reference in New Issue