Implement basic path following for Meldewesen

The PathNavigatorForKinematicBody node can take a KinematicBody as a
child and move it along its path. It doesn't strictly follow the path
though, but also avoids obstacles according to the Navigation (with its
Navmesh).

How the Navigation node is fetched will be changed using Groups later,
the current structure is temporary.

A PathTestWorld has been added for testing this behavior, as well as a
basic Meldewesen.
This commit is contained in:
karl 2019-10-28 01:21:41 +01:00
parent 28775eef3c
commit 9c583ed694
6 changed files with 208 additions and 0 deletions

View File

@ -0,0 +1,13 @@
extends KinematicBody
# Declare member variables here. Examples:
# var a = 2
# var b = "text"
# Called when the node enters the scene tree for the first time.
func _ready():
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
# pass

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,75 @@
extends Path
var _current_nav_path: PoolVector3Array
var _current_nav_index = 0
var _current_path_index = 1
var _arrived_distance_threshold = 0.1
export(float) var speed = 8
export(NodePath) var navigation_nodepath
export(NodePath) var body_nodepath
var navigation: Navigation
var body: KinematicBody
func _ready():
navigation = get_node(navigation_nodepath) as Navigation
body = get_node(body_nodepath) as KinematicBody
# Initialize the position
body.transform.origin = curve.get_point_position(0)
# Get the first goal
_get_new_navigation()
func _process(delta):
var current_goal = _get_current_goal()
# Move towards the current goal
var direction = (current_goal - _get_body_position()).normalized()
body.move_and_slide(direction * speed)
# Look towards that goal as well
body.look_at(_get_body_position() + direction, Vector3.UP)
# Returns the point we should currently be moving towards
func _get_current_goal():
# If we haven't arrived at the current goal, then that's still the goal
if _current_nav_path[_current_nav_index].distance_to(_get_body_position()) > _arrived_distance_threshold:
return _current_nav_path[_current_nav_index]
if _current_nav_index < _current_nav_path.size() - 1:
# We still have points left in the current navigation -> use the next one
_current_nav_index += 1
else:
# We're done following the current navigation to the next path point
if _current_path_index < curve.get_point_count() - 1:
# We still have points left in the path -> use the next one and generate the navigation to it
_current_path_index += 1
else:
# We're done following the path -> Go back to the start
_current_nav_index = 0
_current_path_index = 0
_get_new_navigation()
return _current_nav_path[_current_nav_index]
# Reset the navigation and build a new one for the current path index
func _get_new_navigation():
_current_nav_index = 0
var goal = curve.get_point_position(_current_path_index)
_current_nav_path = navigation.get_simple_path(_get_body_position(), goal)
# Return the current position of the body we're controlling
func _get_body_position():
return body.transform.origin

View File

@ -0,0 +1,15 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://Characters/Util/PathNavigatorForKinematicBody.gd" type="Script" id=1]
[sub_resource type="Curve3D" id=4]
_data = {
"points": PoolVector3Array( 0, 0, 0, 0, 0, 0, -7.92509, 2.86102e-05, -6.86376, 0, 0, 0, 0, 0, 0, 0.703341, 0.398803, 1.99739, 0, 0, 0, 0, 0, 0, 9.39952, 0.263628, 7.15156, 0, 0, 0, 0, 0, 0, -4.38803, 1.73835, 6.52798 ),
"tilts": PoolRealArray( 0, 0, 0, 0 )
}
[node name="PathNavigatorForKinematicBody" type="Path"]
curve = SubResource( 4 )
script = ExtResource( 1 )
navigation_nodepath = NodePath("..")
body_nodepath = NodePath("../KinematicBody")

43
Level/PathTestWorld.tscn Normal file
View File

