Compare commits
22 Commits
Author | SHA1 | Date | |
---|---|---|---|
fa5375534b | |||
f5d91b4e6e | |||
dfd8abe5fe | |||
b97ecfb7de | |||
8f3a81c124 | |||
dbdd19436e | |||
5ae367996d | |||
88f3abf978 | |||
f75b6a4515 | |||
e68f280f54 | |||
eb7fa528dc | |||
f92a58b08d | |||
f2d25ec2ec | |||
21a8a0a702 | |||
aeff6f56e4 | |||
2cbc3ea3af | |||
8295671644 | |||
13c31ac83f | |||
1cdfe1836e | |||
5fe963de8f | |||
124ab95723 | |||
1d8a77ea51 |
@ -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
@ -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
|
||||
|
39
3d/procedural_trees/Main.tscn
Normal file
@ -0,0 +1,39 @@
|
||||
[gd_scene load_steps=9 format=3]
|
||||
|
||||
[ext_resource path="res://floor.png" type="Texture" id=1]
|
||||
[ext_resource path="res://twig.png" type="Texture" id=2]
|
||||
[ext_resource path="res://bark.jpg" type="Texture" id=3]
|
||||
|
||||
[sub_resource type="PlaneMesh" id=1]
|
||||
size = Vector2( 100, 100 )
|
||||
|
||||
[sub_resource type="SpatialMaterial" id=2]
|
||||
albedo_texture = ExtResource( 1 )
|
||||
uv1_scale = Vector3( 5, 5, 5 )
|
||||
|
||||
[sub_resource type="SpatialMaterial" id=5]
|
||||
albedo_texture = ExtResource( 3 )
|
||||
|
||||
[sub_resource type="SpatialMaterial" id=4]
|
||||
flags_transparent = true
|
||||
albedo_texture = ExtResource( 2 )
|
||||
|
||||
[sub_resource type="ProceduralTreeMesh" id=3]
|
||||
twig_material = SubResource( 4 )
|
||||
trunk_material = SubResource( 5 )
|
||||
|
||||
[node name="Main" type="Spatial"]
|
||||
|
||||
[node name="Camera" type="Camera" parent="."]
|
||||
transform = Transform( 1, 0, 0, 0, 0.995856, 0.0909454, 0, -0.0909454, 0.995856, 0, 3.24964, 6.08982 )
|
||||
|
||||
[node name="Floor" type="MeshInstance" parent="."]
|
||||
mesh = SubResource( 1 )
|
||||
material/0 = SubResource( 2 )
|
||||
|
||||
[node name="Tree" type="MeshInstance" parent="."]
|
||||
mesh = SubResource( 3 )
|
||||
|
||||
[node name="DirectionalLight" type="DirectionalLight" parent="."]
|
||||
transform = Transform( 0.999979, -0.00633815, 0.00104455, 0.0021793, 0.487706, 0.873005, -0.00604267, -0.872985, 0.487709, 0, 12.7518, 7.74885 )
|
||||
light_energy = 0.413
|
BIN
3d/procedural_trees/bark.jpg
Normal file
After Width: | Height: | Size: 191 KiB |
37
3d/procedural_trees/bark.jpg.import
Normal file
@ -0,0 +1,37 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path.s3tc="res://.import/bark.jpg-db1925684069186df966c2d6a5bd27d7.s3tc.stex"
|
||||
path.etc="res://.import/bark.jpg-db1925684069186df966c2d6a5bd27d7.etc.stex"
|
||||
metadata={
|
||||
"imported_formats": [ "s3tc", "etc" ],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://bark.jpg"
|
||||
dest_files=[ "res://.import/bark.jpg-db1925684069186df966c2d6a5bd27d7.s3tc.stex", "res://.import/bark.jpg-db1925684069186df966c2d6a5bd27d7.etc.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=2
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=true
|
||||
flags/filter=true
|
||||
flags/mipmaps=true
|
||||
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=false
|
||||
svg/scale=1.0
|
7
3d/procedural_trees/default_env.tres
Normal file
@ -0,0 +1,7 @@
|
||||
[gd_resource type="Environment3D" load_steps=2 format=3]
|
||||
|
||||
[sub_resource type="ProceduralSky" id=1]
|
||||
|
||||
[resource]
|
||||
background_mode = 2
|
||||
background_sky = SubResource( 1 )
|
BIN
3d/procedural_trees/floor.png
Normal file
After Width: | Height: | Size: 136 KiB |
37
3d/procedural_trees/floor.png.import
Normal file
@ -0,0 +1,37 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path.s3tc="res://.import/floor.png-d43f03cb7a8f42941311ed90ed2021b9.s3tc.stex"
|
||||
path.etc="res://.import/floor.png-d43f03cb7a8f42941311ed90ed2021b9.etc.stex"
|
||||
metadata={
|
||||
"imported_formats": [ "s3tc", "etc" ],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://floor.png"
|
||||
dest_files=[ "res://.import/floor.png-d43f03cb7a8f42941311ed90ed2021b9.s3tc.stex", "res://.import/floor.png-d43f03cb7a8f42941311ed90ed2021b9.etc.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=2
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=true
|
||||
flags/filter=true
|
||||
flags/mipmaps=true
|
||||
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=false
|
||||
svg/scale=1.0
|
BIN
3d/procedural_trees/icon.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
35
3d/procedural_trees/icon.png.import
Normal file
@ -0,0 +1,35 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://icon.png"
|
||||
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.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
|
25
3d/procedural_trees/project.pandemonium
Normal file
@ -0,0 +1,25 @@
|
||||
; 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
|
||||
|
||||
[application]
|
||||
|
||||
config/name="Procedural Trees"
|
||||
run/main_scene="res://Main.tscn"
|
||||
config/icon="res://icon.png"
|
||||
|
||||
[physics]
|
||||
|
||||
common/enable_pause_aware_picking=true
|
||||
|
||||
[rendering]
|
||||
|
||||
vram_compression/import_etc=true
|
||||
vram_compression/import_etc2=false
|
||||
environment/default_environment="res://default_env.tres"
|
12
3d/procedural_trees/readme.md
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
The textures are from the https://github.com/jarikomppa/proctree repository.
|
||||
|
||||
From the original readme:
|
||||
|
||||
All of the textures are CC0 / public domain material (primarily, if not completely, by nobiax.deviantart.com). The additional textures do let you make more varieties of trees though; the base package only comes with one trunk and twig texture.
|
||||
|
||||
Additional (not mandatory) 400 megs of trunk / twig textures
|
||||
http://iki.fi/sol/zip/happytree_20150118_tex.zip
|
||||
|
||||
If you opt to download the additional textures, just unzip both zips in the same place. HappyTree will work without the additional textures (it'll actually be faster), so if you're just trying it out, I recommend NOT downloading the additional stuff.
|
||||
|
BIN
3d/procedural_trees/twig.png
Normal file
After Width: | Height: | Size: 1013 KiB |
37
3d/procedural_trees/twig.png.import
Normal file
@ -0,0 +1,37 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path.s3tc="res://.import/twig.png-dfe3c857b25e019a9891469879fedf6a.s3tc.stex"
|
||||
path.etc="res://.import/twig.png-dfe3c857b25e019a9891469879fedf6a.etc.stex"
|
||||
metadata={
|
||||
"imported_formats": [ "s3tc", "etc" ],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://twig.png"
|
||||
dest_files=[ "res://.import/twig.png-dfe3c857b25e019a9891469879fedf6a.s3tc.stex", "res://.import/twig.png-dfe3c857b25e019a9891469879fedf6a.etc.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=2
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=true
|
||||
flags/filter=true
|
||||
flags/mipmaps=true
|
||||
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=false
|
||||
svg/scale=1.0
|
88
database/database_simple/Main.gd
Normal file
@ -0,0 +1,88 @@
|
||||
extends Node
|
||||
|
||||
export(String) var database_location : String = "user://database.sqlite"
|
||||
|
||||
func _ready() -> void:
|
||||
DatabaseManager.connect("initialized", self, "on_databases_initialized", [], CONNECT_ONESHOT)
|
||||
|
||||
var d : Directory = Directory.new()
|
||||
var bd : String = database_location.get_base_dir()
|
||||
var loc : String = d.get_filesystem_abspath_for(bd).append_path(database_location.get_file())
|
||||
|
||||
PLogger.log_message("Database file location: " + loc)
|
||||
PLogger.log_message("(Editor->Project->Open User Data Folder)")
|
||||
|
||||
var file : File = File.new()
|
||||
if !file.file_exists(loc):
|
||||
PLogger.log_message("Database file doesn't exists, will run migrations!")
|
||||
PLogger.log_message("(Editor->Project->Open User Data Folder)")
|
||||
call_deferred("migrate")
|
||||
else:
|
||||
DatabaseManager.call_deferred("initialized")
|
||||
|
||||
var db : SQLite3Database = SQLite3Database.new()
|
||||
db.connection_string = loc
|
||||
DatabaseManager.add_database(db)
|
||||
|
||||
func migrate() -> void:
|
||||
PLogger.log_message("Running migrations!")
|
||||
DatabaseManager.connect("migration", self, "_migration")
|
||||
DatabaseManager.migrate(true, false, 0)
|
||||
|
||||
DatabaseManager.call_deferred("initialized")
|
||||
|
||||
func on_databases_initialized() -> void:
|
||||
# Load sessions after the databases are initialized
|
||||
# This happens on the Main node.
|
||||
call_deferred("load_data")
|
||||
|
||||
func _migration(clear: bool, should_seed: bool, pseed: int) -> void:
|
||||
randomize()
|
||||
|
||||
var tb : TableBuilder = DatabaseManager.ddb.get_connection().get_table_builder()
|
||||
|
||||
tb.create_table("data_table");
|
||||
tb.integer("id").auto_increment().next_row();
|
||||
tb.varchar("data_varchar", 60).not_null().next_row();
|
||||
tb.text("data_text").not_null().next_row();
|
||||
tb.integer("data_int").not_null().next_row();
|
||||
tb.real_double("data_double").not_null().next_row();
|
||||
tb.primary_key("id");
|
||||
tb.ccreate_table();
|
||||
tb.run_query();
|
||||
|
||||
print("Running:")
|
||||
print(tb.result)
|
||||
|
||||
var qb : QueryBuilder = DatabaseManager.ddb.get_connection().get_query_builder()
|
||||
|
||||
for i in range(10):
|
||||
qb.reset()
|
||||
|
||||
qb.insert("data_table", "data_varchar,data_text,data_int,data_double").values()
|
||||
qb.vals("vc" + str(randi()))
|
||||
qb.vals("text" + str(randi()))
|
||||
qb.vali(randi())
|
||||
qb.vald(randf() * 100000)
|
||||
qb.cvalues()
|
||||
qb.end_command()
|
||||
|
||||
qb.run_query()
|
||||
|
||||
print("Running:")
|
||||
print(qb.result)
|
||||
|
||||
func load_data() -> void:
|
||||
print("Querying data from table:")
|
||||
|
||||
var qb : QueryBuilder = DatabaseManager.ddb.get_connection().get_query_builder()
|
||||
|
||||
var qr : QueryResult = qb.select("id,data_varchar,data_text,data_int,data_double").from("data_table").run()
|
||||
|
||||
while qr.next_row():
|
||||
print("ROW:")
|
||||
print("id: " + str(qr.get_cell_int(0)))
|
||||
print("data_varchar: " + str(qr.get_cell(1)))
|
||||
print("data_text: " + str(qr.get_cell(2)))
|
||||
print("data_int: " + str(qr.get_cell_int(3)))
|
||||
print("data_double: " + str(qr.get_cell_double(4)))
|
6
database/database_simple/Main.tscn
Normal file
@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource path="res://Main.gd" type="Script" id=4]
|
||||
|
||||
[node name="Main" type="Node"]
|
||||
script = ExtResource( 4 )
|
7
database/database_simple/default_env.tres
Normal file
@ -0,0 +1,7 @@
|
||||
[gd_resource type="Environment3D" load_steps=2 format=3]
|
||||
|
||||
[sub_resource type="ProceduralSky" id=1]
|
||||
|
||||
[resource]
|
||||
background_mode = 2
|
||||
background_sky = SubResource( 1 )
|
BIN
database/database_simple/icon.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
35
database/database_simple/icon.png.import
Normal file
@ -0,0 +1,35 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://icon.png"
|
||||
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.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
|
25
database/database_simple/project.pandemonium
Normal file
@ -0,0 +1,25 @@
|
||||
; 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
|
||||
|
||||
[application]
|
||||
|
||||
config/name="Database Simple"
|
||||
run/main_scene="res://Main.tscn"
|
||||
config/icon="res://icon.png"
|
||||
|
||||
[physics]
|
||||
|
||||
common/enable_pause_aware_picking=true
|
||||
|
||||
[rendering]
|
||||
|
||||
vram_compression/import_etc=true
|
||||
vram_compression/import_etc2=false
|
||||
environment/default_environment="res://default_env.tres"
|
122
database/prepared_statements/Main.gd
Normal file
@ -0,0 +1,122 @@
|
||||
extends Node
|
||||
|
||||
export(String) var database_location : String = "user://database.sqlite"
|
||||
|
||||
func _ready() -> void:
|
||||
DatabaseManager.connect("initialized", self, "on_databases_initialized", [], CONNECT_ONESHOT)
|
||||
|
||||
var d : Directory = Directory.new()
|
||||
var bd : String = database_location.get_base_dir()
|
||||
var loc : String = d.get_filesystem_abspath_for(bd).append_path(database_location.get_file())
|
||||
|
||||
PLogger.log_message("Database file location: " + loc)
|
||||
PLogger.log_message("(Editor->Project->Open User Data Folder)")
|
||||
|
||||
var file : File = File.new()
|
||||
if !file.file_exists(loc):
|
||||
PLogger.log_message("Database file doesn't exists, will run migrations!")
|
||||
PLogger.log_message("(Editor->Project->Open User Data Folder)")
|
||||
call_deferred("migrate")
|
||||
else:
|
||||
DatabaseManager.call_deferred("initialized")
|
||||
|
||||
var db : SQLite3Database = SQLite3Database.new()
|
||||
db.connection_string = loc
|
||||
DatabaseManager.add_database(db)
|
||||
|
||||
func migrate() -> void:
|
||||
PLogger.log_message("Running migrations!")
|
||||
DatabaseManager.connect("migration", self, "_migration")
|
||||
DatabaseManager.migrate(true, false, 0)
|
||||
|
||||
DatabaseManager.call_deferred("initialized")
|
||||
|
||||
func on_databases_initialized() -> void:
|
||||
# Load sessions after the databases are initialized
|
||||
# This happens on the Main node.
|
||||
call_deferred("load_data")
|
||||
|
||||
func _migration(clear: bool, should_seed: bool, pseed: int) -> void:
|
||||
randomize()
|
||||
|
||||
var tb : TableBuilder = DatabaseManager.ddb.get_connection().get_table_builder()
|
||||
|
||||
tb.create_table("data_table");
|
||||
tb.integer("id").auto_increment().next_row();
|
||||
tb.varchar("data_varchar", 60).not_null().next_row();
|
||||
tb.text("data_text").not_null().next_row();
|
||||
tb.integer("data_int").not_null().next_row();
|
||||
tb.real_double("data_double").not_null().next_row();
|
||||
tb.primary_key("id");
|
||||
tb.ccreate_table();
|
||||
tb.run_query();
|
||||
|
||||
print("Running:")
|
||||
print(tb.result)
|
||||
|
||||
var qb : QueryBuilder = DatabaseManager.ddb.get_connection().get_query_builder()
|
||||
qb.insert("data_table", "data_varchar,data_text,data_int,data_double").values()
|
||||
qb.valph().valph().valph().valph()
|
||||
qb.cvalues()
|
||||
qb.end_command()
|
||||
print("Prepared statement:")
|
||||
print(qb.result)
|
||||
|
||||
var ps : PreparedStatement = qb.create_prepared_statement()
|
||||
ps.prepare()
|
||||
|
||||
print("Inserting 10 values!")
|
||||
|
||||
for i in range(10):
|
||||
ps.reset()
|
||||
|
||||
ps.bind_text(1, "vc" + str(randi()))
|
||||
ps.bind_text(2, "text" + str(randi()))
|
||||
ps.bind_int(3, randi())
|
||||
ps.bind_double(4, randf() * 100000)
|
||||
ps.step()
|
||||
|
||||
|
||||
|
||||
func load_data() -> void:
|
||||
print("Querying data from table using prepared statements:")
|
||||
|
||||
var qb : QueryBuilder = DatabaseManager.ddb.get_connection().get_query_builder()
|
||||
|
||||
var qr : QueryResult = qb.select("id").from("data_table").run()
|
||||
|
||||
var ids : PoolIntArray = PoolIntArray()
|
||||
|
||||
while qr.next_row():
|
||||
ids.push_back(qr.get_cell_int(0))
|
||||
|
||||
qb.reset()
|
||||
|
||||
qb.select("id,data_varchar,data_text,data_int,data_double").from("data_table")
|
||||
qb.where().wph("id")
|
||||
qb.end_command()
|
||||
print("Query prepared statement:")
|
||||
print(qb.result)
|
||||
|
||||
var ps : PreparedStatement = qb.create_prepared_statement()
|
||||
ps.prepare()
|
||||
|
||||
print("Querying rows one by one:")
|
||||
for index in ids:
|
||||
ps.reset()
|
||||
|
||||
ps.bind_int(1, index)
|
||||
ps.step()
|
||||
|
||||
print("ps.column_count(): " + str(ps.column_count()))
|
||||
print("id: " + str(ps.column_int(0)))
|
||||
print("data_varchar: " + str(ps.column_text(1)))
|
||||
print("data_text: " + str(ps.column_text(2)))
|
||||
print("data_int: " + str(ps.column_int(3)))
|
||||
print("data_double: " + str(ps.column_double(4)))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
6
database/prepared_statements/Main.tscn
Normal file
@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource path="res://Main.gd" type="Script" id=4]
|
||||
|
||||
[node name="Main" type="Node"]
|
||||
script = ExtResource( 4 )
|
7
database/prepared_statements/default_env.tres
Normal file
@ -0,0 +1,7 @@
|
||||
[gd_resource type="Environment3D" load_steps=2 format=3]
|
||||
|
||||
[sub_resource type="ProceduralSky" id=1]
|
||||
|
||||
[resource]
|
||||
background_mode = 2
|
||||
background_sky = SubResource( 1 )
|
BIN
database/prepared_statements/icon.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
35
database/prepared_statements/icon.png.import
Normal file
@ -0,0 +1,35 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://icon.png"
|
||||
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.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
|
25
database/prepared_statements/project.pandemonium
Normal file
@ -0,0 +1,25 @@
|
||||
; 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
|
||||
|
||||
[application]
|
||||
|
||||
config/name="Database Prepared Statements"
|
||||
run/main_scene="res://Main.tscn"
|
||||
config/icon="res://icon.png"
|
||||
|
||||
[physics]
|
||||
|
||||
common/enable_pause_aware_picking=true
|
||||
|
||||
[rendering]
|
||||
|
||||
vram_compression/import_etc=true
|
||||
vram_compression/import_etc2=false
|
||||
environment/default_environment="res://default_env.tres"
|
23
misc/markdown_renderer/CustomMarkdownRenderer.gd
Normal file
@ -0,0 +1,23 @@
|
||||
extends MarkdownRenderer
|
||||
class_name CustomMarkdownRenderer
|
||||
|
||||
var count : int = 0
|
||||
|
||||
func _renderer_callback(data: MarkdownRendererCustomRendererCallback) -> void:
|
||||
data.result = str(count) + "\n"
|
||||
data.result += "callback_type:" + str(data.callback_type) + "\n"
|
||||
data.result += "text:" + data.text + "\n"
|
||||
data.result += "content:" + data.content + "\n"
|
||||
data.result += "level:" + str(data.level) + "\n"
|
||||
data.result += "list_flags:" + str(data.list_flags) + "\n"
|
||||
data.result += "table_flags:" + str(data.table_flags) + "\n"
|
||||
data.result += "link:" + data.link + "\n"
|
||||
data.result += "auto_link_type:" + str(data.auto_link_type) + "\n"
|
||||
data.result += "title:" + data.title + "\n"
|
||||
data.result += "alt:" + data.alt + "\n"
|
||||
data.result += "num:" + str(data.num) + "\n"
|
||||
data.result += "display_mode:" + str(data.display_mode) + "\n"
|
||||
data.result += "inline_render:" + str(data.inline_render) + "\n"
|
||||
data.result += "\n\n"
|
||||
|
||||
count += 1
|
14
misc/markdown_renderer/CustomRenderer.gd
Normal file
@ -0,0 +1,14 @@
|
||||
extends TextEdit
|
||||
|
||||
|
||||
func _ready():
|
||||
var f : File = File.new()
|
||||
|
||||
var mdr : CustomMarkdownRenderer = CustomMarkdownRenderer.new()
|
||||
mdr.render_type = MarkdownRenderer.RENDERER_TYPE_CUSTOM
|
||||
|
||||
f.open("res://TEST.md", File.READ)
|
||||
|
||||
text = mdr.render(f.get_as_text())
|
||||
|
||||
f.close()
|
31
misc/markdown_renderer/Main.tscn
Normal file
@ -0,0 +1,31 @@
|
||||
[gd_scene load_steps=3 format=3]
|
||||
|
||||
[ext_resource path="res://CustomRenderer.gd" type="Script" id=1]
|
||||
[ext_resource path="res://NormalRenderer.gd" type="Script" id=2]
|
||||
|
||||
[node name="PanelContainer" type="PanelContainer"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
|
||||
[node name="Main" type="HBoxContainer" parent="."]
|
||||
margin_left = 7.0
|
||||
margin_top = 7.0
|
||||
margin_right = 1017.0
|
||||
margin_bottom = 593.0
|
||||
|
||||
[node name="NormalRenderer" type="TextEdit" parent="Main"]
|
||||
margin_right = 503.0
|
||||
margin_bottom = 586.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
wrap_enabled = true
|
||||
script = ExtResource( 2 )
|
||||
|
||||
[node name="CustomRenderer" type="TextEdit" parent="Main"]
|
||||
margin_left = 507.0
|
||||
margin_right = 1010.0
|
||||
margin_bottom = 586.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
wrap_enabled = true
|
||||
script = ExtResource( 1 )
|
13
misc/markdown_renderer/NormalRenderer.gd
Normal file
@ -0,0 +1,13 @@
|
||||
extends TextEdit
|
||||
|
||||
|
||||
func _ready():
|
||||
var f : File = File.new()
|
||||
|
||||
var mdr : MarkdownRenderer = MarkdownRenderer.new()
|
||||
|
||||
f.open("res://TEST.md", File.READ)
|
||||
|
||||
text = mdr.render(f.get_as_text())
|
||||
|
||||
f.close()
|
336
misc/markdown_renderer/TEST.md
Normal file
@ -0,0 +1,336 @@
|
||||
# File
|
||||
|
||||
This is a test file from https://github.com/mxstbr/markdown-test-file/blob/master/TEST.md
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Max Stoiber
|
||||
|
||||
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.
|
||||
|
||||
# Markdown: Syntax
|
||||
|
||||
* [Overview](#overview)
|
||||
* [Philosophy](#philosophy)
|
||||
* [Inline HTML](#html)
|
||||
* [Automatic Escaping for Special Characters](#autoescape)
|
||||
* [Block Elements](#block)
|
||||
* [Paragraphs and Line Breaks](#p)
|
||||
* [Headers](#header)
|
||||
* [Blockquotes](#blockquote)
|
||||
* [Lists](#list)
|
||||
* [Code Blocks](#precode)
|
||||
* [Horizontal Rules](#hr)
|
||||
* [Span Elements](#span)
|
||||
* [Links](#link)
|
||||
* [Emphasis](#em)
|
||||
* [Code](#code)
|
||||
* [Images](#img)
|
||||
* [Miscellaneous](#misc)
|
||||
* [Backslash Escapes](#backslash)
|
||||
* [Automatic Links](#autolink)
|
||||
|
||||
|
||||
**Note:** This document is itself written using Markdown; you
|
||||
can [see the source for it by adding '.text' to the URL](/projects/markdown/syntax.text).
|
||||
|
||||
----
|
||||
|
||||
## Overview
|
||||
|
||||
### Philosophy
|
||||
|
||||
Markdown is intended to be as easy-to-read and easy-to-write as is feasible.
|
||||
|
||||
Readability, however, is emphasized above all else. A Markdown-formatted
|
||||
document should be publishable as-is, as plain text, without looking
|
||||
like it's been marked up with tags or formatting instructions. While
|
||||
Markdown's syntax has been influenced by several existing text-to-HTML
|
||||
filters -- including [Setext](http://docutils.sourceforge.net/mirror/setext.html), [atx](http://www.aaronsw.com/2002/atx/), [Textile](http://textism.com/tools/textile/), [reStructuredText](http://docutils.sourceforge.net/rst.html),
|
||||
[Grutatext](http://www.triptico.com/software/grutatxt.html), and [EtText](http://ettext.taint.org/doc/) -- the single biggest source of
|
||||
inspiration for Markdown's syntax is the format of plain text email.
|
||||
|
||||
## Block Elements
|
||||
|
||||
### Paragraphs and Line Breaks
|
||||
|
||||
A paragraph is simply one or more consecutive lines of text, separated
|
||||
by one or more blank lines. (A blank line is any line that looks like a
|
||||
blank line -- a line containing nothing but spaces or tabs is considered
|
||||
blank.) Normal paragraphs should not be indented with spaces or tabs.
|
||||
|
||||
The implication of the "one or more consecutive lines of text" rule is
|
||||
that Markdown supports "hard-wrapped" text paragraphs. This differs
|
||||
significantly from most other text-to-HTML formatters (including Movable
|
||||
Type's "Convert Line Breaks" option) which translate every line break
|
||||
character in a paragraph into a `<br />` tag.
|
||||
|
||||
When you *do* want to insert a `<br />` break tag using Markdown, you
|
||||
end a line with two or more spaces, then type return.
|
||||
|
||||
### Headers
|
||||
|
||||
Markdown supports two styles of headers, [Setext] [1] and [atx] [2].
|
||||
|
||||
Optionally, you may "close" atx-style headers. This is purely
|
||||
cosmetic -- you can use this if you think it looks better. The
|
||||
closing hashes don't even need to match the number of hashes
|
||||
used to open the header. (The number of opening hashes
|
||||
determines the header level.)
|
||||
|
||||
|
||||
### Blockquotes
|
||||
|
||||
Markdown uses email-style `>` characters for blockquoting. If you're
|
||||
familiar with quoting passages of text in an email message, then you
|
||||
know how to create a blockquote in Markdown. It looks best if you hard
|
||||
wrap the text and put a `>` before every line:
|
||||
|
||||
> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
|
||||
> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
|
||||
> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
|
||||
>
|
||||
> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
|
||||
> id sem consectetuer libero luctus adipiscing.
|
||||
|
||||
Markdown allows you to be lazy and only put the `>` before the first
|
||||
line of a hard-wrapped paragraph:
|
||||
|
||||
> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
|
||||
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
|
||||
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
|
||||
|
||||
> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
|
||||
id sem consectetuer libero luctus adipiscing.
|
||||
|
||||
Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by
|
||||
adding additional levels of `>`:
|
||||
|
||||
> This is the first level of quoting.
|
||||
>
|
||||
> > This is nested blockquote.
|
||||
>
|
||||
> Back to the first level.
|
||||
|
||||
Blockquotes can contain other Markdown elements, including headers, lists,
|
||||
and code blocks:
|
||||
|
||||
> ## This is a header.
|
||||
>
|
||||
> 1. This is the first list item.
|
||||
> 2. This is the second list item.
|
||||
>
|
||||
> Here's some example code:
|
||||
>
|
||||
> return shell_exec("echo $input | $markdown_script");
|
||||
|
||||
Any decent text editor should make email-style quoting easy. For
|
||||
example, with BBEdit, you can make a selection and choose Increase
|
||||
Quote Level from the Text menu.
|
||||
|
||||
|
||||
### Lists
|
||||
|
||||
Markdown supports ordered (numbered) and unordered (bulleted) lists.
|
||||
|
||||
Unordered lists use asterisks, pluses, and hyphens -- interchangably
|
||||
-- as list markers:
|
||||
|
||||
* Red
|
||||
* Green
|
||||
* Blue
|
||||
|
||||
is equivalent to:
|
||||
|
||||
+ Red
|
||||
+ Green
|
||||
+ Blue
|
||||
|
||||
and:
|
||||
|
||||
- Red
|
||||
- Green
|
||||
- Blue
|
||||
|
||||
Ordered lists use numbers followed by periods:
|
||||
|
||||
1. Bird
|
||||
2. McHale
|
||||
3. Parish
|
||||
|
||||
It's important to note that the actual numbers you use to mark the
|
||||
list have no effect on the HTML output Markdown produces. The HTML
|
||||
Markdown produces from the above list is:
|
||||
|
||||
If you instead wrote the list in Markdown like this:
|
||||
|
||||
1. Bird
|
||||
1. McHale
|
||||
1. Parish
|
||||
|
||||
or even:
|
||||
|
||||
3. Bird
|
||||
1. McHale
|
||||
8. Parish
|
||||
|
||||
you'd get the exact same HTML output. The point is, if you want to,
|
||||
you can use ordinal numbers in your ordered Markdown lists, so that
|
||||
the numbers in your source match the numbers in your published HTML.
|
||||
But if you want to be lazy, you don't have to.
|
||||
|
||||
To make lists look nice, you can wrap items with hanging indents:
|
||||
|
||||
* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
|
||||
Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
|
||||
viverra nec, fringilla in, laoreet vitae, risus.
|
||||
* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
|
||||
Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||
|
||||
But if you want to be lazy, you don't have to:
|
||||
|
||||
* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
|
||||
Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
|
||||
viverra nec, fringilla in, laoreet vitae, risus.
|
||||
* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
|
||||
Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||
|
||||
List items may consist of multiple paragraphs. Each subsequent
|
||||
paragraph in a list item must be indented by either 4 spaces
|
||||
or one tab:
|
||||
|
||||
1. This is a list item with two paragraphs. Lorem ipsum dolor
|
||||
sit amet, consectetuer adipiscing elit. Aliquam hendrerit
|
||||
mi posuere lectus.
|
||||
|
||||
Vestibulum enim wisi, viverra nec, fringilla in, laoreet
|
||||
vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
|
||||
sit amet velit.
|
||||
|
||||
2. Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||
|
||||
It looks nice if you indent every line of the subsequent
|
||||
paragraphs, but here again, Markdown will allow you to be
|
||||
lazy:
|
||||
|
||||
* This is a list item with two paragraphs.
|
||||
|
||||
This is the second paragraph in the list item. You're
|
||||
only required to indent the first line. Lorem ipsum dolor
|
||||
sit amet, consectetuer adipiscing elit.
|
||||
|
||||
* Another item in the same list.
|
||||
|
||||
To put a blockquote within a list item, the blockquote's `>`
|
||||
delimiters need to be indented:
|
||||
|
||||
* A list item with a blockquote:
|
||||
|
||||
> This is a blockquote
|
||||
> inside a list item.
|
||||
|
||||
To put a code block within a list item, the code block needs
|
||||
to be indented *twice* -- 8 spaces or two tabs:
|
||||
|
||||
* A list item with a code block:
|
||||
|
||||
<code goes here>
|
||||
|
||||
### Code Blocks
|
||||
|
||||
Pre-formatted code blocks are used for writing about programming or
|
||||
markup source code. Rather than forming normal paragraphs, the lines
|
||||
of a code block are interpreted literally. Markdown wraps a code block
|
||||
in both `<pre>` and `<code>` tags.
|
||||
|
||||
To produce a code block in Markdown, simply indent every line of the
|
||||
block by at least 4 spaces or 1 tab.
|
||||
|
||||
This is a normal paragraph:
|
||||
|
||||
This is a code block.
|
||||
|
||||
Here is an example of AppleScript:
|
||||
|
||||
tell application "Foo"
|
||||
beep
|
||||
end tell
|
||||
|
||||
A code block continues until it reaches a line that is not indented
|
||||
(or the end of the article).
|
||||
|
||||
Within a code block, ampersands (`&`) and angle brackets (`<` and `>`)
|
||||
are automatically converted into HTML entities. This makes it very
|
||||
easy to include example HTML source code using Markdown -- just paste
|
||||
it and indent it, and Markdown will handle the hassle of encoding the
|
||||
ampersands and angle brackets. For example, this:
|
||||
|
||||
<div class="footer">
|
||||
© 2004 Foo Corporation
|
||||
</div>
|
||||
|
||||
Regular Markdown syntax is not processed within code blocks. E.g.,
|
||||
asterisks are just literal asterisks within a code block. This means
|
||||
it's also easy to use Markdown to write about Markdown's own syntax.
|
||||
|
||||
```
|
||||
tell application "Foo"
|
||||
beep
|
||||
end tell
|
||||
```
|
||||
|
||||
## Span Elements
|
||||
|
||||
### Links
|
||||
|
||||
Markdown supports two style of links: *inline* and *reference*.
|
||||
|
||||
In both styles, the link text is delimited by [square brackets].
|
||||
|
||||
To create an inline link, use a set of regular parentheses immediately
|
||||
after the link text's closing square bracket. Inside the parentheses,
|
||||
put the URL where you want the link to point, along with an *optional*
|
||||
title for the link, surrounded in quotes. For example:
|
||||
|
||||
This is [an example](http://example.com/) inline link.
|
||||
|
||||
[This link](http://example.net/) has no title attribute.
|
||||
|
||||
### Emphasis
|
||||
|
||||
Markdown treats asterisks (`*`) and underscores (`_`) as indicators of
|
||||
emphasis. Text wrapped with one `*` or `_` will be wrapped with an
|
||||
HTML `<em>` tag; double `*`'s or `_`'s will be wrapped with an HTML
|
||||
`<strong>` tag. E.g., this input:
|
||||
|
||||
*single asterisks*
|
||||
|
||||
_single underscores_
|
||||
|
||||
**double asterisks**
|
||||
|
||||
__double underscores__
|
||||
|
||||
### Code
|
||||
|
||||
To indicate a span of code, wrap it with backtick quotes (`` ` ``).
|
||||
Unlike a pre-formatted code block, a code span indicates code within a
|
||||
normal paragraph. For example:
|
||||
|
||||
Use the `printf()` function.
|
7
misc/markdown_renderer/default_env.tres
Normal file
@ -0,0 +1,7 @@
|
||||
[gd_resource type="Environment3D" load_steps=2 format=3]
|
||||
|
||||
[sub_resource type="ProceduralSky" id=1]
|
||||
|
||||
[resource]
|
||||
background_mode = 2
|
||||
background_sky = SubResource( 1 )
|
BIN
misc/markdown_renderer/icon.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
35
misc/markdown_renderer/icon.png.import
Normal file
@ -0,0 +1,35 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://icon.png"
|
||||
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.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
|
35
misc/markdown_renderer/project.pandemonium
Normal file
@ -0,0 +1,35 @@
|
||||
; 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": "MarkdownRenderer",
|
||||
"class": @"CustomMarkdownRenderer",
|
||||
"language": @"GDScript",
|
||||
"path": "res://CustomMarkdownRenderer.gd"
|
||||
} ]
|
||||
_global_script_class_icons={
|
||||
@"CustomMarkdownRenderer": ""
|
||||
}
|
||||
|
||||
[application]
|
||||
|
||||
config/name="Markdown Renderer Test"
|
||||
run/main_scene="res://Main.tscn"
|
||||
config/icon="res://icon.png"
|
||||
|
||||
[physics]
|
||||
|
||||
common/enable_pause_aware_picking=true
|
||||
|
||||
[rendering]
|
||||
|
||||
vram_compression/import_etc=true
|
||||
vram_compression/import_etc2=false
|
||||
environment/default_environment="res://default_env.tres"
|
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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
After Width: | Height: | Size: 2.1 KiB |
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
@ -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 |