Compare commits

..

9 Commits

16 changed files with 33879 additions and 76 deletions

BIN
assets/spider/result.bin Normal file

Binary file not shown.

33434
assets/spider/result.gltf Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,53 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://bcsjr6kydgdqy"
path="res://.godot/imported/result.gltf-fa6e7d401ecc486ebc1efbad267cda09.scn"
[deps]
source_file="res://assets/spider/result.gltf"
dest_files=["res://.godot/imported/result.gltf-fa6e7d401ecc486ebc1efbad267cda09.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
_subresources={
"meshes": {
"result_Cube": {
"generate/lightmap_uv": 0,
"generate/lods": 0,
"generate/shadow_meshes": 1,
"lods/normal_merge_angle": 60.0,
"lods/normal_split_angle": 25.0,
"save_to_file/enabled": true,
"save_to_file/path": "res://assets/spider/spider_mesh.res"
}
},
"nodes": {
"PATH:RootNode/SpiderArmature/Skeleton3D": {
"rest_pose/external_animation_library": null
}
}
}
gltf/naming_version=1
gltf/embedded_image_handling=1

Binary file not shown.

View File

@ -17,6 +17,9 @@ var not_dead := true
@export_multiline var death_message : Array[String] @export_multiline var death_message : Array[String]
#@onready var color_rect: ColorRect = $CanvasLayer/ColorRect #@onready var color_rect: ColorRect = $CanvasLayer/ColorRect
func _process(delta: float) -> void:
DebugDraw3D.draw_sphere(position, .5)
func handle_dying(): func handle_dying():
not_dead = false not_dead = false
#weapon_slot_2.queue_free() #weapon_slot_2.queue_free()

View File

@ -0,0 +1,7 @@
extends Resource
class_name ColorHelper
static func get_direction_color(direction: Vector3) -> Color:
var angle = atan2(direction.z, direction.x)
var hue = (angle / (2.0 * PI)) + 0.5
return Color.from_hsv(hue, 1.0, 1.0)

View File

@ -1 +0,0 @@

View File

@ -1,11 +0,0 @@
extends Resource
class_name FlowFieldCell
var position:Vector3 = Vector3(0.0, 0.0, 0.0)
var flow_direction:Vector3 = Vector3(randf(), 0.0, randf())
func debug_process() -> void:
if flow_direction.length() > 0.0:
DebugDraw3D.draw_arrow(position, position + flow_direction, Color(1,1,1,1), 0.1)
else:
DebugDraw3D.draw_sphere(position, .05)

View File

@ -0,0 +1,34 @@
#[compute]
#version 450
// Speicher für FlowField-Daten
layout(std430, set = 0, binding = 0) buffer FlowFieldBuffer {
vec2 flow_field[];
};
// Zielposition und Grid-Daten
layout(push_constant) uniform Params {
vec2 target_pos;
float cell_size;
int grid_size_x;
int grid_size_z;
};
void main(){
uint x = gl_GlobalInvocationID.x;
uint z = gl_GlobalInvocationID.y;
if (x >= grid_size_x || z >= grid_size_z) return;
int index = int(z * grid_size_x + x);
// Zellzentrum berechnen
vec2 cell_center = vec2(x, z) * cell_size + vec2(cell_size * 0.5);
// Richtung zum Ziel berechnen
vec2 direction = normalize(target_pos - cell_center);
// Ergebnis in FlowField speichern
flow_field[index] = direction;
}

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://bf4mkjohkqpox"
path="res://.godot/imported/flow_field_compute.glsl-51e5023d4249c63dbf26c3aa62523e13.res"
[deps]
source_file="res://swarm_engine/flow_field_navigation/flow_field_compute.glsl"
dest_files=["res://.godot/imported/flow_field_compute.glsl-51e5023d4249c63dbf26c3aa62523e13.res"]
[params]

View File

@ -1,71 +1,234 @@
extends Node3D extends Node3D
class_name FlowFieldNav
@export_group("Debug") # https://docs.godotengine.org/cs/4.x/tutorials/shaders/compute_shaders.html#create-a-local-renderingdevice
@export var debugVisu: bool = true # Das Updaten der flow richtung kann auf der grafikkarte gemacht werden mit compute shader
@export var line_color: Color = Color(1, 1, 1, 1)
@export_group("Grid") @export_category("Debug Visualization")
@export var grid_size: int = 10 @export_group("Grid Center")
@export var show_grid_center: bool = false
@export_color_no_alpha var grid_center_color: Color = Color(1, 1, 1, 1)
@export var grid_center_size: float = 0.5
@export_group("Border")
@export var show_border: bool = false
@export_color_no_alpha var border_color: Color = Color(1, 1, 1, 1)
@export_group("Cells")
@export_subgroup("X Lines")
@export var show_x_lines: bool = false
@export_color_no_alpha var x_lines_color: Color = Color(1, 1, 1)
@export_subgroup("Z Lines")
@export var show_z_lines: bool = false
@export_color_no_alpha var z_lines_color: Color = Color(1, 1, 1)
@export_group("Arrows")
@export var show_arrows: bool = false
@export var arrows_size: float = 0.1
@export_color_no_alpha var cell_center_color: Color = Color(1, 1, 1)
@export var cell_center_size: float = 0.2
@export_category("Grid")
@export var cell_size: float = 1.0 @export var cell_size: float = 1.0
@export_group("Grid Size", "grid_size_")
@export var grid_size_x: int = 2
@export var grid_size_z: int = 5
var _cells: Dictionary
var grid_offset: Vector3 @export var target: Node3D = null
var flow_direction_list: Array[Vector2] = []
var half_size_x: float
var half_size_z: float
var rd: RenderingDevice
var shader: RID
var pipeline: RID
var flow_field_buffer: RID
var flow_field_data: PackedVector2Array
func _ready() -> void: func _ready() -> void:
var half_size = (grid_size * cell_size) * 0.5 #var rendering_device := RenderingServer.create_local_rendering_device()
grid_offset = Vector3(-half_size + (cell_size * 0.5), 0, -half_size + (cell_size * 0.5)) #var shader_file := load("res://swarm_engine/flow_field_navigation/flow_field_compute.glsl")
create_grid() #var shader_spirv: RDShaderSPIRV = shader_file.get_spirv()
#var shader_RID := rendering_device.shader_create_from_spirv(shader_spirv)
#
#var center_array: PackedVector3Array
#for x in range(grid_size_x):
#for z in range(grid_size_z):
#center_array.append(_get_cell_center_with_coordinates(x,z))
#
#var center_byte_array = center_array.to_byte_array()
#var storage_buffer_RID = rendering_device.storage_buffer_create(center_byte_array.size(), center_byte_array)
#
#var uniform := RDUniform.new()
#uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER
#uniform.binding = 0
#uniform.add_id(storage_buffer_RID)
#var uniform_set_RID := rendering_device.uniform_set_create([uniform], shader_RID, 0)
#
#var pipeline_RID := rendering_device.compute_pipeline_create(shader_RID)
#var compute_list_id := rendering_device.compute_list_begin()
#
#rendering_device.compute_list_bind_compute_pipeline(compute_list_id, pipeline_RID)
#rendering_device.compute_list_bind_uniform_set(compute_list_id, uniform_set_RID, 0)
#rendering_device.compute_list_dispatch(compute_list_id, 1, 1, 1)
#rendering_device.compute_list_end()
#rendering_device.submit()
func create_grid() -> void: #rd = RenderingServer.get_rendering_device()
_cells.clear() #
for x in range(grid_size): ## Compute Shader laden
for z in range(grid_size): #var shader_file = load("res://swarm_engine/flow_field_navigation/flow_field_compute.glsl")
var cell = FlowFieldCell.new() #shader = rd.shader_create_from_spirv(shader_file.get_spirv())
var world_x = x * cell_size + grid_offset.x #pipeline = rd.compute_pipeline_create(shader)
var world_z = z * cell_size + grid_offset.z #
cell.position = Vector3(world_x, 0, world_z) ## Speicher für FlowField erstellen
_cells[Vector3(x, 0, z)] = cell # Dictionary mit Grid-Koordinaten als Key #var buffer_size = grid_size_x * grid_size_z * 8 # Vector2 -> 2 floats = 8 Bytes pro Eintrag
#flow_field_buffer = rd.storage_buffer_create(buffer_size)
#flow_field_data.resize(grid_size_x * grid_size_z)
#
for x in range(grid_size_x):
for z in range(grid_size_z):
flow_direction_list.append(Vector2(0.0, 0.0))
half_size_x = (grid_size_x * cell_size) * 0.5
half_size_z = (grid_size_z * cell_size) * 0.5
func _process(delta: float) -> void: func _process(delta: float) -> void:
if debugVisu:
_debug_draw_grid()
for cell in _cells.values():
cell.debug_process()
func _debug_draw_grid() -> void: #_update_gpu_flow_field()
for x in range(grid_size + 1): _update_flow_field()
var pos_x = x * cell_size + grid_offset.x - (cell_size * 0.5) _draw_debug()
DebugDraw3D.draw_line(Vector3(pos_x, 0, grid_offset.z - (cell_size * 0.5)), Vector3(pos_x, 0, grid_offset.z + grid_size * cell_size - (cell_size * 0.5)), line_color)
for z in range(grid_size + 1): func _update_gpu_flow_field():
var pos_z = z * cell_size + grid_offset.z - (cell_size * 0.5) if not target:
DebugDraw3D.draw_line(Vector3(grid_offset.x - (cell_size * 0.5), 0, pos_z), Vector3(grid_offset.x + grid_size * cell_size - (cell_size * 0.5), 0, pos_z), line_color) return
# Push-Constants für Shader setzen
var push_constants = PackedByteArray()
push_constants.append_array(PackedByteArray([
target.position.x,
target.position.z,
cell_size,
float(grid_size_x),
float(grid_size_z)
]))
# GPU Command erstellen
var compute_list = rd.compute_list_begin()
rd.compute_list_bind_compute_pipeline(compute_list, pipeline)
rd.compute_list_bind_storage_buffer(compute_list, flow_field_buffer, 0, 0)
rd.compute_list_set_push_constant(compute_list, push_constants, 0)
rd.compute_list_dispatch(compute_list, grid_size_x, grid_size_z, 1)
rd.compute_list_end()
# GPU Berechnung starten
rd.submit()
rd.sync()
# Daten von der GPU zurückholen
var buffer_data = rd.buffer_get_data(flow_field_buffer)
var output = buffer_data.to_float32_array()
# 2D-Array für FlowField initialisieren
flow_direction_list = []
for x in range(grid_size_x):
flow_direction_list.append([]) # Erstellt leere Arrays für jede X-Spalte
# Konvertiere die 1D-GPU-Daten in ein 2D-Array
for z in range(grid_size_z):
for x in range(grid_size_x):
var index = (z * grid_size_x + x) * 2 # 2 Floats pro Vector2
var flow_vector = Vector2(output[index], output[index + 1])
flow_direction_list[index] = flow_vector
func _update_flow_field():
if target != null:
for x in range(grid_size_x):
for z in range(grid_size_z):
var index = z * grid_size_x + x
var flow_direction = (target.position - _get_cell_center_with_coordinates(x,z)).normalized() * (cell_size/2)
flow_direction_list[index] = Vector2(flow_direction.x, flow_direction.z)
var target_index = _get_index_from_position(target.position)
flow_direction_list[target_index] = Vector2(0, 0)
# Gibt die Zelle basierend auf einer Weltposition zurück func _draw_debug():
func get_cell_from_pos(world_pos: Vector3) -> FlowFieldCell: if show_grid_center:
var grid_x = int((world_pos.x - grid_offset.x) / cell_size) DebugDraw3D.draw_sphere(position, grid_center_size, grid_center_color)
var grid_z = int((world_pos.z - grid_offset.z) / cell_size) if show_border:
var cell_pos = Vector3(grid_x, 0, grid_z) _draw_border()
return _cells.get(cell_pos, null) if show_x_lines:
_draw_x_lines()
if show_z_lines:
_draw_z_lines()
# Raycast zur Bestimmung der Zelle unter dem Mauszeiger if show_arrows:
func _input(event): _draw_arrows()
if event is InputEventMouseButton and event.pressed:
var camera = get_viewport().get_camera_3d()
var from = camera.project_ray_origin(get_viewport().get_mouse_position())
var to = from + camera.project_ray_normal(get_viewport().get_mouse_position()) * 1000
var space_state = get_world_3d().direct_space_state func _draw_border():
var query = PhysicsRayQueryParameters3D.create(from, to) var top_left = position - Vector3(half_size_x, 0 , half_size_z)
var result = space_state.intersect_ray(query) var top_right = position + Vector3(half_size_x, 0, -half_size_z)
var bottom_left = position - Vector3(half_size_x, 0, -half_size_z)
var bottom_right = position + Vector3(half_size_x, 0, half_size_z)
if result.has("position"): var lines: PackedVector3Array
var cell = get_cell_from_pos(result["position"]) lines.append_array(PackedVector3Array([top_left, top_right]))
if cell: lines.append_array(PackedVector3Array([top_right, bottom_right]))
print("Zelle an", cell.position, ":", cell.flow_direction) lines.append_array(PackedVector3Array([bottom_right, bottom_left]))
lines.append_array(PackedVector3Array([bottom_left, top_left]))
DebugDraw3D.draw_lines(lines, border_color)
func _draw_x_lines():
var lines: PackedVector3Array
for x in range(grid_size_x - 1):
var start = position - Vector3(half_size_x - ((x + 1) * cell_size), 0, half_size_z)
var end = position - Vector3(half_size_x - ((x + 1) * cell_size), 0, -half_size_z)
lines.append_array(PackedVector3Array([start, end]))
DebugDraw3D.draw_lines(lines, x_lines_color)
func _draw_z_lines():
var lines: PackedVector3Array
for z in range(grid_size_z - 1):
var start = position - Vector3(half_size_x, 0, half_size_z - ((z + 1) * cell_size))
var end = position - Vector3(-half_size_x, 0, half_size_z - ((z + 1) * cell_size))
lines.append_array(PackedVector3Array([start, end]))
DebugDraw3D.draw_lines(lines, z_lines_color)
func _draw_arrows():
var points: PackedVector3Array
for x in range(grid_size_x):
for z in range(grid_size_z):
var cell_center = _get_cell_center_with_coordinates(x,z)
var index = z * grid_size_x + x
if flow_direction_list[index].length() > 0.0:
var direction = Vector3(flow_direction_list[index].x, 0, flow_direction_list[index].y).normalized()
var arrow_end = cell_center + direction * (cell_size * 0.4)
DebugDraw3D.draw_arrow(cell_center, arrow_end, ColorHelper.get_direction_color(direction), arrows_size)
else: else:
print("Keine Zelle gefunden!") points.append(cell_center)
DebugDraw3D.draw_points(points, DebugDraw3D.POINT_TYPE_SQUARE, cell_center_size, cell_center_color)
func _get_cell_center_with_coordinates(x:int, z:int) -> Vector3:
return position + Vector3(
(-half_size_x + (x * cell_size) + (cell_size * 0.5)),
0,
(-half_size_z + (z * cell_size) + (cell_size * 0.5)))
func _get_coordinates_from_position(pos: Vector3) -> Vector2i:
return Vector2i(int((pos.x - position.x + half_size_x) / cell_size),
int((pos.z - position.z + half_size_z) / cell_size))
func _get_index_from_position(pos: Vector3) -> int:
var pos_coord = _get_coordinates_from_position(pos)
if _is_coordinate_valid(pos_coord):
return -1
return pos_coord.y * grid_size_x + pos_coord.x
func _is_coordinate_valid(coord: Vector2i) -> bool:
return coord.x < 0 or coord.x >= grid_size_x or coord.y < 0 or coord.y >= grid_size_z
func get_direction_from_position(position: Vector3) -> Vector3:
var index = _get_index_from_position(position)
return Vector3(flow_direction_list[index].x, 0, flow_direction_list[index].y)

View File

@ -1 +0,0 @@
extends Node3D

View File

@ -1,20 +1,71 @@
[gd_scene load_steps=3 format=3 uid="uid://bwo12me8h21q5"] [gd_scene load_steps=6 format=3 uid="uid://bwo12me8h21q5"]
[ext_resource type="Script" path="res://swarm_engine/swarm_engine_debug_level.gd" id="1_f0ttr"]
[ext_resource type="PackedScene" uid="uid://cn2xvs2g7box5" path="res://swarm_engine/flow_field_navigation/flow_field_navigation.tscn" id="1_xwcpn"] [ext_resource type="PackedScene" uid="uid://cn2xvs2g7box5" path="res://swarm_engine/flow_field_navigation/flow_field_navigation.tscn" id="1_xwcpn"]
[ext_resource type="PackedScene" uid="uid://cdau7qryen3uq" path="res://swarm_engine/swarm_unit/swarm_unit.tscn" id="3_6kohq"]
[ext_resource type="PackedScene" uid="uid://dycbdcrwsm6wu" path="res://experimente/felox/player.tscn" id="6_wayso"]
[sub_resource type="PlaneMesh" id="PlaneMesh_3dwe5"]
size = Vector2(400, 400)
[sub_resource type="ConvexPolygonShape3D" id="ConvexPolygonShape3D_vtddf"]
points = PackedVector3Array(-200, 0, -200, -200, 0, 200, 200, 0, -200, 200, 0, 200)
[node name="World" type="Node3D"] [node name="World" type="Node3D"]
script = ExtResource("1_f0ttr")
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] [node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(-0.866023, -0.433016, 0.250001, 0, 0.499998, 0.866027, -0.500003, 0.749999, -0.43301, 0, 0, 0) transform = Transform3D(-0.866023, -0.433016, 0.250001, 0, 0.499998, 0.866027, -0.500003, 0.749999, -0.43301, 0, 0, 0)
shadow_enabled = true shadow_enabled = true
[node name="FlowFieldNavigation" parent="." instance=ExtResource("1_xwcpn")] [node name="FlowFieldNavigation" parent="." node_paths=PackedStringArray("target") instance=ExtResource("1_xwcpn")]
grid_size = 100 unique_name_in_owner = true
cell_size = 2.0 show_grid_center = true
grid_center_color = Color(0, 0.0833333, 1, 1)
show_border = true
show_x_lines = true
x_lines_color = Color(1, 0.45, 0, 1)
show_z_lines = true
z_lines_color = Color(1, 0, 0.0166664, 1)
show_arrows = true
cell_center_color = Color(0.702375, 0.0507974, 0.96251, 1)
cell_size = 4.0
grid_size_x = 50
grid_size_z = 50
target = NodePath("../player")
[node name="CSGSphere3D" type="CSGSphere3D" parent="FlowFieldNavigation"] [node name="MeshInstance3D" type="MeshInstance3D" parent="."]
mesh = SubResource("PlaneMesh_3dwe5")
[node name="Camera3D" type="Camera3D" parent="."] [node name="StaticBody3D" type="StaticBody3D" parent="MeshInstance3D"]
transform = Transform3D(1, 0, 0, 0, 0.331371, 0.943501, 0, -0.943501, 0.331371, 0, 13.203, 5.65752)
[node name="CollisionShape3D" type="CollisionShape3D" parent="MeshInstance3D/StaticBody3D"]
shape = SubResource("ConvexPolygonShape3D_vtddf")
[node name="player" parent="." instance=ExtResource("6_wayso")]
unique_name_in_owner = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 3.50529)
[node name="Camera3D" type="Camera3D" parent="player"]
unique_name_in_owner = true
transform = Transform3D(1, 0, 0, 0, 0.707107, 0.707107, 0, -0.707107, 0.707107, 0, 10, 8)
[node name="Node3D" type="Node3D" parent="."]
[node name="SwarmUnit" parent="Node3D" node_paths=PackedStringArray("flow_field_navigation") instance=ExtResource("3_6kohq")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.0338392, 0, -41.7085)
move_speed = 4
flow_field_navigation = NodePath("../../FlowFieldNavigation")
[node name="SwarmUnit2" parent="Node3D" node_paths=PackedStringArray("flow_field_navigation") instance=ExtResource("3_6kohq")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -17.4426, 0, -41.7085)
move_speed = 4
flow_field_navigation = NodePath("../../FlowFieldNavigation")
[node name="SwarmUnit3" parent="Node3D" node_paths=PackedStringArray("flow_field_navigation") instance=ExtResource("3_6kohq")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.0338392, 0, -58.7671)
move_speed = 4
flow_field_navigation = NodePath("../../FlowFieldNavigation")
[node name="SwarmUnit4" parent="Node3D" node_paths=PackedStringArray("flow_field_navigation") instance=ExtResource("3_6kohq")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -17.4426, 0, -58.7671)
move_speed = 4
flow_field_navigation = NodePath("../../FlowFieldNavigation")

