commit fa38e603a1b78e8feb7670710ac110ce3ec7f6a2 Author: Jonas Reith Date: Wed Aug 26 19:05:30 2026 +0200 Initial commit: WayfarersWanderer project state Godot 4.6 exploration game with player movement, step-rotation camera rig, and POI interaction system (explore/rest/close menu). main.tscn is a test scene with placeholder props; debug/ holds unwired terrain prototypes (voxel river, procedural island mesh, cross-shaped hub diff --git a/.editorconfig b/.editorconfig new file mode 100755 index 0000000..f28239b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +root = true + +[*] +charset = utf-8 diff --git a/.gitattributes b/.gitattributes new file mode 100755 index 0000000..8ad74f7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Normalize EOL for all files that Git considers text files. +* text=auto eol=lf diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..0af181c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# Godot 4+ specific ignores +.godot/ +/android/ diff --git a/assets/debug/checkerboard.png b/assets/debug/checkerboard.png new file mode 100755 index 0000000..dde451a Binary files /dev/null and b/assets/debug/checkerboard.png differ diff --git a/assets/debug/checkerboard.png.import b/assets/debug/checkerboard.png.import new file mode 100755 index 0000000..9f838f2 --- /dev/null +++ b/assets/debug/checkerboard.png.import @@ -0,0 +1,41 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c3ajv7vb8c4fb" +path.s3tc="res://.godot/imported/checkerboard.png-4dad1517039036e2382fd0e75874c867.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://assets/debug/checkerboard.png" +dest_files=["res://.godot/imported/checkerboard.png-4dad1517039036e2382fd0e75874c867.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/assets/models/forest.glb b/assets/models/forest.glb new file mode 100644 index 0000000..1750919 Binary files /dev/null and b/assets/models/forest.glb differ diff --git a/assets/models/forest.glb.import b/assets/models/forest.glb.import new file mode 100644 index 0000000..f24416f --- /dev/null +++ b/assets/models/forest.glb.import @@ -0,0 +1,42 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://be2uq7ixlbv6b" +path="res://.godot/imported/forest.glb-afdae727313ccf3677ce0399e0a685a4.scn" + +[deps] + +source_file="res://assets/models/forest.glb" +dest_files=["res://.godot/imported/forest.glb-afdae727313ccf3677ce0399e0a685a4.scn"] + +[params] + +nodes/root_type="StaticBody3D" +nodes/root_name="" +nodes/root_script=null +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +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="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 diff --git a/assets/models/forest_tree_greenv1.png b/assets/models/forest_tree_greenv1.png new file mode 100644 index 0000000..3a9c657 Binary files /dev/null and b/assets/models/forest_tree_greenv1.png differ diff --git a/assets/models/forest_tree_greenv1.png.import b/assets/models/forest_tree_greenv1.png.import new file mode 100644 index 0000000..0e2aad1 --- /dev/null +++ b/assets/models/forest_tree_greenv1.png.import @@ -0,0 +1,44 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://2lcgru3xuc8" +path.s3tc="res://.godot/imported/forest_tree_greenv1.png-41eb1d87b8c434eab69a5036447034b0.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} +generator_parameters={ +"md5": "2a028cc382b673f5e99d7e8ee1469ea2" +} + +[deps] + +source_file="res://assets/models/forest_tree_greenv1.png" +dest_files=["res://.godot/imported/forest_tree_greenv1.png-41eb1d87b8c434eab69a5036447034b0.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/assets/models/mountain.glb b/assets/models/mountain.glb new file mode 100644 index 0000000..6015d15 Binary files /dev/null and b/assets/models/mountain.glb differ diff --git a/assets/models/mountain.glb.import b/assets/models/mountain.glb.import new file mode 100644 index 0000000..fa6036e --- /dev/null +++ b/assets/models/mountain.glb.import @@ -0,0 +1,42 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://dmhs1oy1kh6hi" +path="res://.godot/imported/mountain.glb-8b287651a1bb38426cf17e1af324657c.scn" + +[deps] + +source_file="res://assets/models/mountain.glb" +dest_files=["res://.godot/imported/mountain.glb-8b287651a1bb38426cf17e1af324657c.scn"] + +[params] + +nodes/root_type="StaticBody3D" +nodes/root_name="" +nodes/root_script=null +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +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="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 diff --git a/assets/models/mountain2v5.glb b/assets/models/mountain2v5.glb new file mode 100644 index 0000000..9ae19f1 Binary files /dev/null and b/assets/models/mountain2v5.glb differ diff --git a/assets/models/mountain2v5.glb.import b/assets/models/mountain2v5.glb.import new file mode 100644 index 0000000..30e15b8 --- /dev/null +++ b/assets/models/mountain2v5.glb.import @@ -0,0 +1,42 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://gl4qpk4wto1e" +path="res://.godot/imported/mountain2v5.glb-cc550bf83dc570ce62fc6eaf2007f3e5.scn" + +[deps] + +source_file="res://assets/models/mountain2v5.glb" +dest_files=["res://.godot/imported/mountain2v5.glb-cc550bf83dc570ce62fc6eaf2007f3e5.scn"] + +[params] + +nodes/root_type="StaticBody3D" +nodes/root_name="" +nodes/root_script=null +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +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="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 diff --git a/assets/sprites/enviroment/Brown-gray_ruins2.png b/assets/sprites/enviroment/Brown-gray_ruins2.png new file mode 100755 index 0000000..a78f8a9 Binary files /dev/null and b/assets/sprites/enviroment/Brown-gray_ruins2.png differ diff --git a/assets/sprites/enviroment/Brown-gray_ruins2.png.import b/assets/sprites/enviroment/Brown-gray_ruins2.png.import new file mode 100755 index 0000000..fbe0957 --- /dev/null +++ b/assets/sprites/enviroment/Brown-gray_ruins2.png.import @@ -0,0 +1,41 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c0u8xjymrfw2x" +path.s3tc="res://.godot/imported/Brown-gray_ruins2.png-84005ae1fb5515afcbec8705a5b236e9.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://assets/sprites/enviroment/Brown-gray_ruins2.png" +dest_files=["res://.godot/imported/Brown-gray_ruins2.png-84005ae1fb5515afcbec8705a5b236e9.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/assets/sprites/player/debug_player.png b/assets/sprites/player/debug_player.png new file mode 100755 index 0000000..437e2a6 Binary files /dev/null and b/assets/sprites/player/debug_player.png differ diff --git a/assets/sprites/player/debug_player.png.import b/assets/sprites/player/debug_player.png.import new file mode 100755 index 0000000..957886e --- /dev/null +++ b/assets/sprites/player/debug_player.png.import @@ -0,0 +1,41 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://epcqli428yem" +path.s3tc="res://.godot/imported/debug_player.png-3f02112dbaffc1fe27016269e0bd44e1.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://assets/sprites/player/debug_player.png" +dest_files=["res://.godot/imported/debug_player.png-3f02112dbaffc1fe27016269e0bd44e1.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/camera_rig.gd b/camera_rig.gd new file mode 100755 index 0000000..0d00f63 --- /dev/null +++ b/camera_rig.gd @@ -0,0 +1,77 @@ +extends Node3D + +@export var target: NodePath # Player-Pfad hier im Inspector setzen! +@export var rotation_step: float = 45.0 # 360/8 Steps +@export var rotation_speed: float = 3.0 # Smooth-Rotation +@export var zoom_min: float = 4.0 +@export var zoom_max: float = 20.0 +@export var zoom_step: float = 1.5 +@export var mouse_sensitivity: float = 0.3 + +var _target_node: Node3D +var _current_zoom: float = 10.0 +var _target_rotation_y: float = 0.0 +var _mouse_rotating: bool = false + +@onready var arm: Node3D = $CameraArm +@onready var camera: Camera3D = $CameraArm/Camera3D + +func _ready() -> void: + _target_node = get_node(target) + _current_zoom = camera.position.z + +func _input(event: InputEvent) -> void: + # Maus-Scroll Zoom + if event is InputEventMouseButton: + if event.button_index == MOUSE_BUTTON_WHEEL_UP: + _current_zoom = clamp(_current_zoom - zoom_step, zoom_min, zoom_max) + elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN: + _current_zoom = clamp(_current_zoom + zoom_step, zoom_min, zoom_max) + # Rechte Maustaste für Maus-Kamerarotation + elif event.button_index == MOUSE_BUTTON_RIGHT: + _mouse_rotating = event.pressed + Input.set_mouse_mode( + Input.MOUSE_MODE_CAPTURED if _mouse_rotating else Input.MOUSE_MODE_VISIBLE + ) + + # Maus-Bewegung → Kamera-Rotation + if event is InputEventMouseMotion and _mouse_rotating: + _target_rotation_y -= event.relative.x * mouse_sensitivity + +func _process(delta: float) -> void: + if not _target_node: + return + + # Kamera folgt Player (Position) + #global_position = global_position.lerp(_target_node.global_position, 10.0 * delta) + global_position = _target_node.global_position # Kein Lerp, exakt folgen + + # Step-Rotation (Q/E + LB/RB) + if Input.is_action_just_pressed("cam_rotate_left"): + _target_rotation_y += rotation_step + if Input.is_action_just_pressed("cam_rotate_right"): + _target_rotation_y -= rotation_step + + # Rechter Stick X → kontinuierliche Rotation + # var stick_x = Input.get_axis("", "") # → siehe Hinweis unten + # Füge in Input Map "cam_rotate_analog_left/right" für Stick hinzu + # var stick_x = Input.get_axis("cam_rotate_analog_left", "cam_rotate_analog_right") + # _target_rotation_y -= stick_x * rotation_speed * delta * 100 + + # Controller Trigger Zoom + var zoom_in_val = Input.get_action_strength("zoom_in") + var zoom_out_val = Input.get_action_strength("zoom_out") + _current_zoom = clamp( + _current_zoom - (zoom_in_val - zoom_out_val) * zoom_step * delta * 5, + zoom_min, zoom_max + ) + + # Rotation smoothen + rotation_degrees.y = lerp_angle( + deg_to_rad(rotation_degrees.y), + deg_to_rad(_target_rotation_y), + rotation_speed * delta + ) * (180.0 / PI) + + # Zoom anwenden + camera.position.z = lerp(camera.position.z, _current_zoom, 10.0 * delta) diff --git a/camera_rig.gd.uid b/camera_rig.gd.uid new file mode 100755 index 0000000..357af39 --- /dev/null +++ b/camera_rig.gd.uid @@ -0,0 +1 @@ +uid://b0y06y7c0bihj diff --git a/debug/FreeCam.gd b/debug/FreeCam.gd new file mode 100644 index 0000000..af438b7 --- /dev/null +++ b/debug/FreeCam.gd @@ -0,0 +1,34 @@ +extends Node3D + +@export var fly_speed : float = 20.0 +@export var fast_speed : float = 60.0 +@export var sensitivity: float = 0.003 + +var yaw : float = PI +var pitch : float = -0.38 +var captured: bool = false + +func _unhandled_input(e: InputEvent) -> void: + if e is InputEventMouseButton and e.button_index == MOUSE_BUTTON_RIGHT: + captured = e.pressed + Input.set_mouse_mode( + Input.MOUSE_MODE_CAPTURED if captured else Input.MOUSE_MODE_VISIBLE) + if e is InputEventMouseMotion and captured: + yaw -= e.relative.x * sensitivity + pitch = clamp(pitch - e.relative.y * sensitivity, -1.4, 0.2) + rotation = Vector3(pitch, yaw, 0) + if e is InputEventKey and e.pressed and e.keycode == KEY_ESCAPE: + captured = false + Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) + +func _process(delta: float) -> void: + var spd := fast_speed if Input.is_key_pressed(KEY_SHIFT) else fly_speed + var move := Vector3.ZERO + if Input.is_key_pressed(KEY_W): move -= global_transform.basis.z + if Input.is_key_pressed(KEY_S): move += global_transform.basis.z + if Input.is_key_pressed(KEY_A): move -= global_transform.basis.x + if Input.is_key_pressed(KEY_D): move += global_transform.basis.x + if Input.is_key_pressed(KEY_E): move += Vector3.UP + if Input.is_key_pressed(KEY_Q): move -= Vector3.UP + if move.length_squared() > 0: + position += move.normalized() * spd * delta diff --git a/debug/FreeCam.gd.uid b/debug/FreeCam.gd.uid new file mode 100644 index 0000000..e15c86a --- /dev/null +++ b/debug/FreeCam.gd.uid @@ -0,0 +1 @@ +uid://bia8axed2ndwj diff --git a/debug/Grenze.gd b/debug/Grenze.gd new file mode 100644 index 0000000..dd94268 --- /dev/null +++ b/debug/Grenze.gd @@ -0,0 +1,271 @@ +extends Node3D + +@export var berg_scale : float = .002 + +# Welt-Parameter +const ISLAND_RADIUS : float = 512.0 +const GRID : float = 1.0 # 1m pro Block +const CORRIDOR_WIDTH : int = 3 # Korridor-Breite in Blöcken +const CENTER_RADIUS : float = 120.0 # Radius Mittelzone + +# Pass-Position: Anteil vom Rand der Mittelzone (0=Mitte, 1=Inselrand) +# 0.35 = ca. erstes Drittel ab Mittelzone Richtung Rand +const PASS_POS : float = 0.35 +const PASS_WIDTH : int = 3 # Lücke in Blöcken + +func _ready() -> void: + _spawn_kreuz() + _spawn_mittelring() + _spawn_ozean() + +# ═══════════════════════════════════════════════════════════════ +# KREUZ — 4 Arme: Nord, Süd, West = Berge | Ost = Fluss +# ═══════════════════════════════════════════════════════════════ +func _spawn_kreuz() -> void: + # Jeder Arm geht von CENTER_RADIUS bis ISLAND_RADIUS + _spawn_arm_berge("Nord", Vector3( 0, 0, -1)) + _spawn_arm_berge("Sued", Vector3( 0, 0, 1)) + _spawn_arm_berge("West", Vector3(-1, 0, 0)) + _spawn_arm_fluss("Ost", Vector3( 1, 0, 0)) + +# ── Berg-Arm ───────────────────────────────────────────────── +func _spawn_arm_berge(label: String, dir: Vector3) -> void: + var grp := Node3D.new() + grp.name = "Arm_" + label + add_child(grp) + + var perp := dir.cross(Vector3.UP).normalized() + var arm_len := ISLAND_RADIUS - CENTER_RADIUS + var steps := int(arm_len / GRID) + + # Pass-Bereich berechnen (in Steps ab Mittelzone) + var pass_start := int(steps * PASS_POS) + var pass_end := pass_start + PASS_WIDTH + + # Große Berg-Modelle vorbauen + var large_meshes := _make_large_berge() + var small_meshes := _make_small_berge() + + for step in range(steps): + # Position entlang des Arms + var dist := CENTER_RADIUS + step * GRID + GRID * 0.5 + var center := dir * dist + + var in_pass := (step >= pass_start and step < pass_end) + + for col in range(-CORRIDOR_WIDTH / 2, CORRIDOR_WIDTH / 2 + 1): + var pos := center + perp * (col * GRID) + pos.y = 0.0 + + if in_pass: + # Im Pass: nur außen kleine Berge, Mitte frei + if abs(col) == CORRIDOR_WIDTH / 2: + _place_berg(grp, pos, small_meshes) + # col == 0 → frei (Durchgang) + else: + # Außenreihen → kleine Berge dicht + if abs(col) >= 1: + _place_berg(grp, pos, small_meshes) + # Mittelreihe → große Berge + else: + _place_berg(grp, pos, large_meshes) + + # Pass-Marker (Platzhalter Tor) + var pass_dist := CENTER_RADIUS + (pass_start + PASS_WIDTH * 0.5) * GRID + var pass_center := dir * pass_dist + _spawn_pass_marker(grp, pass_center) + +func _place_berg(parent: Node3D, pos: Vector3, meshes: Array) -> void: + var mi := MeshInstance3D.new() + mi.mesh = meshes[randi() % meshes.size()] + mi.position = pos + # Zufällige Y-Rotation für Abwechslung + mi.rotation.y = randf() * TAU + parent.add_child(mi) + +# ── Fluss-Arm ──────────────────────────────────────────────── +func _spawn_arm_fluss(label: String, dir: Vector3) -> void: + var grp := Node3D.new() + grp.name = "Arm_" + label + add_child(grp) + + var arm_len := ISLAND_RADIUS - CENTER_RADIUS + var steps := int(arm_len / GRID) + + var pass_start := int(steps * PASS_POS) + var pass_end := pass_start + PASS_WIDTH + + var mat_wasser := StandardMaterial3D.new() + mat_wasser.albedo_color = Color(0.18, 0.45, 0.78) + mat_wasser.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + + for step in range(steps): + var dist := CENTER_RADIUS + step * GRID + GRID * 0.5 + var pos := dir * dist + pos.y = -0.5 # 1m tief eingeschnitten + + var in_pass := (step >= pass_start and step < pass_end) + + if in_pass: + # Brücken-Block + _spawn_bruecke_block(grp, dir * dist) + else: + # Fluss-Block: 1x1m Wasser + var mi := MeshInstance3D.new() + var box := BoxMesh.new() + box.size = Vector3(GRID, GRID, GRID) + box.surface_set_material(0, mat_wasser) + mi.mesh = box + mi.position = pos + mi.name = "Fluss_" + str(step) + grp.add_child(mi) + +func _spawn_bruecke_block(parent: Node3D, pos: Vector3) -> void: + var mi := MeshInstance3D.new() + var box := BoxMesh.new() + box.size = Vector3(GRID * 3.0, 0.3, GRID * 3.0) + var mat := StandardMaterial3D.new() + mat.albedo_color = Color(0.55, 0.45, 0.32) + mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + box.surface_set_material(0, mat) + mi.mesh = box + mi.position = pos + Vector3(0, 0.65, 0) + mi.name = "Bruecke" + parent.add_child(mi) + +# ── Pass-Marker ─────────────────────────────────────────────── +func _spawn_pass_marker(parent: Node3D, pos: Vector3) -> void: + var mi := MeshInstance3D.new() + var box := BoxMesh.new() + box.size = Vector3(2.0, 4.0, 2.0) + var mat := StandardMaterial3D.new() + mat.albedo_color = Color(0.85, 0.78, 0.40) + mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + box.surface_set_material(0, mat) + mi.mesh = box + mi.position = pos + Vector3(0, 2.0, 0) + mi.name = "PassMarker" + parent.add_child(mi) + +# ═══════════════════════════════════════════════════════════════ +# MITTELRING — Bergring um die Mittelzone +# ═══════════════════════════════════════════════════════════════ +func _spawn_mittelring() -> void: + var grp := Node3D.new() + grp.name = "Mittelring" + add_child(grp) + + var large_meshes := _make_large_berge() + var small_meshes := _make_small_berge() + + # Umfang des Kreises in 1m-Schritten + var circumference := TAU * CENTER_RADIUS + var steps := int(circumference / GRID) + + # Die 4 Kreuz-Arme blockieren bestimmte Winkel → dort Pässe + # Arm-Winkel: Nord=270°, Süd=90°, West=180°, Ost=0° + var arm_angles := [0.0, PI * 0.5, PI, PI * 1.5] + var pass_half := (float(PASS_WIDTH) * GRID) / CENTER_RADIUS # Winkel-Halbbreite + + for step in range(steps): + var angle := float(step) / steps * TAU + + # Prüfen ob dieser Winkel in einem Arm-Durchgang liegt + var in_arm := false + for arm_a in arm_angles: + var diff: float = abs(angle_difference(angle, arm_a)) + if diff < pass_half * 1.5: + in_arm = true + break + + # Innenring (dicht am Center_radius) + var r_inner := CENTER_RADIUS - 1.0 + var pos_i := Vector3(cos(angle)*r_inner, 0, sin(angle)*r_inner) + # Außenring + var r_outer := CENTER_RADIUS + 2.0 + var pos_o := Vector3(cos(angle)*r_outer, 0, sin(angle)*r_outer) + + if not in_arm: + _place_berg(grp, pos_i, large_meshes) + _place_berg(grp, pos_o, small_meshes) + +# Hilfsfunktion: Winkel-Differenz -PI..PI +func angle_difference(a: float, b: float) -> float: + var d := fmod(a - b + TAU, TAU) + if d > PI: d -= TAU + return d + +# ═══════════════════════════════════════════════════════════════ +# BERG-MODELLE — prozedural, mehrere Varianten +# ═══════════════════════════════════════════════════════════════ +func _make_large_berge() -> Array: + var result := [] + # 4 große Varianten: breiter, massiver + var configs := [ + [8.0, 0.05, 22.0, 6], + [10.0, 0.05, 18.0, 7], + [7.0, 0.05, 26.0, 5], + [12.0, 0.05, 20.0, 8], + ] + for cfg in configs: + result.append(_make_berg_mesh(cfg[0], cfg[1], cfg[2] * berg_scale, int(cfg[3]), false)) + return result + +func _make_small_berge() -> Array: + var result := [] + # 6 kleine Varianten: schmaler, dichter packbar + var configs := [ + [3.0, 0.02, 10.0, 5], + [2.5, 0.02, 8.0, 6], + [4.0, 0.02, 12.0, 5], + [2.0, 0.02, 7.0, 4], + [3.5, 0.02, 11.0, 6], + [2.8, 0.02, 9.0, 5], + ] + for cfg in configs: + result.append(_make_berg_mesh(cfg[0], cfg[1], cfg[2], int(cfg[3]), true)) + return result + +func _make_berg_mesh(bot_r: float, top_r: float, h: float, + sides: int, small: bool) -> Mesh: + var st := SurfaceTool.new() + st.begin(Mesh.PRIMITIVE_TRIANGLES) + + var tip := Vector3(0, h, 0) + var gray := randf_range(0.35, 0.55) if not small else randf_range(0.40, 0.58) + var col := Color(gray, gray * 0.97, gray * 0.93) + var col_b := Color(gray * 0.7, gray * 0.68, gray * 0.65) + + for s in range(sides): + var a0 := float(s) / sides * TAU + var a1 := float(s+1) / sides * TAU + var b0 := Vector3(cos(a0)*bot_r, 0, sin(a0)*bot_r) + var b1 := Vector3(cos(a1)*bot_r, 0, sin(a1)*bot_r) + var t0 := Vector3(cos(a0)*top_r, h, sin(a0)*top_r) + var t1 := Vector3(cos(a1)*top_r, h, sin(a1)*top_r) + + # Seite + var n := (b1 - b0).cross(tip - b0).normalized() + st.set_normal(n); st.set_color(col) + st.add_vertex(b0); st.add_vertex(tip); st.add_vertex(b1) + # Boden-Cap + st.set_normal(Vector3(0,-1,0)); st.set_color(col_b) + st.add_vertex(Vector3(0,0,0)); st.add_vertex(b1); st.add_vertex(b0) + + return st.commit() + +# ═══════════════════════════════════════════════════════════════ +# OZEAN unter der Insel +# ═══════════════════════════════════════════════════════════════ +func _spawn_ozean() -> void: + var mi := MeshInstance3D.new() + var plane := PlaneMesh.new() + plane.size = Vector2(4096, 4096) + var mat := StandardMaterial3D.new() + mat.albedo_color = Color(0.08, 0.25, 0.52) + mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + plane.surface_set_material(0, mat) + mi.mesh = plane + mi.position = Vector3(0, -40, 0) + mi.name = "Ozean" + add_child(mi) diff --git a/debug/Grenze.gd.uid b/debug/Grenze.gd.uid new file mode 100644 index 0000000..22a9b55 --- /dev/null +++ b/debug/Grenze.gd.uid @@ -0,0 +1 @@ +uid://cql864jt4i24 diff --git a/debug/IslandMesh.gd b/debug/IslandMesh.gd new file mode 100644 index 0000000..7bd7c58 --- /dev/null +++ b/debug/IslandMesh.gd @@ -0,0 +1,100 @@ +extends Node3D + +@export var radius : float = 1024.0 +@export var segments: int = 128 +@export var seed_val: int = 42 +@export var erosion : float = 0.18 + +func _ready() -> void: + _build() + +func _build() -> void: + var noise := FastNoiseLite.new() + noise.seed = seed_val + noise.noise_type = FastNoiseLite.TYPE_SIMPLEX_SMOOTH + noise.frequency = 0.008 + + var st := SurfaceTool.new() + st.begin(Mesh.PRIMITIVE_TRIANGLES) + var verts: PackedVector3Array = [] + var colrs: PackedColorArray = [] + var seg := segments + + for i in range(seg + 1): + for j in range(seg + 1): + var u := float(i) / seg + var v := float(j) / seg + var angle := u * TAU + var r := v * radius + var en := 1.0 + noise.get_noise_2d( + cos(angle) * 80.0, + sin(angle) * 80.0) * erosion + var x := cos(angle) * r * en + var z := sin(angle) * r * en + var dn := r / radius + # Komplett flach — nur Rand fällt ab + var y := -6.0 * pow(dn, 6.0) + verts.append(Vector3(x, y, z)) + colrs.append(_col(dn)) + + for i in range(seg): + for j in range(seg): + var idx := i * (seg + 1) + j + var a := idx; var b := idx + 1 + var c := idx+(seg+1); var d := idx+(seg+1)+1 + var n := (verts[b]-verts[a]).cross(verts[c]-verts[a]).normalized() + for vtx in [a, b, c]: + st.set_normal(n); st.set_color(colrs[vtx]) + st.add_vertex(verts[vtx]) + for vtx in [b, d, c]: + st.set_normal(n); st.set_color(colrs[vtx]) + st.add_vertex(verts[vtx]) + + var mesh := st.commit() + var mat := StandardMaterial3D.new() + mat.vertex_color_use_as_albedo = true + mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + mesh.surface_set_material(0, mat) + var mi := MeshInstance3D.new() + mi.mesh = mesh + add_child(mi) + + _build_underside() + +func _col(dn: float) -> Color: + if dn > 0.93: return Color(0.45, 0.38, 0.28) # Erdrand + if dn > 0.85: return Color(0.38, 0.55, 0.25) # Gras außen + return Color(0.42, 0.65, 0.30) # Gras + +func _build_underside() -> void: + var st := SurfaceTool.new() + st.begin(Mesh.PRIMITIVE_TRIANGLES) + var seg := 80 + var bot := Vector3(0, -18.0, 0) + var noise := FastNoiseLite.new() + noise.seed = seed_val + 1 + for i in range(seg): + var a0 := float(i) / seg * TAU + var a1 := float(i+1) / seg * TAU + var r := radius * 0.9 + var e0 := 1.0 + noise.get_noise_2d(cos(a0)*80, sin(a0)*80) * erosion + var e1 := 1.0 + noise.get_noise_2d(cos(a1)*80, sin(a1)*80) * erosion + var p0 := Vector3(cos(a0)*r*e0, -2.0, sin(a0)*r*e0) + var p1 := Vector3(cos(a1)*r*e1, -2.0, sin(a1)*r*e1) + var col := Color(0.30, 0.25, 0.18) + st.set_color(col); st.set_normal(Vector3(0,-1,0)) + st.add_vertex(bot); st.add_vertex(p1); st.add_vertex(p0) + # Seite + var t0 := Vector3(p0.x, 0.0, p0.z) + var t1 := Vector3(p1.x, 0.0, p1.z) + st.add_vertex(p0); st.add_vertex(t0); st.add_vertex(p1) + st.add_vertex(t0); st.add_vertex(t1); st.add_vertex(p1) + var mesh := st.commit() + var mat := StandardMaterial3D.new() + mat.vertex_color_use_as_albedo = true + mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + mat.cull_mode = BaseMaterial3D.CULL_DISABLED + mesh.surface_set_material(0, mat) + var mi := MeshInstance3D.new() + mi.mesh = mesh + add_child(mi) diff --git a/debug/IslandMesh.gd.uid b/debug/IslandMesh.gd.uid new file mode 100644 index 0000000..2017f65 --- /dev/null +++ b/debug/IslandMesh.gd.uid @@ -0,0 +1 @@ +uid://d0xuftjl5xssi diff --git a/debug/fluss_proto.tscn b/debug/fluss_proto.tscn new file mode 100644 index 0000000..78a1aac --- /dev/null +++ b/debug/fluss_proto.tscn @@ -0,0 +1,22 @@ +[gd_scene format=3 uid="uid://cidsmilm68b5q"] + +[ext_resource type="PackedScene" uid="uid://dljjlqptwc2a2" path="res://player.tscn" id="1_ei44b"] +[ext_resource type="Script" uid="uid://syb1gkanuju7" path="res://debug/voxel.gd" id="1_iosed"] +[ext_resource type="Script" uid="uid://bia8axed2ndwj" path="res://debug/FreeCam.gd" id="2_sjo6i"] + +[node name="FlussProto" type="Node3D" unique_id=962938880] + +[node name="Player" parent="." unique_id=1949521754 instance=ExtResource("1_ei44b")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.98786944, 4.5496826, 4.1674347) + +[node name="Voxel" type="Node3D" parent="." unique_id=1517507308] +script = ExtResource("1_iosed") + +[node name="FlyCamera2" type="Node3D" parent="." unique_id=409666653] +transform = Transform3D(1, 0, 0, 0, 0.92718387, 0.3746066, 0, -0.3746066, 0.92718387, 0, 20, 40) +script = ExtResource("2_sjo6i") + +[node name="Camera3D" type="Camera3D" parent="FlyCamera2" unique_id=808390848] +fov = 65.0 +near = 0.1 +far = 1000.0 diff --git a/debug/flying_island.tscn b/debug/flying_island.tscn new file mode 100644 index 0000000..78984cb --- /dev/null +++ b/debug/flying_island.tscn @@ -0,0 +1,36 @@ +[gd_scene format=3 uid="uid://xes77y1x72b6"] + +[ext_resource type="Script" uid="uid://bia8axed2ndwj" path="res://debug/FreeCam.gd" id="1_idwjx"] +[ext_resource type="Script" uid="uid://d0xuftjl5xssi" path="res://debug/IslandMesh.gd" id="2_obm1k"] +[ext_resource type="Script" uid="uid://cql864jt4i24" path="res://debug/Grenze.gd" id="3_3bsno"] + +[sub_resource type="Environment" id="Environment_obm1k"] +background_mode = 1 +background_color = Color(0.16470589, 0.25490198, 0.36078432, 1) +ambient_light_source = 2 +ambient_light_color = Color(0.23529412, 0.25490198, 0.29411766, 1) +ambient_light_energy = 0.8 + +[node name="FlyingIsland" type="Node3D" unique_id=1133718991] + +[node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=1194180535] +environment = SubResource("Environment_obm1k") + +[node name="Sun" type="DirectionalLight3D" parent="." unique_id=919416523] +transform = Transform3D(0.8660254, -0.35355338, 0.35355338, 0, 0.70710677, 0.70710677, -0.5, -0.6123724, 0.6123724, 0, 0, 0) +light_energy = 1.2 + +[node name="FlyCamera" type="Node3D" parent="." unique_id=86070119] +transform = Transform3D(1, 0, 0, 0, 0.92718387, 0.3746066, 0, -0.3746066, 0.92718387, 0, 60, 120) +script = ExtResource("1_idwjx") + +[node name="Camera3D" type="Camera3D" parent="FlyCamera" unique_id=1353892435] +fov = 65.0 +near = 0.1 +far = 1000.0 + +[node name="IslandMesh" type="Node3D" parent="." unique_id=1416580731] +script = ExtResource("2_obm1k") + +[node name="Grenze" type="Node3D" parent="." unique_id=139532892] +script = ExtResource("3_3bsno") diff --git a/debug/voxel.gd b/debug/voxel.gd new file mode 100644 index 0000000..1dc9183 --- /dev/null +++ b/debug/voxel.gd @@ -0,0 +1,134 @@ +extends Node3D + +const W := 10 # Breite X +const D := 10 # Tiefe Z +const H := 3 # Höhe Y + +# Fluss läuft entlang Z, mittig auf X +const FLUSS_X := 5 # Welche X-Spalte (0-basiert, Mitte = 4 oder 5) +const FLUSS_TIEFE := 2 # Wie viele Blöcke von oben rausgenommen +const WASSER_Y := 0 # Y-Index wo Wasser sitzt (unterster Block des Grabens) + +# Materialien — einmal erstellen, mehrfach nutzen +var mat_erde : StandardMaterial3D +var mat_gras : StandardMaterial3D +var mat_wasser : ShaderMaterial + +func _ready() -> void: + _make_materials() + _build() + +# ═══════════════════════════════════════════════ +# MATERIALIEN +# ═══════════════════════════════════════════════ +func _make_materials() -> void: + mat_erde = StandardMaterial3D.new() + mat_erde.albedo_color = Color(0.38, 0.26, 0.16) + mat_erde.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + + mat_gras = StandardMaterial3D.new() + mat_gras.albedo_color = Color(0.35, 0.60, 0.22) + mat_gras.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + + # Wasser-Shader + var shader := Shader.new() + shader.code = """ +shader_type spatial; +render_mode unshaded, cull_disabled, blend_mix; + +uniform vec4 color_shallow : source_color = vec4(0.2, 0.55, 0.85, 0.75); +uniform vec4 color_deep : source_color = vec4(0.1, 0.35, 0.70, 0.90); +uniform float speed : hint_range(0.0, 2.0) = 0.6; +uniform float wave_scale : hint_range(0.1, 5.0) = 1.5; + +void fragment() { + vec2 uv = UV * wave_scale + vec2(TIME * speed, TIME * speed * 0.4); + float wave = sin(uv.x * 6.28) * 0.5 + 0.5; + wave += sin(uv.y * 6.28 * 1.3 + TIME * speed) * 0.3; + wave = clamp(wave * 0.5, 0.0, 1.0); + ALBEDO = mix(color_shallow.rgb, color_deep.rgb, wave); + ALPHA = mix(color_shallow.a, color_deep.a, wave); +} +""" + mat_wasser = ShaderMaterial.new() + mat_wasser.shader = shader + +# ═══════════════════════════════════════════════ +# WELT BAUEN +# ═══════════════════════════════════════════════ +func _build() -> void: + for x in range(W): + for z in range(D): + _build_spalte(x, z) + +func _build_spalte(x: int, z: int) -> void: + var ist_fluss := (x == FLUSS_X) + + for y in range(H): + # Fluss-Graben: oberste FLUSS_TIEFE Blöcke fehlen + if ist_fluss and y >= (H - FLUSS_TIEFE): + continue + + var mat : StandardMaterial3D + if y == H - 1 and not ist_fluss: + mat = mat_gras # Oberste Schicht = Gras + else: + mat = mat_erde # Alles darunter = Erde + + _place_block(Vector3(x, y, z), mat) + + # Wasser in den Graben + if ist_fluss: + var wasser_y := H - FLUSS_TIEFE # Wasser sitzt auf dem Boden des Grabens + _place_wasser(Vector3(x, wasser_y, z)) + + # Wasserfall: wo Fluss auf Z-Rand trifft + if ist_fluss and (z == 0 or z == D - 1): + _spawn_wasserfall(x, z) + +# ═══════════════════════════════════════════════ +# BLÖCKE PLATZIEREN +# ═══════════════════════════════════════════════ +func _place_block(pos: Vector3, mat: StandardMaterial3D) -> void: + var mi := MeshInstance3D.new() + var box := BoxMesh.new() + box.size = Vector3(1, 1, 1) + box.surface_set_material(0, mat) + mi.mesh = box + mi.position = pos + Vector3(0.5, 0.5, 0.5) # Pivot unten-links + add_child(mi) + +func _place_wasser(pos: Vector3) -> void: + var mi := MeshInstance3D.new() + var box := BoxMesh.new() + # Wasser etwas flacher als 1m damit man Tiefe sieht + box.size = Vector3(1.0, 0.65, 1.0) + box.surface_set_material(0, mat_wasser) + mi.mesh = box + mi.position = pos + Vector3(0.5, 0.33, 0.5) + mi.transparency = 0.3 + add_child(mi) + +# ═══════════════════════════════════════════════ +# WASSERFALL +# ═══════════════════════════════════════════════ +func _spawn_wasserfall(x: int, z: int) -> void: + # Vertikale Wasser-Plane von Graben-Unterkante bis Boden + var fall_h := float(H - FLUSS_TIEFE) # Höhe des Falls + var mi := MeshInstance3D.new() + var quad := QuadMesh.new() + quad.size = Vector2(1.0, fall_h) + quad.surface_set_material(0, mat_wasser) + mi.mesh = quad + + # Positionierung: Außenkante der Platte + var dir_z := -1.0 if z == 0 else 1.0 + mi.position = Vector3( + x + 0.5, + fall_h * 0.5, # Vertikal zentriert + z + 0.5 * dir_z # Außenkante + ) + # Plane zeigt nach außen + mi.rotation.y = 0.0 if z == D - 1 else PI + + add_child(mi) diff --git a/debug/voxel.gd.uid b/debug/voxel.gd.uid new file mode 100644 index 0000000..77ada88 --- /dev/null +++ b/debug/voxel.gd.uid @@ -0,0 +1 @@ +uid://syb1gkanuju7 diff --git a/interaction_manager.gd b/interaction_manager.gd new file mode 100755 index 0000000..ff7a495 --- /dev/null +++ b/interaction_manager.gd @@ -0,0 +1,59 @@ +extends Node + +signal interaction_opened +signal interaction_closed + +var active: bool = false +var current_poi: Node = null + +func open_poi(poi: Node) -> void: + active = true + current_poi = poi + InteractionUI.show_menu(poi.poi_name, _get_main_options()) + +func _get_main_options() -> Array: + return [ + { "label": "Erkunden", "action": "explore" }, + { "label": "Ausruhen", "action": "rest" }, + { "label": "Beenden", "action": "close" }, + ] + +func handle_selection(action: String) -> void: + match action: + "explore": + InteractionUI.show_menu("Erkunden", _get_explore_options()) + "rest": + InteractionUI.show_text("Du rastest eine Weile...\nDu fühlst dich erholt.") + "close": + close() + +func handle_explore(action: String) -> void: + match action: + "track_follow": + var success = randf() > 0.5 + if success: + InteractionUI.show_text("Du folgst den Spuren...\nEine seltene Tierbeobachtung!") + else: + InteractionUI.show_text("Du folgst den Spuren...\nDas Tier ist verschwunden.") + "track_leave": + close() + +func _get_explore_options() -> Array: + # Zufälliges Ereignis beim Erkunden + var roll = randf() + if roll < 0.5: + InteractionUI.show_text("Du findest Tierspuren!") + return [ + { "label": "Tier verfolgen", "action": "track_follow" }, + { "label": "In Ruhe lassen", "action": "track_leave" }, + ] + else: + InteractionUI.show_text("Nichts Besonderes zu finden.") + return [ + { "label": "Zurück", "action": "close" }, + ] + +func close() -> void: + active = false + current_poi = null + InteractionUI.hide_menu() diff --git a/interaction_manager.gd.uid b/interaction_manager.gd.uid new file mode 100755 index 0000000..f815713 --- /dev/null +++ b/interaction_manager.gd.uid @@ -0,0 +1 @@ +uid://cbg1abspfwgxo diff --git a/interaction_ui.gd b/interaction_ui.gd new file mode 100755 index 0000000..535a8a9 --- /dev/null +++ b/interaction_ui.gd @@ -0,0 +1,68 @@ +extends CanvasLayer + +@onready var panel = $Panel +@onready var title_label = $Panel/TitleLabel +@onready var message_label = $Panel/MessageLabel +@onready var option_container = $Panel/OptionContainer +@onready var hint_label = $Panel/HintLabel + +var current_options: Array = [] +var selected_index: int = 0 +var mode: String = "menu" # "menu" oder "text" + +func _ready() -> void: + panel.visible = false + +func show_menu(title: String, options: Array) -> void: + mode = "menu" + panel.visible = true + title_label.text = title + message_label.text = "" + hint_label.text = "[ESC/B] Beenden" + current_options = options + selected_index = 0 + _rebuild_options() + +func show_text(text: String) -> void: + mode = "text" + message_label.text = text + hint_label.text = "[F/A] Weiter [ESC/B] Beenden" + _clear_options() + +func hide_menu() -> void: + panel.visible = false + current_options = [] + +func _rebuild_options() -> void: + _clear_options() + for i in current_options.size(): + var btn = Button.new() + btn.text = current_options[i]["label"] + btn.focus_mode = Control.FOCUS_ALL + option_container.add_child(btn) + var action = current_options[i]["action"] + btn.pressed.connect(_on_option_pressed.bind(action)) + # Ersten Button fokussieren + if option_container.get_child_count() > 0: + option_container.get_child(0).grab_focus() + +func _clear_options() -> void: + for child in option_container.get_children(): + child.queue_free() + +func _on_option_pressed(action: String) -> void: + # Unterscheiden ob wir im Erkunden-Submenu sind + if action in ["track_follow", "track_leave"]: + InteractionManager.handle_explore(action) + else: + InteractionManager.handle_selection(action) + +func _input(event: InputEvent) -> void: + if not panel.visible: + return + if Input.is_action_just_pressed("cancel"): + InteractionManager.close() + # Im Text-Mode mit F/A weiterklicken + if mode == "text" and Input.is_action_just_pressed("interact"): + # Zurück zum Hauptmenü + InteractionManager.open_poi(InteractionManager.current_poi) diff --git a/interaction_ui.gd.uid b/interaction_ui.gd.uid new file mode 100755 index 0000000..abb3b56 --- /dev/null +++ b/interaction_ui.gd.uid @@ -0,0 +1 @@ +uid://dv2w4x8t53ym diff --git a/interaction_ui.tscn b/interaction_ui.tscn new file mode 100755 index 0000000..e5dc802 --- /dev/null +++ b/interaction_ui.tscn @@ -0,0 +1,57 @@ +[gd_scene format=3 uid="uid://cmg2008xfel2v"] + +[ext_resource type="Script" uid="uid://dv2w4x8t53ym" path="res://interaction_ui.gd" id="1_y37vg"] + +[node name="InteractionUI" type="CanvasLayer" unique_id=1122298615] +script = ExtResource("1_y37vg") + +[node name="Panel" type="Panel" parent="." unique_id=1371415037] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 0 +size_flags_vertical = 8 + +[node name="HintLabel" type="Label" parent="Panel" unique_id=2014325289] +layout_mode = 1 +anchors_preset = 3 +anchor_left = 1.0 +anchor_top = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = -308.0 +offset_top = -43.0 +grow_horizontal = 0 +grow_vertical = 0 + +[node name="TitleLabel" type="Label" parent="Panel" unique_id=1341922505] +layout_mode = 1 +offset_left = 40.0 +offset_top = 31.0 +offset_right = 716.0 +offset_bottom = 54.0 +size_flags_vertical = 0 + +[node name="OptionContainer" type="VBoxContainer" parent="Panel" unique_id=58274880] +layout_mode = 0 +offset_left = 302.0 +offset_top = 204.0 +offset_right = 978.0 +offset_bottom = 204.0 +size_flags_vertical = 8 + +[node name="MessageLabel" type="Label" parent="Panel" unique_id=2104555059] +layout_mode = 1 +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -38.0 +offset_top = -184.0 +offset_right = 299.0 +offset_bottom = -161.0 +grow_horizontal = 2 +grow_vertical = 2 diff --git a/main.tscn b/main.tscn new file mode 100755 index 0000000..2055292 --- /dev/null +++ b/main.tscn @@ -0,0 +1,323 @@ +[gd_scene format=3 uid="uid://bju1lndv8l1mo"] + +[ext_resource type="Script" uid="uid://ckrqvbqw08kin" path="res://player.gd" id="1_0xm2m"] +[ext_resource type="Texture2D" uid="uid://c3ajv7vb8c4fb" path="res://assets/debug/checkerboard.png" id="1_1bvp3"] +[ext_resource type="Texture2D" uid="uid://epcqli428yem" path="res://assets/sprites/player/debug_player.png" id="2_h2yge"] +[ext_resource type="Script" uid="uid://b0y06y7c0bihj" path="res://camera_rig.gd" id="3_h2yge"] +[ext_resource type="PackedScene" uid="uid://be6ufrc3dsjge" path="res://poi.tscn" id="5_lquwl"] +[ext_resource type="PackedScene" uid="uid://dmhs1oy1kh6hi" path="res://assets/models/mountain.glb" id="6_7mycd"] +[ext_resource type="PackedScene" uid="uid://gl4qpk4wto1e" path="res://assets/models/mountain2v5.glb" id="7_272bh"] +[ext_resource type="PackedScene" uid="uid://be2uq7ixlbv6b" path="res://assets/models/forest.glb" id="8_5vw27"] + +[sub_resource type="Environment" id="Environment_h2yge"] +ambient_light_color = Color(0, 0, 0.31764707, 1) +ambient_light_energy = 0.3 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_lquwl"] +albedo_texture = ExtResource("1_1bvp3") + +[sub_resource type="CylinderMesh" id="CylinderMesh_lquwl"] +top_radius = 100.0 +bottom_radius = 100.0 +height = 0.2 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_h2yge"] +shading_mode = 0 +albedo_color = Color(0, 0.32156864, 0, 1) + +[sub_resource type="CylinderShape3D" id="CylinderShape3D_lquwl"] +height = 0.2 +radius = 100.0 + +[sub_resource type="CylinderShape3D" id="CylinderShape3D_7mycd"] +height = 0.5 +radius = 0.16 + +[sub_resource type="AtlasTexture" id="AtlasTexture_lquwl"] +atlas = ExtResource("2_h2yge") +region = Rect2(0, 0, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_7mycd"] +atlas = ExtResource("2_h2yge") +region = Rect2(48, 0, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_272bh"] +atlas = ExtResource("2_h2yge") +region = Rect2(96, 0, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_5vw27"] +atlas = ExtResource("2_h2yge") +region = Rect2(0, 0, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_kek77"] +atlas = ExtResource("2_h2yge") +region = Rect2(48, 0, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_4c57u"] +atlas = ExtResource("2_h2yge") +region = Rect2(96, 0, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_efxa6"] +atlas = ExtResource("2_h2yge") +region = Rect2(0, 60, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_dg77c"] +atlas = ExtResource("2_h2yge") +region = Rect2(48, 60, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_ycdy4"] +atlas = ExtResource("2_h2yge") +region = Rect2(96, 60, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_w48qg"] +atlas = ExtResource("2_h2yge") +region = Rect2(0, 120, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_vivmo"] +atlas = ExtResource("2_h2yge") +region = Rect2(48, 120, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_2cqfq"] +atlas = ExtResource("2_h2yge") +region = Rect2(96, 120, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_yaehf"] +atlas = ExtResource("2_h2yge") +region = Rect2(0, 180, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_074og"] +atlas = ExtResource("2_h2yge") +region = Rect2(48, 180, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_cegan"] +atlas = ExtResource("2_h2yge") +region = Rect2(96, 180, 48, 60) + +[sub_resource type="SpriteFrames" id="SpriteFrames_82xsv"] +animations = [{ +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_lquwl") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_7mycd") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_272bh") +}], +"loop": true, +"name": &"idle", +"speed": 5.0 +}, { +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_5vw27") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_kek77") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_4c57u") +}], +"loop": true, +"name": &"move_down", +"speed": 5.0 +}, { +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_efxa6") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_dg77c") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_ycdy4") +}], +"loop": true, +"name": &"move_left", +"speed": 5.0 +}, { +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_w48qg") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_vivmo") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_2cqfq") +}], +"loop": true, +"name": &"move_right", +"speed": 5.0 +}, { +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_yaehf") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_074og") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_cegan") +}], +"loop": true, +"name": &"move_up", +"speed": 5.0 +}] + +[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_7mycd"] +radius = 7.0 +height = 20.0 + +[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_5vw27"] +radius = 8.5078125 +height = 17.015625 + +[sub_resource type="CylinderShape3D" id="CylinderShape3D_5vw27"] +height = 2.2817383 +radius = 0.72021484 + +[sub_resource type="CylinderShape3D" id="CylinderShape3D_kek77"] +height = 1.8276367 +radius = 0.5517578 + +[node name="Main" type="Node3D" unique_id=1313637872] + +[node name="Environment" type="WorldEnvironment" parent="." unique_id=753803863] +environment = SubResource("Environment_h2yge") + +[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=630943989] + +[node name="Ground" type="StaticBody3D" parent="." unique_id=309197966] + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Ground" unique_id=479475733] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00084638596, -0.2, -0.001806736) +material_override = SubResource("StandardMaterial3D_lquwl") +mesh = SubResource("CylinderMesh_lquwl") +surface_material_override/0 = SubResource("StandardMaterial3D_h2yge") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Ground" unique_id=1301061872] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.2, 0) +shape = SubResource("CylinderShape3D_lquwl") + +[node name="Player" type="CharacterBody3D" parent="." unique_id=1504574304 groups=["player"]] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.25, 0) +script = ExtResource("1_0xm2m") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Player" unique_id=1483851051] +shape = SubResource("CylinderShape3D_7mycd") + +[node name="AnimatedSprite3D" type="AnimatedSprite3D" parent="Player" unique_id=155581900] +billboard = 2 +texture_filter = 0 +sprite_frames = SubResource("SpriteFrames_82xsv") +animation = &"idle" + +[node name="CameraRig" type="Node3D" parent="." unique_id=1094565525 groups=["camera_rig"]] +script = ExtResource("3_h2yge") +target = NodePath("../Player") + +[node name="CameraArm" type="Node3D" parent="CameraRig" unique_id=1827622739] +transform = Transform3D(1, 0, 0, 0, 0.81915206, 0.57357645, 0, -0.57357645, 0.81915206, 0, 0, 0) + +[node name="Camera3D" type="Camera3D" parent="CameraRig/CameraArm" unique_id=1414235198] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 12) +fov = 50.0 +near = 0.1 +far = 500.0 + +[node name="POI" parent="." unique_id=1770000468 instance=ExtResource("5_lquwl")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 0.5, 2) + +[node name="Node3D" type="Node3D" parent="." unique_id=597556846] +transform = Transform3D(0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 3.6214647, -0.23645921, 0.47627413) + +[node name="mountain" parent="Node3D" unique_id=2116024014 instance=ExtResource("6_7mycd")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -7.0459113) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Node3D/mountain" unique_id=1378662574] +shape = SubResource("CapsuleShape3D_7mycd") + +[node name="mountain2" parent="Node3D" unique_id=1164111955 instance=ExtResource("6_7mycd")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 7.6505966, 0, -7.0459113) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Node3D/mountain2" unique_id=1044531282] +shape = SubResource("CapsuleShape3D_7mycd") + +[node name="mountain3" parent="Node3D" unique_id=1031030133 instance=ExtResource("6_7mycd")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3.5228462, 0, -2.3011575) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Node3D/mountain3" unique_id=1670981761] +shape = SubResource("CapsuleShape3D_7mycd") + +[node name="mountain4" parent="Node3D" unique_id=213527076 instance=ExtResource("6_7mycd")] + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Node3D/mountain4" unique_id=370339188] +shape = SubResource("CapsuleShape3D_7mycd") + +[node name="Node3D2" type="Node3D" parent="." unique_id=97687536] + +[node name="mountain2v5" parent="Node3D2" unique_id=1347056585 instance=ExtResource("7_272bh")] +transform = Transform3D(0.05, 0, 0, 0, 0.05, 0, 0, 0, 0.05, 5.449942, -0.15, 0.60275173) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Node3D2/mountain2v5" unique_id=1250318876] +shape = SubResource("CapsuleShape3D_5vw27") + +[node name="mountain2v6" parent="Node3D2" unique_id=722974757 instance=ExtResource("7_272bh")] +transform = Transform3D(0.05, 0, 0, 0, 0.05, 0, 0, 0, 0.05, 5.309197, -0.15, 0.16273117) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Node3D2/mountain2v6" unique_id=232796233] +shape = SubResource("CapsuleShape3D_5vw27") + +[node name="mountain2v7" parent="Node3D2" unique_id=279879297 instance=ExtResource("7_272bh")] +transform = Transform3D(0.05, 0, 0, 0, 0.05, 0, 0, 0, 0.05, 5.801124, -0.15, -0.25847834) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Node3D2/mountain2v7" unique_id=271099516] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.04194641, 0.13291359, -0.03959179) +shape = SubResource("CapsuleShape3D_5vw27") + +[node name="mountain2v8" parent="Node3D2" unique_id=1413121196 instance=ExtResource("7_272bh")] +transform = Transform3D(0.05, 0, 0, 0, 0.05, 0, 0, 0, 0.05, 6.2565756, -0.15, 0.1419242) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Node3D2/mountain2v8" unique_id=632282427] +shape = SubResource("CapsuleShape3D_5vw27") + +[node name="mountain2v9" parent="Node3D2" unique_id=888354952 instance=ExtResource("7_272bh")] +transform = Transform3D(0.05, 0, 0, 0, 0.05, 0, 0, 0, 0.05, 5.309197, -0.15, -0.051428914) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Node3D2/mountain2v9" unique_id=1549534653] +shape = SubResource("CapsuleShape3D_5vw27") + +[node name="Node3D3" type="Node3D" parent="." unique_id=2010190045] +transform = Transform3D(0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 6.5570726, 0.80977285, 4.959112) + +[node name="forest" parent="Node3D3" unique_id=1142695276 instance=ExtResource("8_5vw27")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.89663315, -3.8352594, -0.41697693) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Node3D3/forest" unique_id=1992100035] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0569582, -0.37715888, -0.2822442) +shape = SubResource("CylinderShape3D_5vw27") + +[node name="CollisionShape3D2" type="CollisionShape3D" parent="Node3D3/forest" unique_id=2004443612] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.1139164, -0.75431776, 0.11189556) +shape = SubResource("CylinderShape3D_5vw27") + +[node name="CollisionShape3D3" type="CollisionShape3D" parent="Node3D3/forest" unique_id=1398520795] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.4591012, -0.5861306, 0.51387644) +shape = SubResource("CylinderShape3D_5vw27") + +[node name="forest2" parent="Node3D3" unique_id=2120638756 instance=ExtResource("8_5vw27")] +transform = Transform3D(-0.87206924, 0, 0.4893825, 0, 1, 0, -0.4893825, 0, -0.87206924, 0, -3.83526, 0) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Node3D3/forest2" unique_id=92773776] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.15763283, -0.2685547, -0.28089857) +shape = SubResource("CylinderShape3D_kek77") + +[node name="CollisionShape3D2" type="CollisionShape3D" parent="Node3D3/forest2" unique_id=291722829] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.021739006, -0.5371094, 0.2103684) +shape = SubResource("CylinderShape3D_kek77") + +[node name="CollisionShape3D3" type="CollisionShape3D" parent="Node3D3/forest2" unique_id=1876581014] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.084690094, -0.5371094, 0.40002155) +shape = SubResource("CylinderShape3D_kek77") diff --git a/modeltest.tscn b/modeltest.tscn new file mode 100644 index 0000000..4046fed --- /dev/null +++ b/modeltest.tscn @@ -0,0 +1,8 @@ +[gd_scene format=3 uid="uid://b645207svctxk"] + +[ext_resource type="PackedScene" uid="uid://dmhs1oy1kh6hi" path="res://assets/models/mountain.glb" id="1_lqtyj"] + +[node name="TestModelworld" type="Node3D" unique_id=2084483331] + +[node name="mountain" parent="." unique_id=2029213902 instance=ExtResource("1_lqtyj")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.034547806, 1.1920929e-07, -0.028554201) diff --git a/player.gd b/player.gd new file mode 100755 index 0000000..ce64b65 --- /dev/null +++ b/player.gd @@ -0,0 +1,62 @@ +extends CharacterBody3D + +@export var move_speed: float = 5.0 +@export var gravity: float = 9.8 + +var camera_rig: Node3D + +@onready var sprite: AnimatedSprite3D = $AnimatedSprite3D + +func _ready() -> void: + camera_rig = get_tree().get_first_node_in_group("camera_rig") + if camera_rig == null: + push_error("CameraRig nicht gefunden! Gruppe 'camera_rig' gesetzt?") + +func _physics_process(delta: float) -> void: + # Bewegung sperren während Interaction + if InteractionManager.active: + velocity = Vector3.ZERO + return + # Schwerkraft + if not is_on_floor(): + velocity.y -= gravity * delta + + # Eingabe + var input_dir = Vector2( + Input.get_axis("move_left", "move_right"), + Input.get_axis("move_forward", "move_backward") + ) + + if input_dir != Vector2.ZERO: + var cam_basis = camera_rig.global_transform.basis + var forward = -cam_basis.z + var right = cam_basis.x + forward.y = 0 + right.y = 0 + forward = forward.normalized() + right = right.normalized() + + var move_dir = (forward * -input_dir.y + right * input_dir.x).normalized() + velocity.x = move_dir.x * move_speed + velocity.z = move_dir.z * move_speed + + _update_animation(input_dir) + else: + velocity.x = move_toward(velocity.x, 0, move_speed) + velocity.z = move_toward(velocity.z, 0, move_speed) + sprite.play("idle") + + move_and_slide() + +func _update_animation(input_dir: Vector2) -> void: + + if input_dir.y > 0.1: + sprite.play("move_down") + elif input_dir.y < -0.1: + sprite.play("move_up") + elif input_dir.x > 0.1: + sprite.play("move_right") + elif input_dir.x < -0.1: + sprite.play("move_left") + else: + sprite.play("idle") diff --git a/player.gd.uid b/player.gd.uid new file mode 100755 index 0000000..cd9b419 --- /dev/null +++ b/player.gd.uid @@ -0,0 +1 @@ +uid://ckrqvbqw08kin diff --git a/player.tscn b/player.tscn new file mode 100644 index 0000000..dfeb729 --- /dev/null +++ b/player.tscn @@ -0,0 +1,153 @@ +[gd_scene format=3 uid="uid://dljjlqptwc2a2"] + +[ext_resource type="Script" uid="uid://ckrqvbqw08kin" path="res://player.gd" id="1_onrkg"] +[ext_resource type="Texture2D" uid="uid://epcqli428yem" path="res://assets/sprites/player/debug_player.png" id="2_i3pqv"] + +[sub_resource type="CylinderShape3D" id="CylinderShape3D_7mycd"] +height = 0.5 +radius = 0.16 + +[sub_resource type="AtlasTexture" id="AtlasTexture_lquwl"] +atlas = ExtResource("2_i3pqv") +region = Rect2(0, 0, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_7mycd"] +atlas = ExtResource("2_i3pqv") +region = Rect2(48, 0, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_272bh"] +atlas = ExtResource("2_i3pqv") +region = Rect2(96, 0, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_5vw27"] +atlas = ExtResource("2_i3pqv") +region = Rect2(0, 0, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_kek77"] +atlas = ExtResource("2_i3pqv") +region = Rect2(48, 0, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_4c57u"] +atlas = ExtResource("2_i3pqv") +region = Rect2(96, 0, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_efxa6"] +atlas = ExtResource("2_i3pqv") +region = Rect2(0, 60, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_dg77c"] +atlas = ExtResource("2_i3pqv") +region = Rect2(48, 60, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_ycdy4"] +atlas = ExtResource("2_i3pqv") +region = Rect2(96, 60, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_w48qg"] +atlas = ExtResource("2_i3pqv") +region = Rect2(0, 120, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_vivmo"] +atlas = ExtResource("2_i3pqv") +region = Rect2(48, 120, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_2cqfq"] +atlas = ExtResource("2_i3pqv") +region = Rect2(96, 120, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_yaehf"] +atlas = ExtResource("2_i3pqv") +region = Rect2(0, 180, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_074og"] +atlas = ExtResource("2_i3pqv") +region = Rect2(48, 180, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_cegan"] +atlas = ExtResource("2_i3pqv") +region = Rect2(96, 180, 48, 60) + +[sub_resource type="SpriteFrames" id="SpriteFrames_82xsv"] +animations = [{ +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_lquwl") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_7mycd") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_272bh") +}], +"loop": true, +"name": &"idle", +"speed": 5.0 +}, { +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_5vw27") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_kek77") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_4c57u") +}], +"loop": true, +"name": &"move_down", +"speed": 5.0 +}, { +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_efxa6") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_dg77c") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_ycdy4") +}], +"loop": true, +"name": &"move_left", +"speed": 5.0 +}, { +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_w48qg") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_vivmo") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_2cqfq") +}], +"loop": true, +"name": &"move_right", +"speed": 5.0 +}, { +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_yaehf") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_074og") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_cegan") +}], +"loop": true, +"name": &"move_up", +"speed": 5.0 +}] + +[node name="Player" type="CharacterBody3D" unique_id=1949521754 groups=["player"]] +script = ExtResource("1_onrkg") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=2092151561] +shape = SubResource("CylinderShape3D_7mycd") + +[node name="AnimatedSprite3D" type="AnimatedSprite3D" parent="." unique_id=1093854571] +billboard = 2 +texture_filter = 0 +sprite_frames = SubResource("SpriteFrames_82xsv") +animation = &"idle" diff --git a/poi.gd b/poi.gd new file mode 100755 index 0000000..33879ca --- /dev/null +++ b/poi.gd @@ -0,0 +1,48 @@ +extends Area3D + +@export var poi_name: String = "Ruinen" + +@onready var sprite: AnimatedSprite3D = $AnimatedSprite3D +@onready var name_label: Label3D = $Billboard/NameLabel +@onready var prompt: Label3D = $Billboard/InteractionPrompt + +var player_nearby: bool = false +var visited: bool = false + +func _ready() -> void: + prompt.visible = false + prompt.text = "[F] Interact" + _update_visuals() + body_entered.connect(_on_body_entered) + body_exited.connect(_on_body_exited) + +func _update_visuals() -> void: + if visited: + name_label.text = poi_name + # Normale Farbe + sprite.modulate = Color(1.0, 1.0, 1.0, 1.0) + name_label.modulate = Color(1.0, 1.0, 1.0, 1.0) + else: + name_label.text = "???" + # Ausgegraut + sprite.modulate = Color(0.4, 0.4, 0.4, 1.0) + name_label.modulate = Color(0.6, 0.6, 0.6, 1.0) + +func _on_body_entered(body: Node3D) -> void: + if body.is_in_group("player"): + player_nearby = true + prompt.text = "[F] Interact" + prompt.visible = true + +func _on_body_exited(body: Node3D) -> void: + if body.is_in_group("player"): + player_nearby = false + prompt.visible = false + +func _input(event: InputEvent) -> void: + if player_nearby and Input.is_action_just_pressed("interact"): + # Beim ersten Besuch entdecken + if not visited: + visited = true + _update_visuals() + InteractionManager.open_poi(self) diff --git a/poi.gd.uid b/poi.gd.uid new file mode 100755 index 0000000..cf3fbda --- /dev/null +++ b/poi.gd.uid @@ -0,0 +1 @@ +uid://c12tpdqhr2l5 diff --git a/poi.tscn b/poi.tscn new file mode 100755 index 0000000..c325cc7 --- /dev/null +++ b/poi.tscn @@ -0,0 +1,55 @@ +[gd_scene format=3 uid="uid://be6ufrc3dsjge"] + +[ext_resource type="Script" uid="uid://c12tpdqhr2l5" path="res://poi.gd" id="1_gwpk6"] +[ext_resource type="Texture2D" uid="uid://c0u8xjymrfw2x" path="res://assets/sprites/enviroment/Brown-gray_ruins2.png" id="2_yof6k"] + +[sub_resource type="SphereShape3D" id="SphereShape3D_gwpk6"] +radius = 0.8699188 + +[sub_resource type="AtlasTexture" id="AtlasTexture_mekjb"] +atlas = ExtResource("2_yof6k") +region = Rect2(0, 0, 80, 80) + +[sub_resource type="SpriteFrames" id="SpriteFrames_0surh"] +animations = [{ +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_mekjb") +}], +"loop": true, +"name": &"default", +"speed": 5.0 +}] + +[sub_resource type="BoxShape3D" id="BoxShape3D_gwpk6"] +size = Vector3(0.8, 2.132, 2.333828) + +[node name="POI" type="Area3D" unique_id=1770000468] +script = ExtResource("1_gwpk6") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=2115487742] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.6096671) +shape = SubResource("SphereShape3D_gwpk6") + +[node name="AnimatedSprite3D" type="AnimatedSprite3D" parent="." unique_id=1205831120] +sprite_frames = SubResource("SpriteFrames_0surh") + +[node name="StaticBody3D" type="StaticBody3D" parent="." unique_id=1488376384] + +[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D" unique_id=461988177] +transform = Transform3D(0.6, 0, 0, 0, 0.6, 0, 0, 0, 0.6, 0, 0, -0.69380605) +shape = SubResource("BoxShape3D_gwpk6") + +[node name="Billboard" type="Node3D" parent="." unique_id=36237536] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0) + +[node name="NameLabel" type="Label3D" parent="Billboard" unique_id=1419647885] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0) +billboard = 1 +text = "???" +font_size = 16 + +[node name="InteractionPrompt" type="Label3D" parent="Billboard" unique_id=2059219662] +visible = false +billboard = 1 +font_size = 12 diff --git a/preview_scene.tscn3183368435.tmp b/preview_scene.tscn3183368435.tmp new file mode 100755 index 0000000..3f88902 --- /dev/null +++ b/preview_scene.tscn3183368435.tmp @@ -0,0 +1,16 @@ +[gd_scene format=3 uid="uid://e8b1otd57xce"] + +[ext_resource type="Script" uid="uid://dehw4udbgwx4f" path="res://hightmap_gen.gd" id="1_regv8"] +[ext_resource type="Script" uid="uid://db1kymxglg8m1" path="res://preview_camera.gd" id="2_ji7iu"] + +[node name="PreviewScene" type="Node2D" unique_id=887284748] + +[node name="HightmapGen" type="Node" parent="." unique_id=1525090931] +script = ExtResource("1_regv8") + +[node name="preview_camera" type="Camera2D" parent="." unique_id=1468922324] +script = ExtResource("2_ji7iu") + +[node name="TextureRect" type="TextureRect" parent="." unique_id=1360046958] +offset_right = 40.0 +offset_bottom = 40.0 diff --git a/preview_scene.tscn3781868854.tmp b/preview_scene.tscn3781868854.tmp new file mode 100755 index 0000000..3f88902 --- /dev/null +++ b/preview_scene.tscn3781868854.tmp @@ -0,0 +1,16 @@ +[gd_scene format=3 uid="uid://e8b1otd57xce"] + +[ext_resource type="Script" uid="uid://dehw4udbgwx4f" path="res://hightmap_gen.gd" id="1_regv8"] +[ext_resource type="Script" uid="uid://db1kymxglg8m1" path="res://preview_camera.gd" id="2_ji7iu"] + +[node name="PreviewScene" type="Node2D" unique_id=887284748] + +[node name="HightmapGen" type="Node" parent="." unique_id=1525090931] +script = ExtResource("1_regv8") + +[node name="preview_camera" type="Camera2D" parent="." unique_id=1468922324] +script = ExtResource("2_ji7iu") + +[node name="TextureRect" type="TextureRect" parent="." unique_id=1360046958] +offset_right = 40.0 +offset_bottom = 40.0 diff --git a/project.godot b/project.godot new file mode 100755 index 0000000..364ac0c --- /dev/null +++ b/project.godot @@ -0,0 +1,128 @@ +; 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=5 + +[application] + +config/name="WayfarersWanderer" +run/main_scene="uid://bju1lndv8l1mo" +config/features=PackedStringArray("4.6", "GL Compatibility") + +[autoload] + +InteractionManager="*uid://cbg1abspfwgxo" +InteractionUI="*uid://cmg2008xfel2v" + +[display] + +window/size/viewport_width=1280 +window/size/viewport_height=720 + +[editor_plugins] + +enabled=PackedStringArray("res://addons/zylann.hterrain/plugin.cfg") + +[input] + +move_forward={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":-1.0,"script":null) +] +} +move_backward={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":1.0,"script":null) +] +} +move_left={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":-1.0,"script":null) +] +} +move_right={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":1.0,"script":null) +] +} +cam_rotate_left={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":81,"key_label":0,"unicode":113,"location":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":9,"pressure":0.0,"pressed":false,"script":null) +] +} +cam_rotate_right={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":69,"key_label":0,"unicode":101,"location":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":10,"pressure":0.0,"pressed":false,"script":null) +] +} +zoom_in={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194437,"key_label":0,"unicode":43,"location":0,"echo":false,"script":null) +, Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":4,"canceled":false,"pressed":false,"double_click":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":4,"axis_value":1.0,"script":null) +] +} +zoom_out={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194435,"key_label":0,"unicode":45,"location":0,"echo":false,"script":null) +, Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":5,"canceled":false,"pressed":false,"double_click":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":5,"axis_value":1.0,"script":null) +] +} +interact={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":70,"key_label":0,"unicode":102,"location":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":0,"pressure":0.0,"pressed":false,"script":null) +] +} +cancel={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194305,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":1,"pressure":0.0,"pressed":false,"script":null) +] +} +ui_select_up={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194320,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":11,"pressure":0.0,"pressed":false,"script":null) +] +} +ui_select_down={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194322,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":12,"pressure":0.0,"pressed":false,"script":null) +] +} +ui_select_left={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194319,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":13,"pressure":0.0,"pressed":false,"script":null) +] +} +ui_select_right={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194321,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":14,"pressure":0.0,"pressed":false,"script":null) +] +} + +[physics] + +3d/physics_engine="Jolt Physics" + +[rendering] + +rendering_device/driver.windows="d3d12" +renderer/rendering_method="gl_compatibility" +renderer/rendering_method.mobile="gl_compatibility"