@ -0,0 +1,43 @@
[gd_scene load_steps=6 format=2]
[ext_resource path="res://Characters/Util/PathNavigatorForKinematicBody.tscn" type="PackedScene" id=1]
[ext_resource path="res://Characters/Meldewesen/Meldewesen.tscn" type="PackedScene" id=2]
[sub_resource type="NavigationMesh" id=1]
vertices = PoolVector3Array( -1.3, 0.4, -1.6, 0.200001, 0.4, -1.6, 0.200001, 0.4, -9.4, -9.4, 0.4, -0.0999994, -1.6, 0.4, -0.0999994, -1.3, 0.4, -1.6, 0.200001, 0.4, -9.4, -9.4, 0.4, -9.4, 0.200001, 0.4, -9.4, 0.200001, 0.4, -1.6, 1.4, 0.4, -1.6, 1.4, 0.4, -1.6, 1.7, 0.4, -0.0999994, 9.5, 0.4, -0.0999994, 9.5, 0.4, -9.4, 0.200001, 0.4, -9.4, 0.200001, 0.4, 9.5, 0.200001, 0.4, 8.3, -1.6, 0.4, 8, -9.4, 0.4, 9.5, -1.6, 0.4, 5, 0.200001, 0.4, 4.7, 0.200001, 0.4, 1.7, -1.6, 0.4, 1.4, -1.6, 0.4, 5, -1.6, 0.4, 1.4, -9.4, 0.4, -0.0999994, -9.4, 0.4, 9.5, -1.6, 0.4, 1.4, -1.6, 0.4, -0.0999994, -9.4, 0.4, -0.0999994, -9.4, 0.4, 9.5, -1.6, 0.4, 8, -1.6, 0.4, 5, 1.7, 0.4, 8, 0.200001, 0.4, 8.3, 0.200001, 0.4, 9.5, 9.5, 0.4, 9.5, 0.200001, 0.4, 1.7, 0.200001, 0.4, 4.7, 1.7, 0.4, 5, 1.7, 0.4, 1.4, 1.7, 0.4, 5, 9.5, 0.4, 9.5, 9.5, 0.4, -0.0999994, 1.7, 0.4, 1.4, 1.7, 0.4, 5, 1.7, 0.4, 8, 9.5, 0.4, 9.5, 9.5, 0.4, -0.0999994, 1.7, 0.4, -0.0999994, 1.7, 0.4, 1.4 )
polygons = [ PoolIntArray( 2, 0, 1 ), PoolIntArray( 7, 3, 6 ), PoolIntArray( 3, 5, 6 ), PoolIntArray( 3, 4, 5 ), PoolIntArray( 10, 8, 9 ), PoolIntArray( 15, 11, 14 ), PoolIntArray( 11, 12, 14 ), PoolIntArray( 12, 13, 14 ), PoolIntArray( 19, 16, 18 ), PoolIntArray( 16, 17, 18 ), PoolIntArray( 23, 20, 22 ), PoolIntArray( 20, 21, 22 ), PoolIntArray( 27, 24, 26 ), PoolIntArray( 24, 25, 26 ), PoolIntArray( 30, 28, 29 ), PoolIntArray( 33, 31, 32 ), PoolIntArray( 37, 34, 36 ), PoolIntArray( 34, 35, 36 ), PoolIntArray( 41, 38, 40 ), PoolIntArray( 38, 39, 40 ), PoolIntArray( 45, 42, 44 ), PoolIntArray( 42, 43, 44 ), PoolIntArray( 48, 46, 47 ), PoolIntArray( 51, 49, 50 ) ]
[sub_resource type="CubeMesh" id=2]
[sub_resource type="PlaneMesh" id=3]
size = Vector2( 20, 20 )
[node name="Navigation" type="Navigation"]
[node name="Camera" type="Camera" parent="."]
transform = Transform( 1, 0, 0, 0, 0.866025, 0.5, 0, -0.5, 0.866025, 0, 10, 16 )
current = true
[node name="DirectionalLight" type="DirectionalLight" parent="."]
transform = Transform( 0.766044, -0.582564, 0.271654, 0, 0.422618, 0.906308, -0.642788, -0.694272, 0.323744, 0, 5, 0 )
[node name="NavigationMeshInstance" type="NavigationMeshInstance" parent="."]
navmesh = SubResource( 1 )
[node name="MeshInstance" type="MeshInstance" parent="NavigationMeshInstance"]
mesh = SubResource( 2 )
material/0 = null
[node name="MeshInstance3" type="MeshInstance" parent="NavigationMeshInstance"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 6.53892 )
mesh = SubResource( 2 )
material/0 = null
[node name="MeshInstance2" type="MeshInstance" parent="NavigationMeshInstance"]
mesh = SubResource( 3 )
material/0 = null
[node name="PathNavigatorForKinematicBody" parent="." instance=ExtResource( 1 )]
body_nodepath = NodePath("Meldewesen")
[node name="Meldewesen" parent="PathNavigatorForKinematicBody" instance=ExtResource( 2 )]

View File

@ -16,6 +16,7 @@ _global_script_class_icons={
[application]
config/name="retrace"
run/main_scene="res://Level/PathTestWorld.tscn"
config/icon="res://icon.png"
[layer_names]
@ -24,6 +25,7 @@ config/icon="res://icon.png"
3d_physics/layer_1="Masked"
3d_render/layer_2="True"
3d_physics/layer_2="True"
3d_physics/layer_3="Player"
[rendering]