add bug mesh - colorize flowfield - very simple enemy - and first test with multimesh

This commit is contained in:
Henrik Neumann 2025-02-22 18:47:06 +01:00
parent 690940a6c3
commit b9c94eeed6
13 changed files with 408 additions and 35 deletions

BIN
assets/bug/bug_mesh.res Normal file

Binary file not shown.

11
assets/bug/license.txt Normal file
View File

@ -0,0 +1,11 @@
Model Information:
* title: Bug
* source: https://sketchfab.com/3d-models/bug-3f3e2ed9e31c4fff9e44637173514d7b
* author: Miguel Atienza (https://sketchfab.com/miguelatienza93)
Model License:
* license type: CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
* requirements: Author must be credited. Commercial use is allowed.
If you use this 3D model in your project be sure to copy paste this credit wherever you share it:
This work is based on "Bug" (https://sketchfab.com/3d-models/bug-3f3e2ed9e31c4fff9e44637173514d7b) by Miguel Atienza (https://sketchfab.com/miguelatienza93) licensed under CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)

BIN
assets/bug/scene.bin Normal file

Binary file not shown.

173
assets/bug/scene.gltf Normal file
View File

@ -0,0 +1,173 @@
{
"accessors": [
{
"bufferView": 1,
"componentType": 5126,
"count": 49086,
"max": [
1.9926960468292236,
2.4550979137420654,
0.9601231217384338
],
"min": [
-1.9935812950134277,
-5.510632038116455,
-1.192002773284912
],
"type": "VEC3"
},
{
"bufferView": 1,
"byteOffset": 589032,
"componentType": 5126,
"count": 49086,
"max": [
0.9999630451202393,
0.9999982118606567,
0.9999945759773254
],
"min": [
-0.99997478723526,
-0.9999390244483948,
-0.999993085861206
],
"type": "VEC3"
},
{
"bufferView": 2,
"componentType": 5126,
"count": 49086,
"max": [
0.9882352948188782,
0.6352941393852234,
0.6431372761726379,
1.0
],
"min": [
0.0,
0.0,
0.0,
1.0
],
"type": "VEC4"
},
{
"bufferView": 0,
"componentType": 5125,
"count": 292026,
"type": "SCALAR"
}
],
"asset": {
"extras": {
"author": "Miguel Atienza (https://sketchfab.com/miguelatienza93)",
"license": "CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)",
"source": "https://sketchfab.com/3d-models/bug-3f3e2ed9e31c4fff9e44637173514d7b",
"title": "Bug"
},
"generator": "Sketchfab-12.68.0",
"version": "2.0"
},
"bufferViews": [
{
"buffer": 0,
"byteLength": 1168104,
"name": "floatBufferViews",
"target": 34963
},
{
"buffer": 0,
"byteLength": 1178064,
"byteOffset": 1168104,
"byteStride": 12,
"name": "floatBufferViews",
"target": 34962
},
{
"buffer": 0,
"byteLength": 785376,
"byteOffset": 2346168,
"byteStride": 16,
"name": "floatBufferViews",
"target": 34962
}
],
"buffers": [
{
"byteLength": 3131544,
"uri": "scene.bin"
}
],
"materials": [
{
"doubleSided": true,
"name": "Scene_-_Root",
"pbrMetallicRoughness": {
"metallicFactor": 0.0,
"roughnessFactor": 0.6
}
}
],
"meshes": [
{
"name": "Object_0",
"primitives": [
{
"attributes": {
"COLOR_0": 2,
"NORMAL": 1,
"POSITION": 0
},
"indices": 3,
"material": 0,
"mode": 4
}
]
}
],
"nodes": [
{
"children": [
1
],
"matrix": [
-2.220446049250313e-16,
-6.123234262925839e-17,
1.0,
0.0,
1.0,
1.6081226229577287e-16,
2.2204460492503136e-16,
0.0,
-1.6081226229577292e-16,
1.0,
6.123234262925839e-17,
0.0,
1.5273232460021973,
-8.953146193411835e-17,
1.5282138586044312,
1.0
],
"name": "Sketchfab_model"
},
{
"children": [
2
],
"name": "bug.OBJ.cleaner.materialmerger.gles"
},
{
"mesh": 0,
"name": "Object_2"
}
],
"scene": 0,
"scenes": [
{
"name": "Sketchfab_Scene",
"nodes": [
0
]
}
]
}

View File

@ -0,0 +1,48 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://be1j1x6skha50"
path="res://.godot/imported/scene.gltf-40b9b7639a7cec48946880b758e17814.scn"
[deps]
source_file="res://assets/bug/scene.gltf"
dest_files=["res://.godot/imported/scene.gltf-40b9b7639a7cec48946880b758e17814.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": {
"Sketchfab_Scene_Object_0": {
"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/bug/bug_mesh.res"
}
}
}
gltf/naming_version=1
gltf/embedded_image_handling=1

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()

24
swarm_engine/bug.gd Normal file
View File

@ -0,0 +1,24 @@
extends Node3D
@onready var flow_field_navigation: FlowFieldNav = %FlowFieldNavigation
@export var move_speed = 3
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
DebugDraw3D.draw_sphere(position, .5)
var cell = flow_field_navigation.get_cell_from_pos(position)
if cell.flow_direction.length() > 0.0:
# Normalisierte Bewegung in Flow-Richtung
var movement = cell.flow_direction.normalized() * move_speed * delta
global_transform.origin += movement # Position aktualisierennormalized() * speed
# Rotation: Gegner schaut in Bewegungsrichtung (XZ-Ebene)
var target_rotation = Quaternion(Vector3.UP, atan2(-cell.flow_direction.x, -cell.flow_direction.z))
global_transform.basis = Basis(target_rotation)

View File

@ -1,11 +1,31 @@
extends Resource extends Resource
class_name FlowFieldCell class_name FlowFieldCell
var position:Vector3 = Vector3(0.0, 0.0, 0.0) @export var cell_size: float = 1.0
var flow_direction:Vector3 = Vector3(randf(), 0.0, randf()) @export var position: Vector3 = Vector3.ZERO
var flow_direction: Vector3 = Vector3.ZERO
var is_target:bool = false
func update(targetPos: Vector3):
if is_target:
flow_direction = Vector3.ZERO
return
if targetPos != position:
flow_direction = (targetPos - position).normalized() * (cell_size/2)
else:
flow_direction = Vector3.ZERO
func debug_process() -> void: func debug_process() -> void:
if flow_direction.length() > 0.0: if flow_direction.length() > 0.0:
DebugDraw3D.draw_arrow(position, position + flow_direction, Color(1,1,1,1), 0.1) var arrow_color = get_direction_color(flow_direction.normalized())
DebugDraw3D.draw_arrow(position, position + flow_direction, arrow_color, 0.1)
else: else:
DebugDraw3D.draw_sphere(position, .05) DebugDraw3D.draw_sphere(position, 0.05)
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,4 +1,8 @@
extends Node3D extends Node3D
class_name FlowFieldNav
@onready var player: Player = %player
@export_group("Debug") @export_group("Debug")
@export var debugVisu: bool = true @export var debugVisu: bool = true
@ -11,11 +15,28 @@ extends Node3D
var _cells: Dictionary var _cells: Dictionary
var grid_offset: Vector3 var grid_offset: Vector3
var target_position: Vector3
var target_cell: FlowFieldCell
var lines: PackedVector3Array
func _ready() -> void: func _ready() -> void:
var half_size = (grid_size * cell_size) * 0.5 var half_size = (grid_size * cell_size) * 0.5
grid_offset = Vector3(-half_size + (cell_size * 0.5), 0, -half_size + (cell_size * 0.5)) grid_offset = Vector3(-half_size + (cell_size * 0.5), 0, -half_size + (cell_size * 0.5))
create_grid() create_grid()
# Vertikale Linien
for x in range(grid_size + 1):
var pos_x = x * cell_size + grid_offset.x - (cell_size * 0.5)
lines.append(Vector3(pos_x, 0, grid_offset.z - (cell_size * 0.5)))
lines.append(Vector3(pos_x, 0, grid_offset.z + grid_size * cell_size - (cell_size * 0.5)))
# Horizontale Linien
for z in range(grid_size + 1):
var pos_z = z * cell_size + grid_offset.z - (cell_size * 0.5)
lines.append(Vector3(grid_offset.x - (cell_size * 0.5), 0, pos_z))
lines.append(Vector3(grid_offset.x + grid_size * cell_size - (cell_size * 0.5), 0, pos_z))
func create_grid() -> void: func create_grid() -> void:
_cells.clear() _cells.clear()
for x in range(grid_size): for x in range(grid_size):
@ -24,48 +45,36 @@ func create_grid() -> void:
var world_x = x * cell_size + grid_offset.x var world_x = x * cell_size + grid_offset.x
var world_z = z * cell_size + grid_offset.z var world_z = z * cell_size + grid_offset.z
cell.position = Vector3(world_x, 0, world_z) cell.position = Vector3(world_x, 0, world_z)
cell.cell_size = cell_size
_cells[Vector3(x, 0, z)] = cell # Dictionary mit Grid-Koordinaten als Key _cells[Vector3(x, 0, z)] = cell # Dictionary mit Grid-Koordinaten als Key
func _process(delta: float) -> void: func _process(delta: float) -> void:
target_position = Vector3(player.position.x, 0, player.position.z)
var new_target_cell = get_cell_from_pos(target_position)
if target_cell != null and target_cell != new_target_cell:
target_cell.is_target = false
new_target_cell.is_target = true
target_cell = new_target_cell
else:
target_cell = new_target_cell
target_cell.is_target = true
if debugVisu: if debugVisu:
_debug_draw_grid() _debug_draw_grid()
for cell in _cells.values(): for cell in _cells.values():
cell.debug_process() cell.debug_process()
for cell in _cells.values():
cell.update(target_position)
func _debug_draw_grid() -> void: func _debug_draw_grid() -> void:
for x in range(grid_size + 1): DebugDraw3D.draw_lines(lines, line_color)
var pos_x = x * cell_size + grid_offset.x - (cell_size * 0.5)
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):
var pos_z = z * cell_size + grid_offset.z - (cell_size * 0.5)
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)
# Gibt die Zelle basierend auf einer Weltposition zurück
func get_cell_from_pos(world_pos: Vector3) -> FlowFieldCell: func get_cell_from_pos(world_pos: Vector3) -> FlowFieldCell:
var grid_x = int((world_pos.x - grid_offset.x) / cell_size) var grid_x = int((world_pos.x - grid_offset.x) / cell_size)
var grid_z = int((world_pos.z - grid_offset.z) / cell_size) var grid_z = int((world_pos.z - grid_offset.z) / cell_size)
var cell_pos = Vector3(grid_x, 0, grid_z) var cell_pos = Vector3(grid_x, 0, grid_z)
return _cells.get(cell_pos, null) return _cells.get(cell_pos, null)
# Raycast zur Bestimmung der Zelle unter dem Mauszeiger
func _input(event):
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
var query = PhysicsRayQueryParameters3D.create(from, to)
var result = space_state.intersect_ray(query)
if result.has("position"):
var cell = get_cell_from_pos(result["position"])
if cell:
print("Zelle an", cell.position, ":", cell.flow_direction)
else:
print("Keine Zelle gefunden!")

