mirror of
https://github.com/Relintai/pandemonium_demo_projects.git
synced 2025-04-09 21:02:40 +02:00
Compare commits
17 Commits
Author | SHA1 | Date | |
---|---|---|---|
fa5375534b | |||
f5d91b4e6e | |||
dfd8abe5fe | |||
b97ecfb7de | |||
8f3a81c124 | |||
dbdd19436e | |||
5ae367996d | |||
88f3abf978 | |||
f75b6a4515 | |||
e68f280f54 | |||
eb7fa528dc | |||
f92a58b08d | |||
f2d25ec2ec | |||
21a8a0a702 | |||
aeff6f56e4 | |||
2cbc3ea3af | |||
8295671644 |
@ -1,4 +1,3 @@
|
||||
tool
|
||||
extends Spatial
|
||||
|
||||
# A FABRIK IK chain with a middle joint helper.
|
||||
@ -14,9 +13,10 @@ export(PoolRealArray) var bones_in_chain_lengths setget _set_bone_chain_lengths
|
||||
|
||||
export(int, "_process", "_physics_process", "_notification", "none") var update_mode = 0 setget _set_update_mode
|
||||
|
||||
var target: Spatial = null
|
||||
var target : Spatial = null
|
||||
|
||||
var skeleton: Skeleton
|
||||
var skeleton : Skeleton
|
||||
var skeleton_up : Vector3
|
||||
|
||||
# A dictionary holding all of the bone IDs (from the skeleton) and a dictionary holding
|
||||
# all of the bone helper nodes
|
||||
@ -151,7 +151,7 @@ func update_skeleton():
|
||||
bone_nodes[i].global_transform = get_bone_transform(i)
|
||||
# If this is not the last bone in the bone chain, make it look at the next bone in the bone chain
|
||||
if i < bone_IDs.size()-1:
|
||||
bone_nodes[i].look_at(get_bone_transform(i+1).origin + skeleton.global_transform.origin, Vector3.UP)
|
||||
bone_nodes[i].look_at(get_bone_transform(i+1).origin + skeleton.global_transform.origin, skeleton_up)
|
||||
|
||||
i += 1
|
||||
|
||||
@ -293,7 +293,7 @@ func chain_apply_rotation():
|
||||
else:
|
||||
var b_target = target.global_transform
|
||||
b_target.origin = skeleton.global_transform.xform_inv(b_target.origin)
|
||||
bone_trans = bone_trans.looking_at(b_target.origin, Vector3.UP)
|
||||
bone_trans = bone_trans.looking_at(b_target.origin, skeleton_up)
|
||||
|
||||
# A bit of a hack. Because we only have two bones, we have to use the previous
|
||||
# bone to position the last bone in the chain.
|
||||
@ -319,7 +319,7 @@ func chain_apply_rotation():
|
||||
var dir = (b_target_two.origin - b_target.origin).normalized()
|
||||
|
||||
# Make this bone look towards the direction of the next bone
|
||||
bone_trans = bone_trans.looking_at(b_target.origin + dir, Vector3.UP)
|
||||
bone_trans = bone_trans.looking_at(b_target.origin + dir, skeleton_up)
|
||||
|
||||
# Set the position of the bone to the bone target.
|
||||
# Prior to Godot 3.2, this was not necessary, but because we can now completely
|
||||
@ -332,7 +332,7 @@ func chain_apply_rotation():
|
||||
|
||||
func get_bone_transform(bone, convert_to_world_space = true):
|
||||
# Get the global transform of the bone
|
||||
var ret: Transform = skeleton.get_bone_global_pose(bone_IDs[bones_in_chain[bone]])
|
||||
var ret: Transform = skeleton.get_bone_global_pose_no_override(bone_IDs[bones_in_chain[bone]])
|
||||
|
||||
# If we need to convert the bone position from bone/skeleton space to world space, we
|
||||
# use the Xform of the skeleton (because bone/skeleton space is relative to the position of the skeleton node).
|
||||
@ -413,6 +413,7 @@ func _set_skeleton_path(new_value):
|
||||
# If it has the method "get_bone_global_pose" it is likely a Skeleton
|
||||
if temp.has_method("get_bone_global_pose"):
|
||||
skeleton = temp
|
||||
skeleton_up = skeleton.global_transform.xform_inv(Vector3.UP)
|
||||
bone_IDs = {}
|
||||
|
||||
# (Delete all of the old bone nodes and) Make all of the bone nodes for each bone in the IK chain
|
||||
|
@ -1,4 +1,3 @@
|
||||
tool
|
||||
extends Spatial
|
||||
|
||||
export(NodePath) var skeleton_path setget _set_skeleton_path
|
||||
@ -78,23 +77,22 @@ func update_skeleton():
|
||||
return
|
||||
|
||||
# get the bone's global transform pose.
|
||||
var rest = skeleton_to_use.get_bone_global_pose(bone)
|
||||
|
||||
var rest : Transform = skeleton_to_use.get_bone_global_pose_no_override(bone)
|
||||
# Convert our position relative to the skeleton's transform.
|
||||
var target_pos = skeleton_to_use.global_transform.xform_inv(global_transform.origin)
|
||||
var target_pos : Vector3 = skeleton_to_use.global_transform.xform_inv(global_transform.origin)
|
||||
|
||||
# Call helper's look_at function with the chosen up axis.
|
||||
if look_at_axis == 0:
|
||||
rest = rest.looking_at(target_pos, Vector3.RIGHT)
|
||||
rest = rest.looking_at(target_pos, skeleton_to_use.global_transform.xform_inv(Vector3.RIGHT))
|
||||
elif look_at_axis == 1:
|
||||
rest = rest.looking_at(target_pos, Vector3.UP)
|
||||
rest = rest.looking_at(target_pos, skeleton_to_use.global_transform.xform_inv(Vector3.UP))
|
||||
elif look_at_axis == 2:
|
||||
rest = rest.looking_at(target_pos, Vector3.FORWARD)
|
||||
rest = rest.looking_at(target_pos, skeleton_to_use.global_transform.xform_inv(Vector3.FORWARD))
|
||||
else:
|
||||
rest = rest.looking_at(target_pos, Vector3.UP)
|
||||
rest = rest.looking_at(target_pos, skeleton_to_use.global_transform.xform_inv(Vector3.UP))
|
||||
if debug_messages:
|
||||
print(name, " - IK_LookAt: Unknown look_at_axis value!")
|
||||
|
||||
|
||||
# Get the rotation euler of the bone and of this node.
|
||||
var rest_euler = rest.basis.get_euler()
|
||||
var self_euler = global_transform.basis.orthonormalized().get_euler()
|
||||
|
@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=13 format=2]
|
||||
[gd_scene load_steps=13 format=3]
|
||||
|
||||
[ext_resource path="res://addons/sade/editor_gizmo_texture.png" type="Texture" id=1]
|
||||
[ext_resource path="res://model/godot_battle_bot.gltf" type="PackedScene" id=2]
|
||||
@ -37,6 +37,109 @@ transform = Transform( 0.56827, 0.673454, -0.472789, 0, 0.574581, 0.818448, 0.82
|
||||
|
||||
[node name="GodotBattleBot" parent="." instance=ExtResource( 2 )]
|
||||
|
||||
[node name="Skeleton" parent="GodotBattleBot/Z_UP/Armature" index="0"]
|
||||
bones/0/position = Vector3( 0, 0.273024, 7.74588 )
|
||||
bones/0/rotation = Quaternion( 0.759715, 7.75166e-08, 9.06254e-08, 0.650256 )
|
||||
bones/1/position = Vector3( -0.858803, 0.0572646, 0.105923 )
|
||||
bones/1/rotation = Quaternion( 0.662256, -0.013691, 0.740854, 0.111198 )
|
||||
bones/1/scale = Vector3( 0.999998, 1, 0.999999 )
|
||||
bones/2/position = Vector3( -2.98023e-08, 3.3419, -3.20375e-07 )
|
||||
bones/2/rotation = Quaternion( 0.0400348, -0.0480878, -0.010588, 0.997984 )
|
||||
bones/2/scale = Vector3( 1, 1, 1 )
|
||||
bones/3/position = Vector3( -2.80359e-08, 3.53825, 1.61034e-08 )
|
||||
bones/3/rotation = Quaternion( 0.513193, 0.52962, -0.484649, 0.470374 )
|
||||
bones/3/scale = Vector3( 1, 1, 1 )
|
||||
bones/4/position = Vector3( 0.863247, 0.0572646, 0.105923 )
|
||||
bones/4/rotation = Quaternion( 0.671069, 0.109276, 0.732881, -0.0247196 )
|
||||
bones/4/scale = Vector3( 0.999997, 1, 0.999998 )
|
||||
bones/5/position = Vector3( -1.49012e-08, 3.3419, 1.99303e-07 )
|
||||
bones/5/rotation = Quaternion( -0.0387784, -0.051742, -0.0145302, 0.997802 )
|
||||
bones/6/position = Vector3( 4.21492e-09, 3.53825, -2.17745e-08 )
|
||||
bones/6/rotation = Quaternion( 0.484649, 0.470374, -0.513194, 0.529619 )
|
||||
bones/6/scale = Vector3( 1, 1, 1 )
|
||||
bones/7/position = Vector3( -9.64506e-15, 1.7917, 5.65778e-08 )
|
||||
bones/7/rotation = Quaternion( -0.15185, -3.93786e-11, -3.62496e-08, 0.988404 )
|
||||
bones/7/scale = Vector3( 1, 1, 1 )
|
||||
bones/8/position = Vector3( -1.5334, 2.29565, 0.106341 )
|
||||
bones/8/rotation = Quaternion( 0.694368, -0.212646, 0.677236, 0.118263 )
|
||||
bones/8/scale = Vector3( 0.999999, 1, 1 )
|
||||
bones/9/position = Vector3( 9.31323e-09, 1.90503, 1.91387e-07 )
|
||||
bones/9/rotation = Quaternion( 0.0430889, -0.00651108, 0.00492581, 0.999038 )
|
||||
bones/9/scale = Vector3( 1, 1, 1 )
|
||||
bones/10/position = Vector3( -1.54338e-08, 2.97659, 1.80687e-07 )
|
||||
bones/10/rotation = Quaternion( 0.0254076, 0.0314977, -0.0425505, 0.998274 )
|
||||
bones/10/scale = Vector3( 1, 1, 1 )
|
||||
bones/11/position = Vector3( -0.251191, 0.961984, 0.0683811 )
|
||||
bones/11/rotation = Quaternion( 0.0734265, -0.0198738, 0.116597, 0.990262 )
|
||||
bones/11/scale = Vector3( 1, 1, 1 )
|
||||
bones/12/position = Vector3( -4.47035e-08, 0.221738, 1.02445e-08 )
|
||||
bones/12/rotation = Quaternion( 0.161002, 0.714417, 0.150246, 0.664163 )
|
||||
bones/12/scale = Vector3( 1, 1, 1 )
|
||||
bones/13/position = Vector3( -0.0779908, 1.04339, 0.000736893 )
|
||||
bones/13/rotation = Quaternion( 0.122292, 0.00257627, 0.104377, 0.986987 )
|
||||
bones/13/scale = Vector3( 1, 1, 1 )
|
||||
bones/14/position = Vector3( -2.98023e-08, 0.267715, -8.27014e-07 )
|
||||
bones/14/rotation = Quaternion( 0.147368, 0.694839, 0.0466993, 0.702353 )
|
||||
bones/14/scale = Vector3( 1, 1, 1 )
|
||||
bones/15/position = Vector3( 0.0960594, 1.04882, 0.0192584 )
|
||||
bones/15/rotation = Quaternion( 0.0901164, 0.0392194, 0.00840297, 0.995123 )
|
||||
bones/16/position = Vector3( 1.86265e-08, 0.277596, -4.6991e-07 )
|
||||
bones/16/rotation = Quaternion( 0.115872, 0.681565, 0.114615, 0.713377 )
|
||||
bones/16/scale = Vector3( 1, 1, 1 )
|
||||
bones/17/position = Vector3( 0.26401, 0.982311, 0.0351903 )
|
||||
bones/17/rotation = Quaternion( 0.0915952, 0.0987206, -0.130385, 0.982275 )
|
||||
bones/17/scale = Vector3( 1, 1, 1 )
|
||||
bones/18/position = Vector3( -2.23517e-07, 0.27682, 1.3411e-07 )
|
||||
bones/18/rotation = Quaternion( 0.111001, 0.648784, 0.123964, 0.742557 )
|
||||
bones/18/scale = Vector3( 1, 1, 1 )
|
||||
bones/19/position = Vector3( 0.408326, 0.607306, 0.0419031 )
|
||||
bones/19/rotation = Quaternion( 0.104368, 0.154824, -0.245653, 0.951205 )
|
||||
bones/19/scale = Vector3( 1, 1, 1 )
|
||||
bones/20/position = Vector3( -2.98023e-08, 0.301735, 4.47035e-08 )
|
||||
bones/20/rotation = Quaternion( -0.0481356, 0.617453, 0.0348587, 0.784359 )
|
||||
bones/20/scale = Vector3( 1, 1, 1 )
|
||||
bones/21/position = Vector3( 1.53444, 2.29565, 0.106341 )
|
||||
bones/21/rotation = Quaternion( 0.625464, 0.10264, 0.741343, -0.220612 )
|
||||
bones/21/scale = Vector3( 1, 1, 1 )
|
||||
bones/22/position = Vector3( 2.98023e-08, 1.90503, 1.08033e-07 )
|
||||
bones/22/rotation = Quaternion( -0.0433319, -0.0654617, 0.00180953, 0.996912 )
|
||||
bones/22/scale = Vector3( 1, 1, 1 )
|
||||
bones/23/position = Vector3( 1.22048e-08, 2.97659, -6.07568e-07 )
|
||||
bones/23/rotation = Quaternion( -0.0240965, -0.00100487, -0.0433063, 0.998771 )
|
||||
bones/24/position = Vector3( -0.246549, 0.961984, -0.083585 )
|
||||
bones/24/rotation = Quaternion( -0.0826772, 0.0401178, 0.11023, 0.989649 )
|
||||
bones/24/scale = Vector3( 1, 1, 1 )
|
||||
bones/25/position = Vector3( -1.49012e-07, 0.221738, -1.13621e-07 )
|
||||
bones/25/rotation = Quaternion( -0.119531, 0.715918, -0.184954, 0.662544 )
|
||||
bones/25/scale = Vector3( 1, 1, 1 )
|
||||
bones/26/position = Vector3( -0.0778003, 1.04339, -0.00549548 )
|
||||
bones/26/rotation = Quaternion( -0.132841, 0.0438432, 0.0905715, 0.986016 )
|
||||
bones/26/scale = Vector3( 1, 1, 1 )
|
||||
bones/27/position = Vector3( 1.04308e-07, 0.267716, -1.37836e-07 )
|
||||
bones/27/rotation = Quaternion( -0.0236808, 0.700911, -0.152766, 0.696294 )
|
||||
bones/27/scale = Vector3( 1, 1, 1 )
|
||||
bones/28/position = Vector3( 0.0970556, 1.04882, -0.01336 )
|
||||
bones/28/rotation = Quaternion( -0.0904035, 0.0402447, -0.00433424, 0.995082 )
|
||||
bones/28/scale = Vector3( 1, 1, 1 )
|
||||
bones/29/position = Vector3( 7.68341e-09, 0.277596, -5.1083e-07 )
|
||||
bones/29/rotation = Quaternion( -0.0926483, 0.681722, -0.134087, 0.713227 )
|
||||
bones/29/scale = Vector3( 1, 1, 1 )
|
||||
bones/30/position = Vector3( 0.265665, 0.982311, -0.019011 )
|
||||
bones/30/rotation = Quaternion( -0.0656662, 0.0260568, -0.145182, 0.98688 )
|
||||
bones/30/scale = Vector3( 1, 1, 1 )
|
||||
bones/31/position = Vector3( 3.12924e-07, 0.276819, -7.82311e-08 )
|
||||
bones/31/rotation = Quaternion( -0.102156, 0.648696, -0.131348, 0.742634 )
|
||||
bones/31/scale = Vector3( 1, 1, 1 )
|
||||
bones/32/position = Vector3( 0.410121, 0.607306, -0.0169033 )
|
||||
bones/32/rotation = Quaternion( -0.0424852, 0.0187641, -0.263502, 0.96354 )
|
||||
bones/32/scale = Vector3( 1, 1, 1 )
|
||||
bones/33/position = Vector3( 1.19209e-07, 0.301735, 1.56462e-07 )
|
||||
bones/33/rotation = Quaternion( -0.0440545, 0.63492, 0.039892, 0.770289 )
|
||||
bones/33/scale = Vector3( 1, 1, 1 )
|
||||
bones/34/position = Vector3( 1.17961e-15, 2.97461, 2.98023e-08 )
|
||||
bones/34/rotation = Quaternion( -1.13845e-08, 0.997388, 0.0722371, 7.53007e-08 )
|
||||
bones/34/scale = Vector3( 1, 1, 1 )
|
||||
|
||||
[node name="Camera" type="Camera" parent="."]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 11.5, 11 )
|
||||
fov = 74.0
|
||||
@ -54,7 +157,6 @@ __meta__ = {
|
||||
}
|
||||
skeleton_path = NodePath("../../../GodotBattleBot/Z_UP/Armature/Skeleton")
|
||||
bone_name = "Head"
|
||||
additional_rotation = Vector3( 90, 0, 0 )
|
||||
additional_bone_length = 1
|
||||
|
||||
[node name="IK_FABRIK_Left_Arm" type="Spatial" parent="Camera/Targets"]
|
||||
@ -65,7 +167,6 @@ __meta__ = {
|
||||
skeleton_path = NodePath("../../../GodotBattleBot/Z_UP/Armature/Skeleton")
|
||||
bones_in_chain = PoolStringArray( "Left_UpperArm", "Left_LowerArm" )
|
||||
bones_in_chain_lengths = PoolRealArray( 1.97, 3 )
|
||||
chain_iterations = 10
|
||||
limit_chain_iterations = false
|
||||
use_middle_joint_target = true
|
||||
|
||||
@ -80,8 +181,6 @@ __meta__ = {
|
||||
}
|
||||
skeleton_path = NodePath("../../../../../GodotBattleBot/Z_UP/Armature/Skeleton")
|
||||
bone_name = "Left_Hand"
|
||||
additional_rotation = Vector3( 0, 0, 90 )
|
||||
position_using_additional_bone = true
|
||||
additional_bone_name = "Left_LowerArm"
|
||||
additional_bone_length = 3.0
|
||||
|
||||
@ -89,10 +188,10 @@ additional_bone_length = 3.0
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 7.16849, 0, -5.31922 )
|
||||
|
||||
[node name="Left_UpperArm" type="Spatial" parent="Camera/Targets/IK_FABRIK_Left_Arm"]
|
||||
transform = Transform( -0.66477, 0.0771345, -0.743055, -2.23517e-08, 0.994655, 0.103252, 0.747048, 0.0686391, -0.661217, 1.53444, 0.300478, -3.63533 )
|
||||
transform = Transform( 0.138269, 0.566654, -0.812271, 0, 0.820149, 0.57215, 0.990395, -0.0791108, 0.113401, 1.53444, 0.30189, -3.23425 )
|
||||
|
||||
[node name="Left_LowerArm" type="Spatial" parent="Camera/Targets/IK_FABRIK_Left_Arm"]
|
||||
transform = Transform( -0.773624, -0.0228999, 0.633231, 2.98023e-08, 0.999347, 0.03614, -0.633645, 0.0279588, -0.773119, 2.94998, 0.10378, -2.37569 )
|
||||
transform = Transform( -0.986259, -0.122992, 0.110302, 3.72529e-09, 0.667656, 0.74447, -0.165208, 0.73424, -0.658481, 3.13461, -11.9576, -13.6748 )
|
||||
|
||||
[node name="IK_FABRIK_Right_Arm" type="Spatial" parent="Camera/Targets"]
|
||||
script = ExtResource( 8 )
|
||||
@ -102,35 +201,34 @@ __meta__ = {
|
||||
skeleton_path = NodePath("../../../GodotBattleBot/Z_UP/Armature/Skeleton")
|
||||
bones_in_chain = PoolStringArray( "Right_UpperArm", "Right_LowerArm", "Right_Hand" )
|
||||
bones_in_chain_lengths = PoolRealArray( 1.97, 3, 1.2 )
|
||||
chain_iterations = 10
|
||||
limit_chain_iterations = false
|
||||
use_middle_joint_target = true
|
||||
|
||||
[node name="Target" type="Spatial" parent="Camera/Targets/IK_FABRIK_Right_Arm"]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -0.229958, 0, 0.929313 )
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -0.902034, 0, -0.046618 )
|
||||
|
||||
[node name="IK_LookAt_RH" type="Spatial" parent="Camera/Targets/IK_FABRIK_Right_Arm/Target"]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0544824, -0.133381, 0.332403 )
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0.251035, -0.133381, 0.332403 )
|
||||
script = ExtResource( 6 )
|
||||
__meta__ = {
|
||||
"_editor_icon": ExtResource( 7 )
|
||||
}
|
||||
skeleton_path = NodePath("../../../../../GodotBattleBot/Z_UP/Armature/Skeleton")
|
||||
bone_name = "Right_Hand"
|
||||
additional_rotation = Vector3( 0, 0, 90 )
|
||||
additional_rotation = Vector3( 0, 180, 0 )
|
||||
additional_bone_length = 1
|
||||
|
||||
[node name="MiddleJoint" type="Spatial" parent="Camera/Targets/IK_FABRIK_Right_Arm"]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -6.34515, 0, -3.7843 )
|
||||
|
||||
[node name="Right_UpperArm" type="Spatial" parent="Camera/Targets/IK_FABRIK_Right_Arm"]
|
||||
transform = Transform( -0.694982, -0.0753926, 0.715064, -7.45058e-09, 0.994488, 0.104854, -0.719028, 0.0728714, -0.691151, -1.53339, 0.300478, -3.63533 )
|
||||
transform = Transform( -0.13677, -0.793967, 0.592377, 2.98023e-08, 0.597996, 0.801499, -0.990603, 0.109621, -0.0817881, -1.5334, 0.30189, -3.23425 )
|
||||
|
||||
[node name="Right_LowerArm" type="Spatial" parent="Camera/Targets/IK_FABRIK_Right_Arm"]
|
||||
transform = Transform( -0.792023, 0.0165711, -0.610266, -1.49012e-08, 0.999631, 0.0271438, 0.610491, 0.0214986, -0.791732, -2.89561, 0.100755, -2.31866 )
|
||||
transform = Transform( -0.258068, 0.758367, -0.598565, 2.98023e-08, 0.619551, 0.784956, 0.966127, 0.202572, -0.159886, -2.70038, 0.463014, -1.6553 )
|
||||
|
||||
[node name="Right_Hand" type="Spatial" parent="Camera/Targets/IK_FABRIK_Right_Arm"]
|
||||
transform = Transform( -0.678336, 0.00698721, -0.734719, -2.32831e-09, 0.999955, 0.00950961, 0.734752, 0.00645071, -0.678305, -1.07914, 0.020072, 0.03791 )
|
||||
transform = Transform( 0.933847, -0.293386, -0.204584, 0, 0.571985, -0.820264, 0.357673, 0.766001, 0.534147, -0.946222, 0.944532, 0.730302 )
|
||||
|
||||
[node name="1MeterCube" type="MeshInstance" parent="Camera/Targets"]
|
||||
mesh = SubResource( 3 )
|
||||
|
@ -20,10 +20,13 @@ nodes/use_legacy_names=false
|
||||
materials/location=0
|
||||
materials/storage=0
|
||||
materials/keep_on_reimport=true
|
||||
meshes/octahedral_compression=true
|
||||
meshes/compress=true
|
||||
meshes/ensure_tangents=true
|
||||
meshes/octahedral_compression=true
|
||||
meshes/vertex_cache_optimization=true
|
||||
meshes/storage=0
|
||||
meshes/light_baking=0
|
||||
meshes/lightmap_texel_size=0.1
|
||||
skins/use_named_skins=true
|
||||
external_files/store_in_subdir=false
|
||||
animation/import=false
|
||||
|
@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=9 format=2]
|
||||
[gd_scene load_steps=9 format=3]
|
||||
|
||||
[ext_resource path="res://addons/sade/editor_gizmo_texture.png" type="Texture" id=1]
|
||||
[ext_resource path="res://model/godot_battle_bot.gltf" type="PackedScene" id=2]
|
||||
@ -28,6 +28,109 @@ transform = Transform( 0.56827, 0.673454, -0.472789, 0, 0.574581, 0.818448, 0.82
|
||||
|
||||
[node name="GodotBattleBot" parent="." instance=ExtResource( 2 )]
|
||||
|
||||
[node name="Skeleton" parent="GodotBattleBot/Z_UP/Armature" index="0"]
|
||||
bones/0/position = Vector3( 0, 0.273024, 7.74588 )
|
||||
bones/0/rotation = Quaternion( 0.759715, 7.75166e-08, 9.06254e-08, 0.650256 )
|
||||
bones/1/position = Vector3( -0.858803, 0.0572646, 0.105923 )
|
||||
bones/1/rotation = Quaternion( 0.662256, -0.013691, 0.740854, 0.111198 )
|
||||
bones/1/scale = Vector3( 0.999998, 1, 0.999999 )
|
||||
bones/2/position = Vector3( -2.98023e-08, 3.3419, -3.20375e-07 )
|
||||
bones/2/rotation = Quaternion( 0.0400348, -0.0480878, -0.010588, 0.997984 )
|
||||
bones/2/scale = Vector3( 1, 1, 1 )
|
||||
bones/3/position = Vector3( -2.80359e-08, 3.53825, 1.61034e-08 )
|
||||
bones/3/rotation = Quaternion( 0.513193, 0.52962, -0.484649, 0.470374 )
|
||||
bones/3/scale = Vector3( 1, 1, 1 )
|
||||
bones/4/position = Vector3( 0.863247, 0.0572646, 0.105923 )
|
||||
bones/4/rotation = Quaternion( 0.671069, 0.109276, 0.732881, -0.0247196 )
|
||||
bones/4/scale = Vector3( 0.999997, 1, 0.999998 )
|
||||
bones/5/position = Vector3( -1.49012e-08, 3.3419, 1.99303e-07 )
|
||||
bones/5/rotation = Quaternion( -0.0387784, -0.051742, -0.0145302, 0.997802 )
|
||||
bones/6/position = Vector3( 4.21492e-09, 3.53825, -2.17745e-08 )
|
||||
bones/6/rotation = Quaternion( 0.484649, 0.470374, -0.513194, 0.529619 )
|
||||
bones/6/scale = Vector3( 1, 1, 1 )
|
||||
bones/7/position = Vector3( -9.64506e-15, 1.7917, 5.65778e-08 )
|
||||
bones/7/rotation = Quaternion( -0.15185, -3.93786e-11, -3.62496e-08, 0.988404 )
|
||||
bones/7/scale = Vector3( 1, 1, 1 )
|
||||
bones/8/position = Vector3( -1.5334, 2.29565, 0.106341 )
|
||||
bones/8/rotation = Quaternion( 0.694368, -0.212646, 0.677236, 0.118263 )
|
||||
bones/8/scale = Vector3( 0.999999, 1, 1 )
|
||||
bones/9/position = Vector3( 9.31323e-09, 1.90503, 1.91387e-07 )
|
||||
bones/9/rotation = Quaternion( 0.0430889, -0.00651108, 0.00492581, 0.999038 )
|
||||
bones/9/scale = Vector3( 1, 1, 1 )
|
||||
bones/10/position = Vector3( -1.54338e-08, 2.97659, 1.80687e-07 )
|
||||
bones/10/rotation = Quaternion( 0.0254076, 0.0314977, -0.0425505, 0.998274 )
|
||||
bones/10/scale = Vector3( 1, 1, 1 )
|
||||
bones/11/position = Vector3( -0.251191, 0.961984, 0.0683811 )
|
||||
bones/11/rotation = Quaternion( 0.0734265, -0.0198738, 0.116597, 0.990262 )
|
||||
bones/11/scale = Vector3( 1, 1, 1 )
|
||||
bones/12/position = Vector3( -4.47035e-08, 0.221738, 1.02445e-08 )
|
||||
bones/12/rotation = Quaternion( 0.161002, 0.714417, 0.150246, 0.664163 )
|
||||
bones/12/scale = Vector3( 1, 1, 1 )
|
||||
bones/13/position = Vector3( -0.0779908, 1.04339, 0.000736893 )
|
||||
bones/13/rotation = Quaternion( 0.122292, 0.00257627, 0.104377, 0.986987 )
|
||||
bones/13/scale = Vector3( 1, 1, 1 )
|
||||
bones/14/position = Vector3( -2.98023e-08, 0.267715, -8.27014e-07 )
|
||||
bones/14/rotation = Quaternion( 0.147368, 0.694839, 0.0466993, 0.702353 )
|
||||
bones/14/scale = Vector3( 1, 1, 1 )
|
||||
bones/15/position = Vector3( 0.0960594, 1.04882, 0.0192584 )
|
||||
bones/15/rotation = Quaternion( 0.0901164, 0.0392194, 0.00840297, 0.995123 )
|
||||
bones/16/position = Vector3( 1.86265e-08, 0.277596, -4.6991e-07 )
|
||||
bones/16/rotation = Quaternion( 0.115872, 0.681565, 0.114615, 0.713377 )
|
||||
bones/16/scale = Vector3( 1, 1, 1 )
|
||||
bones/17/position = Vector3( 0.26401, 0.982311, 0.0351903 )
|
||||
bones/17/rotation = Quaternion( 0.0915952, 0.0987206, -0.130385, 0.982275 )
|
||||
bones/17/scale = Vector3( 1, 1, 1 )
|
||||
bones/18/position = Vector3( -2.23517e-07, 0.27682, 1.3411e-07 )
|
||||
bones/18/rotation = Quaternion( 0.111001, 0.648784, 0.123964, 0.742557 )
|
||||
bones/18/scale = Vector3( 1, 1, 1 )
|
||||
bones/19/position = Vector3( 0.408326, 0.607306, 0.0419031 )
|
||||
bones/19/rotation = Quaternion( 0.104368, 0.154824, -0.245653, 0.951205 )
|
||||
bones/19/scale = Vector3( 1, 1, 1 )
|
||||
bones/20/position = Vector3( -2.98023e-08, 0.301735, 4.47035e-08 )
|
||||
bones/20/rotation = Quaternion( -0.0481356, 0.617453, 0.0348587, 0.784359 )
|
||||
bones/20/scale = Vector3( 1, 1, 1 )
|
||||
bones/21/position = Vector3( 1.53444, 2.29565, 0.106341 )
|
||||
bones/21/rotation = Quaternion( 0.625464, 0.10264, 0.741343, -0.220612 )
|
||||
bones/21/scale = Vector3( 1, 1, 1 )
|
||||
bones/22/position = Vector3( 2.98023e-08, 1.90503, 1.08033e-07 )
|
||||
bones/22/rotation = Quaternion( -0.0433319, -0.0654617, 0.00180953, 0.996912 )
|
||||
bones/22/scale = Vector3( 1, 1, 1 )
|
||||
bones/23/position = Vector3( 1.22048e-08, 2.97659, -6.07568e-07 )
|
||||
bones/23/rotation = Quaternion( -0.0240965, -0.00100487, -0.0433063, 0.998771 )
|
||||
bones/24/position = Vector3( -0.246549, 0.961984, -0.083585 )
|
||||
bones/24/rotation = Quaternion( -0.0826772, 0.0401178, 0.11023, 0.989649 )
|
||||
bones/24/scale = Vector3( 1, 1, 1 )
|
||||
bones/25/position = Vector3( -1.49012e-07, 0.221738, -1.13621e-07 )
|
||||
bones/25/rotation = Quaternion( -0.119531, 0.715918, -0.184954, 0.662544 )
|
||||
bones/25/scale = Vector3( 1, 1, 1 )
|
||||
bones/26/position = Vector3( -0.0778003, 1.04339, -0.00549548 )
|
||||
bones/26/rotation = Quaternion( -0.132841, 0.0438432, 0.0905715, 0.986016 )
|
||||
bones/26/scale = Vector3( 1, 1, 1 )
|
||||
bones/27/position = Vector3( 1.04308e-07, 0.267716, -1.37836e-07 )
|
||||
bones/27/rotation = Quaternion( -0.0236808, 0.700911, -0.152766, 0.696294 )
|
||||
bones/27/scale = Vector3( 1, 1, 1 )
|
||||
bones/28/position = Vector3( 0.0970556, 1.04882, -0.01336 )
|
||||
bones/28/rotation = Quaternion( -0.0904035, 0.0402447, -0.00433424, 0.995082 )
|
||||
bones/28/scale = Vector3( 1, 1, 1 )
|
||||
bones/29/position = Vector3( 7.68341e-09, 0.277596, -5.1083e-07 )
|
||||
bones/29/rotation = Quaternion( -0.0926483, 0.681722, -0.134087, 0.713227 )
|
||||
bones/29/scale = Vector3( 1, 1, 1 )
|
||||
bones/30/position = Vector3( 0.265665, 0.982311, -0.019011 )
|
||||
bones/30/rotation = Quaternion( -0.0656662, 0.0260568, -0.145182, 0.98688 )
|
||||
bones/30/scale = Vector3( 1, 1, 1 )
|
||||
bones/31/position = Vector3( 3.12924e-07, 0.276819, -7.82311e-08 )
|
||||
bones/31/rotation = Quaternion( -0.102156, 0.648696, -0.131348, 0.742634 )
|
||||
bones/31/scale = Vector3( 1, 1, 1 )
|
||||
bones/32/position = Vector3( 0.410121, 0.607306, -0.0169033 )
|
||||
bones/32/rotation = Quaternion( -0.0424852, 0.0187641, -0.263502, 0.96354 )
|
||||
bones/32/scale = Vector3( 1, 1, 1 )
|
||||
bones/33/position = Vector3( 1.19209e-07, 0.301735, 1.56462e-07 )
|
||||
bones/33/rotation = Quaternion( -0.0440545, 0.63492, 0.039892, 0.770289 )
|
||||
bones/33/scale = Vector3( 1, 1, 1 )
|
||||
bones/34/position = Vector3( 1.17961e-15, 2.97461, 2.98023e-08 )
|
||||
bones/34/rotation = Quaternion( -1.13845e-08, 0.997388, 0.0722371, 7.53007e-08 )
|
||||
bones/34/scale = Vector3( 1, 1, 1 )
|
||||
|
||||
[node name="Camera" type="Camera" parent="."]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 11.501, 11 )
|
||||
fov = 74.0
|
||||
@ -44,7 +147,6 @@ __meta__ = {
|
||||
}
|
||||
skeleton_path = NodePath("../../../GodotBattleBot/Z_UP/Armature/Skeleton")
|
||||
bone_name = "Head"
|
||||
additional_rotation = Vector3( 90, 0, 0 )
|
||||
additional_bone_length = 1
|
||||
|
||||
[node name="IK_LookAt_LeftArm" type="Spatial" parent="Camera/Targets"]
|
||||
@ -54,6 +156,8 @@ __meta__ = {
|
||||
}
|
||||
skeleton_path = NodePath("../../../GodotBattleBot/Z_UP/Armature/Skeleton")
|
||||
bone_name = "Left_UpperArm"
|
||||
look_at_axis = 0
|
||||
additional_rotation = Vector3( -90, 0, 0 )
|
||||
additional_bone_length = 1
|
||||
|
||||
[node name="IK_LookAt_RightArm" type="Spatial" parent="Camera/Targets"]
|
||||
@ -63,7 +167,8 @@ __meta__ = {
|
||||
}
|
||||
skeleton_path = NodePath("../../../GodotBattleBot/Z_UP/Armature/Skeleton")
|
||||
bone_name = "Right_UpperArm"
|
||||
additional_rotation = Vector3( 0, 0, 180 )
|
||||
look_at_axis = 0
|
||||
additional_rotation = Vector3( -90, 0, 0 )
|
||||
additional_bone_length = 1
|
||||
|
||||
[node name="Control" type="Control" parent="."]
|
||||
|
@ -18,12 +18,15 @@ nodes/custom_script=""
|
||||
nodes/storage=0
|
||||
nodes/use_legacy_names=false
|
||||
materials/location=0
|
||||
materials/storage=0
|
||||
materials/storage=1
|
||||
materials/keep_on_reimport=true
|
||||
meshes/octahedral_compression=true
|
||||
meshes/compress=true
|
||||
meshes/ensure_tangents=true
|
||||
meshes/storage=0
|
||||
meshes/octahedral_compression=true
|
||||
meshes/vertex_cache_optimization=true
|
||||
meshes/storage=1
|
||||
meshes/light_baking=0
|
||||
meshes/lightmap_texel_size=0.1
|
||||
skins/use_named_skins=true
|
||||
external_files/store_in_subdir=false
|
||||
animation/import=true
|
||||
|
BIN
3d/ik/model/godot_battle_bot_Cube_012.mesh
Normal file
BIN
3d/ik/model/godot_battle_bot_Cube_012.mesh
Normal file
Binary file not shown.
@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=12 format=2]
|
||||
[gd_scene load_steps=12 format=3]
|
||||
|
||||
[ext_resource path="res://skeleton_ik_runner.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/sade/ik_look_at.png" type="Texture" id=2]
|
||||
@ -69,7 +69,6 @@ __meta__ = {
|
||||
}
|
||||
skeleton_path = NodePath("../../../GodotBattleBot/Z_UP/Armature/Skeleton")
|
||||
bone_name = "Head"
|
||||
additional_rotation = Vector3( 90, 0, 0 )
|
||||
additional_bone_length = 1
|
||||
|
||||
[node name="1MeterCube" type="MeshInstance" parent="Camera/Targets"]
|
||||
@ -84,6 +83,109 @@ transform = Transform( -0.0217688, 0.998559, -0.0490576, 0.992503, 0.0274873, 0.
|
||||
|
||||
[node name="GodotBattleBot" parent="." instance=ExtResource( 4 )]
|
||||
|
||||
[node name="Skeleton" parent="GodotBattleBot/Z_UP/Armature" index="0"]
|
||||
bones/0/position = Vector3( 0, 0.273024, 7.74588 )
|
||||
bones/0/rotation = Quaternion( 0.759715, 7.75166e-08, 9.06254e-08, 0.650256 )
|
||||
bones/1/position = Vector3( -0.858803, 0.0572646, 0.105923 )
|
||||
bones/1/rotation = Quaternion( 0.662256, -0.013691, 0.740854, 0.111198 )
|
||||
bones/1/scale = Vector3( 0.999998, 1, 0.999999 )
|
||||
bones/2/position = Vector3( -2.98023e-08, 3.3419, -3.20375e-07 )
|
||||
bones/2/rotation = Quaternion( 0.0400348, -0.0480878, -0.010588, 0.997984 )
|
||||
bones/2/scale = Vector3( 1, 1, 1 )
|
||||
bones/3/position = Vector3( -2.80359e-08, 3.53825, 1.61034e-08 )
|
||||
bones/3/rotation = Quaternion( 0.513193, 0.52962, -0.484649, 0.470374 )
|
||||
bones/3/scale = Vector3( 1, 1, 1 )
|
||||
bones/4/position = Vector3( 0.863247, 0.0572646, 0.105923 )
|
||||
bones/4/rotation = Quaternion( 0.671069, 0.109276, 0.732881, -0.0247196 )
|
||||
bones/4/scale = Vector3( 0.999997, 1, 0.999998 )
|
||||
bones/5/position = Vector3( -1.49012e-08, 3.3419, 1.99303e-07 )
|
||||
bones/5/rotation = Quaternion( -0.0387784, -0.051742, -0.0145302, 0.997802 )
|
||||
bones/6/position = Vector3( 4.21492e-09, 3.53825, -2.17745e-08 )
|
||||
bones/6/rotation = Quaternion( 0.484649, 0.470374, -0.513194, 0.529619 )
|
||||
bones/6/scale = Vector3( 1, 1, 1 )
|
||||
bones/7/position = Vector3( -9.64506e-15, 1.7917, 5.65778e-08 )
|
||||
bones/7/rotation = Quaternion( -0.15185, -3.93786e-11, -3.62496e-08, 0.988404 )
|
||||
bones/7/scale = Vector3( 1, 1, 1 )
|
||||
bones/8/position = Vector3( -1.5334, 2.29565, 0.106341 )
|
||||
bones/8/rotation = Quaternion( 0.694368, -0.212646, 0.677236, 0.118263 )
|
||||
bones/8/scale = Vector3( 0.999999, 1, 1 )
|
||||
bones/9/position = Vector3( 9.31323e-09, 1.90503, 1.91387e-07 )
|
||||
bones/9/rotation = Quaternion( 0.0430889, -0.00651108, 0.00492581, 0.999038 )
|
||||
bones/9/scale = Vector3( 1, 1, 1 )
|
||||
bones/10/position = Vector3( -1.54338e-08, 2.97659, 1.80687e-07 )
|
||||
bones/10/rotation = Quaternion( 0.0254076, 0.0314977, -0.0425505, 0.998274 )
|
||||
bones/10/scale = Vector3( 1, 1, 1 )
|
||||
bones/11/position = Vector3( -0.251191, 0.961984, 0.0683811 )
|
||||
bones/11/rotation = Quaternion( 0.0734265, -0.0198738, 0.116597, 0.990262 )
|
||||
bones/11/scale = Vector3( 1, 1, 1 )
|
||||
bones/12/position = Vector3( -4.47035e-08, 0.221738, 1.02445e-08 )
|
||||
bones/12/rotation = Quaternion( 0.161002, 0.714417, 0.150246, 0.664163 )
|
||||
bones/12/scale = Vector3( 1, 1, 1 )
|
||||
bones/13/position = Vector3( -0.0779908, 1.04339, 0.000736893 )
|
||||
bones/13/rotation = Quaternion( 0.122292, 0.00257627, 0.104377, 0.986987 )
|
||||
bones/13/scale = Vector3( 1, 1, 1 )
|
||||
bones/14/position = Vector3( -2.98023e-08, 0.267715, -8.27014e-07 )
|
||||
bones/14/rotation = Quaternion( 0.147368, 0.694839, 0.0466993, 0.702353 )
|
||||
bones/14/scale = Vector3( 1, 1, 1 )
|
||||
bones/15/position = Vector3( 0.0960594, 1.04882, 0.0192584 )
|
||||
bones/15/rotation = Quaternion( 0.0901164, 0.0392194, 0.00840297, 0.995123 )
|
||||
bones/16/position = Vector3( 1.86265e-08, 0.277596, -4.6991e-07 )
|
||||
bones/16/rotation = Quaternion( 0.115872, 0.681565, 0.114615, 0.713377 )
|
||||
bones/16/scale = Vector3( 1, 1, 1 )
|
||||
bones/17/position = Vector3( 0.26401, 0.982311, 0.0351903 )
|
||||
bones/17/rotation = Quaternion( 0.0915952, 0.0987206, -0.130385, 0.982275 )
|
||||
bones/17/scale = Vector3( 1, 1, 1 )
|
||||
bones/18/position = Vector3( -2.23517e-07, 0.27682, 1.3411e-07 )
|
||||
bones/18/rotation = Quaternion( 0.111001, 0.648784, 0.123964, 0.742557 )
|
||||
bones/18/scale = Vector3( 1, 1, 1 )
|
||||
bones/19/position = Vector3( 0.408326, 0.607306, 0.0419031 )
|
||||
bones/19/rotation = Quaternion( 0.104368, 0.154824, -0.245653, 0.951205 )
|
||||
bones/19/scale = Vector3( 1, 1, 1 )
|
||||
bones/20/position = Vector3( -2.98023e-08, 0.301735, 4.47035e-08 )
|
||||
bones/20/rotation = Quaternion( -0.0481356, 0.617453, 0.0348587, 0.784359 )
|
||||
bones/20/scale = Vector3( 1, 1, 1 )
|
||||
bones/21/position = Vector3( 1.53444, 2.29565, 0.106341 )
|
||||
bones/21/rotation = Quaternion( 0.625464, 0.10264, 0.741343, -0.220612 )
|
||||
bones/21/scale = Vector3( 1, 1, 1 )
|
||||
bones/22/position = Vector3( 2.98023e-08, 1.90503, 1.08033e-07 )
|
||||
bones/22/rotation = Quaternion( -0.0433319, -0.0654617, 0.00180953, 0.996912 )
|
||||
bones/22/scale = Vector3( 1, 1, 1 )
|
||||
bones/23/position = Vector3( 1.22048e-08, 2.97659, -6.07568e-07 )
|
||||
bones/23/rotation = Quaternion( -0.0240965, -0.00100487, -0.0433063, 0.998771 )
|
||||
bones/24/position = Vector3( -0.246549, 0.961984, -0.083585 )
|
||||
bones/24/rotation = Quaternion( -0.0826772, 0.0401178, 0.11023, 0.989649 )
|
||||
bones/24/scale = Vector3( 1, 1, 1 )
|
||||
bones/25/position = Vector3( -1.49012e-07, 0.221738, -1.13621e-07 )
|
||||
bones/25/rotation = Quaternion( -0.119531, 0.715918, -0.184954, 0.662544 )
|
||||
bones/25/scale = Vector3( 1, 1, 1 )
|
||||
bones/26/position = Vector3( -0.0778003, 1.04339, -0.00549548 )
|
||||
bones/26/rotation = Quaternion( -0.132841, 0.0438432, 0.0905715, 0.986016 )
|
||||
bones/26/scale = Vector3( 1, 1, 1 )
|
||||
bones/27/position = Vector3( 1.04308e-07, 0.267716, -1.37836e-07 )
|
||||
bones/27/rotation = Quaternion( -0.0236808, 0.700911, -0.152766, 0.696294 )
|
||||
bones/27/scale = Vector3( 1, 1, 1 )
|
||||
bones/28/position = Vector3( 0.0970556, 1.04882, -0.01336 )
|
||||
bones/28/rotation = Quaternion( -0.0904035, 0.0402447, -0.00433424, 0.995082 )
|
||||
bones/28/scale = Vector3( 1, 1, 1 )
|
||||
bones/29/position = Vector3( 7.68341e-09, 0.277596, -5.1083e-07 )
|
||||
bones/29/rotation = Quaternion( -0.0926483, 0.681722, -0.134087, 0.713227 )
|
||||
bones/29/scale = Vector3( 1, 1, 1 )
|
||||
bones/30/position = Vector3( 0.265665, 0.982311, -0.019011 )
|
||||
bones/30/rotation = Quaternion( -0.0656662, 0.0260568, -0.145182, 0.98688 )
|
||||
bones/30/scale = Vector3( 1, 1, 1 )
|
||||
bones/31/position = Vector3( 3.12924e-07, 0.276819, -7.82311e-08 )
|
||||
bones/31/rotation = Quaternion( -0.102156, 0.648696, -0.131348, 0.742634 )
|
||||
bones/31/scale = Vector3( 1, 1, 1 )
|
||||
bones/32/position = Vector3( 0.410121, 0.607306, -0.0169033 )
|
||||
bones/32/rotation = Quaternion( -0.0424852, 0.0187641, -0.263502, 0.96354 )
|
||||
bones/32/scale = Vector3( 1, 1, 1 )
|
||||
bones/33/position = Vector3( 1.19209e-07, 0.301735, 1.56462e-07 )
|
||||
bones/33/rotation = Quaternion( -0.0440545, 0.63492, 0.039892, 0.770289 )
|
||||
bones/33/scale = Vector3( 1, 1, 1 )
|
||||
bones/34/position = Vector3( 1.17961e-15, 2.97461, 2.98023e-08 )
|
||||
bones/34/rotation = Quaternion( -1.13845e-08, 0.997388, 0.0722371, 7.53007e-08 )
|
||||
bones/34/scale = Vector3( 1, 1, 1 )
|
||||
|
||||
[node name="Control" type="Control" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
|
51
steering_ai/Demos/Arrive/ArriveDemo.gd
Normal file
51
steering_ai/Demos/Arrive/ArriveDemo.gd
Normal file
@ -0,0 +1,51 @@
|
||||
extends Node
|
||||
|
||||
export (float, 0, 3200, 100) var linear_speed_max := 800.0 setget set_linear_speed_max
|
||||
export (float, 0, 10000, 100) var linear_acceleration_max := 80.0 setget set_linear_acceleration_max
|
||||
export (float, 0, 100, 0.1) var arrival_tolerance := 25.0 setget set_arrival_tolerance
|
||||
export (float, 0, 500, 10) var deceleration_radius := 125.0 setget set_deceleration_radius
|
||||
|
||||
onready var arriver := $Arriver
|
||||
onready var target_drawer := $TargetDrawer
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
arriver.setup(linear_speed_max, linear_acceleration_max, arrival_tolerance, deceleration_radius)
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseButton and event.button_index == BUTTON_LEFT and event.is_pressed():
|
||||
arriver.target.position = Vector3(event.position.x, event.position.y, 0)
|
||||
target_drawer.update()
|
||||
|
||||
|
||||
func set_arrival_tolerance(value: float) -> void:
|
||||
arrival_tolerance = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
arriver.arrive.arrival_tolerance = value
|
||||
|
||||
|
||||
func set_deceleration_radius(value: float) -> void:
|
||||
deceleration_radius = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
arriver.arrive.deceleration_radius = value
|
||||
|
||||
|
||||
func set_linear_speed_max(value: float) -> void:
|
||||
linear_speed_max = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
arriver.agent.linear_speed_max = value
|
||||
|
||||
|
||||
func set_linear_acceleration_max(value: float) -> void:
|
||||
linear_acceleration_max = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
arriver.agent.linear_acceleration_max = value
|
39
steering_ai/Demos/Arrive/ArriveDemo.tscn
Normal file
39
steering_ai/Demos/Arrive/ArriveDemo.tscn
Normal file
@ -0,0 +1,39 @@
|
||||
[gd_scene load_steps=8 format=3]
|
||||
|
||||
[ext_resource path="res://Demos/Arrive/Arriver.gd" type="Script" id=1]
|
||||
[ext_resource path="res://Demos/Utils/DemoInterface.tscn" type="PackedScene" id=2]
|
||||
[ext_resource path="res://Demos/Arrive/ArriveDemo.gd" type="Script" id=3]
|
||||
[ext_resource path="res://Demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=4]
|
||||
[ext_resource path="res://Demos/Arrive/TargetDrawer.gd" type="Script" id=5]
|
||||
[ext_resource path="res://Demos/Utils/CircleDraw.gd" type="Script" id=6]
|
||||
|
||||
[sub_resource type="CircleShape2D" id=1]
|
||||
radius = 23.2163
|
||||
|
||||
[node name="ArriveDemo" type="Node"]
|
||||
script = ExtResource( 3 )
|
||||
linear_speed_max = 1600.0
|
||||
linear_acceleration_max = 5000.0
|
||||
arrival_tolerance = 35.0
|
||||
deceleration_radius = 180.0
|
||||
|
||||
[node name="BackgroudLayer" parent="." instance=ExtResource( 4 )]
|
||||
|
||||
[node name="TargetDrawer" type="Node2D" parent="."]
|
||||
script = ExtResource( 5 )
|
||||
|
||||
[node name="Arriver" type="KinematicBody2D" parent="."]
|
||||
show_behind_parent = true
|
||||
position = Vector2( 960, 540 )
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="Arriver"]
|
||||
shape = SubResource( 1 )
|
||||
script = ExtResource( 6 )
|
||||
inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
|
||||
outer_color = Color( 0.560784, 0.870588, 0.364706, 1 )
|
||||
stroke = 6.0
|
||||
|
||||
[node name="DemoInterface" parent="." instance=ExtResource( 2 )]
|
||||
text_bbcode = "Arrive Demo
|
||||
Mouse click to make the [color=lime]green \"Player\"[/color] move to the [color=fuchsia]purple target[/color]"
|
32
steering_ai/Demos/Arrive/Arriver.gd
Normal file
32
steering_ai/Demos/Arrive/Arriver.gd
Normal file
@ -0,0 +1,32 @@
|
||||
extends KinematicBody2D
|
||||
|
||||
var agent := GSAIKinematicBody2DAgent.new()
|
||||
var target := GSAIAgentLocation.new()
|
||||
var arrive := GSAIArrive.new()
|
||||
var _accel := GSAITargetAcceleration.new()
|
||||
|
||||
var _velocity := Vector2()
|
||||
var _drag := 0.1
|
||||
|
||||
func _init() -> void:
|
||||
agent.body = self
|
||||
arrive.agent = agent
|
||||
arrive.target = target
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
arrive.calculate_steering(_accel)
|
||||
agent.apply_steering(_accel, delta)
|
||||
|
||||
|
||||
func setup(
|
||||
linear_speed_max: float,
|
||||
linear_acceleration_max: float,
|
||||
arrival_tolerance: float,
|
||||
deceleration_radius: float
|
||||
) -> void:
|
||||
agent.linear_speed_max = linear_speed_max
|
||||
agent.linear_acceleration_max = linear_acceleration_max
|
||||
agent.linear_drag_percentage = _drag
|
||||
arrive.deceleration_radius = deceleration_radius
|
||||
arrive.arrival_tolerance = arrival_tolerance
|
||||
target.position = agent.position
|
17
steering_ai/Demos/Arrive/TargetDrawer.gd
Normal file
17
steering_ai/Demos/Arrive/TargetDrawer.gd
Normal file
@ -0,0 +1,17 @@
|
||||
extends Node2D
|
||||
|
||||
var deceleration_radius_color : Color = Color(1.0, 0.419, 0.592, 0.5)
|
||||
var arrival_tolerance_color : Color = Color(0.278, 0.231, 0.47, 0.3)
|
||||
|
||||
var arriver: Node2D
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
yield(owner, "ready")
|
||||
arriver = owner.arriver
|
||||
|
||||
|
||||
func _draw():
|
||||
var target_position := GSAIUtils.to_vector2(arriver.target.position)
|
||||
draw_circle(target_position, owner.deceleration_radius, deceleration_radius_color)
|
||||
draw_circle(target_position, owner.arrival_tolerance, arrival_tolerance_color)
|
95
steering_ai/Demos/Arrive3d/Arrive3dDemo.tscn
Normal file
95
steering_ai/Demos/Arrive3d/Arrive3dDemo.tscn
Normal file
@ -0,0 +1,95 @@
|
||||
[gd_scene load_steps=14 format=3]
|
||||
|
||||
[ext_resource path="res://Demos/Utils/DemoInterface.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://Demos/Arrive3d/Camera.gd" type="Script" id=2]
|
||||
[ext_resource path="res://Demos/Arrive3d/Seek3dDemo.gd" type="Script" id=3]
|
||||
[ext_resource path="res://Demos/Arrive3d/Seeker.gd" type="Script" id=4]
|
||||
[ext_resource path="res://Demos/Arrive3d/SeekerMat.tres" type="Material" id=5]
|
||||
|
||||
[sub_resource type="CapsuleShape" id=1]
|
||||
|
||||
[sub_resource type="CapsuleMesh" id=2]
|
||||
|
||||
[sub_resource type="CubeMesh" id=3]
|
||||
material = ExtResource( 5 )
|
||||
size = Vector3( 0.5, 0.5, 1 )
|
||||
|
||||
[sub_resource type="CylinderMesh" id=4]
|
||||
top_radius = 2.0
|
||||
bottom_radius = 2.0
|
||||
height = 0.1
|
||||
|
||||
[sub_resource type="SpatialMaterial" id=5]
|
||||
albedo_color = Color( 0.945098, 0.85098, 0.0745098, 1 )
|
||||
|
||||
[sub_resource type="BoxShape" id=6]
|
||||
extents = Vector3( 1000, 0.1, 1000 )
|
||||
|
||||
[sub_resource type="PlaneMesh" id=7]
|
||||
size = Vector2( 250, 250 )
|
||||
|
||||
[sub_resource type="SpatialMaterial" id=8]
|
||||
albedo_color = Color( 0.0941176, 0.235294, 0.486275, 1 )
|
||||
|
||||
[node name="Arrive3dDemo" type="Node"]
|
||||
script = ExtResource( 3 )
|
||||
linear_speed_max = 50.0
|
||||
linear_acceleration_max = 53.2
|
||||
deceleration_radius = 10.8
|
||||
angular_speed_max = 550
|
||||
angular_accel_max = 910
|
||||
|
||||
[node name="Arriver" type="KinematicBody" parent="."]
|
||||
script = ExtResource( 4 )
|
||||
|
||||
[node name="CollisionShape" type="CollisionShape" parent="Arriver"]
|
||||
transform = Transform( 1, 0, 0, 0, -1.62921e-07, 1, 0, -1, -1.62921e-07, 0, 1.5, 0 )
|
||||
shape = SubResource( 1 )
|
||||
|
||||
[node name="Capsule" type="MeshInstance" parent="Arriver"]
|
||||
transform = Transform( 1, 0, 0, 0, -1.62921e-07, 1, 0, -1, -1.62921e-07, 0, 1.5, 0 )
|
||||
mesh = SubResource( 2 )
|
||||
material/0 = ExtResource( 5 )
|
||||
|
||||
[node name="Nose" type="MeshInstance" parent="Arriver"]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 1.25 )
|
||||
mesh = SubResource( 3 )
|
||||
|
||||
[node name="Camera" type="Camera" parent="."]
|
||||
transform = Transform( 0.989952, 0.0720094, -0.121693, 0.0339305, 0.714503, 0.69881, 0.137271, -0.695917, 0.70488, -7.68317, 14.1265, 25.616 )
|
||||
current = true
|
||||
script = ExtResource( 2 )
|
||||
|
||||
[node name="RayCast" type="RayCast" parent="Camera"]
|
||||
enabled = true
|
||||
cast_to = Vector3( -627, 200, -777 )
|
||||
collision_mask = 2
|
||||
|
||||
[node name="MouseTarget" type="Spatial" parent="."]
|
||||
transform = Transform( 1, 0, 7.45058e-09, 0, 1, 0, 7.45058e-09, 0, 1, -4.76837e-07, 9.53674e-07, 1.90735e-06 )
|
||||
|
||||
[node name="MeshInstance" type="MeshInstance" parent="MouseTarget"]
|
||||
mesh = SubResource( 4 )
|
||||
material/0 = SubResource( 5 )
|
||||
|
||||
[node name="StaticBody" type="StaticBody" parent="."]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.1, 0 )
|
||||
collision_layer = 2
|
||||
collision_mask = 2
|
||||
|
||||
[node name="CollisionShape" type="CollisionShape" parent="StaticBody"]
|
||||
shape = SubResource( 6 )
|
||||
|
||||
[node name="Ground" type="MeshInstance" parent="."]
|
||||
mesh = SubResource( 7 )
|
||||
material/0 = SubResource( 8 )
|
||||
|
||||
[node name="DirectionalLight" type="DirectionalLight" parent="."]
|
||||
transform = Transform( -0.588165, 0.462179, -0.663666, -0.804031, -0.245728, 0.541436, 0.087159, 0.852061, 0.516134, -17.6076, 12.1748, 0 )
|
||||
light_energy = 0.5
|
||||
shadow_enabled = true
|
||||
|
||||
[node name="DemoInterface" parent="." instance=ExtResource( 1 )]
|
||||
mouse_filter = 2
|
||||
text_bbcode = "3D Arrive Demo
|
||||
Move the mouse about the field to have the agent turn towards and smoothly arrive at the target marker."
|
24
steering_ai/Demos/Arrive3d/Camera.gd
Normal file
24
steering_ai/Demos/Arrive3d/Camera.gd
Normal file
@ -0,0 +1,24 @@
|
||||
extends Camera
|
||||
|
||||
var target: Spatial
|
||||
|
||||
onready var ray := $RayCast
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseMotion:
|
||||
_set_target_position(event.position)
|
||||
|
||||
|
||||
func setup(_target: Spatial) -> void:
|
||||
self.target = _target
|
||||
_set_target_position(get_viewport().get_mouse_position())
|
||||
|
||||
|
||||
func _set_target_position(position: Vector2) -> void:
|
||||
var to = project_local_ray_normal(position) * 10000
|
||||
ray.cast_to = to
|
||||
ray.force_raycast_update()
|
||||
if ray.is_colliding():
|
||||
var point = ray.get_collision_point()
|
||||
target.transform.origin = point
|
92
steering_ai/Demos/Arrive3d/Seek3dDemo.gd
Normal file
92
steering_ai/Demos/Arrive3d/Seek3dDemo.gd
Normal file
@ -0,0 +1,92 @@
|
||||
extends Node
|
||||
|
||||
export (float, 0, 100, 5) var linear_speed_max := 10.0 setget set_linear_speed_max
|
||||
export (float, 0, 100, 0.1) var linear_acceleration_max := 1.0 setget set_linear_acceleration_max
|
||||
export (float, 0, 50, 0.1) var arrival_tolerance := 0.5 setget set_arrival_tolerance
|
||||
export (float, 0, 50, 0.1) var deceleration_radius := 5.0 setget set_deceleration_radius
|
||||
export (int, 0, 1080, 10) var angular_speed_max := 270 setget set_angular_speed_max
|
||||
export (int, 0, 2048, 10) var angular_accel_max := 45 setget set_angular_accel_max
|
||||
export (int, 0, 178, 2) var align_tolerance := 5 setget set_align_tolerance
|
||||
export (int, 0, 180, 2) var angular_deceleration_radius := 45 setget set_angular_deceleration_radius
|
||||
|
||||
onready var target := $MouseTarget
|
||||
onready var arriver := $Arriver
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
arriver.setup(
|
||||
deg2rad(align_tolerance),
|
||||
deg2rad(angular_deceleration_radius),
|
||||
deg2rad(angular_accel_max),
|
||||
deg2rad(angular_speed_max),
|
||||
deceleration_radius,
|
||||
arrival_tolerance,
|
||||
linear_acceleration_max,
|
||||
linear_speed_max,
|
||||
target
|
||||
)
|
||||
$Camera.setup(target)
|
||||
|
||||
|
||||
func set_align_tolerance(value: int) -> void:
|
||||
align_tolerance = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
arriver.face.alignment_tolerance = deg2rad(value)
|
||||
|
||||
|
||||
func set_angular_deceleration_radius(value: int) -> void:
|
||||
deceleration_radius = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
arriver.face.deceleration_radius = deg2rad(value)
|
||||
|
||||
|
||||
func set_angular_accel_max(value: int) -> void:
|
||||
angular_accel_max = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
arriver.agent.angular_acceleration_max = deg2rad(value)
|
||||
|
||||
|
||||
func set_angular_speed_max(value: int) -> void:
|
||||
angular_speed_max = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
arriver.agent.angular_speed_max = deg2rad(value)
|
||||
|
||||
|
||||
func set_arrival_tolerance(value: float) -> void:
|
||||
arrival_tolerance = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
arriver.arrive.arrival_tolerance = value
|
||||
|
||||
|
||||
func set_deceleration_radius(value: float) -> void:
|
||||
deceleration_radius = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
arriver.arrive.deceleration_radius = value
|
||||
|
||||
|
||||
func set_linear_speed_max(value: float) -> void:
|
||||
linear_speed_max = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
arriver.agent.linear_speed_max = value
|
||||
|
||||
|
||||
func set_linear_acceleration_max(value: float) -> void:
|
||||
linear_acceleration_max = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
arriver.agent.linear_acceleration_max = value
|
64
steering_ai/Demos/Arrive3d/Seeker.gd
Normal file
64
steering_ai/Demos/Arrive3d/Seeker.gd
Normal file
@ -0,0 +1,64 @@
|
||||
extends KinematicBody
|
||||
|
||||
var target_node: Spatial
|
||||
|
||||
var agent : GSAIKinematicBody3DAgent = null
|
||||
var target : GSAIAgentLocation = null
|
||||
var accel : GSAITargetAcceleration = null
|
||||
var blend : GSAIBlend = null
|
||||
var face : GSAIFace = null
|
||||
var arrive : GSAIArrive = null
|
||||
|
||||
func _init() -> void:
|
||||
agent = GSAIKinematicBody3DAgent.new()
|
||||
agent.body = self
|
||||
|
||||
target = GSAIAgentLocation.new()
|
||||
accel = GSAITargetAcceleration.new()
|
||||
blend = GSAIBlend.new()
|
||||
blend.agent = agent
|
||||
|
||||
face = GSAIFace.new()
|
||||
face.agent = agent
|
||||
face.target = target
|
||||
face.use_z = true
|
||||
|
||||
arrive = GSAIArrive.new()
|
||||
arrive.agent = agent
|
||||
arrive.target = target
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
target.position = target_node.transform.origin
|
||||
target.position.y = transform.origin.y
|
||||
blend.calculate_steering(accel)
|
||||
agent.apply_steering(accel, delta)
|
||||
|
||||
|
||||
func setup(
|
||||
align_tolerance: float,
|
||||
angular_deceleration_radius: float,
|
||||
angular_accel_max: float,
|
||||
angular_speed_max: float,
|
||||
deceleration_radius: float,
|
||||
arrival_tolerance: float,
|
||||
linear_acceleration_max: float,
|
||||
linear_speed_max: float,
|
||||
_target: Spatial
|
||||
) -> void:
|
||||
agent.linear_speed_max = linear_speed_max
|
||||
agent.linear_acceleration_max = linear_acceleration_max
|
||||
agent.linear_drag_percentage = 0.05
|
||||
agent.angular_acceleration_max = angular_accel_max
|
||||
agent.angular_speed_max = angular_speed_max
|
||||
agent.angular_drag_percentage = 0.1
|
||||
|
||||
arrive.arrival_tolerance = arrival_tolerance
|
||||
arrive.deceleration_radius = deceleration_radius
|
||||
|
||||
face.alignment_tolerance = align_tolerance
|
||||
face.deceleration_radius = angular_deceleration_radius
|
||||
|
||||
target_node = _target
|
||||
self.target.position = target_node.transform.origin
|
||||
blend.add_behavior(arrive, 1)
|
||||
blend.add_behavior(face, 1)
|
4
steering_ai/Demos/Arrive3d/SeekerMat.tres
Normal file
4
steering_ai/Demos/Arrive3d/SeekerMat.tres
Normal file
@ -0,0 +1,4 @@
|
||||
[gd_resource type="SpatialMaterial" format=2]
|
||||
|
||||
[resource]
|
||||
albedo_color = Color( 0.152941, 0.764706, 0.247059, 1 )
|
40
steering_ai/Demos/AvoidCollisions/AvoidCollisionsDemo.gd
Normal file
40
steering_ai/Demos/AvoidCollisions/AvoidCollisionsDemo.gd
Normal file
@ -0,0 +1,40 @@
|
||||
extends Node
|
||||
|
||||
export (float, 0, 1000, 40) var linear_speed_max := 350.0 setget set_linear_speed_max
|
||||
export (float, 0, 4000, 2) var linear_acceleration_max := 40.0 setget set_linear_accel_max
|
||||
export (float, 0, 500, 10) var proximity_radius := 140.0 setget set_proximity_radius
|
||||
export var draw_proximity := true setget set_draw_proximity
|
||||
|
||||
onready var spawner := $Spawner
|
||||
|
||||
|
||||
func set_linear_speed_max(value: float) -> void:
|
||||
linear_speed_max = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
spawner.set_linear_speed_max(value)
|
||||
|
||||
|
||||
func set_linear_accel_max(value: float) -> void:
|
||||
linear_acceleration_max = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
spawner.set_linear_accel_max(value)
|
||||
|
||||
|
||||
func set_proximity_radius(value: float) -> void:
|
||||
proximity_radius = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
spawner.set_proximity_radius(value)
|
||||
|
||||
|
||||
func set_draw_proximity(value: bool) -> void:
|
||||
draw_proximity = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
spawner.set_draw_proximity(value)
|
26
steering_ai/Demos/AvoidCollisions/AvoidCollisionsDemo.tscn
Normal file
26
steering_ai/Demos/AvoidCollisions/AvoidCollisionsDemo.tscn
Normal file
@ -0,0 +1,26 @@
|
||||
[gd_scene load_steps=6 format=3]
|
||||
|
||||
[ext_resource path="res://Demos/AvoidCollisions/Spawner.gd" type="Script" id=1]
|
||||
[ext_resource path="res://Demos/AvoidCollisions/AvoidCollisionsDemo.gd" type="Script" id=2]
|
||||
[ext_resource path="res://Demos/AvoidCollisions/Avoider.tscn" type="PackedScene" id=3]
|
||||
[ext_resource path="res://Demos/Utils/DemoInterface.tscn" type="PackedScene" id=4]
|
||||
[ext_resource path="res://Demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=5]
|
||||
|
||||
[node name="AvoidCollisionsDemo" type="Node"]
|
||||
script = ExtResource( 2 )
|
||||
linear_speed_max = 520.0
|
||||
linear_acceleration_max = 2250.0
|
||||
proximity_radius = 100.0
|
||||
|
||||
[node name="BackgroudLayer" parent="." instance=ExtResource( 5 )]
|
||||
|
||||
[node name="Spawner" type="Node2D" parent="."]
|
||||
script = ExtResource( 1 )
|
||||
avoider_template = ExtResource( 3 )
|
||||
inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
|
||||
outer_color = Color( 0.560784, 0.870588, 0.364706, 1 )
|
||||
agent_count = 80
|
||||
|
||||
[node name="DemoInterface" parent="." instance=ExtResource( 4 )]
|
||||
text_bbcode = "Avoid Collisions Demo
|
||||
Watch each agent try to keep traveling in a particular direction, but prioritize avoiding collisions with other agents."
|
112
steering_ai/Demos/AvoidCollisions/Avoider.gd
Normal file
112
steering_ai/Demos/AvoidCollisions/Avoider.gd
Normal file
@ -0,0 +1,112 @@
|
||||
extends KinematicBody2D
|
||||
|
||||
var draw_proximity: bool
|
||||
|
||||
var _boundary_right: float
|
||||
var _boundary_bottom: float
|
||||
var _radius: float
|
||||
var _accel := GSAITargetAcceleration.new()
|
||||
var _velocity := Vector2.ZERO
|
||||
var _direction := Vector2()
|
||||
var _drag := 0.1
|
||||
var _color := Color(0.4, 1.0, 0.89, 0.3)
|
||||
|
||||
onready var collision := $CollisionShape2D
|
||||
var agent :GSAIKinematicBody2DAgent= null
|
||||
var proximity :GSAIRadiusProximity= null
|
||||
var avoid :GSAIAvoidCollisions= null
|
||||
var target :GSAIAgentLocation= null
|
||||
var seek :GSAISeek= null
|
||||
var priority :GSAIPriority= null
|
||||
|
||||
func _ready() -> void:
|
||||
agent = GSAIKinematicBody2DAgent.new()
|
||||
agent.body = self
|
||||
|
||||
proximity = GSAIRadiusProximity.new()
|
||||
proximity.agent = agent
|
||||
proximity.radius = 140
|
||||
|
||||
avoid = GSAIAvoidCollisions.new()
|
||||
avoid.agent = agent
|
||||
avoid.proximity = proximity
|
||||
|
||||
target = GSAIAgentLocation.new()
|
||||
|
||||
seek = GSAISeek.new()
|
||||
seek.agent = agent
|
||||
seek.target = target
|
||||
|
||||
priority = GSAIPriority.new()
|
||||
priority.agent = agent
|
||||
priority.zero_threshold = 0.0001
|
||||
|
||||
func _draw() -> void:
|
||||
if draw_proximity:
|
||||
draw_circle(Vector2.ZERO, proximity.radius, _color)
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
target.position.x = agent.position.x + _direction.x * _radius
|
||||
target.position.y = agent.position.y + _direction.y * _radius
|
||||
|
||||
priority.calculate_steering(_accel)
|
||||
agent.apply_steering(_accel, delta)
|
||||
|
||||
|
||||
func setup(
|
||||
linear_speed_max: float,
|
||||
linear_accel_max: float,
|
||||
proximity_radius: float,
|
||||
boundary_right: float,
|
||||
boundary_bottom: float,
|
||||
_draw_proximity: bool,
|
||||
rng: RandomNumberGenerator
|
||||
) -> void:
|
||||
rng.randomize()
|
||||
_direction = Vector2(rng.randf_range(-1, 1), rng.randf_range(-1, 1)).normalized()
|
||||
|
||||
agent.linear_speed_max = linear_speed_max
|
||||
agent.linear_acceleration_max = linear_accel_max
|
||||
|
||||
proximity.radius = proximity_radius
|
||||
_boundary_bottom = boundary_bottom
|
||||
_boundary_right = boundary_right
|
||||
|
||||
_radius = collision.shape.radius
|
||||
agent.bounding_radius = _radius
|
||||
|
||||
agent.linear_drag_percentage = _drag
|
||||
|
||||
self.draw_proximity = _draw_proximity
|
||||
|
||||
priority.add_behavior(avoid)
|
||||
priority.add_behavior(seek)
|
||||
|
||||
|
||||
func set_proximity_agents(agents: Array) -> void:
|
||||
proximity.agents = agents
|
||||
|
||||
|
||||
func set_random_nonoverlapping_position(others: Array, distance_from_boundary_min: float) -> void:
|
||||
var rng := RandomNumberGenerator.new()
|
||||
rng.randomize()
|
||||
var tries_max := max(100, others.size() * others.size())
|
||||
while tries_max > 0:
|
||||
tries_max -= 1
|
||||
global_position.x = rng.randf_range(
|
||||
distance_from_boundary_min, _boundary_right - distance_from_boundary_min
|
||||
)
|
||||
global_position.y = rng.randf_range(
|
||||
distance_from_boundary_min, _boundary_bottom - distance_from_boundary_min
|
||||
)
|
||||
var done := true
|
||||
for i in range(others.size()):
|
||||
var other: Node2D = others[i]
|
||||
if (
|
||||
other.global_position.distance_to(position)
|
||||
<= _radius * 2 + distance_from_boundary_min
|
||||
):
|
||||
done = false
|
||||
if done:
|
||||
break
|
17
steering_ai/Demos/AvoidCollisions/Avoider.tscn
Normal file
17
steering_ai/Demos/AvoidCollisions/Avoider.tscn
Normal file
@ -0,0 +1,17 @@
|
||||
[gd_scene load_steps=4 format=3]
|
||||
|
||||
[ext_resource path="res://Demos/Utils/CircleDraw.gd" type="Script" id=1]
|
||||
[ext_resource path="res://Demos/AvoidCollisions/Avoider.gd" type="Script" id=2]
|
||||
|
||||
[sub_resource type="CircleShape2D" id=1]
|
||||
radius = 21.3503
|
||||
|
||||
[node name="Avoider" type="KinematicBody2D"]
|
||||
script = ExtResource( 2 )
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
shape = SubResource( 1 )
|
||||
script = ExtResource( 1 )
|
||||
inner_color = Color( 0.890196, 0.411765, 0.337255, 1 )
|
||||
outer_color = Color( 1, 0.709804, 0.439216, 1 )
|
||||
stroke = 5.0
|
66
steering_ai/Demos/AvoidCollisions/Spawner.gd
Normal file
66
steering_ai/Demos/AvoidCollisions/Spawner.gd
Normal file
@ -0,0 +1,66 @@
|
||||
extends Node2D
|
||||
|
||||
export var avoider_template: PackedScene
|
||||
export var inner_color := Color()
|
||||
export var outer_color := Color()
|
||||
export var agent_count := 60
|
||||
|
||||
var boundaries: Vector2
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
boundaries = Vector2(
|
||||
ProjectSettings["display/window/size/width"], ProjectSettings["display/window/size/height"]
|
||||
)
|
||||
var rng := RandomNumberGenerator.new()
|
||||
var avoiders := []
|
||||
var avoider_agents := []
|
||||
for i in range(agent_count):
|
||||
var avoider := avoider_template.instance()
|
||||
add_child(avoider)
|
||||
avoider.setup(
|
||||
owner.linear_speed_max,
|
||||
owner.linear_acceleration_max,
|
||||
owner.proximity_radius,
|
||||
boundaries.x,
|
||||
boundaries.y,
|
||||
true if i == 0 and owner.draw_proximity else false,
|
||||
rng
|
||||
)
|
||||
avoider_agents.append(avoider.agent)
|
||||
avoider.set_random_nonoverlapping_position(avoiders, 16)
|
||||
if i == 0:
|
||||
avoider.collision.inner_color = inner_color
|
||||
avoider.collision.outer_color = outer_color
|
||||
avoiders.append(avoider)
|
||||
if i % 10 == 0:
|
||||
yield(get_tree(), "idle_frame")
|
||||
for child in get_children():
|
||||
child.set_proximity_agents(avoider_agents)
|
||||
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
for child in get_children():
|
||||
child.global_position = child.global_position.posmodv(boundaries)
|
||||
|
||||
|
||||
func set_linear_speed_max(value: float) -> void:
|
||||
for child in get_children():
|
||||
child.agent.linear_speed_max = value
|
||||
|
||||
|
||||
func set_linear_accel_max(value: float) -> void:
|
||||
for child in get_children():
|
||||
child.agent.linear_acceleration_max = value
|
||||
|
||||
|
||||
func set_proximity_radius(value: float) -> void:
|
||||
for child in get_children():
|
||||
child.proximity.radius = value
|
||||
get_child(0).update()
|
||||
|
||||
|
||||
func set_draw_proximity(value: bool) -> void:
|
||||
var child := get_child(0)
|
||||
child.draw_proximity = value
|
||||
child.update()
|
28
steering_ai/Demos/DemoPickerUI.gd
Normal file
28
steering_ai/Demos/DemoPickerUI.gd
Normal file
@ -0,0 +1,28 @@
|
||||
class_name DemoPickerUI
|
||||
extends Control
|
||||
|
||||
# warning-ignore:unused_signal
|
||||
signal demo_requested
|
||||
|
||||
var demo_path := "" setget set_demo_path
|
||||
|
||||
onready var list: ItemList = $VBoxContainer/ItemList
|
||||
onready var button: Button = $VBoxContainer/Button
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
# warning-ignore:return_value_discarded
|
||||
list.connect("demo_selected", self, "set_demo_path")
|
||||
# warning-ignore:return_value_discarded
|
||||
list.connect("item_activated", self, "_on_ItemList_item_activated")
|
||||
# warning-ignore:return_value_discarded
|
||||
button.connect("pressed", self, "emit_signal", ["demo_requested"])
|
||||
demo_path = list.file_paths[0]
|
||||
|
||||
|
||||
func set_demo_path(value: String) -> void:
|
||||
demo_path = value
|
||||
|
||||
|
||||
func _on_ItemList_item_activated(_index: int) -> void:
|
||||
emit_signal("demo_requested")
|
16
steering_ai/Demos/DemoPlayer.gd
Normal file
16
steering_ai/Demos/DemoPlayer.gd
Normal file
@ -0,0 +1,16 @@
|
||||
extends Node2D
|
||||
|
||||
|
||||
func load_demo(scene_path: String) -> void:
|
||||
if not scene_path:
|
||||
return
|
||||
|
||||
var demo = load(scene_path)
|
||||
if demo:
|
||||
add_child(demo.instance())
|
||||
|
||||
|
||||
func unload() -> void:
|
||||
for node in get_children():
|
||||
call_deferred("remove_child", node)
|
||||
node.queue_free()
|
81
steering_ai/Demos/DemoSelector.tscn
Normal file
81
steering_ai/Demos/DemoSelector.tscn
Normal file
@ -0,0 +1,81 @@
|
||||
[gd_scene load_steps=7 format=3]
|
||||
|
||||
[ext_resource path="res://Demos/PopulateItemList.gd" type="Script" id=1]
|
||||
[ext_resource path="res://assets/theme/gdquest.theme" type="Theme" id=2]
|
||||
[ext_resource path="res://assets/sprites/background.png" type="Texture" id=3]
|
||||
[ext_resource path="res://Demos/DemoPickerUI.gd" type="Script" id=4]
|
||||
[ext_resource path="res://Demos/DemoPlayer.gd" type="Script" id=5]
|
||||
[ext_resource path="res://Demos/Demos.gd" type="Script" id=6]
|
||||
|
||||
[node name="Demos" type="Node"]
|
||||
script = ExtResource( 6 )
|
||||
|
||||
[node name="DemoPlayer" type="Node2D" parent="."]
|
||||
script = ExtResource( 5 )
|
||||
|
||||
[node name="DemoPickerUI" type="Control" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
theme = ExtResource( 2 )
|
||||
script = ExtResource( 4 )
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="DemoPickerUI"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
rect_min_size = Vector2( 1024, 600 )
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
texture = ExtResource( 3 )
|
||||
expand = true
|
||||
stretch_mode = 2
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="DemoPickerUI"]
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
margin_left = -341.0
|
||||
margin_top = -290.0
|
||||
margin_right = 341.0
|
||||
margin_bottom = 290.0
|
||||
rect_min_size = Vector2( 682, 0 )
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
alignment = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="ItemList" type="ItemList" parent="DemoPickerUI/VBoxContainer"]
|
||||
margin_top = 231.0
|
||||
margin_right = 682.0
|
||||
margin_bottom = 240.0
|
||||
auto_height = true
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="Button" type="Button" parent="DemoPickerUI/VBoxContainer"]
|
||||
margin_left = 201.0
|
||||
margin_top = 248.0
|
||||
margin_right = 481.0
|
||||
margin_bottom = 348.0
|
||||
rect_min_size = Vector2( 280, 100 )
|
||||
size_flags_horizontal = 4
|
||||
size_flags_vertical = 13
|
||||
text = "Load scene"
|
||||
|
||||
[node name="ButtonGoBack" type="Button" parent="."]
|
||||
visible = false
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = 48.0
|
||||
margin_top = -156.0
|
||||
margin_right = 328.0
|
||||
margin_bottom = -56.0
|
||||
rect_min_size = Vector2( 280, 100 )
|
||||
size_flags_horizontal = 4
|
||||
size_flags_vertical = 13
|
||||
theme = ExtResource( 2 )
|
||||
text = "Go back"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
30
steering_ai/Demos/Demos.gd
Normal file
30
steering_ai/Demos/Demos.gd
Normal file
@ -0,0 +1,30 @@
|
||||
extends Node
|
||||
|
||||
onready var demo_picker: DemoPickerUI = $DemoPickerUI
|
||||
onready var demo_player := $DemoPlayer
|
||||
onready var button_go_back: Button = $ButtonGoBack
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
# warning-ignore:return_value_discarded
|
||||
demo_picker.connect("demo_requested", self, "_on_DemoPickerUI_demo_requested")
|
||||
# warning-ignore:return_value_discarded
|
||||
button_go_back.connect("pressed", self, "_on_ButtonGoBack_pressed")
|
||||
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if event.is_action_pressed("toggle_fullscreen"):
|
||||
OS.window_fullscreen = not OS.window_fullscreen
|
||||
get_tree().set_input_as_handled()
|
||||
|
||||
|
||||
func _on_DemoPickerUI_demo_requested() -> void:
|
||||
demo_player.load_demo(demo_picker.demo_path)
|
||||
demo_picker.hide()
|
||||
button_go_back.show()
|
||||
|
||||
|
||||
func _on_ButtonGoBack_pressed() -> void:
|
||||
demo_player.unload()
|
||||
button_go_back.hide()
|
||||
demo_picker.show()
|
61
steering_ai/Demos/Face/FaceDemo.gd
Normal file
61
steering_ai/Demos/Face/FaceDemo.gd
Normal file
@ -0,0 +1,61 @@
|
||||
extends Node
|
||||
|
||||
export (int, 0, 1080, 2) var angular_speed_max := 120 setget set_angular_speed_max
|
||||
export (int, 0, 2048, 2) var angular_accel_max := 10 setget set_angular_accel_max
|
||||
export (int, 0, 180, 2) var align_tolerance := 5 setget set_align_tolerance
|
||||
export (int, 0, 359, 2) var deceleration_radius := 45 setget set_deceleration_radius
|
||||
export (float, 0, 1000, 40) var player_speed := 600.0 setget set_player_speed
|
||||
|
||||
onready var player := $Player
|
||||
onready var turret := $Turret
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
player.speed = player_speed
|
||||
turret.setup(
|
||||
player.agent,
|
||||
deg2rad(align_tolerance),
|
||||
deg2rad(deceleration_radius),
|
||||
deg2rad(angular_accel_max),
|
||||
deg2rad(angular_speed_max)
|
||||
)
|
||||
|
||||
|
||||
func set_align_tolerance(value: int) -> void:
|
||||
align_tolerance = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
turret.face.alignment_tolerance = deg2rad(value)
|
||||
|
||||
|
||||
func set_deceleration_radius(value: int) -> void:
|
||||
deceleration_radius = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
turret.face.deceleration_radius = deg2rad(value)
|
||||
|
||||
|
||||
func set_angular_accel_max(value: int) -> void:
|
||||
angular_accel_max = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
turret.agent.angular_acceleration_max = deg2rad(value)
|
||||
|
||||
|
||||
func set_angular_speed_max(value: int) -> void:
|
||||
angular_speed_max = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
turret.agent.angular_speed_max = deg2rad(value)
|
||||
|
||||
|
||||
func set_player_speed(value: float) -> void:
|
||||
player_speed = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
player.speed = player_speed
|
48
steering_ai/Demos/Face/FaceDemo.tscn
Normal file
48
steering_ai/Demos/Face/FaceDemo.tscn
Normal file
@ -0,0 +1,48 @@
|
||||
[gd_scene load_steps=9 format=3]
|
||||
|
||||
[ext_resource path="res://Demos/Face/Turret.gd" type="Script" id=1]
|
||||
[ext_resource path="res://Demos/Face/FaceDemo.gd" type="Script" id=2]
|
||||
[ext_resource path="res://Demos/Face/Player.gd" type="Script" id=3]
|
||||
[ext_resource path="res://Demos/Utils/DemoInterface.tscn" type="PackedScene" id=4]
|
||||
[ext_resource path="res://Demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=5]
|
||||
[ext_resource path="res://Demos/Utils/CircleDraw.gd" type="Script" id=8]
|
||||
|
||||
[sub_resource type="CircleShape2D" id=1]
|
||||
radius = 20.2633
|
||||
|
||||
[sub_resource type="CircleShape2D" id=2]
|
||||
radius = 37.1052
|
||||
|
||||
[node name="FaceDemo" type="Node"]
|
||||
script = ExtResource( 2 )
|
||||
angular_speed_max = 662
|
||||
angular_accel_max = 924
|
||||
deceleration_radius = 136
|
||||
|
||||
[node name="BackgroudLayer" parent="." instance=ExtResource( 5 )]
|
||||
|
||||
[node name="Player" type="KinematicBody2D" parent="."]
|
||||
position = Vector2( 687.363, 351.005 )
|
||||
script = ExtResource( 3 )
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="Player"]
|
||||
shape = SubResource( 1 )
|
||||
script = ExtResource( 8 )
|
||||
inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
|
||||
outer_color = Color( 0.560784, 0.870588, 0.364706, 1 )
|
||||
stroke = 6.0
|
||||
|
||||
[node name="Turret" type="KinematicBody2D" parent="."]
|
||||
position = Vector2( 984.348, 571.959 )
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="Turret"]
|
||||
shape = SubResource( 2 )
|
||||
script = ExtResource( 8 )
|
||||
inner_color = Color( 0.890196, 0.411765, 0.337255, 1 )
|
||||
outer_color = Color( 1, 0.709804, 0.439216, 1 )
|
||||
stroke = 8.0
|
||||
|
||||
[node name="DemoInterface" parent="." instance=ExtResource( 4 )]
|
||||
text_bbcode = "Face Demo
|
||||
Move the [color=lime]green player[/color] around with WASD and notice the [color=#ffb570]orange turret[/color] orient itself"
|
18
steering_ai/Demos/Face/Player.gd
Normal file
18
steering_ai/Demos/Face/Player.gd
Normal file
@ -0,0 +1,18 @@
|
||||
extends KinematicBody2D
|
||||
|
||||
var speed: float
|
||||
|
||||
onready var agent := GSAIAgentLocation.new()
|
||||
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
var movement := _get_movement()
|
||||
move_and_slide(movement * speed)
|
||||
agent.position = Vector3(global_position.x, global_position.y, 0)
|
||||
|
||||
|
||||
func _get_movement() -> Vector2:
|
||||
return Vector2(
|
||||
Input.get_action_strength("sf_right") - Input.get_action_strength("sf_left"),
|
||||
Input.get_action_strength("sf_down") - Input.get_action_strength("sf_up")
|
||||
)
|
47
steering_ai/Demos/Face/Turret.gd
Normal file
47
steering_ai/Demos/Face/Turret.gd
Normal file
@ -0,0 +1,47 @@
|
||||
extends KinematicBody2D
|
||||
|
||||
var face: GSAIFace
|
||||
var agent := GSAIKinematicBody2DAgent.new()
|
||||
|
||||
var _accel := GSAITargetAcceleration.new()
|
||||
var _angular_drag := 0.1
|
||||
var _cannon: Rect2
|
||||
var _color: Color
|
||||
|
||||
onready var collision_shape := $CollisionShape2D
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
agent.body = self
|
||||
|
||||
var radius = collision_shape.shape.radius
|
||||
_cannon = Rect2(Vector2(-5, 0), Vector2(10, -radius * 2))
|
||||
_color = collision_shape.outer_color
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
face.calculate_steering(_accel)
|
||||
agent.apply_steering(_accel, delta)
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
draw_rect(_cannon, _color)
|
||||
|
||||
|
||||
func setup(
|
||||
player_agent: GSAIAgentLocation,
|
||||
align_tolerance: float,
|
||||
deceleration_radius: float,
|
||||
angular_accel_max: float,
|
||||
angular_speed_max: float
|
||||
) -> void:
|
||||
face = GSAIFace.new()
|
||||
face.agent = agent
|
||||
face.target = player_agent
|
||||
|
||||
face.alignment_tolerance = align_tolerance
|
||||
face.deceleration_radius = deceleration_radius
|
||||
|
||||
agent.angular_acceleration_max = angular_accel_max
|
||||
agent.angular_speed_max = angular_speed_max
|
||||
agent.angular_drag_percentage = _angular_drag
|
53
steering_ai/Demos/FollowPath/Drawer.gd
Normal file
53
steering_ai/Demos/FollowPath/Drawer.gd
Normal file
@ -0,0 +1,53 @@
|
||||
extends Node2D
|
||||
|
||||
signal path_established(points)
|
||||
|
||||
var active_points := []
|
||||
var is_drawing := false
|
||||
var distance_threshold := 100.0
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseMotion:
|
||||
if is_drawing:
|
||||
active_points.append(event.position)
|
||||
update()
|
||||
elif event is InputEventMouseButton:
|
||||
if event.pressed and event.button_index == BUTTON_LEFT:
|
||||
active_points.clear()
|
||||
active_points.append(event.position)
|
||||
is_drawing = true
|
||||
update()
|
||||
elif not event.pressed:
|
||||
is_drawing = false
|
||||
if active_points.size() >= 2:
|
||||
_simplify()
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
if is_drawing:
|
||||
for point in active_points:
|
||||
draw_circle(point, 2, Color.red)
|
||||
else:
|
||||
if active_points.size() > 0:
|
||||
draw_circle(active_points.front(), 2, Color.red)
|
||||
draw_circle(active_points.back(), 2, Color.yellow)
|
||||
draw_polyline(active_points, Color.skyblue, 1.0)
|
||||
|
||||
|
||||
func _simplify() -> void:
|
||||
var first: Vector2 = active_points.front()
|
||||
var last: Vector2 = active_points.back()
|
||||
var key := first
|
||||
var simplified_path := [first]
|
||||
for i in range(1, active_points.size()):
|
||||
var point: Vector2 = active_points[i]
|
||||
var distance := point.distance_to(key)
|
||||
if distance > distance_threshold:
|
||||
key = point
|
||||
simplified_path.append(key)
|
||||
active_points = simplified_path
|
||||
if active_points.back() != last:
|
||||
active_points.append(last)
|
||||
update()
|
||||
emit_signal("path_established", active_points)
|
70
steering_ai/Demos/FollowPath/FollowPathDemo.gd
Normal file
70
steering_ai/Demos/FollowPath/FollowPathDemo.gd
Normal file
@ -0,0 +1,70 @@
|
||||
extends Node
|
||||
|
||||
export (float, 0, 2000, 40) var linear_speed_max := 600.0 setget set_linear_speed_max
|
||||
export (float, 0, 9000, 10.0) var linear_acceleration_max := 40.0 setget set_linear_acceleration_max
|
||||
export (float, 0, 100, 0.1) var arrival_tolerance := 10.0 setget set_arrival_tolerance
|
||||
export (float, 0, 500, 10) var deceleration_radius := 100.0 setget set_deceleration_radius
|
||||
export (float, 0, 5, 0.1) var predict_time := 0.3 setget set_predict_time
|
||||
export (float, 0, 200, 10.0) var path_offset := 20.0 setget set_path_offset
|
||||
|
||||
onready var drawer := $Drawer
|
||||
onready var follower := $PathFollower
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
follower.setup(
|
||||
path_offset,
|
||||
predict_time,
|
||||
linear_acceleration_max,
|
||||
linear_speed_max,
|
||||
deceleration_radius,
|
||||
arrival_tolerance
|
||||
)
|
||||
|
||||
|
||||
func set_linear_speed_max(value: float) -> void:
|
||||
linear_speed_max = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
follower.agent.linear_speed_max = value
|
||||
|
||||
|
||||
func set_linear_acceleration_max(value: float) -> void:
|
||||
linear_acceleration_max = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
follower.agent.linear_acceleration_max = value
|
||||
|
||||
|
||||
func set_arrival_tolerance(value: float) -> void:
|
||||
arrival_tolerance = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
follower.follow.arrival_tolerance = value
|
||||
|
||||
|
||||
func set_deceleration_radius(value: float) -> void:
|
||||
deceleration_radius = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
follower.follow.deceleration_radius = value
|
||||
|
||||
|
||||
func set_predict_time(value: float) -> void:
|
||||
predict_time = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
follower.follow.prediction_time = value
|
||||
|
||||
|
||||
func set_path_offset(value: float) -> void:
|
||||
path_offset = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
follower.follow.path_offset = value
|
37
steering_ai/Demos/FollowPath/FollowPathDemo.tscn
Normal file
37
steering_ai/Demos/FollowPath/FollowPathDemo.tscn
Normal file
@ -0,0 +1,37 @@
|
||||
[gd_scene load_steps=8 format=3]
|
||||
|
||||
[ext_resource path="res://Demos/FollowPath/Drawer.gd" type="Script" id=1]
|
||||
[ext_resource path="res://Demos/Utils/DemoInterface.tscn" type="PackedScene" id=2]
|
||||
[ext_resource path="res://Demos/FollowPath/PathFollower.gd" type="Script" id=3]
|
||||
[ext_resource path="res://Demos/FollowPath/FollowPathDemo.gd" type="Script" id=4]
|
||||
[ext_resource path="res://Demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=5]
|
||||
[ext_resource path="res://Demos/Utils/CircleDraw.gd" type="Script" id=6]
|
||||
|
||||
[sub_resource type="CircleShape2D" id=1]
|
||||
radius = 24.1954
|
||||
|
||||
[node name="FollowPathDemo" type="Node"]
|
||||
script = ExtResource( 4 )
|
||||
linear_speed_max = 920.0
|
||||
linear_acceleration_max = 3740.0
|
||||
deceleration_radius = 200.0
|
||||
|
||||
[node name="BackgroudLayer" parent="." instance=ExtResource( 5 )]
|
||||
|
||||
[node name="Drawer" type="Node2D" parent="."]
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="PathFollower" type="KinematicBody2D" parent="."]
|
||||
position = Vector2( 960, 540 )
|
||||
script = ExtResource( 3 )
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="PathFollower"]
|
||||
shape = SubResource( 1 )
|
||||
script = ExtResource( 6 )
|
||||
inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
|
||||
outer_color = Color( 0.560784, 0.870588, 0.364706, 1 )
|
||||
stroke = 6.0
|
||||
|
||||
[node name="DemoInterface" parent="." instance=ExtResource( 2 )]
|
||||
text_bbcode = "Follow Path Demo
|
||||
Use the mouse to draw a path on screen and watch the [color=lime]green \"Agent\"[/color] follow it to the end."
|
58
steering_ai/Demos/FollowPath/PathFollower.gd
Normal file
58
steering_ai/Demos/FollowPath/PathFollower.gd
Normal file
@ -0,0 +1,58 @@
|
||||
extends KinematicBody2D
|
||||
|
||||
var _velocity := Vector2.ZERO
|
||||
var _accel := GSAITargetAcceleration.new()
|
||||
var _valid := false
|
||||
var _drag := 0.1
|
||||
|
||||
var agent := GSAIKinematicBody2DAgent.new()
|
||||
var path := GSAIPath.new()
|
||||
var follow := GSAIFollowPath.new()
|
||||
|
||||
func _ready() -> void:
|
||||
agent.body = self
|
||||
|
||||
path.initialize(
|
||||
[
|
||||
Vector3(global_position.x, global_position.y, 0),
|
||||
Vector3(global_position.x, global_position.y, 0)
|
||||
],
|
||||
true
|
||||
)
|
||||
|
||||
follow.agent = agent
|
||||
follow.path = path
|
||||
follow.agent = agent
|
||||
|
||||
func setup(
|
||||
path_offset: float,
|
||||
predict_time: float,
|
||||
accel_max: float,
|
||||
speed_max: float,
|
||||
decel_radius: float,
|
||||
arrival_tolerance: float
|
||||
) -> void:
|
||||
owner.drawer.connect("path_established", self, "_on_Drawer_path_established")
|
||||
follow.path_offset = path_offset
|
||||
follow.prediction_time = predict_time
|
||||
follow.deceleration_radius = decel_radius
|
||||
follow.arrival_tolerance = arrival_tolerance
|
||||
|
||||
agent.linear_acceleration_max = accel_max
|
||||
agent.linear_speed_max = speed_max
|
||||
agent.linear_drag_percentage = _drag
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if _valid:
|
||||
follow.calculate_steering(_accel)
|
||||
agent.apply_steering(_accel, delta)
|
||||
|
||||
|
||||
func _on_Drawer_path_established(points: Array) -> void:
|
||||
var positions : PoolVector3Array = PoolVector3Array()
|
||||
for p in points:
|
||||
positions.append(Vector3(p.x, p.y, 0))
|
||||
|
||||
path.create_path(positions)
|
||||
_valid = true
|
79
steering_ai/Demos/GroupBehaviors/GroupBehaviorsDemo.gd
Normal file
79
steering_ai/Demos/GroupBehaviors/GroupBehaviorsDemo.gd
Normal file
@ -0,0 +1,79 @@
|
||||
extends Node
|
||||
|
||||
onready var spawner := $Spawner
|
||||
|
||||
export (float, 0, 2000, 40.0) var linear_speed_max := 600.0 setget set_linear_speed_max
|
||||
export (float, 0, 9000, 2.0) var linear_accel_max := 40.0 setget set_linear_accel_max
|
||||
export (float, 0, 300, 2.0) var proximity_radius := 140.0 setget set_proximity_radius
|
||||
export (float, 0, 200000, 250) var separation_decay_coefficient := 2000.0 setget set_separation_decay_coef
|
||||
export (float, 0, 2, 0.1) var cohesion_strength := 0.1 setget set_cohesion_strength
|
||||
export (float, 0, 10, 0.2) var separation_strength := 1.5 setget set_separation_strength
|
||||
export var show_proximity_radius := true setget set_show_proximity_radius
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
spawner.setup(
|
||||
linear_speed_max,
|
||||
linear_accel_max,
|
||||
proximity_radius,
|
||||
separation_decay_coefficient,
|
||||
cohesion_strength,
|
||||
separation_strength,
|
||||
show_proximity_radius
|
||||
)
|
||||
|
||||
|
||||
func set_linear_speed_max(value: float) -> void:
|
||||
linear_speed_max = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
spawner.set_linear_speed_max(value)
|
||||
|
||||
|
||||
func set_linear_accel_max(value: float) -> void:
|
||||
linear_accel_max = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
spawner.set_linear_accel_max(value)
|
||||
|
||||
|
||||
func set_proximity_radius(value: float) -> void:
|
||||
proximity_radius = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
spawner.set_proximity_radius(value)
|
||||
|
||||
|
||||
func set_show_proximity_radius(value: bool) -> void:
|
||||
show_proximity_radius = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
spawner.set_show_proximity_radius(value)
|
||||
|
||||
|
||||
func set_separation_decay_coef(value: float) -> void:
|
||||
separation_decay_coefficient = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
spawner.set_separation_decay_coef(value)
|
||||
|
||||
|
||||
func set_cohesion_strength(value: float) -> void:
|
||||
cohesion_strength = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
spawner.set_cohesion_strength(value)
|
||||
|
||||
|
||||
func set_separation_strength(value: float) -> void:
|
||||
separation_strength = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
spawner.set_separation_strength(value)
|
28
steering_ai/Demos/GroupBehaviors/GroupBehaviorsDemo.tscn
Normal file
28
steering_ai/Demos/GroupBehaviors/GroupBehaviorsDemo.tscn
Normal file
@ -0,0 +1,28 @@
|
||||
[gd_scene load_steps=6 format=3]
|
||||
|
||||
[ext_resource path="res://Demos/GroupBehaviors/Member.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://Demos/GroupBehaviors/Spawner.gd" type="Script" id=2]
|
||||
[ext_resource path="res://Demos/GroupBehaviors/GroupBehaviorsDemo.gd" type="Script" id=3]
|
||||
[ext_resource path="res://Demos/Utils/DemoInterface.tscn" type="PackedScene" id=4]
|
||||
[ext_resource path="res://Demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=5]
|
||||
|
||||
[node name="GroupBehaviorsDemo" type="Node"]
|
||||
script = ExtResource( 3 )
|
||||
linear_accel_max = 4234.0
|
||||
proximity_radius = 158.0
|
||||
separation_decay_coefficient = 121500.0
|
||||
cohesion_strength = 0.2
|
||||
separation_strength = 8.8
|
||||
|
||||
[node name="BackgroudLayer" parent="." instance=ExtResource( 5 )]
|
||||
|
||||
[node name="Spawner" type="Node2D" parent="."]
|
||||
position = Vector2( 973.261, 528.829 )
|
||||
script = ExtResource( 2 )
|
||||
member = ExtResource( 1 )
|
||||
|
||||
[node name="DemoInterface" parent="." instance=ExtResource( 4 )]
|
||||
mouse_filter = 2
|
||||
text_bbcode = "Group Behavior Demo
|
||||
Each of the \"Agents\" are both attempting to stay separated from each other but within reach of their nearest group's center of mass.
|
||||
Click on agent to see it's proximity."
|
69
steering_ai/Demos/GroupBehaviors/Member.gd
Normal file
69
steering_ai/Demos/GroupBehaviors/Member.gd
Normal file
@ -0,0 +1,69 @@
|
||||
extends KinematicBody2D
|
||||
|
||||
var separation: GSAISeparation
|
||||
var cohesion: GSAICohesion
|
||||
var proximity: GSAIRadiusProximity
|
||||
var agent :GSAIKinematicBody2DAgent = null
|
||||
var blend : GSAIBlend = null
|
||||
var acceleration : GSAITargetAcceleration = null
|
||||
var draw_proximity := false
|
||||
|
||||
var _color := Color.red
|
||||
var _velocity := Vector2()
|
||||
|
||||
onready var collision_shape := $CollisionShape2D
|
||||
|
||||
func _init() -> void:
|
||||
agent = GSAIKinematicBody2DAgent.new()
|
||||
agent.body = self
|
||||
|
||||
blend = GSAIBlend.new()
|
||||
blend.agent = agent
|
||||
|
||||
acceleration = GSAITargetAcceleration.new()
|
||||
|
||||
func setup(
|
||||
linear_speed_max: float,
|
||||
linear_accel_max: float,
|
||||
proximity_radius: float,
|
||||
separation_decay_coefficient: float,
|
||||
cohesion_strength: float,
|
||||
separation_strength: float
|
||||
) -> void:
|
||||
_color = Color(rand_range(0.5, 1), rand_range(0.25, 1), rand_range(0, 1))
|
||||
collision_shape.inner_color = _color
|
||||
|
||||
agent.linear_acceleration_max = linear_accel_max
|
||||
agent.linear_speed_max = linear_speed_max
|
||||
agent.linear_drag_percentage = 0.1
|
||||
|
||||
proximity = GSAIRadiusProximity.new()
|
||||
proximity.agent = agent
|
||||
proximity.radius = proximity_radius
|
||||
|
||||
separation = GSAISeparation.new()
|
||||
separation.agent = agent
|
||||
separation.proximity = proximity
|
||||
separation.decay_coefficient = separation_decay_coefficient
|
||||
|
||||
cohesion = GSAICohesion.new()
|
||||
cohesion.agent = agent
|
||||
cohesion.proximity = proximity
|
||||
|
||||
blend.add_behavior(separation, separation_strength)
|
||||
blend.add_behavior(cohesion, cohesion_strength)
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
if draw_proximity:
|
||||
draw_circle(Vector2.ZERO, proximity.radius, Color(0.4, 1.0, 0.89, 0.3))
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if blend:
|
||||
blend.calculate_steering(acceleration)
|
||||
agent.apply_steering(acceleration, delta)
|
||||
|
||||
|
||||
func set_neighbors(neighbor: Array) -> void:
|
||||
proximity.agents = neighbor
|
17
steering_ai/Demos/GroupBehaviors/Member.tscn
Normal file
17
steering_ai/Demos/GroupBehaviors/Member.tscn
Normal file
@ -0,0 +1,17 @@
|
||||
[gd_scene load_steps=4 format=3]
|
||||
|
||||
[ext_resource path="res://Demos/GroupBehaviors/Member.gd" type="Script" id=1]
|
||||
[ext_resource path="res://Demos/Utils/CircleDraw.gd" type="Script" id=3]
|
||||
|
||||
[sub_resource type="CircleShape2D" id=1]
|
||||
radius = 16.0
|
||||
|
||||
[node name="Member" type="KinematicBody2D"]
|
||||
input_pickable = true
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
shape = SubResource( 1 )
|
||||
script = ExtResource( 3 )
|
||||
outer_color = Color( 0.301961, 0.65098, 1, 1 )
|
||||
stroke = 4.0
|
92
steering_ai/Demos/GroupBehaviors/Spawner.gd
Normal file
92
steering_ai/Demos/GroupBehaviors/Spawner.gd
Normal file
@ -0,0 +1,92 @@
|
||||
extends Node2D
|
||||
|
||||
export var member: PackedScene
|
||||
|
||||
|
||||
func follower_input_event(
|
||||
viewport: Node,
|
||||
event: InputEvent,
|
||||
shape_idx: int,
|
||||
follower: KinematicBody2D
|
||||
) -> void:
|
||||
if event.is_action_pressed("click"):
|
||||
for other in get_children():
|
||||
if other.draw_proximity:
|
||||
other.draw_proximity = false
|
||||
other.update()
|
||||
follower.draw_proximity = true
|
||||
follower.update()
|
||||
move_child(follower, get_child_count())
|
||||
|
||||
|
||||
func setup(
|
||||
linear_speed_max: float,
|
||||
linear_accel_max: float,
|
||||
proximity_radius: float,
|
||||
separation_decay_coefficient: float,
|
||||
cohesion_strength: float,
|
||||
separation_strength: float,
|
||||
show_proximity_radius: bool
|
||||
) -> void:
|
||||
var followers := []
|
||||
for i in range(19):
|
||||
var follower : KinematicBody2D = member.instance()
|
||||
add_child(follower)
|
||||
follower.position += Vector2(rand_range(-60, 60), rand_range(-60, 60))
|
||||
followers.append(follower)
|
||||
follower.setup(
|
||||
linear_speed_max,
|
||||
linear_accel_max,
|
||||
proximity_radius,
|
||||
separation_decay_coefficient,
|
||||
cohesion_strength,
|
||||
separation_strength
|
||||
)
|
||||
|
||||
if i == 0 and show_proximity_radius:
|
||||
follower.draw_proximity = true
|
||||
follower.update()
|
||||
follower.connect("input_event", self, "follower_input_event", [follower])
|
||||
|
||||
var agents := []
|
||||
for i in followers:
|
||||
agents.append(i.agent)
|
||||
for i in followers:
|
||||
i.proximity.agents = agents
|
||||
|
||||
|
||||
func set_linear_speed_max(value: float) -> void:
|
||||
for child in get_children():
|
||||
child.agent.linear_speed_max = value
|
||||
|
||||
|
||||
func set_linear_accel_max(value: float) -> void:
|
||||
for child in get_children():
|
||||
child.agent.linear_acceleration_max = value
|
||||
|
||||
|
||||
func set_proximity_radius(value: float) -> void:
|
||||
for child in get_children():
|
||||
child.proximity.radius = value
|
||||
if child == get_child(0):
|
||||
child.update()
|
||||
|
||||
|
||||
func set_show_proximity_radius(value: bool) -> void:
|
||||
get_child(0).draw_proximity = value
|
||||
get_child(0).update()
|
||||
|
||||
|
||||
func set_separation_decay_coef(value: float) -> void:
|
||||
for child in get_children():
|
||||
child.separation.decay_coefficient = value
|
||||
|
||||
|
||||
func set_cohesion_strength(value: float) -> void:
|
||||
for child in get_children():
|
||||
child.blend.get_behavior(1).weight = value
|
||||
|
||||
|
||||
func set_separation_strength(value: float) -> void:
|
||||
for child in get_children():
|
||||
child.blend.get_behavior(0).weight = value
|
68
steering_ai/Demos/PopulateItemList.gd
Normal file
68
steering_ai/Demos/PopulateItemList.gd
Normal file
@ -0,0 +1,68 @@
|
||||
extends ItemList
|
||||
|
||||
signal demo_selected(scene_path)
|
||||
|
||||
var file_paths := PoolStringArray()
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
# warning-ignore:return_value_discarded
|
||||
self.connect("item_selected", self, "_on_item_selected")
|
||||
|
||||
var this_directory: String = get_tree().current_scene.filename.rsplit("/", false, 1)[0]
|
||||
file_paths = _find_files(this_directory, ["*Demo.tscn"], true)
|
||||
populate(file_paths)
|
||||
select(0)
|
||||
|
||||
|
||||
func populate(demos: PoolStringArray) -> void:
|
||||
for path in demos:
|
||||
var demo_name: String = path.rsplit("/", true, 1)[-1]
|
||||
demo_name = demo_name.rsplit("Demo", true, 1)[0]
|
||||
demo_name = sentencify(demo_name)
|
||||
add_item(demo_name)
|
||||
|
||||
|
||||
func sentencify(line: String) -> String:
|
||||
var regex := RegEx.new()
|
||||
# warning-ignore:return_value_discarded
|
||||
regex.compile("[A-Z]")
|
||||
|
||||
line = line.split(".", true, 1)[0]
|
||||
line = regex.sub(line, " $0", true)
|
||||
return line
|
||||
|
||||
|
||||
func _find_files(
|
||||
dirpath := "", patterns := PoolStringArray(), is_recursive := false, do_skip_hidden := true
|
||||
) -> PoolStringArray:
|
||||
var paths := PoolStringArray()
|
||||
var directory := Directory.new()
|
||||
|
||||
if not directory.dir_exists(dirpath):
|
||||
printerr("The directory does not exist: %s" % dirpath)
|
||||
return paths
|
||||
if not directory.open(dirpath) == OK:
|
||||
printerr("Could not open the following dirpath: %s" % dirpath)
|
||||
return paths
|
||||
|
||||
# warning-ignore:return_value_discarded
|
||||
directory.list_dir_begin(true, do_skip_hidden)
|
||||
var file_name := directory.get_next()
|
||||
while file_name != "":
|
||||
if directory.current_is_dir() and is_recursive:
|
||||
var subdirectory := dirpath.plus_file(file_name)
|
||||
paths.append_array(_find_files(subdirectory, patterns, is_recursive))
|
||||
else:
|
||||
for pattern in patterns:
|
||||
if file_name.match(pattern):
|
||||
paths.append(dirpath.plus_file(file_name))
|
||||
file_name = directory.get_next()
|
||||
|
||||
directory.list_dir_end()
|
||||
return paths
|
||||
|
||||
|
||||
func _on_item_selected(index: int) -> void:
|
||||
var demo_path := file_paths[index]
|
||||
emit_signal("demo_selected", demo_path)
|
15
steering_ai/Demos/PursueSeek/BoundaryManager.gd
Normal file
15
steering_ai/Demos/PursueSeek/BoundaryManager.gd
Normal file
@ -0,0 +1,15 @@
|
||||
extends Node2D
|
||||
# Wraps the ships' positions around the world border.
|
||||
|
||||
var _world_bounds: Vector2
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_world_bounds = Vector2(
|
||||
ProjectSettings["display/window/size/width"], ProjectSettings["display/window/size/height"]
|
||||
)
|
||||
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
for ship in get_children():
|
||||
ship.position = ship.position.posmodv(_world_bounds)
|
96
steering_ai/Demos/PursueSeek/Player.gd
Normal file
96
steering_ai/Demos/PursueSeek/Player.gd
Normal file
@ -0,0 +1,96 @@
|
||||
extends KinematicBody2D
|
||||
# Controls the player ship's movements based on player input.
|
||||
|
||||
export var thruster_strength := 175.0
|
||||
export var side_thruster_strength := 10.0
|
||||
export var velocity_max := 300.0
|
||||
export var angular_velocity_max := 2.0
|
||||
export var angular_drag := 0.025
|
||||
export var linear_drag := 0.025
|
||||
|
||||
var _linear_velocity := Vector2()
|
||||
var _angular_velocity := 0.0
|
||||
|
||||
onready var agent := GSAISteeringAgent.new()
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
var movement := _get_movement()
|
||||
_angular_velocity = _calculate_angular_velocity(
|
||||
movement.x,
|
||||
_angular_velocity,
|
||||
side_thruster_strength,
|
||||
angular_velocity_max,
|
||||
angular_drag,
|
||||
delta
|
||||
)
|
||||
rotation += _angular_velocity * delta
|
||||
|
||||
_linear_velocity = _calculate_linear_velocity(
|
||||
movement.y,
|
||||
_linear_velocity,
|
||||
Vector2.UP.rotated(rotation),
|
||||
linear_drag,
|
||||
thruster_strength,
|
||||
velocity_max,
|
||||
delta
|
||||
)
|
||||
|
||||
_linear_velocity = move_and_slide(_linear_velocity)
|
||||
_update_agent()
|
||||
|
||||
|
||||
func _calculate_angular_velocity(
|
||||
horizontal_movement: float,
|
||||
current_velocity: float,
|
||||
_thruster_strength: float,
|
||||
_velocity_max: float,
|
||||
ship_drag: float,
|
||||
delta: float
|
||||
) -> float:
|
||||
var velocity := clamp(
|
||||
current_velocity + _thruster_strength * horizontal_movement * delta,
|
||||
-_velocity_max,
|
||||
_velocity_max
|
||||
)
|
||||
|
||||
velocity = lerp(velocity, 0, ship_drag)
|
||||
|
||||
return velocity
|
||||
|
||||
|
||||
func _calculate_linear_velocity(
|
||||
vertical_movement: float,
|
||||
current_velocity: Vector2,
|
||||
facing_direction: Vector2,
|
||||
ship_drag_coefficient: float,
|
||||
strength: float,
|
||||
speed_max: float,
|
||||
delta: float
|
||||
) -> Vector2:
|
||||
var actual_strength := 0.0
|
||||
if vertical_movement > 0:
|
||||
actual_strength = strength
|
||||
elif vertical_movement < 0:
|
||||
actual_strength = -strength / 1.5
|
||||
|
||||
var velocity := current_velocity + facing_direction * actual_strength * delta
|
||||
velocity = velocity.linear_interpolate(Vector2.ZERO, ship_drag_coefficient)
|
||||
|
||||
return velocity.limit_length(speed_max)
|
||||
|
||||
|
||||
func _get_movement() -> Vector2:
|
||||
return Vector2(
|
||||
Input.get_action_strength("sf_right") - Input.get_action_strength("sf_left"),
|
||||
Input.get_action_strength("sf_up") - Input.get_action_strength("sf_down")
|
||||
)
|
||||
|
||||
|
||||
func _update_agent() -> void:
|
||||
agent.position.x = global_position.x
|
||||
agent.position.y = global_position.y
|
||||
agent.linear_velocity.x = _linear_velocity.x
|
||||
agent.linear_velocity.y = _linear_velocity.y
|
||||
agent.angular_velocity = _angular_velocity
|
||||
agent.orientation = rotation
|
39
steering_ai/Demos/PursueSeek/PursueAndSeekDemo.gd
Normal file
39
steering_ai/Demos/PursueSeek/PursueAndSeekDemo.gd
Normal file
@ -0,0 +1,39 @@
|
||||
extends Node
|
||||
|
||||
export (float, 0, 2000, 40) var linear_speed_max := 120.0 setget set_linear_speed_max
|
||||
export (float, 0, 2000, 20) var linear_accel_max := 10.0 setget set_linear_accel_max
|
||||
export (float, 0, 5, 0.1) var predict_time := 1.0 setget set_predict_time
|
||||
|
||||
onready var pursuer := $BoundaryManager/Pursuer
|
||||
onready var seeker := $BoundaryManager/Seeker
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
pursuer.setup(predict_time, linear_speed_max, linear_accel_max)
|
||||
seeker.setup(predict_time, linear_speed_max, linear_accel_max)
|
||||
|
||||
|
||||
func set_linear_speed_max(value: float) -> void:
|
||||
linear_speed_max = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
pursuer.agent.linear_speed_max = value
|
||||
seeker.agent.linear_speed_max = value
|
||||
|
||||
|
||||
func set_linear_accel_max(value: float) -> void:
|
||||
linear_accel_max = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
pursuer.agent.linear_acceleration_max = value
|
||||
seeker.agent.linear_acceleration_max = value
|
||||
|
||||
|
||||
func set_predict_time(value: float) -> void:
|
||||
predict_time = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
pursuer._behavior.predict_time_max = value
|
92
steering_ai/Demos/PursueSeek/PursueAndSeekDemo.tscn
Normal file
92
steering_ai/Demos/PursueSeek/PursueAndSeekDemo.tscn
Normal file
@ -0,0 +1,92 @@
|
||||
[gd_scene load_steps=8 format=3]
|
||||
|
||||
[ext_resource path="res://Demos/PursueSeek/Pursuer.gd" type="Script" id=1]
|
||||
[ext_resource path="res://Demos/PursueSeek/Player.gd" type="Script" id=2]
|
||||
[ext_resource path="res://Demos/PursueSeek/BoundaryManager.gd" type="Script" id=3]
|
||||
[ext_resource path="res://Demos/PursueSeek/PursueAndSeekDemo.gd" type="Script" id=4]
|
||||
[ext_resource path="res://Demos/Utils/DemoInterface.tscn" type="PackedScene" id=5]
|
||||
[ext_resource path="res://Demos/Utils/Line2DDraw.gd" type="Script" id=6]
|
||||
[ext_resource path="res://Demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=7]
|
||||
|
||||
[node name="PursueVSSeekDemo" type="Node"]
|
||||
script = ExtResource( 4 )
|
||||
linear_speed_max = 1280.0
|
||||
linear_accel_max = 1040.0
|
||||
predict_time = 1.1
|
||||
|
||||
[node name="BackgroudLayer" parent="." instance=ExtResource( 7 )]
|
||||
|
||||
[node name="BoundaryManager" type="Node2D" parent="."]
|
||||
script = ExtResource( 3 )
|
||||
|
||||
[node name="Player" type="KinematicBody2D" parent="BoundaryManager"]
|
||||
position = Vector2( 307.552, 555.999 )
|
||||
rotation = 1.5708
|
||||
collision_mask = 2
|
||||
script = ExtResource( 2 )
|
||||
__meta__ = {
|
||||
"_edit_group_": true
|
||||
}
|
||||
thruster_strength = 1000.0
|
||||
side_thruster_strength = 40.0
|
||||
velocity_max = 450.0
|
||||
angular_velocity_max = 3.0
|
||||
|
||||
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="BoundaryManager/Player"]
|
||||
polygon = PoolVector2Array( 0, -32, -24, 32, 24, 32 )
|
||||
|
||||
[node name="Line2D" type="Line2D" parent="BoundaryManager/Player"]
|
||||
points = PoolVector2Array( 0, 32, 24, 32, 0, -32, -24, 32, 0, 32 )
|
||||
width = 8.0
|
||||
default_color = Color( 0.560784, 0.870588, 0.364706, 1 )
|
||||
joint_mode = 2
|
||||
antialiased = true
|
||||
script = ExtResource( 6 )
|
||||
inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
|
||||
|
||||
[node name="Pursuer" type="KinematicBody2D" parent="BoundaryManager"]
|
||||
position = Vector2( 1240.22, 866.784 )
|
||||
collision_layer = 2
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_group_": true
|
||||
}
|
||||
|
||||
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="BoundaryManager/Pursuer"]
|
||||
polygon = PoolVector2Array( 0, -32, -24, 32, 24, 32 )
|
||||
|
||||
[node name="Line2D" type="Line2D" parent="BoundaryManager/Pursuer"]
|
||||
points = PoolVector2Array( 0, 32, 24, 32, 0, -32, -24, 32, 0, 32 )
|
||||
width = 8.0
|
||||
default_color = Color( 1, 0.709804, 0.439216, 1 )
|
||||
joint_mode = 2
|
||||
antialiased = true
|
||||
script = ExtResource( 6 )
|
||||
inner_color = Color( 0.890196, 0.411765, 0.337255, 1 )
|
||||
|
||||
[node name="Seeker" type="KinematicBody2D" parent="BoundaryManager"]
|
||||
position = Vector2( 1240.22, 280.108 )
|
||||
rotation = 3.14159
|
||||
collision_layer = 2
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_group_": true
|
||||
}
|
||||
use_seek = true
|
||||
|
||||
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="BoundaryManager/Seeker"]
|
||||
polygon = PoolVector2Array( 0, -32, -24, 32, 24, 32 )
|
||||
|
||||
[node name="Line2D" type="Line2D" parent="BoundaryManager/Seeker"]
|
||||
points = PoolVector2Array( 0, 32, 24, 32, 0, -32, -24, 32, 0, 32 )
|
||||
width = 8.0
|
||||
default_color = Color( 0.301961, 0.65098, 1, 1 )
|
||||
joint_mode = 2
|
||||
antialiased = true
|
||||
script = ExtResource( 6 )
|
||||
inner_color = Color( 0.294118, 0.356863, 0.670588, 1 )
|
||||
|
||||
[node name="DemoInterface" parent="." instance=ExtResource( 5 )]
|
||||
text_bbcode = "Pursue vs. Seek Demo
|
||||
Move the player around with WASD and notice the [color=#ffb570]orange Pursuer[/color] and the [color=aqua]blue Seeker[/color] follow
|
||||
the [color=lime]green \"Ship\"[/color] around"
|
80
steering_ai/Demos/PursueSeek/Pursuer.gd
Normal file
80
steering_ai/Demos/PursueSeek/Pursuer.gd
Normal file
@ -0,0 +1,80 @@
|
||||
extends KinematicBody2D
|
||||
# Represents a ship that chases after the player.
|
||||
|
||||
export var use_seek: bool = false
|
||||
|
||||
var _blend: GSAIBlend
|
||||
|
||||
var _linear_drag_coefficient := 0.025
|
||||
var _angular_drag := 0.1
|
||||
var _direction_face := GSAIAgentLocation.new()
|
||||
|
||||
var agent : GSAIKinematicBody2DAgent= null
|
||||
var accel : GSAITargetAcceleration = null
|
||||
var player_agent : GSAISteeringAgent = null
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
agent = GSAIKinematicBody2DAgent.new()
|
||||
agent.body = self
|
||||
|
||||
accel = GSAITargetAcceleration.new()
|
||||
player_agent = owner.find_node("Player", true, false).agent
|
||||
|
||||
agent.calculate_velocities = false
|
||||
set_physics_process(false)
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
_direction_face.position = agent.position + accel.linear.normalized()
|
||||
|
||||
_blend.calculate_steering(accel)
|
||||
|
||||
agent.angular_velocity = clamp(
|
||||
agent.angular_velocity + accel.angular * delta, -agent.angular_speed_max, agent.angular_speed_max
|
||||
)
|
||||
agent.angular_velocity = lerp(agent.angular_velocity, 0, _angular_drag)
|
||||
|
||||
rotation += agent.angular_velocity * delta
|
||||
|
||||
var linear_velocity := (
|
||||
GSAIUtils.to_vector2(agent.linear_velocity)
|
||||
+ (GSAIUtils.angle_to_vector2(rotation) * -agent.linear_acceleration_max * delta)
|
||||
)
|
||||
linear_velocity = linear_velocity.limit_length(agent.linear_speed_max)
|
||||
linear_velocity = linear_velocity.linear_interpolate(Vector2.ZERO, _linear_drag_coefficient)
|
||||
|
||||
linear_velocity = move_and_slide(linear_velocity)
|
||||
agent.linear_velocity = GSAIUtils.to_vector3(linear_velocity)
|
||||
|
||||
|
||||
func setup(predict_time: float, linear_speed_max: float, linear_accel_max: float) -> void:
|
||||
var behavior: GSAISteeringBehavior
|
||||
if use_seek:
|
||||
behavior = GSAISeek.new()
|
||||
behavior.agent = agent
|
||||
behavior.target = player_agent
|
||||
else:
|
||||
behavior = GSAIPursue.new()
|
||||
behavior.agent = agent
|
||||
behavior.target = player_agent
|
||||
behavior.predict_time_max = predict_time
|
||||
|
||||
var orient_behavior : GSAIFace = GSAIFace.new()
|
||||
orient_behavior.agent = agent
|
||||
orient_behavior.target = _direction_face
|
||||
|
||||
orient_behavior.alignment_tolerance = deg2rad(5)
|
||||
orient_behavior.deceleration_radius = deg2rad(30)
|
||||
|
||||
_blend = GSAIBlend.new()
|
||||
_blend.agent = agent
|
||||
_blend.add_behavior(behavior, 1)
|
||||
_blend.add_behavior(orient_behavior, 1)
|
||||
|
||||
agent.angular_acceleration_max = deg2rad(1080)
|
||||
agent.angular_speed_max = deg2rad(360)
|
||||
agent.linear_acceleration_max = linear_accel_max
|
||||
agent.linear_speed_max = linear_speed_max
|
||||
|
||||
set_physics_process(true)
|
195
steering_ai/Demos/Quickstart/Agent.gd
Normal file
195
steering_ai/Demos/Quickstart/Agent.gd
Normal file
@ -0,0 +1,195 @@
|
||||
extends KinematicBody2D
|
||||
|
||||
# Maximum possible linear velocity
|
||||
export var speed_max := 450.0
|
||||
# Maximum change in linear velocity
|
||||
export var acceleration_max := 50.0
|
||||
# Maximum rotation velocity represented in degrees
|
||||
export var angular_speed_max := 240
|
||||
# Maximum change in rotation velocity represented in degrees
|
||||
export var angular_acceleration_max := 40
|
||||
|
||||
export var health_max := 100
|
||||
export var flee_health_threshold := 20
|
||||
|
||||
var velocity := Vector2.ZERO
|
||||
var angular_velocity := 0.0
|
||||
var linear_drag := 0.1
|
||||
var angular_drag := 0.1
|
||||
|
||||
# Holds the linear and angular components calculated by our steering behaviors.
|
||||
var acceleration : GSAITargetAcceleration = null
|
||||
|
||||
onready var current_health := health_max
|
||||
|
||||
# GSAISteeringAgent holds our agent's position, orientation, maximum speed and acceleration.
|
||||
var agent : GSAISteeringAgent = null
|
||||
|
||||
var player: Node = null
|
||||
# This assumes that our player class will keep its own agent updated.
|
||||
var player_agent : GSAISteeringAgent = null
|
||||
|
||||
# Proximities represent an area with which an agent can identify where neighbors in its relevant
|
||||
# group are. In our case, the group will feature the player, which will be used to avoid a
|
||||
# collision with them. We use a radius proximity so the player is only relevant inside 100 pixels.
|
||||
var proximity : GSAIRadiusProximity = null
|
||||
|
||||
# GSAIBlend combines behaviors together, calculating all of their acceleration together and adding
|
||||
# them together, multiplied by a strength. We will have one for fleeing, and one for pursuing,
|
||||
# toggling them depending on the agent's health. Since we want the agent to rotate AND move, then
|
||||
# we aim to blend them together.
|
||||
var flee_blend : GSAIBlend = null
|
||||
var pursue_blend : GSAIBlend = null
|
||||
|
||||
# GSAIPriority will be the main steering behavior we use. It holds sub-behaviors and will pick the
|
||||
# first one that returns non-zero acceleration, ignoring any afterwards.
|
||||
var priority : GSAIPriority = null
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
acceleration = GSAITargetAcceleration.new()
|
||||
agent = GSAISteeringAgent.new()
|
||||
player = get_tree().get_nodes_in_group("Player")[0]
|
||||
player_agent = player.agent
|
||||
|
||||
proximity = GSAIRadiusProximity.new()
|
||||
proximity.agent = agent
|
||||
proximity.agents = [ player_agent ]
|
||||
proximity.radius = 100
|
||||
|
||||
flee_blend = GSAIBlend.new()
|
||||
flee_blend.agent = agent
|
||||
|
||||
pursue_blend = GSAIBlend.new()
|
||||
pursue_blend.agent = agent
|
||||
|
||||
priority = GSAIPriority.new()
|
||||
priority.agent = agent
|
||||
|
||||
# ---------- Configuration for our agent ----------
|
||||
agent.linear_speed_max = speed_max
|
||||
agent.linear_acceleration_max = acceleration_max
|
||||
agent.angular_speed_max = deg2rad(angular_speed_max)
|
||||
agent.angular_acceleration_max = deg2rad(angular_acceleration_max)
|
||||
agent.bounding_radius = calculate_radius($CollisionPolygon2D.polygon)
|
||||
update_agent()
|
||||
|
||||
# ---------- Configuration for our behaviors ----------
|
||||
# Pursue will happen while the agent is in good health. It produces acceleration that takes
|
||||
# the agent on an intercept course with the target, predicting its position in the future.
|
||||
var pursue : GSAIPursue = GSAIPursue.new()
|
||||
pursue.agent = agent
|
||||
pursue.target = player_agent
|
||||
pursue.predict_time_max = 1.5
|
||||
|
||||
# Flee will happen while the agent is in bad health, so will start disabled. It produces
|
||||
# acceleration that takes the agent directly away from the target with no prediction.
|
||||
var flee : GSAIFlee = GSAIFlee.new()
|
||||
flee.agent = agent
|
||||
flee.target = player_agent
|
||||
|
||||
# AvoidCollision tries to keep the agent from running into any of the neighbors found in its
|
||||
# proximity group. In our case, this will be the player, if they are close enough.
|
||||
var avoid : GSAIAvoidCollisions = GSAIAvoidCollisions.new()
|
||||
avoid.agent = agent
|
||||
avoid.proximity = proximity
|
||||
|
||||
# Face turns the agent to keep looking towards its target. It will be enabled while the agent
|
||||
# is not fleeing due to low health. It tries to arrive 'on alignment' with 0 remaining velocity.
|
||||
var face : GSAIFace = GSAIFace.new()
|
||||
face.agent = agent
|
||||
face.target = player_agent
|
||||
|
||||
# We use deg2rad because the math in the toolkit assumes radians.
|
||||
# How close for the agent to be 'aligned', if not exact.
|
||||
face.alignment_tolerance = deg2rad(5)
|
||||
# When to start slowing down
|
||||
face.deceleration_radius = deg2rad(60)
|
||||
|
||||
# LookWhereYouGo turns the agent to keep looking towards its direction of travel. It will only
|
||||
# be enabled while the agent is at low health.
|
||||
var look : GSAILookWhereYouGo = GSAILookWhereYouGo.new()
|
||||
look.agent = agent
|
||||
# How close for the agent to be 'aligned', if not exact
|
||||
look.alignment_tolerance = deg2rad(5)
|
||||
# When to start slowing down.
|
||||
look.deceleration_radius = deg2rad(60)
|
||||
|
||||
# Behaviors that are not enabled produce 0 acceleration.
|
||||
# Adding our fleeing behaviors to a blend. The order does not matter.
|
||||
flee_blend.is_enabled = false
|
||||
flee_blend.add_behavior(look, 1)
|
||||
flee_blend.add_behavior(flee, 1)
|
||||
|
||||
# Adding our pursuit behaviors to a blend. The order does not matter.
|
||||
pursue_blend.add_behavior(face, 1)
|
||||
pursue_blend.add_behavior(pursue, 1)
|
||||
|
||||
# Adding our final behaviors to the main priority behavior. The order does matter here.
|
||||
# We want to avoid collision with the player first, flee from the player second when enabled,
|
||||
# and pursue the player last when enabled.
|
||||
priority.add_behavior(avoid)
|
||||
priority.add_behavior(flee_blend)
|
||||
priority.add_behavior(pursue_blend)
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
# Make sure any change in position and speed has been recorded.
|
||||
update_agent()
|
||||
|
||||
if current_health <= flee_health_threshold:
|
||||
pursue_blend.is_enabled = false
|
||||
flee_blend.is_enabled = true
|
||||
|
||||
# Calculate the desired acceleration.
|
||||
priority.calculate_steering(acceleration)
|
||||
|
||||
# We add the discovered acceleration to our linear velocity. The toolkit does not limit
|
||||
# velocity, just acceleration, so we clamp the result ourselves here.
|
||||
velocity = (velocity + Vector2(acceleration.linear.x, acceleration.linear.y) * delta).limit_length(
|
||||
agent.linear_speed_max
|
||||
)
|
||||
|
||||
# This applies drag on the agent's motion, helping it to slow down naturally.
|
||||
velocity = velocity.linear_interpolate(Vector2.ZERO, linear_drag)
|
||||
|
||||
# And since we're using a KinematicBody2D, we use Godot's excellent move_and_slide to actually
|
||||
# apply the final movement, and record any change in velocity the physics engine discovered.
|
||||
velocity = move_and_slide(velocity)
|
||||
|
||||
# We then do something similar to apply our agent's rotational speed.
|
||||
angular_velocity = clamp(
|
||||
angular_velocity + acceleration.angular * delta, -agent.angular_speed_max, agent.angular_speed_max
|
||||
)
|
||||
# This applies drag on the agent's rotation, helping it slow down naturally.
|
||||
angular_velocity = lerp(angular_velocity, 0, angular_drag)
|
||||
rotation += angular_velocity * delta
|
||||
|
||||
|
||||
# In order to support both 2D and 3D, the toolkit uses Vector3, so the conversion is required
|
||||
# when using 2D nodes. The Z component can be left to 0 safely.
|
||||
func update_agent() -> void:
|
||||
agent.position.x = global_position.x
|
||||
agent.position.y = global_position.y
|
||||
agent.orientation = rotation
|
||||
agent.linear_velocity.x = velocity.x
|
||||
agent.linear_velocity.y = velocity.y
|
||||
agent.angular_velocity = angular_velocity
|
||||
|
||||
|
||||
# We calculate the radius from the collision shape - this will approximate the agent's size in the
|
||||
# game world, to avoid collisions with the player.
|
||||
func calculate_radius(polygon: PoolVector2Array) -> float:
|
||||
var furthest_point := Vector2(-INF, -INF)
|
||||
for p in polygon:
|
||||
if abs(p.x) > furthest_point.x:
|
||||
furthest_point.x = p.x
|
||||
if abs(p.y) > furthest_point.y:
|
||||
furthest_point.y = p.y
|
||||
return furthest_point.length()
|
||||
|
||||
|
||||
func damage(amount: int) -> void:
|
||||
current_health -= amount
|
||||
if current_health <= 0:
|
||||
queue_free()
|
33
steering_ai/Demos/Quickstart/Bullet.gd
Normal file
33
steering_ai/Demos/Quickstart/Bullet.gd
Normal file
@ -0,0 +1,33 @@
|
||||
extends KinematicBody2D
|
||||
|
||||
export var speed := 1500.0
|
||||
|
||||
var velocity := Vector2.ZERO
|
||||
var player: Node
|
||||
|
||||
onready var timer := $Lifetime
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
timer.connect("timeout", self, "_on_Lifetime_timeout")
|
||||
timer.start()
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
var collision := move_and_collide(velocity * delta)
|
||||
if collision:
|
||||
timer.stop()
|
||||
clear()
|
||||
collision.collider.damage(10)
|
||||
|
||||
|
||||
func start(direction: Vector2) -> void:
|
||||
velocity = direction * speed
|
||||
|
||||
|
||||
func clear() -> void:
|
||||
queue_free()
|
||||
|
||||
|
||||
func _on_Lifetime_timeout() -> void:
|
||||
clear()
|
23
steering_ai/Demos/Quickstart/Bullet.tscn
Normal file
23
steering_ai/Demos/Quickstart/Bullet.tscn
Normal file
@ -0,0 +1,23 @@
|
||||
[gd_scene load_steps=4 format=3]
|
||||
|
||||
[ext_resource path="res://Demos/Utils/CircleDraw.gd" type="Script" id=1]
|
||||
[ext_resource path="res://Demos/Quickstart/Bullet.gd" type="Script" id=2]
|
||||
|
||||
[sub_resource type="CircleShape2D" id=1]
|
||||
radius = 4.0
|
||||
|
||||
[node name="Bullet" type="KinematicBody2D"]
|
||||
collision_layer = 4
|
||||
collision_mask = 2
|
||||
script = ExtResource( 2 )
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
shape = SubResource( 1 )
|
||||
script = ExtResource( 1 )
|
||||
inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
|
||||
outer_color = Color( 0.560784, 0.870588, 0.364706, 1 )
|
||||
stroke = 2.0
|
||||
|
||||
[node name="Lifetime" type="Timer" parent="."]
|
||||
process_mode = 0
|
||||
wait_time = 3.0
|
99
steering_ai/Demos/Quickstart/Player.gd
Normal file
99
steering_ai/Demos/Quickstart/Player.gd
Normal file
@ -0,0 +1,99 @@
|
||||
extends KinematicBody2D
|
||||
|
||||
export var speed_max := 650.0
|
||||
export var acceleration_max := 70.0
|
||||
export var rotation_speed_max := 240
|
||||
export var rotation_accel_max := 40
|
||||
export var bullet: PackedScene
|
||||
|
||||
var velocity := Vector2.ZERO
|
||||
var angular_velocity := 0.0
|
||||
var direction := Vector2.RIGHT
|
||||
|
||||
var agent : GSAISteeringAgent = null
|
||||
var proxy_target : GSAIAgentLocation = null
|
||||
var face : GSAIFace = null
|
||||
|
||||
onready var accel := GSAITargetAcceleration.new()
|
||||
onready var bullets := owner.get_node("Bullets")
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
agent = GSAISteeringAgent.new()
|
||||
proxy_target = GSAIAgentLocation.new()
|
||||
face = GSAIFace.new()
|
||||
face.agent = agent
|
||||
face.target = proxy_target
|
||||
|
||||
agent.linear_speed_max = speed_max
|
||||
agent.linear_acceleration_max = acceleration_max
|
||||
agent.angular_speed_max = deg2rad(rotation_speed_max)
|
||||
agent.angular_acceleration_max = deg2rad(rotation_accel_max)
|
||||
agent.bounding_radius = calculate_radius($CollisionPolygon2D.polygon)
|
||||
update_agent()
|
||||
|
||||
var mouse_pos := get_global_mouse_position()
|
||||
proxy_target.position.x = mouse_pos.x
|
||||
proxy_target.position.y = mouse_pos.y
|
||||
|
||||
face.alignment_tolerance = deg2rad(5)
|
||||
face.deceleration_radius = deg2rad(45)
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
update_agent()
|
||||
|
||||
var movement := get_movement()
|
||||
|
||||
direction = GSAIUtils.angle_to_vector2(rotation)
|
||||
|
||||
velocity += direction * acceleration_max * movement * delta
|
||||
velocity = velocity.limit_length(speed_max)
|
||||
velocity = velocity.linear_interpolate(Vector2.ZERO, 0.1)
|
||||
velocity = move_and_slide(velocity)
|
||||
|
||||
face.calculate_steering(accel)
|
||||
angular_velocity += accel.angular * delta
|
||||
angular_velocity = clamp(angular_velocity, -agent.angular_speed_max, agent.angular_speed_max)
|
||||
angular_velocity = lerp(angular_velocity, 0, 0.1)
|
||||
rotation += angular_velocity * delta
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseMotion:
|
||||
var mouse_pos: Vector2 = event.position
|
||||
proxy_target.position.x = mouse_pos.x
|
||||
proxy_target.position.y = mouse_pos.y
|
||||
elif event is InputEventMouseButton:
|
||||
if event.button_index == BUTTON_LEFT and event.pressed:
|
||||
var next_bullet := bullet.instance()
|
||||
next_bullet.global_position = (
|
||||
global_position
|
||||
- direction * (agent.bounding_radius - 5)
|
||||
)
|
||||
next_bullet.player = self
|
||||
next_bullet.start(-direction)
|
||||
bullets.add_child(next_bullet)
|
||||
|
||||
|
||||
func get_movement() -> float:
|
||||
return Input.get_action_strength("sf_down") - Input.get_action_strength("sf_up")
|
||||
|
||||
|
||||
func update_agent() -> void:
|
||||
agent.position.x = global_position.x
|
||||
agent.position.y = global_position.y
|
||||
agent.orientation = rotation
|
||||
agent.linear_velocity.x = velocity.x
|
||||
agent.linear_velocity.y = velocity.y
|
||||
agent.angular_velocity = angular_velocity
|
||||
|
||||
|
||||
func calculate_radius(polygon: PoolVector2Array) -> float:
|
||||
var furthest_point := Vector2(-INF, -INF)
|
||||
for p in polygon:
|
||||
if abs(p.x) > furthest_point.x:
|
||||
furthest_point.x = p.x
|
||||
if abs(p.y) > furthest_point.y:
|
||||
furthest_point.y = p.y
|
||||
return furthest_point.length()
|
59
steering_ai/Demos/Quickstart/QuickStartDemo.tscn
Normal file
59
steering_ai/Demos/Quickstart/QuickStartDemo.tscn
Normal file
@ -0,0 +1,59 @@
|
||||
[gd_scene load_steps=6 format=3]
|
||||
|
||||
[ext_resource path="res://Demos/Utils/Line2DDraw.gd" type="Script" id=1]
|
||||
[ext_resource path="res://Demos/Quickstart/Agent.gd" type="Script" id=2]
|
||||
[ext_resource path="res://Demos/Quickstart/Player.gd" type="Script" id=3]
|
||||
[ext_resource path="res://Demos/Quickstart/Bullet.tscn" type="PackedScene" id=4]
|
||||
[ext_resource path="res://Demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=5]
|
||||
|
||||
[node name="QuickStartDemo" type="Node"]
|
||||
|
||||
[node name="BackgroudLayer" parent="." instance=ExtResource( 5 )]
|
||||
|
||||
[node name="Player" type="KinematicBody2D" parent="." groups=["Player"]]
|
||||
position = Vector2( 402.346, 573.791 )
|
||||
rotation = 1.5708
|
||||
collision_mask = 2
|
||||
script = ExtResource( 3 )
|
||||
speed_max = 900.0
|
||||
acceleration_max = 4200.0
|
||||
rotation_speed_max = 360
|
||||
rotation_accel_max = 1280
|
||||
bullet = ExtResource( 4 )
|
||||
|
||||
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Player"]
|
||||
polygon = PoolVector2Array( 0, -32, -24, 32, 24, 32 )
|
||||
|
||||
[node name="Line2D" type="Line2D" parent="Player"]
|
||||
points = PoolVector2Array( 0, 32, 24, 32, 0, -32, -24, 32, 0, 32 )
|
||||
width = 8.0
|
||||
default_color = Color( 0.560784, 0.870588, 0.364706, 1 )
|
||||
joint_mode = 2
|
||||
antialiased = true
|
||||
script = ExtResource( 1 )
|
||||
inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
|
||||
|
||||
[node name="Agent" type="KinematicBody2D" parent="."]
|
||||
position = Vector2( 974.675, 266.224 )
|
||||
rotation = 1.5708
|
||||
collision_layer = 2
|
||||
collision_mask = 5
|
||||
script = ExtResource( 2 )
|
||||
speed_max = 600.0
|
||||
acceleration_max = 2800.0
|
||||
angular_speed_max = 360
|
||||
angular_acceleration_max = 1280
|
||||
|
||||
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Agent"]
|
||||
polygon = PoolVector2Array( 0, -32, -24, 32, 24, 32 )
|
||||
|
||||
[node name="Line2D" type="Line2D" parent="Agent"]
|
||||
points = PoolVector2Array( 0, 32, 24, 32, 0, -32, -24, 32, 0, 32 )
|
||||
width = 8.0
|
||||
default_color = Color( 1, 0.709804, 0.439216, 1 )
|
||||
joint_mode = 2
|
||||
antialiased = true
|
||||
script = ExtResource( 1 )
|
||||
inner_color = Color( 0.890196, 0.411765, 0.337255, 1 )
|
||||
|
||||
[node name="Bullets" type="Node2D" parent="."]
|
32
steering_ai/Demos/SeekFlee/Boundaries.gd
Normal file
32
steering_ai/Demos/SeekFlee/Boundaries.gd
Normal file
@ -0,0 +1,32 @@
|
||||
extends Node2D
|
||||
|
||||
const COLOR := Color("8fde5d")
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
get_tree().root.connect("size_changed", self, "_on_SceneTree_size_changed")
|
||||
_on_SceneTree_size_changed()
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
for b in get_children():
|
||||
var extents: Vector2 = b.get_node("CollisionShape2D").shape.extents
|
||||
draw_rect(Rect2(b.global_position - extents, extents * 2), COLOR)
|
||||
|
||||
|
||||
func _on_SceneTree_size_changed() -> void:
|
||||
var size := Vector2(
|
||||
ProjectSettings["display/window/size/width"], ProjectSettings["display/window/size/height"]
|
||||
)
|
||||
for b in get_children():
|
||||
var boundary: String = str(b.name).rsplit("Boundary")[0]
|
||||
match boundary:
|
||||
"Left":
|
||||
b.global_position = Vector2(0, size.y / 2)
|
||||
"Right":
|
||||
b.global_position = Vector2(size.x, size.y / 2)
|
||||
"Top":
|
||||
b.global_position = Vector2(size.x / 2, 0)
|
||||
"Bottom":
|
||||
b.global_position = Vector2(size.x / 2, size.y)
|
||||
update()
|
26
steering_ai/Demos/SeekFlee/Player.gd
Normal file
26
steering_ai/Demos/SeekFlee/Player.gd
Normal file
@ -0,0 +1,26 @@
|
||||
extends KinematicBody2D
|
||||
# Class to control the player in basic left/right up/down movement.
|
||||
|
||||
var speed: float
|
||||
onready var agent := GSAIAgentLocation.new()
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
agent.position = GSAIUtils.to_vector3(global_position)
|
||||
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
var movement := _get_movement()
|
||||
if movement.length_squared() < 0.01:
|
||||
return
|
||||
|
||||
# warning-ignore:return_value_discarded
|
||||
move_and_slide(movement * speed)
|
||||
agent.position = GSAIUtils.to_vector3(global_position)
|
||||
|
||||
|
||||
func _get_movement() -> Vector2:
|
||||
return Vector2(
|
||||
Input.get_action_strength("sf_right") - Input.get_action_strength("sf_left"),
|
||||
Input.get_action_strength("sf_down") - Input.get_action_strength("sf_up")
|
||||
)
|
82
steering_ai/Demos/SeekFlee/SeekFleeDemo.gd
Normal file
82
steering_ai/Demos/SeekFlee/SeekFleeDemo.gd
Normal file
@ -0,0 +1,82 @@
|
||||
extends Node
|
||||
# Access helper class for children to access window boundaries.
|
||||
|
||||
enum Mode { FLEE, SEEK }
|
||||
|
||||
export (Mode) var behavior_mode := Mode.SEEK setget set_behavior_mode
|
||||
export (float, 0, 1000, 30) var linear_speed_max := 200.0 setget set_linear_speed_max
|
||||
export (float, 0, 2000, 40) var linear_accel_max := 10.0 setget set_linear_accel_max
|
||||
export (float) var player_speed := 600.0 setget set_player_speed
|
||||
|
||||
var camera_boundaries: Rect2
|
||||
|
||||
onready var player: KinematicBody2D = $Player
|
||||
onready var spawner: Node2D = $Spawner
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
camera_boundaries = Rect2(
|
||||
Vector2.ZERO,
|
||||
Vector2(
|
||||
ProjectSettings["display/window/size/width"],
|
||||
ProjectSettings["display/window/size/height"]
|
||||
)
|
||||
)
|
||||
|
||||
var rng := RandomNumberGenerator.new()
|
||||
rng.randomize()
|
||||
|
||||
player.speed = player_speed
|
||||
|
||||
for i in range(spawner.entity_count):
|
||||
var new_pos := Vector2(
|
||||
rng.randf_range(0, camera_boundaries.size.x),
|
||||
rng.randf_range(0, camera_boundaries.size.y)
|
||||
)
|
||||
var entity: KinematicBody2D = spawner.entity.instance()
|
||||
entity.global_position = new_pos
|
||||
entity.player_agent = player.agent
|
||||
entity.start_speed = linear_speed_max
|
||||
entity.start_accel = linear_accel_max
|
||||
entity.use_seek = behavior_mode == Mode.SEEK
|
||||
spawner.add_child(entity)
|
||||
|
||||
|
||||
func set_behavior_mode(mode: int) -> void:
|
||||
behavior_mode = mode
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
match mode:
|
||||
Mode.SEEK:
|
||||
for child in spawner.get_children():
|
||||
child.use_seek = true
|
||||
Mode.FLEE:
|
||||
for child in spawner.get_children():
|
||||
child.use_seek = false
|
||||
|
||||
|
||||
func set_linear_speed_max(value: float) -> void:
|
||||
linear_speed_max = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
for child in spawner.get_children():
|
||||
child.agent.linear_speed_max = value
|
||||
|
||||
|
||||
func set_linear_accel_max(value: float) -> void:
|
||||
linear_accel_max = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
for child in spawner.get_children():
|
||||
child.agent.linear_acceleration_max = value
|
||||
|
||||
|
||||
func set_player_speed(value: float) -> void:
|
||||
player_speed = value
|
||||
if not is_inside_tree():
|
||||
return
|
||||
|
||||
player.speed = player_speed
|
81
steering_ai/Demos/SeekFlee/SeekFleeDemo.tscn
Normal file
81
steering_ai/Demos/SeekFlee/SeekFleeDemo.tscn
Normal file
@ -0,0 +1,81 @@
|
||||
[gd_scene load_steps=12 format=3]
|
||||
|
||||
[ext_resource path="res://Demos/SeekFlee/Player.gd" type="Script" id=2]
|
||||
[ext_resource path="res://Demos/SeekFlee/SeekFleeDemo.gd" type="Script" id=3]
|
||||
[ext_resource path="res://Demos/SeekFlee/Spawner.gd" type="Script" id=4]
|
||||
[ext_resource path="res://Demos/Utils/DemoInterface.tscn" type="PackedScene" id=5]
|
||||
[ext_resource path="res://Demos/SeekFlee/Seeker.tscn" type="PackedScene" id=6]
|
||||
[ext_resource path="res://Demos/Utils/CircleDraw.gd" type="Script" id=7]
|
||||
[ext_resource path="res://Demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=8]
|
||||
[ext_resource path="res://Demos/SeekFlee/Boundaries.gd" type="Script" id=9]
|
||||
|
||||
[sub_resource type="CircleShape2D" id=1]
|
||||
radius = 32.0
|
||||
|
||||
[sub_resource type="RectangleShape2D" id=2]
|
||||
extents = Vector2( 10, 542 )
|
||||
|
||||
[sub_resource type="RectangleShape2D" id=3]
|
||||
extents = Vector2( 965.654, 10 )
|
||||
|
||||
[node name="SeekFleeDemo" type="Node"]
|
||||
script = ExtResource( 3 )
|
||||
linear_speed_max = 570.0
|
||||
linear_accel_max = 1160.0
|
||||
|
||||
[node name="BackgroudLayer" parent="." instance=ExtResource( 8 )]
|
||||
|
||||
[node name="Player" type="KinematicBody2D" parent="."]
|
||||
position = Vector2( 960, 540 )
|
||||
collision_mask = 2
|
||||
script = ExtResource( 2 )
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="Player"]
|
||||
shape = SubResource( 1 )
|
||||
script = ExtResource( 7 )
|
||||
inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
|
||||
outer_color = Color( 0.560784, 0.870588, 0.364706, 1 )
|
||||
stroke = 4.0
|
||||
|
||||
[node name="Boundaries" type="Node2D" parent="."]
|
||||
script = ExtResource( 9 )
|
||||
|
||||
[node name="LeftBoundary" type="StaticBody2D" parent="Boundaries"]
|
||||
position = Vector2( 0, 540 )
|
||||
collision_layer = 2
|
||||
collision_mask = 5
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="Boundaries/LeftBoundary"]
|
||||
shape = SubResource( 2 )
|
||||
|
||||
[node name="RightBoundary" type="StaticBody2D" parent="Boundaries"]
|
||||
position = Vector2( 1920, 540 )
|
||||
collision_layer = 2
|
||||
collision_mask = 5
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="Boundaries/RightBoundary"]
|
||||
shape = SubResource( 2 )
|
||||
|
||||
[node name="TopBoundary" type="StaticBody2D" parent="Boundaries"]
|
||||
position = Vector2( 960, 0 )
|
||||
collision_layer = 2
|
||||
collision_mask = 5
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="Boundaries/TopBoundary"]
|
||||
shape = SubResource( 3 )
|
||||
|
||||
[node name="BottomBoundary" type="StaticBody2D" parent="Boundaries"]
|
||||
position = Vector2( 960, 1080 )
|
||||
collision_layer = 2
|
||||
collision_mask = 5
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="Boundaries/BottomBoundary"]
|
||||
shape = SubResource( 3 )
|
||||
|
||||
[node name="Spawner" type="Node2D" parent="."]
|
||||
script = ExtResource( 4 )
|
||||
entity = ExtResource( 6 )
|
||||
|
||||
[node name="DemoInterface" parent="." instance=ExtResource( 5 )]
|
||||
text_bbcode = "Seek & Flee Demo
|
||||
Move the [color=lime]green \"Player\"[/color] around with WASD and notice the [color=#ffb570]orange \"Enemies\"[/color] try to seek to or flee from the player."
|
42
steering_ai/Demos/SeekFlee/Seeker.gd
Normal file
42
steering_ai/Demos/SeekFlee/Seeker.gd
Normal file
@ -0,0 +1,42 @@
|
||||
extends KinematicBody2D
|
||||
|
||||
var player_agent: GSAIAgentLocation
|
||||
var velocity := Vector2.ZERO
|
||||
var start_speed: float
|
||||
var start_accel: float
|
||||
var use_seek := true
|
||||
|
||||
var agent : GSAIKinematicBody2DAgent = null
|
||||
var accel : GSAITargetAcceleration = null
|
||||
var seek : GSAISeek = null
|
||||
var flee : GSAIFlee = null
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
agent = GSAIKinematicBody2DAgent.new()
|
||||
agent.body = self
|
||||
|
||||
accel = GSAITargetAcceleration.new()
|
||||
|
||||
seek = GSAISeek.new()
|
||||
seek.agent = agent
|
||||
seek.target = player_agent
|
||||
|
||||
flee = GSAIFlee.new()
|
||||
flee.agent = agent
|
||||
flee.target = player_agent
|
||||
|
||||
agent.linear_acceleration_max = start_accel
|
||||
agent.linear_speed_max = start_speed
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if not player_agent:
|
||||
return
|
||||
|
||||
if use_seek:
|
||||
seek.calculate_steering(accel)
|
||||
else:
|
||||
flee.calculate_steering(accel)
|
||||
|
||||
agent.apply_steering(accel, delta)
|
19
steering_ai/Demos/SeekFlee/Seeker.tscn
Normal file
19
steering_ai/Demos/SeekFlee/Seeker.tscn
Normal file
@ -0,0 +1,19 @@
|
||||
[gd_scene load_steps=4 format=3]
|
||||
|
||||
[ext_resource path="res://Demos/SeekFlee/Seeker.gd" type="Script" id=1]
|
||||
[ext_resource path="res://Demos/Utils/CircleDraw.gd" type="Script" id=2]
|
||||
|
||||
[sub_resource type="CircleShape2D" id=1]
|
||||
radius = 16.0
|
||||
|
||||
[node name="Seeker" type="KinematicBody2D"]
|
||||
collision_layer = 4
|
||||
collision_mask = 2
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
shape = SubResource( 1 )
|
||||
script = ExtResource( 2 )
|
||||
inner_color = Color( 0.890196, 0.411765, 0.337255, 1 )
|
||||
outer_color = Color( 1, 0.709804, 0.439216, 1 )
|
||||
stroke = 4.0
|
6
steering_ai/Demos/SeekFlee/Spawner.gd
Normal file
6
steering_ai/Demos/SeekFlee/Spawner.gd
Normal file
@ -0,0 +1,6 @@
|
||||
extends Node2D
|
||||
# Holds data to instantiate and configure a number of agent entities.
|
||||
|
||||
export (PackedScene) var entity: PackedScene
|
||||
export var entity_count := 10
|
||||
export var entity_color := Color.blue
|
17
steering_ai/Demos/Utils/BackgroudLayer.tscn
Normal file
17
steering_ai/Demos/Utils/BackgroudLayer.tscn
Normal file
@ -0,0 +1,17 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource path="res://assets/sprites/background.png" type="Texture" id=1]
|
||||
|
||||
[node name="BackgroudLayer" type="CanvasLayer"]
|
||||
layer = -1
|
||||
|
||||
[node name="Background" type="TextureRect" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
mouse_filter = 2
|
||||
texture = ExtResource( 1 )
|
||||
expand = true
|
||||
stretch_mode = 7
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
26
steering_ai/Demos/Utils/CircleDraw.gd
Normal file
26
steering_ai/Demos/Utils/CircleDraw.gd
Normal file
@ -0,0 +1,26 @@
|
||||
tool
|
||||
extends CollisionShape2D
|
||||
|
||||
export (Color) var inner_color := Color() setget set_inner_color
|
||||
export (Color) var outer_color := Color() setget set_outer_color
|
||||
export (float) var stroke := 0.0 setget set_stroke
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
draw_circle(Vector2.ZERO, shape.radius + stroke, outer_color)
|
||||
draw_circle(Vector2.ZERO, shape.radius, inner_color)
|
||||
|
||||
|
||||
func set_inner_color(val: Color) -> void:
|
||||
inner_color = val
|
||||
update()
|
||||
|
||||
|
||||
func set_outer_color(val: Color) -> void:
|
||||
outer_color = val
|
||||
update()
|
||||
|
||||
|
||||
func set_stroke(val: float) -> void:
|
||||
stroke = val
|
||||
update()
|
13
steering_ai/Demos/Utils/DemoInterface.gd
Normal file
13
steering_ai/Demos/Utils/DemoInterface.gd
Normal file
@ -0,0 +1,13 @@
|
||||
tool
|
||||
extends PanelContainer
|
||||
|
||||
export (String, MULTILINE) var text_bbcode := "" setget set_text_bbcode
|
||||
|
||||
onready var rich_text_label: RichTextLabel = $MarginContainer/RichTextLabel
|
||||
|
||||
|
||||
func set_text_bbcode(value: String) -> void:
|
||||
text_bbcode = value
|
||||
if not rich_text_label:
|
||||
yield(self, "ready")
|
||||
rich_text_label.bbcode_text = text_bbcode
|
37
steering_ai/Demos/Utils/DemoInterface.tscn
Normal file
37
steering_ai/Demos/Utils/DemoInterface.tscn
Normal file
@ -0,0 +1,37 @@
|
||||
[gd_scene load_steps=4 format=3]
|
||||
|
||||
[ext_resource path="res://assets/theme/gdquest.theme" type="Theme" id=1]
|
||||
[ext_resource path="res://Demos/Utils/DemoInterface.gd" type="Script" id=2]
|
||||
|
||||
[sub_resource type="GDScript" id=1]
|
||||
script/source = "tool
|
||||
extends RichTextLabel
|
||||
|
||||
"
|
||||
|
||||
[node name="DemoInterface" type="PanelContainer"]
|
||||
anchor_right = 1.0
|
||||
margin_bottom = 140.0
|
||||
rect_min_size = Vector2( 1024, 0 )
|
||||
theme = ExtResource( 1 )
|
||||
script = ExtResource( 2 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
text_bbcode = "Replace this text for the demo."
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||
margin_right = 1920.0
|
||||
margin_bottom = 140.0
|
||||
|
||||
[node name="RichTextLabel" type="RichTextLabel" parent="MarginContainer"]
|
||||
margin_left = 16.0
|
||||
margin_top = 16.0
|
||||
margin_right = 1904.0
|
||||
margin_bottom = 124.0
|
||||
rect_min_size = Vector2( 0, 55 )
|
||||
bbcode_enabled = true
|
||||
bbcode_text = "Replace this text for the demo."
|
||||
text = "Replace this text for the demo."
|
||||
scroll_active = false
|
||||
script = SubResource( 1 )
|
13
steering_ai/Demos/Utils/Line2DDraw.gd
Normal file
13
steering_ai/Demos/Utils/Line2DDraw.gd
Normal file
@ -0,0 +1,13 @@
|
||||
tool
|
||||
extends Line2D
|
||||
|
||||
export (Color) var inner_color := Color() setget set_inner_color
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
draw_colored_polygon(points, inner_color)
|
||||
|
||||
|
||||
func set_inner_color(val: Color) -> void:
|
||||
inner_color = val
|
||||
update()
|
21
steering_ai/LICENSE
Normal file
21
steering_ai/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 GDQuest
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
44
steering_ai/README.md
Normal file
44
steering_ai/README.md
Normal file
@ -0,0 +1,44 @@
|
||||
# Steering AI Framework
|
||||
|
||||
This demo shows the usage of [GDQuest's Godot Steering AI Framework](https://github.com/GDQuest/godot-steering-ai-framework)'s
|
||||
c++ port that is built into the engine. [See here](https://github.com/Relintai/pandemonium_engine/tree/master/modules/steering_ai)
|
||||
|
||||
It supports all essential steering behaviors like flee, follow, look at, but also blended behaviors, group behaviors,
|
||||
avoiding neighbors, following a path, following the leader, and much more.
|
||||
|
||||
## Introduction
|
||||
|
||||
In the 1990s, [Craig Reynolds](http://www.red3d.com/cwr/) developed algorithms for common AI behaviors. They allowed
|
||||
AI agents to seek out or flee from a target, follow a pre-defined path, or face in a particular direction. They were simple,
|
||||
repeatable tasks that could be broken down into programming algorithms, which made them easy to reuse, maintain, combine, and extend.
|
||||
|
||||
While an AI agent's next action is based on decision making and planning algorithms, steering behaviors dictate
|
||||
how it will move from one frame to the next. They use available information and calculate where to move at that moment.
|
||||
|
||||
Joining these systems together can give sophisticated and graceful movement while also being more
|
||||
efficient than complex pathfinding algorithms like A\*.
|
||||
|
||||
## The framework
|
||||
|
||||
This project takes inspiration from the excellent [GDX-AI](https://github.com/libgdx/gdx-ai) framework for the [LibGDX](https://libgdx.badlogicgames.com/)
|
||||
java-based framework.
|
||||
|
||||
Every class in the framework extends Godot's [Reference](https://docs.godotengine.org/en/latest/classes/class_reference.html) type.
|
||||
There is no need to have a complex scene tree; you can contain that has to do with the AI's movement inside GDScript classes.
|
||||
|
||||
### How it works
|
||||
|
||||
In GSAI, a steering agent represents a character or a vehicle. The agent stores its position, orientation,
|
||||
maximum speeds, and current velocity. The agent stores a steering behavior that calculates a linear or
|
||||
angular change in velocity based on its information.
|
||||
|
||||
The coder then applies that acceleration in whatever ways is appropriate to the character to change its v
|
||||
elocities, like RigidBody's `apply_impulse`, or a KinematicBody's `move_and_slide`.
|
||||
|
||||
## Documentation
|
||||
|
||||
The documentation is available in-engine. Search for classes which names start with the word "GSAI".
|
||||
|
||||
The original framework's original documentation and code reference are available here:
|
||||
[Godot steering AI framework documentation](https://gdquest.gitbook.io/godot-3-steering-ai-framework-reference/)
|
||||
|
BIN
steering_ai/assets/icon.png
Normal file
BIN
steering_ai/assets/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
35
steering_ai/assets/icon.png.import
Normal file
35
steering_ai/assets/icon.png.import
Normal file
@ -0,0 +1,35 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/icon.png-b6a7fb2db36edd3d95dc42f1dc8c1c5d.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/icon.png"
|
||||
dest_files=[ "res://.import/icon.png-b6a7fb2db36edd3d95dc42f1dc8c1c5d.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
process/normal_map_invert_y=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
151
steering_ai/assets/icon.svg
Normal file
151
steering_ai/assets/icon.svg
Normal file
@ -0,0 +1,151 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
sodipodi:docname="icon.svg"
|
||||
inkscape:version="1.1-dev (83f2ee46ff, 2020-02-13)"
|
||||
id="svg1340"
|
||||
version="1.1"
|
||||
viewBox="0 0 16.933333 16.933334"
|
||||
height="64"
|
||||
width="64">
|
||||
<defs
|
||||
id="defs1334">
|
||||
<clipPath
|
||||
id="clipPath1560"
|
||||
clipPathUnits="userSpaceOnUse">
|
||||
<rect
|
||||
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#293252;fill-opacity:1;stroke:none;stroke-width:1.40425;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0;stop-color:#000000;stop-opacity:1"
|
||||
id="rect1562"
|
||||
width="16.933332"
|
||||
height="16.933332"
|
||||
x="0"
|
||||
y="9.6346028e-08" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
inkscape:snap-global="true"
|
||||
inkscape:snap-others="false"
|
||||
inkscape:object-nodes="false"
|
||||
inkscape:snap-page="true"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-height="1043"
|
||||
inkscape:window-width="1920"
|
||||
units="px"
|
||||
showgrid="false"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:cy="31.438019"
|
||||
inkscape:cx="15.072392"
|
||||
inkscape:zoom="8"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
borderopacity="1.0"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff"
|
||||
id="base" />
|
||||
<metadata
|
||||
id="metadata1337">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:groupmode="layer"
|
||||
inkscape:label="Layer 1">
|
||||
<rect
|
||||
y="0"
|
||||
x="0"
|
||||
height="16.933332"
|
||||
width="16.933332"
|
||||
id="rect1504"
|
||||
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#293252;fill-opacity:1;stroke:none;stroke-width:1.40425;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0;stop-color:#000000;stop-opacity:1" />
|
||||
<path
|
||||
clip-path="url(#clipPath1560)"
|
||||
id="path2490"
|
||||
d="M 2.8526138,-0.0226856 2.9507848,1.274306 C 2.5771927,1.4791664 2.2289224,1.7185349 1.9075218,1.988743 L 0.29690799,1.3221671 -0.40866643,2.1624613 0.56110833,3.5585158 C 0.33791661,3.9257554 0.15316113,4.3166174 0.00975169,4.7250204 l -0.7432386,0.090259 -0.009472,1.7228785 0.40521717,0.191826 c 0,0.2151562 0.0190602,0.4320655 0.0310875,0.6505844 0.0205584,0.2185642 0.0528327,0.4331209 0.0974454,0.6435666 l -0.54416748,0.401985 -0.008756,1.5907221 1.2930922,-0.090536 C 0.75306491,10.299542 1.0115466,10.64731 1.3029499,10.96517 l -0.672761,1.553839 0.858959,0.689584 1.4456413,-0.959917 c 0.3687832,0.203771 0.7600417,0.372343 1.1673979,0.502553 l 0.2153945,1.714295 1.0964166,0.176342 0.7818497,-1.5822 c 0.2037711,0 0.4094501,-0.01685 0.6159876,-0.03895 H 6.812698 L 9.8042599,12.732617 9.3779282,8.4823903 6.3854715,8.7696026 6.5157868,10.092058 C 4.6330774,10.272636 2.9585336,8.9258916 2.7734622,7.0836627 2.5888891,5.2418454 3.9644158,3.6030022 5.8465387,3.4220125 L 8.8381053,3.1348571 8.5438181,0.20619376 5.5531989,0.49334922 C 5.3459823,0.51050176 5.1420605,0.5378074 4.9415586,0.57229759 L 4.4901554,-0.01349219 Z M 10.360111,2.7244603 9.577372,4.3066562 c -0.2035882,0 -0.4084223,0.016659 -0.6150947,0.038946 L 5.969764,4.633705 6.2641051,7.5605285 9.2556723,7.273373 a 3.4244787,3.3513826 0 0 1 3.7431617,3.007448 3.4244787,3.3513826 0 0 1 -3.0739683,3.662595 l -2.9915662,0.28894 0.2652052,2.646411 2.7965066,0.01566 0.2241417,-0.0215 c 0.206675,-0.01714 0.41087,-0.0444 0.610692,-0.07889 l 0.0814,0.105523 1.973596,0.01109 -0.06151,-0.818622 c 0.373232,-0.204827 0.723028,-0.444409 1.044158,-0.714444 l 1.609666,0.667466 0.705575,-0.840294 -0.968773,-1.396053 c 0.222649,-0.367242 0.407573,-0.758822 0.551301,-1.167399 l 1.699205,-0.205645 0.181684,-1.073405 -1.533445,-0.725078 c 0.01889,-0.214756 -0.01899,-0.432247 -0.03098,-0.6505829 -0.02061,-0.2185654 -0.05301,-0.4339146 -0.09935,-0.6444001 L 17.342103,8.3379231 16.950314,7.3203422 15.242313,7.4418002 C 15.020345,7.0685674 14.760954,6.7200461 14.469323,6.4020456 L 15.142137,4.8490976 14.284072,4.1595128 12.836646,5.1194284 C 12.467685,4.9156577 12.078251,4.7477386 11.671033,4.6177136 L 11.454747,2.9034731 Z"
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#2f395f;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.17682;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
inkscape:connector-curvature="0" />
|
||||
<g
|
||||
style="stroke-width:1.24672"
|
||||
transform="matrix(0.18285727,0,0,0.14154908,150.31973,-187.36868)"
|
||||
id="g2450">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="opacity:1;vector-effect:none;fill:#5e315b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.989584;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.97917, 1.97917;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal"
|
||||
d="m -822.06042,1434.5708 h 9.26041 v 9.2604 h -9.26041 z"
|
||||
id="path2430" />
|
||||
<path
|
||||
id="path2432"
|
||||
d="m -812.80001,1434.5708 h 9.26041 v 9.2604 h -9.26041 z"
|
||||
style="opacity:1;vector-effect:none;fill:#8c3f5d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.989584;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.97917, 1.97917;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="opacity:1;vector-effect:none;fill:#ba6156;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.989584;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.97917, 1.97917;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal"
|
||||
d="m -803.5396,1434.5708 h 9.26041 v 9.2604 h -9.26041 z"
|
||||
id="path2434" />
|
||||
<path
|
||||
id="path2436"
|
||||
d="m -794.27919,1434.5708 h 9.26041 v 9.2604 h -9.26041 z"
|
||||
style="opacity:1;vector-effect:none;fill:#f2a65e;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.989584;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.97917, 1.97917;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="opacity:1;vector-effect:none;fill:#ffe478;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.989584;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.97917, 1.97917;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal"
|
||||
d="m -785.01878,1434.5708 h 9.26041 v 9.2604 h -9.26041 z"
|
||||
id="path2438" />
|
||||
<path
|
||||
id="path2440"
|
||||
d="m -775.75837,1434.5708 h 9.26041 v 9.2604 h -9.26041 z"
|
||||
style="opacity:1;vector-effect:none;fill:#cfff70;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.989584;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.97917, 1.97917;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="opacity:1;vector-effect:none;fill:#8fde5d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.989584;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.97917, 1.97917;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal"
|
||||
d="m -766.49796,1434.5708 h 9.26041 v 9.2604 h -9.26041 z"
|
||||
id="path2442" />
|
||||
<path
|
||||
id="path2444"
|
||||
d="m -757.23755,1434.5708 h 9.26041 v 9.2604 h -9.26041 z"
|
||||
style="opacity:1;vector-effect:none;fill:#3ca370;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.989584;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.97917, 1.97917;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="opacity:1;vector-effect:none;fill:#3d6e70;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.989584;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.97917, 1.97917;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal"
|
||||
d="m -747.97714,1434.5708 h 9.26041 v 9.2604 h -9.26041 z"
|
||||
id="path2446" />
|
||||
<path
|
||||
id="path2448"
|
||||
d="m -738.71673,1434.5708 h 9.26041 v 9.2604 h -9.26041 z"
|
||||
style="opacity:1;vector-effect:none;fill:#323e4f;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.989584;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.97917, 1.97917;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<path
|
||||
sodipodi:nodetypes="cccc"
|
||||
d="M 1.7415414,13.864431 C 2.8091455,12.301646 3.8954985,10.918152 4.8840406,10.004274 M 12.44693,3.6341761 c 0,0 1.658558,-1.2568206 2.909891,-2.065662"
|
||||
style="fill:none;stroke:#a0a9ce;stroke-width:1.087;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:1.6;stroke-dasharray:2.174, 2.174;stroke-dashoffset:1.087;stroke-opacity:1"
|
||||
id="path2283"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path2351"
|
||||
d="M 4.6789148,3.8638581 6.5936823,6.200326 4.9999674,7.512026 7.0448877,10.007103 8.6388709,8.6952013 10.553866,11.032019 11.16251,4.529541 Z"
|
||||
style="vector-effect:none;fill:#293252;fill-opacity:1;fill-rule:nonzero;stroke:#7786bb;stroke-width:0.827338;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 11 KiB |
35
steering_ai/assets/icon.svg.import
Normal file
35
steering_ai/assets/icon.svg.import
Normal file
@ -0,0 +1,35 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/icon.svg-56083ea2a1f1a4f1e49773bdc6d7826c.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/icon.svg"
|
||||
dest_files=[ "res://.import/icon.svg-56083ea2a1f1a4f1e49773bdc6d7826c.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
process/normal_map_invert_y=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
BIN
steering_ai/assets/sprites/background.png
Normal file
BIN
steering_ai/assets/sprites/background.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
35
steering_ai/assets/sprites/background.png.import
Normal file
35
steering_ai/assets/sprites/background.png.import
Normal file
@ -0,0 +1,35 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/background.png-dde469fb1f19281f3784b52d4bea96cd.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/sprites/background.png"
|
||||
dest_files=[ "res://.import/background.png-dde469fb1f19281f3784b52d4bea96cd.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
process/normal_map_invert_y=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
BIN
steering_ai/assets/theme/button/disabled.stylebox
Normal file
BIN
steering_ai/assets/theme/button/disabled.stylebox
Normal file
Binary file not shown.
BIN
steering_ai/assets/theme/button/focused.stylebox
Normal file
BIN
steering_ai/assets/theme/button/focused.stylebox
Normal file
Binary file not shown.
BIN
steering_ai/assets/theme/button/hover.stylebox
Normal file
BIN
steering_ai/assets/theme/button/hover.stylebox
Normal file
Binary file not shown.
BIN
steering_ai/assets/theme/button/normal.stylebox
Normal file
BIN
steering_ai/assets/theme/button/normal.stylebox
Normal file
Binary file not shown.
BIN
steering_ai/assets/theme/button/pressed.stylebox
Normal file
BIN
steering_ai/assets/theme/button/pressed.stylebox
Normal file
Binary file not shown.
BIN
steering_ai/assets/theme/empty.stylebox
Normal file
BIN
steering_ai/assets/theme/empty.stylebox
Normal file
Binary file not shown.
8
steering_ai/assets/theme/fonts/default_font.tres
Normal file
8
steering_ai/assets/theme/fonts/default_font.tres
Normal file
@ -0,0 +1,8 @@
|
||||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://assets/theme/fonts/montserrat/Montserrat-Medium.ttf" type="DynamicFontData" id=1]
|
||||
|
||||
[resource]
|
||||
size = 26
|
||||
use_filter = true
|
||||
font_data = ExtResource( 1 )
|
8
steering_ai/assets/theme/fonts/default_font_bold.tres
Normal file
8
steering_ai/assets/theme/fonts/default_font_bold.tres
Normal file
@ -0,0 +1,8 @@
|
||||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://assets/theme/fonts/montserrat/Montserrat-Bold.ttf" type="DynamicFontData" id=1]
|
||||
|
||||
[resource]
|
||||
size = 26
|
||||
use_filter = true
|
||||
font_data = ExtResource( 1 )
|
8
steering_ai/assets/theme/fonts/default_font_code.tres
Normal file
8
steering_ai/assets/theme/fonts/default_font_code.tres
Normal file
@ -0,0 +1,8 @@
|
||||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://assets/theme/fonts/source_code_pro/SourceCodePro-Medium.otf" type="DynamicFontData" id=1]
|
||||
|
||||
[resource]
|
||||
size = 26
|
||||
use_filter = true
|
||||
font_data = ExtResource( 1 )
|
8
steering_ai/assets/theme/fonts/font_title.tres
Normal file
8
steering_ai/assets/theme/fonts/font_title.tres
Normal file
@ -0,0 +1,8 @@
|
||||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://assets/theme/fonts/montserrat/Montserrat-Black.ttf" type="DynamicFontData" id=1]
|
||||
|
||||
[resource]
|
||||
size = 34
|
||||
use_filter = true
|
||||
font_data = ExtResource( 1 )
|
BIN
steering_ai/assets/theme/fonts/montserrat/Montserrat-Black.ttf
Normal file
BIN
steering_ai/assets/theme/fonts/montserrat/Montserrat-Black.ttf
Normal file
Binary file not shown.
BIN
steering_ai/assets/theme/fonts/montserrat/Montserrat-Bold.ttf
Normal file
BIN
steering_ai/assets/theme/fonts/montserrat/Montserrat-Bold.ttf
Normal file
Binary file not shown.
BIN
steering_ai/assets/theme/fonts/montserrat/Montserrat-Medium.ttf
Normal file
BIN
steering_ai/assets/theme/fonts/montserrat/Montserrat-Medium.ttf
Normal file
Binary file not shown.
Binary file not shown.
BIN
steering_ai/assets/theme/gdquest.theme
Normal file
BIN
steering_ai/assets/theme/gdquest.theme
Normal file
Binary file not shown.
1
steering_ai/assets/theme/icons/chevron-right.svg
Normal file
1
steering_ai/assets/theme/icons/chevron-right.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-right"><polyline points="9 18 15 12 9 6"></polyline></svg>
|
After Width: | Height: | Size: 270 B |
35
steering_ai/assets/theme/icons/chevron-right.svg.import
Normal file
35
steering_ai/assets/theme/icons/chevron-right.svg.import
Normal file
@ -0,0 +1,35 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/chevron-right.svg-f77dee7a088177a2ac1d467f4c7cd3e1.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/theme/icons/chevron-right.svg"
|
||||
dest_files=[ "res://.import/chevron-right.svg-f77dee7a088177a2ac1d467f4c7cd3e1.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
process/normal_map_invert_y=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
1
steering_ai/assets/theme/icons/chevron-up.svg
Normal file
1
steering_ai/assets/theme/icons/chevron-up.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-up"><polyline points="18 15 12 9 6 15"></polyline></svg>
|
After Width: | Height: | Size: 268 B |
35
steering_ai/assets/theme/icons/chevron-up.svg.import
Normal file
35
steering_ai/assets/theme/icons/chevron-up.svg.import
Normal file
@ -0,0 +1,35 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/chevron-up.svg-48b5b69265734774d0a7516dcc6f0863.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/theme/icons/chevron-up.svg"
|
||||
dest_files=[ "res://.import/chevron-up.svg-48b5b69265734774d0a7516dcc6f0863.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
process/normal_map_invert_y=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
BIN
steering_ai/assets/theme/panel/panel.stylebox
Normal file
BIN
steering_ai/assets/theme/panel/panel.stylebox
Normal file
Binary file not shown.
5
steering_ai/assets/theme/separator/line.tres
Normal file
5
steering_ai/assets/theme/separator/line.tres
Normal file
@ -0,0 +1,5 @@
|
||||
[gd_resource type="StyleBoxLine" format=2]
|
||||
|
||||
[resource]
|
||||
color = Color( 1, 1, 1, 0.196078 )
|
||||
thickness = 2
|
BIN
steering_ai/assets/theme/slider/grabber_area.stylebox
Normal file
BIN
steering_ai/assets/theme/slider/grabber_area.stylebox
Normal file
Binary file not shown.
BIN
steering_ai/assets/theme/slider/slider.stylebox
Normal file
BIN
steering_ai/assets/theme/slider/slider.stylebox
Normal file
Binary file not shown.
7
steering_ai/default_env.tres
Normal file
7
steering_ai/default_env.tres
Normal file
@ -0,0 +1,7 @@
|
||||
[gd_resource type="Environment3D" load_steps=2 format=2]
|
||||
|
||||
[sub_resource type="ProceduralSky" id=1]
|
||||
|
||||
[resource]
|
||||
background_mode = 2
|
||||
background_sky = SubResource( 1 )
|
76
steering_ai/project.pandemonium
Normal file
76
steering_ai/project.pandemonium
Normal file
@ -0,0 +1,76 @@
|
||||
; Engine configuration file.
|
||||
; It's best edited using the editor UI and not directly,
|
||||
; since the parameters that go here are not all obvious.
|
||||
;
|
||||
; Format:
|
||||
; [section] ; section goes between []
|
||||
; param=value ; assign values to parameters
|
||||
|
||||
config_version=4
|
||||
|
||||
_global_script_classes=[ {
|
||||
"base": "Control",
|
||||
"class": @"DemoPickerUI",
|
||||
"language": @"GDScript",
|
||||
"path": "res://Demos/DemoPickerUI.gd"
|
||||
} ]
|
||||
_global_script_class_icons={
|
||||
@"DemoPickerUI": ""
|
||||
}
|
||||
|
||||
[application]
|
||||
|
||||
config/name="Godot Steering AI Framework Demos"
|
||||
run/main_scene="res://Demos/DemoSelector.tscn"
|
||||
config/icon="res://assets/icon.png"
|
||||
|
||||
[display]
|
||||
|
||||
window/size/width=1920
|
||||
window/size/height=1080
|
||||
window/size/always_on_top=true
|
||||
window/size/test_width=1280
|
||||
window/size/test_height=720
|
||||
window/stretch/mode="2d"
|
||||
window/stretch/aspect="expand"
|
||||
|
||||
[editor_plugins]
|
||||
|
||||
enabled=PoolStringArray( )
|
||||
|
||||
[input]
|
||||
|
||||
sf_left={
|
||||
"deadzone": 0.5,
|
||||
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":65,"physical_scancode":0,"unicode":0,"echo":false,"action_match_force_exact":false,"script":null)
|
||||
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":-1.0,"script":null)
|
||||
]
|
||||
}
|
||||
sf_right={
|
||||
"deadzone": 0.5,
|
||||
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":68,"physical_scancode":0,"unicode":0,"echo":false,"action_match_force_exact":false,"script":null)
|
||||
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":1.0,"script":null)
|
||||
]
|
||||
}
|
||||
sf_up={
|
||||
"deadzone": 0.5,
|
||||
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":87,"physical_scancode":0,"unicode":0,"echo":false,"action_match_force_exact":false,"script":null)
|
||||
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":-1.0,"script":null)
|
||||
]
|
||||
}
|
||||
sf_down={
|
||||
"deadzone": 0.5,
|
||||
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":83,"physical_scancode":0,"unicode":0,"echo":false,"action_match_force_exact":false,"script":null)
|
||||
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":1.0,"script":null)
|
||||
]
|
||||
}
|
||||
toggle_fullscreen={
|
||||
"deadzone": 0.5,
|
||||
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777254,"physical_scancode":0,"unicode":0,"echo":false,"action_match_force_exact":false,"script":null)
|
||||
]
|
||||
}
|
||||
click={
|
||||
"deadzone": 0.5,
|
||||
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"pressed":false,"canceled":false,"doubleclick":false,"script":null)
|
||||
]
|
||||
}
|
16
voxelman/the_tower_gles2/.gitignore
vendored
Normal file
16
voxelman/the_tower_gles2/.gitignore
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
\exports/
|
||||
\.import/
|
||||
|
||||
addons/scene_notes/
|
||||
|
||||
addons/todo/
|
||||
|
||||
scene-notes\.ini
|
||||
|
||||
todo\.cache\.ini
|
||||
|
||||
todo\.config\.ini
|
||||
|
||||
export_presets\.cfg
|
||||
|
||||
export.cfg
|
19
voxelman/the_tower_gles2/LICENSE
Normal file
19
voxelman/the_tower_gles2/LICENSE
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2019-present Péter Magyar
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
270
voxelman/the_tower_gles2/README.md
Normal file
270
voxelman/the_tower_gles2/README.md
Normal file
@ -0,0 +1,270 @@
|
||||
# The Tower Pandemonium
|
||||
|
||||
A really simple (and visually strange) demonstration project for Voxelman in the Pandemonium engine.
|
||||
|
||||
It is a first person parkour game. Reach the weird glowing teleporter at the end of each level.
|
||||
|
||||
In order to open this, you need to have the proper version of the [Pandemonium Engine](https://github.com/Relintai/pandemonium_engine)!
|
||||
|
||||
You can either just get an executable at the [releases tab](https://github.com/Relintai/the_tower_pandemonium/releases), or
|
||||
you can build one yourself see [here](#compiling).
|
||||
|
||||
You can also try a live version running in the browser [here](https://relintai.github.io/the_tower_pandemonium/).
|
||||
|
||||
Unfortunately the web editor needs custom http headers to work and I can't set that up from github.io, so right now I don't have a hosted version of that.
|
||||
|
||||
Should work on all platforms (even when there is no threading available).\
|
||||
It does not have touchscreen controls tough.
|
||||
|
||||
## Controls
|
||||
|
||||
`w`,`a`,`s`,`d`: Movement \
|
||||
`space`: jump (you can also double jump) \
|
||||
`shift`: run \
|
||||
`r`: reload level \
|
||||
`esc`: ingame menu
|
||||
|
||||
## Screenshots
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## Assets
|
||||
|
||||
### The sound effect
|
||||
|
||||
https://opengameart.org/content/foot-walking-step-sounds-on-stone-water-snow-wood-and-dirt
|
||||
|
||||
Author: \
|
||||
Jute (Submitted by qubodup)\
|
||||
Thursday, February 11, 2010 - 02:27\
|
||||
Art Type: Sound Effect \
|
||||
Tags: snow step walk walking movement dirt Wood water wet footstep foot run Action RPG Fantasy Other\
|
||||
License(s): GPL 3.0, GPL 2.0
|
||||
|
||||
These sounds were made by Jute for DungeonHack. They are based on sounds from pdsounds.org.
|
||||
|
||||
I did modify the effect I use from it.
|
||||
|
||||
### The font
|
||||
|
||||
The font is licensed under the Apache License. (it's next to it.)
|
||||
|
||||
## Editing the game
|
||||
|
||||
Grab an engine which has voxelman built in, and then open the project inside the `game` folder.
|
||||
|
||||
## Compiling
|
||||
|
||||
First make sure, that you have everything installed to be able to compile the godot engine. See [the official docs for compiling Godot](https://docs.godotengine.org/en/latest/development/compiling/index.html) for more info. My setup/compile script uses the same tools, so
|
||||
you don't need to install anything else.
|
||||
|
||||
Now let's clone this repository:
|
||||
|
||||
``` git clone https://github.com/Relintai/the_tower_pandemonium ```
|
||||
|
||||
cd into the new folder:
|
||||
|
||||
``` cd the_tower ```
|
||||
|
||||
Now let's run the project's setup script, by calling scons without arguments.
|
||||
|
||||
``` scons ```
|
||||
|
||||
This will clone and setup the engine, and all of the required modules into a new `engine` folder inside the project, using http.
|
||||
|
||||
(If you want to use the github's ssh links append `repository_type=ssh` like ``` scons repository_type=ssh ```)
|
||||
|
||||
Once it is done you can compile the engine.
|
||||
|
||||
To build the editor on windows with 4 threads run the following command:
|
||||
|
||||
``` scons bew -j4 ```
|
||||
|
||||
To build the editor on linux with 4 threads run the following command:
|
||||
|
||||
``` scons bel -j4 ```
|
||||
|
||||
I call this feature of the setup script build words. [See](#build-words).
|
||||
|
||||
Once the build finishes you can find the editor executable inside the `./engine/bin/` folder.
|
||||
|
||||
For convenience there is a provided `editor.sh`, or `editor.bat` for running it from the project's folder.
|
||||
These will create a copy, so you can even compile while the editor is running.
|
||||
|
||||
Alternatively if you don't want to use build words, you can also just go into the engine folder:
|
||||
|
||||
``` cd engine ```
|
||||
|
||||
And compile godot as per the [official docs](https://docs.godotengine.org/en/latest/development/compiling/index.html).
|
||||
|
||||
### Build words
|
||||
|
||||
The project's setup script contains support for "build words". These can be used from the root of this project.
|
||||
|
||||
For example to build the editor for windows with 4 threads you can use:
|
||||
|
||||
``` scons bew -j4 ```
|
||||
|
||||
The first argument must start with b (build), then it needs to be followed by a few abbreviations (the order does not matters)
|
||||
|
||||
The rest of the arguments will be passed directly to godot's scons script.
|
||||
|
||||
#### Editor
|
||||
|
||||
Append `e` to build with `tools=yes` a.k.a. the editor.
|
||||
|
||||
``` scons bew -j4 ```
|
||||
|
||||
if you omit `e`, the system will build the export template for you. For example:
|
||||
|
||||
``` scons bw -j4 ```
|
||||
|
||||
This will be the `release_debug` windows export template.
|
||||
|
||||
#### Platform abbreviations
|
||||
|
||||
`l`: linux \
|
||||
`w`: windows \
|
||||
`a`: android \
|
||||
`j`: Javascript \
|
||||
`i`: iphone (Not yet finished, use `build_ios.sh`, and `build_ios_release.sh`) \
|
||||
Mac OSX: Not yet finished, use `build_osx.sh`
|
||||
|
||||
#### Target abbreviations
|
||||
|
||||
By default the system builds in release_debug.
|
||||
|
||||
Append `d` for debug, or `r` for release.
|
||||
|
||||
``` scons bewd -j4 ```
|
||||
|
||||
build editor windows debug
|
||||
|
||||
``` scons bwr -j4 ```
|
||||
|
||||
build windows release (this will build the windows release export template)
|
||||
|
||||
#### Shared modules
|
||||
|
||||
Note: This only works on linux!
|
||||
|
||||
append `s` to the build string.
|
||||
|
||||
Optionally you can also make the build system only build a target module, by appending one of these:
|
||||
|
||||
`E`: Entity Spell System \
|
||||
`T`: Texture Packer \
|
||||
`V`: Voxelman \
|
||||
`W`: World Generator \
|
||||
`P`: Procedural Animations
|
||||
|
||||
Example:
|
||||
|
||||
``` scons belsE -j4 ```
|
||||
|
||||
build editor linux shared (Entity Spell System) with 4 threads
|
||||
|
||||
Note: to easily run the editor you can use the `editor.sh` or `editor.bat` in the root of the project.
|
||||
|
||||
#### Other
|
||||
|
||||
Append `v` to pass the `vsproj=yes` parameter to the build script. This will generate Visual Studio project files.
|
||||
|
||||
#### Postfixes
|
||||
|
||||
There are a few postfixes for the build words. These are more complex options. You have to append them to your build word with an underscore.
|
||||
|
||||
You can use as many as you want.
|
||||
|
||||
For example:
|
||||
|
||||
``` scons bel_slim_latomic -j4 ```
|
||||
|
||||
##### slim
|
||||
|
||||
With this postfix you can build a slimmed down version of the engine. This disables quite a few unneeded modules.
|
||||
|
||||
``` scons bel_slim -j4 ```
|
||||
|
||||
##### latomic
|
||||
|
||||
If you get linker errors while building the game/editor about undefined referenced with atomic related functions you can use this postfix.
|
||||
It will add the ` -latomic ` command line switch to the linker flags.
|
||||
|
||||
I ran into this issue while building on a raspberry pi 4 with the x11 platform. It might be related to the recent reworks to threading.
|
||||
|
||||
``` scons bel_latomic -j4 ```
|
||||
|
||||
##### strip
|
||||
|
||||
Appends `debug_symbols=no` to the build command, which will strip the resulting binary from debug symbols.
|
||||
|
||||
``` scons bel_strip -j4 ```
|
||||
|
||||
##### threads
|
||||
|
||||
Appends `threads_enabled=yes` to the build command. Useful for building the editor for html.
|
||||
|
||||
``` scons bej_threads -j4 ```
|
||||
|
||||
#### Scons cache, and sdk locations
|
||||
|
||||
In order to use scons cache and to tell the build system where some of the required sdks are located you usually
|
||||
have to use environment variables. Most of the time you might just want to add them globally,
|
||||
howewer this is sometimes unfeasible (e.g. you don't have administrator access, or you just want to have
|
||||
multiple sdk versions installed).
|
||||
|
||||
In order to solve this a build config file was added.
|
||||
|
||||
If you want to use the config simply rename the provided `build.config.example` to `build.config`, and customize
|
||||
the settings inside.
|
||||
|
||||
### Manual Setup
|
||||
|
||||
If you you don't want to use the setup script (or just want to know what it actually does),
|
||||
this section will explain how to set everything up manually.
|
||||
|
||||
First clone the Pandemonium Engine:
|
||||
|
||||
``` git clone https://github.com/Relintai/pandemonium_engine ```
|
||||
|
||||
go into engine's modules folder.
|
||||
|
||||
``` cd godot/modules/ ```
|
||||
|
||||
Now go ahead and get every single required engine module from [here](#the-required-engine-modules).
|
||||
|
||||
``` cd ../../ ```
|
||||
|
||||
Now if you look at the [HEADS file](https://github.com/Relintai/the_tower_pandemonium/blob/master/HEADS).
|
||||
|
||||
It contains the commit hashes for that particular revision for every module and the engine.
|
||||
|
||||
You need to go through them and checkout the proper commits.
|
||||
|
||||
Now you can go ahead and compile godot normally.
|
||||
|
||||
## Pulling upstream changes
|
||||
|
||||
First pull the changes by calling
|
||||
|
||||
``` git pull orgin master ```
|
||||
|
||||
Then just run `scons`, to update the modules.
|
||||
|
||||
## Upgrading the modules
|
||||
|
||||
Note: this is how to update the HEADS file. Normally you don't need to do this.
|
||||
|
||||
If you want to update the modules, and the engine to the latest, you can use (`action=update`):
|
||||
|
||||
``` scons a=u ```
|
||||
|
||||
You can also update different targets: `all`, `engine`, `modules`, `all_addons`, `addons`, `third_party_addons`
|
||||
|
||||
For example to update the engine to the latest: ``` scons a=u target=engine ```
|
||||
|
||||
|
34
voxelman/the_tower_gles2/areas/ExitPortal.tscn
Normal file
34
voxelman/the_tower_gles2/areas/ExitPortal.tscn
Normal file
@ -0,0 +1,34 @@
|
||||
[gd_scene load_steps=6 format=3]
|
||||
|
||||
[ext_resource path="res://scripts/exit_portal.gd" type="Script" id=1]
|
||||
[ext_resource path="res://particles/flake.png" type="Texture" id=2]
|
||||
|
||||
[sub_resource type="BoxShape" id=4]
|
||||
extents = Vector3( 1, 1.65801, 1 )
|
||||
|
||||
[sub_resource type="SpatialMaterial" id=5]
|
||||
flags_transparent = true
|
||||
vertex_color_use_as_albedo = true
|
||||
params_billboard_mode = 3
|
||||
particles_anim_h_frames = 1
|
||||
particles_anim_v_frames = 1
|
||||
particles_anim_loop = false
|
||||
albedo_texture = ExtResource( 2 )
|
||||
|
||||
[sub_resource type="QuadMesh" id=6]
|
||||
material = SubResource( 5 )
|
||||
|
||||
[node name="ExitPortal" type="Area"]
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="CollisionShape" type="CollisionShape" parent="."]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.67644, 0 )
|
||||
shape = SubResource( 4 )
|
||||
|
||||
[node name="Particles" type="CPUParticles" parent="."]
|
||||
mesh = SubResource( 6 )
|
||||
emission_shape = 2
|
||||
emission_box_extents = Vector3( 0.5, 1, 0.5 )
|
||||
gravity = Vector3( 0, 9.8, 0 )
|
||||
scale_amount = 0.1
|
||||
color = Color( 0.26, 0.33, 0.84, 1 )
|
18
voxelman/the_tower_gles2/default_bus_layout.tres
Normal file
18
voxelman/the_tower_gles2/default_bus_layout.tres
Normal file
@ -0,0 +1,18 @@
|
||||
[gd_resource type="AudioBusLayout" load_steps=2 format=3]
|
||||
|
||||
[sub_resource type="AudioEffectReverb" id=1]
|
||||
resource_name = "Reverb"
|
||||
room_size = 0.13
|
||||
damping = 0.09
|
||||
wet = 0.13
|
||||
|
||||
[resource]
|
||||
bus/0/volume_db = 0.0672607
|
||||
bus/1/name = @"Footsteps"
|
||||
bus/1/solo = false
|
||||
bus/1/mute = false
|
||||
bus/1/bypass_fx = false
|
||||
bus/1/volume_db = -4.25003
|
||||
bus/1/send = @"Master"
|
||||
bus/1/effect/0/effect = SubResource( 1 )
|
||||
bus/1/effect/0/enabled = true
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user