# World.gd # ───────────────────────────────────────────────────────────────────────────── # Spielwelt-Controller # # Verantwortlichkeiten: # • Prozeduraler Boden-Shader (Schachbrettmuster, world-space stabil) # • Prozeduraler Himmel (ProceduralSkyMaterial + WorldEnvironment) # • Hauptmenü → Klassenauswahl → Spielinitialisierung # • Startausrüstung je nach Klasse # • Gegner-Setup, Loot-Weiterleitung, Respawn nach Tod # ───────────────────────────────────────────────────────────────────────────── extends Node3D const ENEMY_SCENE = preload("res://enemy.tscn") const MAIN_MENU = preload("res://main_menu.tscn") const CLASS_SELECTION_MENU = preload("res://class_selection_menu.tscn") const RESPAWN_TIME = 5.0 # Startausrüstung const STARTER_SWORD = preload("res://equipment/iron_sword.tres") const STARTER_STAFF = preload("res://equipment/wooden_staff.tres") const STARTER_CHEST = preload("res://equipment/leather_chest.tres") # Loot Tables const GOBLIN_LOOT = preload("res://loot_tables/goblin_loot.tres") @onready var player = $Player @onready var floor_mesh = $Boden/MeshInstance3D func _ready(): _setup_floor_material() _setup_sky() # Hauptmenü anzeigen var main_menu = MAIN_MENU.instantiate() add_child(main_menu) main_menu.start_game.connect(_on_start_game) func _setup_sky(): var sky_mat = ProceduralSkyMaterial.new() sky_mat.sky_top_color = Color(0.15, 0.35, 0.75) sky_mat.sky_horizon_color = Color(0.55, 0.75, 1.0) sky_mat.ground_horizon_color = Color(0.35, 0.30, 0.25) sky_mat.ground_bottom_color = Color(0.1, 0.1, 0.1) sky_mat.sun_angle_max = 30.0 sky_mat.sun_curve = 0.15 var sky = Sky.new() sky.sky_material = sky_mat var env = Environment.new() env.background_mode = Environment.BG_SKY env.sky = sky env.ambient_light_source = Environment.AMBIENT_SOURCE_SKY env.ambient_light_energy = 0.6 env.tonemap_mode = Environment.TONE_MAPPER_FILMIC var world_env = WorldEnvironment.new() world_env.environment = env add_child(world_env) func _setup_floor_material(): var shader = Shader.new() shader.code = """ shader_type spatial; uniform float grid_size : hint_range(0.5, 10.0) = 2.0; uniform vec4 color_a : source_color = vec4(0.22, 0.22, 0.22, 1.0); uniform vec4 color_b : source_color = vec4(0.38, 0.38, 0.38, 1.0); void fragment() { vec3 world_pos = (INV_VIEW_MATRIX * vec4(VERTEX, 1.0)).xyz; vec2 cell = floor(world_pos.xz / grid_size); float checker = mod(cell.x + cell.y, 2.0); ALBEDO = mix(color_a.rgb, color_b.rgb, checker); ROUGHNESS = 0.85; METALLIC = 0.0; } """ var mat = ShaderMaterial.new() mat.shader = shader floor_mesh.material_override = mat # Nach Hauptmenü: Klassenauswahl anzeigen func _on_start_game(): var menu = CLASS_SELECTION_MENU.instantiate() add_child(menu) menu.class_selected.connect(_on_class_selected) # Spiel wieder pausieren für Klassenauswahl get_tree().paused = true # Klasse ausgewählt: Spieler initialisieren func _on_class_selected(character_class: CharacterClass): player.character_class = character_class # Skills klassenabhängig aufbauen player._init_class_skills() for i in range(9): player._refresh_action_slot(i) # Startausrüstung klassenabhängig if character_class.resource_type == CharacterClass.ResourceType.MANA: player.equip_item(STARTER_STAFF) else: player.equip_item(STARTER_SWORD) player.equip_item(STARTER_CHEST) player._calculate_stats() player.current_hp = player.max_hp player.current_resource = player.max_resource player.hud.update_health(player.current_hp, player.max_hp) player.hud.update_resource(player.current_resource, player.max_resource, player.get_resource_name()) print("Klasse gewählt: ", character_class.class_name_de) # Jetzt Gegner initialisieren var enemy = get_node("Enemy") _setup_enemy(enemy) # Gegner initialisieren und Signal verbinden func _setup_enemy(enemy): if enemy and player: enemy.target = player if enemy.loot_table == null: enemy.loot_table = GOBLIN_LOOT enemy.enemy_died.connect(_on_enemy_died) enemy.enemy_dropped_loot.connect(_on_enemy_dropped_loot) else: print("Fehler: Player oder Enemy nicht gefunden!") # Loot-Drop an Spieler weiterleiten func _on_enemy_dropped_loot(loot: Dictionary, world_pos: Vector3): if player: player.receive_loot(loot, world_pos) # Gegner gestorben: Nach 5 Sekunden respawnen func _on_enemy_died(spawn_position: Vector3, _xp_reward: int): print("Respawn in ", RESPAWN_TIME, " Sekunden...") await get_tree().create_timer(RESPAWN_TIME).timeout _spawn_enemy(spawn_position) # Neuen Gegner an Position spawnen func _spawn_enemy(position: Vector3): var new_enemy = ENEMY_SCENE.instantiate() add_child(new_enemy) new_enemy.global_position = position _setup_enemy(new_enemy) print("Gegner respawned!")