View File

@ -0,0 +1,23 @@
extends MultiMeshInstance3D
@export var speed = 5;
@export var number: int = 100
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, 0.0, -z)))
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)
# Rotation um die Y-Achse (delta für gleichmäßige Drehung)
var rotation_amount = deg_to_rad(10) * delta # 10 Grad pro Sekunde
current_trans.basis = current_trans.basis.rotated(Vector3.UP, rotation_amount)
self.multimesh.set_instance_transform(index, current_trans)

View File

@ -1,5 +1,6 @@
extends Node3D extends Node3D
@onready var camera_3d: Camera3D = %Camera3D
func _process(delta: float) -> void: func _process(delta: float) -> void:
DebugDraw2D.set_text("Frames drawn", Engine.get_frames_drawn()) DebugDraw2D.set_text("Frames drawn", Engine.get_frames_drawn())

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,11 @@
[gd_scene load_steps=3 format=3 uid="uid://ck0ymixmnj446"]
[ext_resource type="Script" path="res://swarm_engine/bug.gd" id="1_ql2rg"]
[ext_resource type="PackedScene" uid="uid://be1j1x6skha50" path="res://assets/bug/scene.gltf" id="2_0pswm"]
[node name="Bug" type="Node3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.85631, 13.4907)
script = ExtResource("1_ql2rg")
[node name="Sketchfab_Scene" parent="." instance=ExtResource("2_0pswm")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -1.5, 0, -1.5)