View File

@ -0,0 +1,36 @@
extends MultiMeshInstance3D
@export var move_speed = 2
@export var number: int = 100
@export var stretch: int = 2
@onready var flow_field_navigation: FlowFieldNav = %FlowFieldNavigation
@onready var player: Player = %player
func _ready() -> void:
for x in range(number):
for z in range(number):
var index = z * number + x
self.multimesh.set_instance_transform(index, Transform3D(Basis(), Vector3(x * stretch, 0.0, -z * stretch)))
func _process(delta: float) -> void:
for x in range(number):
for z in range(number):
var index = z * number + x
var current_trans = self.multimesh.get_instance_transform(index)
var cell = flow_field_navigation.get_cell_from_pos(current_trans.origin)
if cell != null and cell.flow_direction.length() > 0.0:
var movement = cell.flow_direction.normalized() * move_speed * delta
current_trans.origin += movement
var direction_to_player = (player.position - current_trans.origin).normalized()
var target_rotation_y = Quaternion(Vector3.UP, atan2(-direction_to_player.x, -direction_to_player.z))
var fix_rotation_x = Quaternion(Vector3.RIGHT, deg_to_rad(-90))
var fix_rotation_y_180 = Quaternion(Vector3.UP, deg_to_rad(180))
var final_rotation = fix_rotation_y_180 * target_rotation_y * fix_rotation_x
current_trans.basis = Basis(final_rotation)
self.multimesh.set_instance_transform(index, current_trans)

View File

@ -0,0 +1,10 @@
extends CharacterBody3D
@export var move_speed = 2
@export var flow_field_navigation: FlowFieldNav
func _physics_process(delta: float) -> void:
var flow_direction = flow_field_navigation.get_direction_from_position(position)
if flow_direction.length() > 0.0:
var movement = flow_direction.normalized() * move_speed * delta
position += movement

View File

@ -0,0 +1,11 @@
[gd_scene load_steps=3 format=3 uid="uid://cdau7qryen3uq"]
[ext_resource type="Script" path="res://swarm_engine/swarm_unit/swarm_unit.gd" id="1_eynce"]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_o8sb1"]
[node name="SwarmUnit" type="CharacterBody3D"]
script = ExtResource("1_eynce")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
shape = SubResource("CapsuleShape3D_o8sb1")