From a1efaf6294b43e84d5ad0484041b1c02ee88023a Mon Sep 17 00:00:00 2001 From: Dan Baker Date: Sun, 29 Jun 2025 14:05:48 +0100 Subject: [PATCH] Adds basic camp generation and placement Adds basic camp generation and placement logic to the map generation process. It attempts to place the camp in a valid location, avoiding paths and water bodies. It also sets the player's spawn point to the center of the generated camp, including some basic camp props like a tent, campfire, and bed. Additionally, vegetation spawning is now dependent on the `should_spawn_*` methods of the `CellDataResource`, allowing more control over what spawns where. --- Config/Globals.gd | 2 + Entities/GroundTile/scripts/ground_tile.gd | 8 +- Entities/GroundTile/scripts/trees.gd | 2 +- Entities/Player/scripts/player.gd | 3 +- Utilities/MapData/CellDataResource.gd | 133 ++++++++++++++- Utilities/MapData/MapPopulation.gd | 32 +--- Utilities/MapGeneration/MapGeneration.gd | 169 +++++++++++++++++-- stages/Test3D/Test3d.tscn | 178 +++++++++++++-------- 8 files changed, 402 insertions(+), 125 deletions(-) diff --git a/Config/Globals.gd b/Config/Globals.gd index 501de9a..0156a12 100644 --- a/Config/Globals.gd +++ b/Config/Globals.gd @@ -5,6 +5,8 @@ var map_height: int = 200 var map_width: int = 200 var _map_data: Array var _biome_data: Dictionary = {} +var _camp_data: Dictionary = {} +var spawn_point: Vector3 = Vector3(0, 0, 0) # Property for map_data with logging var map_data: Array: diff --git a/Entities/GroundTile/scripts/ground_tile.gd b/Entities/GroundTile/scripts/ground_tile.gd index 639ab11..5827e34 100644 --- a/Entities/GroundTile/scripts/ground_tile.gd +++ b/Entities/GroundTile/scripts/ground_tile.gd @@ -45,13 +45,13 @@ func spawn_content(): if cell_info == null: return - if tree_spawner: + if tree_spawner and cell_info.should_spawn_trees(): tree_spawner.spawn_trees_for_cell(cell_info) - if grass_spawner: + if grass_spawner and cell_info.should_spawn_grass(): grass_spawner.spawn_grass_for_cell(cell_info) - if bush_spawner: + if bush_spawner and cell_info.should_spawn_bushes(): bush_spawner.spawn_bushes_for_cell(cell_info) - if flower_spawner: + if flower_spawner and cell_info.should_spawn_flowers(): flower_spawner.spawn_flowers_for_cell(cell_info) diff --git a/Entities/GroundTile/scripts/trees.gd b/Entities/GroundTile/scripts/trees.gd index 9743906..57705a1 100644 --- a/Entities/GroundTile/scripts/trees.gd +++ b/Entities/GroundTile/scripts/trees.gd @@ -40,7 +40,7 @@ func spawn_trees_for_cell(cell_info: CellDataResource): attempts += 1 - Log.pr("Spawned %d of %d trees in cell" % [spawned_count, cell_info.trees.size()]) + #Log.pr("Spawned %d of %d trees in cell" % [spawned_count, cell_info.trees.size()]) func get_random_position() -> Vector3: var rng = parent_ground_tile.get_rng() diff --git a/Entities/Player/scripts/player.gd b/Entities/Player/scripts/player.gd index 5e3c6b7..af741e8 100644 --- a/Entities/Player/scripts/player.gd +++ b/Entities/Player/scripts/player.gd @@ -6,7 +6,8 @@ extends CharacterBody3D var target_velocity = Vector3.ZERO func _ready() -> void: - position = Vector3.ZERO + position = Global.spawn_point + %Camp.position = Global.spawn_point func _physics_process(delta): RenderingServer.global_shader_parameter_set("player_position", position) diff --git a/Utilities/MapData/CellDataResource.gd b/Utilities/MapData/CellDataResource.gd index 9f661e6..1be2797 100644 --- a/Utilities/MapData/CellDataResource.gd +++ b/Utilities/MapData/CellDataResource.gd @@ -5,13 +5,134 @@ extends Resource @export var x: int = 0 @export var z: int = 0 -@export var vegetation_density: float = 0.5 -@export var ground_compaction: float = 0.0 -@export var water: float = 0 -@export var moisture_level: float = 0.6 +# Core cell type properties - these will trigger automatic updates +@export var camp: bool = false: set = set_camp +@export var path: bool = false: set = set_trail +@export var water: bool = false: set = set_water +# Dependent properties that get automatically managed +@export var vegetation_density: float = 0.5: set = set_vegetation_density +@export var ground_compaction: float = 0.0: set = set_ground_compaction +@export var moisture_level: float = 0.6 @export var trees: Array = [] +# Internal flag to prevent infinite recursion during initialization +var _initializing: bool = false + +func _init(): + _initializing = true + # Set default values + vegetation_density = 0.5 + ground_compaction = 0.0 + camp = false + path = false + water = false + _initializing = false + +func set_camp(value: bool): + camp = value + if not _initializing: + _update_dependent_properties() + +## Using a different name due to Resource using the function set_path in Godot +func set_trail(value: bool): + path = value + if not _initializing: + _update_dependent_properties() + +func set_water(value: bool): + water = value + if not _initializing: + _update_dependent_properties() + +func set_vegetation_density(value: float): + # Only allow manual setting if not a special cell type + if _initializing or not (camp or path or water): + vegetation_density = value + else: + vegetation_density = 0.0 + +func set_ground_compaction(value: float): + # Camp always has maximum compaction, others can be set manually + if camp: + ground_compaction = 1.0 + elif not _initializing: + ground_compaction = value + +func _update_dependent_properties(): + # Update vegetation density - always 0 for camp, path, or water + if camp or path or water: + vegetation_density = 0.0 + + # Update ground compaction - camp always has maximum compaction + if camp: + ground_compaction = 1.0 + +# Utility function to set cell type and ensure only one is active +func set_cell_type(cell_type: String): + _initializing = true + + # Clear all cell types first + camp = false + path = false + water = false + + # Set the specified type + match cell_type.to_lower(): + "camp": + camp = true + "path": + path = true + "water": + water = true + "terrain", "normal", "": + pass # Leave all false for normal terrain + _: + push_warning("Unknown cell type: " + cell_type) + + _initializing = false + _update_dependent_properties() + +# Utility function to get the primary cell type +func get_cell_type() -> String: + if camp: + return "camp" + elif path: + return "path" + elif water: + return "water" + else: + return "terrain" + +# Check if this is a special cell type (not normal terrain) +func is_special_cell() -> bool: + return camp or path or water + func add_trees(tree: TreeDataResource, qty: int) -> void: - for i in qty: - trees.append(tree) + for i in qty: + trees.append(tree) + +# Override vegetation density and ground compaction for special cases +func force_set_vegetation_density(value: float): + # Allows bypassing the automatic management if absolutely needed + vegetation_density = value + +func force_set_ground_compaction(value: float): + # Allows bypassing the automatic management if absolutely needed + ground_compaction = value + +func should_spawn_trees() -> bool: + # Only spawn trees if this is not a special cell type + return not (camp or path or water) and vegetation_density > 0.0 + +func should_spawn_grass() -> bool: + # Grass can spawn in any terrain cell, but not in special cells + return not (camp or path or water) and vegetation_density > 0.0 + +func should_spawn_bushes() -> bool: + # Bushes can spawn in any terrain cell, but not in special cells + return not (camp or path or water) and vegetation_density > 0.1 + +func should_spawn_flowers() -> bool: + # Flowers can spawn in any terrain cell, but not in special cells + return not (camp or path or water) and vegetation_density > 0.1 \ No newline at end of file diff --git a/Utilities/MapData/MapPopulation.gd b/Utilities/MapData/MapPopulation.gd index 68fe2b9..6974a04 100644 --- a/Utilities/MapData/MapPopulation.gd +++ b/Utilities/MapData/MapPopulation.gd @@ -14,41 +14,15 @@ var map_data: Array = Global.map_data ## Density 0.1 to 0.6 - add bushes, varying quantity TBD ## Density 0.1 to 0.4 - add flowers, varying quantity TBD -# Weighted random selection based on tree chances -static func select_weighted_tree(tree_preferences: Dictionary): - if tree_preferences.is_empty(): - return null - - # Calculate total weight - var total_weight = 0.0 - for tree_name in tree_preferences.keys(): - total_weight += tree_preferences[tree_name]["chance"] - - if total_weight <= 0.0: - return null - - # Generate random number between 0 and total_weight - var random_value = randf() * total_weight - - # Find which tree this random value corresponds to - var cumulative_weight = 0.0 - for tree_name in tree_preferences.keys(): - cumulative_weight += tree_preferences[tree_name]["chance"] - if random_value <= cumulative_weight: - return tree_preferences[tree_name]["resource"] - - # Fallback (shouldn't happen, but just in case) - var first_key = tree_preferences.keys()[0] - return tree_preferences[first_key]["resource"] - # Pre-calculate tree distribution for the cell -static func generate_cell_with_distribution(x: int, z: int, density: float, path: bool = false, water: bool = false): +static func generate_cell_with_distribution(x: int, z: int, density: float, path: bool = false, water: bool = false, camp: bool = false): var cell_data = CellDataResource.new() cell_data.x = x cell_data.z = z cell_data.vegetation_density = density + cell_data.camp = camp - if not (path or water): + if not (path or water or camp): if density >= 0.6: var tree_preferences = BiomeData.calculate_tree_probabilities(x, z) var tree_distribution = calculate_tree_distribution(tree_preferences, density) diff --git a/Utilities/MapGeneration/MapGeneration.gd b/Utilities/MapGeneration/MapGeneration.gd index 04301b3..d6088ea 100644 --- a/Utilities/MapGeneration/MapGeneration.gd +++ b/Utilities/MapGeneration/MapGeneration.gd @@ -16,6 +16,11 @@ var map_height: int = Global.map_height @export var min_branch_length_ratio: float = 0.2 # Minimum branch length as ratio of main path @export var max_branch_length_ratio: float = 0.4 # Maximum branch length as ratio of main path +# Camp generation settings +@export var camp_size: int = 2 # Size of the camp (camp_size x camp_size) +@export var camp_placement_attempts: int = 100 # Max attempts to place the camp +@export var camp_buffer_zone: int = 1 # Minimum distance from camp to other features + # Water generation settings @export var num_water_bodies: int = 5 # Number of water bodies to generate @export var min_water_size: int = 15 # Minimum radius of water bodies @@ -32,6 +37,11 @@ var map: Array = [] var map_data: Array = [] var path_data: Array = [] # Separate array to track paths var water_data: Array = [] # Separate array to track water bodies +var camp_data: Array = [] # Separate array to track camp + +# Camp position storage +var camp_position: Vector2 = Vector2(-1, -1) # Top-left corner of the camp +var camp_center: Vector2 = Vector2(-1, -1) # Center of the camp # New data structures for enhanced path generation var path_segments: Array = [] # Store all path segments for better branching @@ -39,22 +49,27 @@ var path_id_counter: int = 0 func _ready(): generate_map() + generate_camp() generate_paths() generate_water_bodies() BiomeGenerationClass.generate_environment_maps(map_width, map_height) generate_final_map_data() - #if export_image: - # export_map_as_image() + if export_image: + export_map_as_image() func generate_final_map_data(): var objects_before = Performance.get_monitor(Performance.OBJECT_COUNT) for y in range(map_height): for x in range(map_width): - MapPopulationClass.generate_cell_with_distribution(x, y, map_data[y][x], is_path_at(x, y), is_water_at(x, y)) + MapPopulationClass.generate_cell_with_distribution(x, y, map_data[y][x], is_path_at(x, y), is_water_at(x, y), is_camp_at(x, y)) + Log.pr(camp_center) + Global.spawn_point = Vector3(camp_position.x * 2, 0, camp_position.y * 2) # Set spawn point to camp center + Log.pr(Global.spawn_point) + # Check immediately after await get_tree().process_frame var objects_after = Performance.get_monitor(Performance.OBJECT_COUNT) @@ -86,14 +101,17 @@ func generate_map(): map_data.resize(map_height) path_data.resize(map_height) water_data.resize(map_height) + camp_data.resize(map_height) for y in range(map_height): map_data[y] = [] path_data[y] = [] water_data[y] = [] + camp_data[y] = [] map_data[y].resize(map_width) path_data[y].resize(map_width) water_data[y].resize(map_width) + camp_data[y].resize(map_width) for x in range(map_width): # Get noise value (-1 to 1) and normalize to (0 to 1) var noise_value = noise.get_noise_2d(x, y) @@ -101,7 +119,66 @@ func generate_map(): map_data[y][x] = round(normalized_value * 10.0) / 10.0 path_data[y][x] = false # Initialize path data water_data[y][x] = false # Initialize water data + camp_data[y][x] = false # Initialize camp data +func generate_camp(): + print("Generating camp...") + + var attempts = 0 + var placed = false + + while attempts < camp_placement_attempts and not placed: + # Random position with margin to ensure camp fits within map bounds + var margin = camp_size + camp_buffer_zone + var camp_x = randi_range(margin, map_width - margin - camp_size) + var camp_y = randi_range(margin, map_height - margin - camp_size) + + # Check if this location is valid for camp placement + if is_valid_camp_location(camp_x, camp_y): + place_camp(camp_x, camp_y) + placed = true + print("Camp placed at (", camp_x, ",", camp_y, ") with size ", camp_size, "x", camp_size) + + attempts += 1 + + if not placed: + print("Could not place camp after ", camp_placement_attempts, " attempts") + # Fallback: place camp in the center of the map + var fallback_x = (map_width - camp_size) / 2 + var fallback_y = (map_height - camp_size) / 2 + place_camp(fallback_x, fallback_y) + print("Camp placed at fallback location (", fallback_x, ",", fallback_y, ")") + +func is_valid_camp_location(camp_x: int, camp_y: int) -> bool: + # Check if the camp area and buffer zone are clear + var check_size = camp_size + (camp_buffer_zone * 2) + var start_x = camp_x - camp_buffer_zone + var start_y = camp_y - camp_buffer_zone + + for y in range(start_y, start_y + check_size): + for x in range(start_x, start_x + check_size): + if x >= 0 and x < map_width and y >= 0 and y < map_height: + # For now, just check if we're within map bounds + # Later we'll prevent paths and water from being placed here + continue + else: + # Outside map bounds + return false + + return true + +func place_camp(camp_x: int, camp_y: int): + # Store camp position + camp_position = Vector2(camp_x, camp_y) + camp_center = Vector2(camp_x + camp_size / 2.0, camp_y + camp_size / 2.0) + + Log.pr("Placing camp at position: ", camp_position, " with center: ", camp_center) + + # Mark camp area in camp_data + for y in range(camp_y, camp_y + camp_size): + for x in range(camp_x, camp_x + camp_size): + if x >= 0 and x < map_width and y >= 0 and y < map_height: + camp_data[y][x] = true func generate_paths(): print("Generating natural paths with branching...") @@ -416,6 +493,10 @@ func evaluate_catmull_rom_spline(points: Array, t: float) -> Vector2: return result func place_organic_path_segment(x: int, y: int, path_id: int, is_main_path: bool = false): + # Don't place paths in camp area + if is_camp_at(x, y): + return + # Base path placement - always place the center tile path_data[y][x] = true @@ -440,6 +521,10 @@ func place_organic_path_segment(x: int, y: int, path_id: int, is_main_path: bool var ny = y + dy if nx >= 0 and nx < map_width and ny >= 0 and ny < map_height: + # Don't place paths in camp area + if is_camp_at(nx, ny): + continue + # Use noise to create organic edges var edge_noise = width_noise.get_noise_2d(nx, ny) var edge_chance = 1.0 - (distance / float(path_width)) @@ -483,7 +568,9 @@ func smooth_paths(): var interp_x = x + int(float(dx * step) / float(steps)) var interp_y = y + int(float(dy * step) / float(steps)) if interp_x >= 0 and interp_x < map_width and interp_y >= 0 and interp_y < map_height: - new_path_data[interp_y][interp_x] = true + # Don't place paths in camp area + if not is_camp_at(interp_x, interp_y): + new_path_data[interp_y][interp_x] = true connected = true break if connected: @@ -509,9 +596,9 @@ func generate_single_water_body(body_index: int): var center_y = randi_range(max_water_size, map_height - max_water_size) # Random size within configured range - var water_radius = randi_range(min_water_size, max_water_size) + var water_radius = randi_range(min_water_size, max_water_size) - attempts - # Check if this location is valid (no paths in the area) + # Check if this location is valid (no paths or camp in the area) if is_valid_water_location(center_x, center_y, water_radius): place_water_body(center_x, center_y, water_radius, body_index) placed = true @@ -523,7 +610,7 @@ func generate_single_water_body(body_index: int): print("Could not place water body ", body_index + 1, " after ", water_placement_attempts, " attempts") func is_valid_water_location(center_x: int, center_y: int, radius: int) -> bool: - # Check if any paths would be intersected by this water body + # Check if any paths or camp would be intersected by this water body # Use a slightly larger radius for safety buffer var safety_buffer = 2 var check_radius = radius + safety_buffer @@ -537,6 +624,12 @@ func is_valid_water_location(center_x: int, center_y: int, radius: int) -> bool: if distance <= check_radius: return false + # Check if this position has camp + if camp_data[y][x]: + var distance = sqrt(pow(x - center_x, 2) + pow(y - center_y, 2)) + if distance <= check_radius: + return false + # Also check if there's already water here (prevent overlap) if water_data[y][x]: var distance = sqrt(pow(x - center_x, 2) + pow(y - center_y, 2)) @@ -556,7 +649,7 @@ func place_water_body(center_x: int, center_y: int, radius: int, body_index: int for y in range(center_y - radius - 2, center_y + radius + 3): for x in range(center_x - radius - 2, center_x + radius + 3): if x >= 0 and x < map_width and y >= 0 and y < map_height: - if path_data[y][x]: # Don't place water on paths + if path_data[y][x] or camp_data[y][x]: # Don't place water on paths or camp continue # Calculate distance from center @@ -574,7 +667,7 @@ func place_water_body(center_x: int, center_y: int, radius: int, body_index: int func print_visual_map_to_console(): print("") print("==================================================") - print("VISUAL MAP WITH BRANCHING PATHS AND DEAD ENDS") + print("VISUAL MAP WITH BRANCHING PATHS, DEAD ENDS, AND CAMP") print("==================================================") print("Path Statistics:") print("- Total path segments: ", path_segments.size()) @@ -585,11 +678,16 @@ func print_visual_map_to_console(): print("- Branches: ", branches.size()) print("- Dead ends: ", dead_ends.size()) print("") + print("Camp Statistics:") + print("- Camp position: (", camp_position.x, ",", camp_position.y, ")") + print("- Camp center: (", camp_center.x, ",", camp_center.y, ")") + print("- Camp size: ", camp_size, "x", camp_size) + print("") print_block_map_with_paths_safe() func print_block_map_with_paths_safe(): - print("Block character map with paths (X = paths, W = water):") + print("Block character map with paths (X = paths, W = water, C = camp):") print("") # Print in smaller chunks @@ -600,8 +698,10 @@ func print_block_map_with_paths_safe(): for y in range(chunk_start, chunk_end): var row_string = "" for x in range(map_width): - # Check priority: paths first, then water, then terrain - if path_data[y][x]: + # Check priority: camp first, then paths, then water, then terrain + if camp_data[y][x]: + row_string += "C" + elif path_data[y][x]: row_string += "X" elif water_data[y][x]: row_string += "W" @@ -639,19 +739,35 @@ func is_water_at(x: int, y: int) -> bool: return water_data[y][x] return false +func is_camp_at(x: int, y: int) -> bool: + if x >= 0 and x < map_width and y >= 0 and y < map_height: + return camp_data[y][x] + return false + func get_terrain_at(x: int, y: int) -> float: if x >= 0 and x < map_width and y >= 0 and y < map_height: return map_data[y][x] return 0.0 func get_tile_type_at(x: int, y: int) -> String: - if is_path_at(x, y): + if is_camp_at(x, y): + return "camp" + elif is_path_at(x, y): return "path" elif is_water_at(x, y): return "water" else: return "terrain" +func get_camp_position() -> Vector2: + return camp_position + +func get_camp_center() -> Vector2: + return camp_center + +func get_camp_size() -> int: + return camp_size + func get_path_segments() -> Array: return path_segments @@ -687,6 +803,26 @@ func export_map_as_image(): var image_y = map_y * tile_size + pixel_y image.set_pixel(image_x, image_y, color) + # Draw camp as a red dot at the center + if camp_position.x >= 0 and camp_position.y >= 0: + var camp_center_pixel_x = int(camp_center.x * tile_size) + var camp_center_pixel_y = int(camp_center.y * tile_size) + + # Draw a red dot (3x3 pixels minimum, scaled with tile size) + var dot_size = 20 + var half_dot = dot_size / 2 + + for dy in range(-half_dot, half_dot + 1): + for dx in range(-half_dot, half_dot + 1): + var pixel_x = camp_center_pixel_x + dx + var pixel_y = camp_center_pixel_y + dy + + # Make sure we're within image bounds + if pixel_x >= 0 and pixel_x < image_width and pixel_y >= 0 and pixel_y < image_height: + # Create a circular dot + if dx * dx + dy * dy <= half_dot * half_dot: + image.set_pixel(pixel_x, pixel_y, Color.RED) + # Save the image - you can choose different locations: var file_path = "user://" + image_filename @@ -700,11 +836,14 @@ func export_map_as_image(): print("Image dimensions: ", image_width, "x", image_height, " pixels") print("Map dimensions: ", map_width, "x", map_height, " tiles") print("Tile size: ", tile_size, "x", tile_size, " pixels per tile") + print("Camp represented as red dot at center: (", camp_center.x, ",", camp_center.y, ")") else: print("Error saving image: ", error) func get_tile_color(x: int, y: int) -> Color: - if is_path_at(x, y): + if is_camp_at(x, y): + return Color(0.4, 0.7, 0.3) + elif is_path_at(x, y): # Brown color for paths return Color(0.6, 0.4, 0.2) # Brown elif is_water_at(x, y): @@ -720,4 +859,4 @@ func get_tile_color(x: int, y: int) -> Color: var light_green = Color(0.4, 0.7, 0.3) # Light green # Interpolate between dark and light green based on terrain value - return dark_green.lerp(light_green, terrain_value) + return dark_green.lerp(light_green, terrain_value) \ No newline at end of file diff --git a/stages/Test3D/Test3d.tscn b/stages/Test3D/Test3d.tscn index 05f23fe..7ee8fd9 100644 --- a/stages/Test3D/Test3d.tscn +++ b/stages/Test3D/Test3d.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=46 format=4 uid="uid://bwsugg4p50fjr"] +[gd_scene load_steps=53 format=4 uid="uid://bwsugg4p50fjr"] [ext_resource type="Environment" uid="uid://cm77bbr0io118" path="res://Stages/Test3D/new_environment.tres" id="1_8ph61"] [ext_resource type="Script" uid="uid://bwed2dwogfmxv" path="res://Entities/Player/scripts/player.gd" id="1_d602n"] @@ -6,6 +6,13 @@ [ext_resource type="Script" uid="uid://bbjv6a7yg7m02" path="res://Stages/Test3D/camera_pivot.gd" id="2_sdmks"] [ext_resource type="Shader" uid="uid://bsemnmdracd4m" path="res://Common/shaders/outline.gdshader" id="4_feu7y"] [ext_resource type="Script" uid="uid://bjco8musjqog4" path="res://Stages/Test3D/particles.gd" id="9_oiyue"] +[ext_resource type="PackedScene" uid="uid://cdbnr0jg2icaj" path="res://Entities/Tree/assets/temp/campfire_bricks.glb" id="13_qasnx"] +[ext_resource type="PackedScene" uid="uid://c4ovjmemnepdy" path="res://Entities/Tree/assets/temp/campfire_logs.glb" id="14_2xm50"] +[ext_resource type="PackedScene" uid="uid://e8wa72ulhegx" path="res://Entities/Tree/assets/temp/log.glb" id="15_e0hgm"] +[ext_resource type="PackedScene" uid="uid://by2v67khppn0j" path="res://Entities/Tree/assets/temp/bed_floor.glb" id="15_pbfwi"] +[ext_resource type="PackedScene" uid="uid://d3y1g22hjq7ch" path="res://Entities/Tree/assets/temp/statue_column.glb" id="16_ynokf"] +[ext_resource type="PackedScene" uid="uid://b0yuw5v7ytyd0" path="res://Entities/Tree/assets/temp/statue_columnDamaged.glb" id="17_pbfwi"] +[ext_resource type="PackedScene" uid="uid://c06cgs47ulyjs" path="res://Entities/Tree/assets/temp/stone_smallC.glb" id="19_ynokf"] [ext_resource type="Texture2D" uid="uid://c78jcjh8fjndd" path="res://Stages/Test3D/assets/3d/particles/flamelet_smooth.png" id="21_xvexm"] [ext_resource type="Script" uid="uid://dglvt140rhg00" path="res://Stages/Test3D/omni_light_3d.gd" id="22_ukp6m"] [ext_resource type="PackedScene" uid="uid://mdxkaqaoybjv" path="res://Stages/Test3D/assets/tent-canvas.glb" id="23_5r2bu"] @@ -365,6 +372,42 @@ size = Vector2(2, 2) [sub_resource type="BoxShape3D" id="BoxShape3D_tfa5t"] size = Vector3(60, 0, 20) +[sub_resource type="Curve" id="Curve_5r2bu"] +_data = [Vector2(0.003125, 0.0237797), 0.0, 0.0, 0, 0, Vector2(0.21875, 0.877972), 0.0, 0.0, 0, 0, Vector2(0.41875, 0.194618), 0.0, 0.0, 0, 0, Vector2(0.478125, 0.576971), -7.27116, -7.27116, 0, 0, Vector2(0.621875, 0.227159), 0.0, 0.0, 0, 0, Vector2(0.7625, 0.365457), 0.0, 0.0, 0, 0, Vector2(1, 0.04005), 0.0, 0.0, 0, 0] +point_count = 7 + +[sub_resource type="CurveTexture" id="CurveTexture_23r73"] +curve = SubResource("Curve_5r2bu") + +[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_p5fn2"] +emission_shape = 6 +emission_ring_axis = Vector3(0, 1, 0) +emission_ring_height = 1.0 +emission_ring_radius = 5.0 +emission_ring_inner_radius = 0.0 +emission_ring_cone_angle = 90.0 +direction = Vector3(0.2, -1, 0) +spread = 5.0 +initial_velocity_max = 10.0 +scale_min = 0.1 +alpha_curve = SubResource("CurveTexture_23r73") +collision_mode = 2 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_p5fn2"] +transparency = 1 +cull_mode = 2 +shading_mode = 0 +vertex_color_use_as_albedo = true +albedo_color = Color(1, 1, 1, 0.807843) +albedo_texture = ExtResource("23_23r73") +use_particle_trails = true + +[sub_resource type="RibbonTrailMesh" id="RibbonTrailMesh_5r2bu"] +material = SubResource("StandardMaterial3D_p5fn2") +size = 0.025 +sections = 2 +section_segments = 1 + [sub_resource type="Curve" id="Curve_ukp6m"] _data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(0.515625, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] point_count = 3 @@ -407,42 +450,6 @@ material = SubResource("StandardMaterial3D_hvb1l") size = Vector2(0.2, 0.2) orientation = 0 -[sub_resource type="Curve" id="Curve_5r2bu"] -_data = [Vector2(0.003125, 0.0237797), 0.0, 0.0, 0, 0, Vector2(0.21875, 0.877972), 0.0, 0.0, 0, 0, Vector2(0.41875, 0.194618), 0.0, 0.0, 0, 0, Vector2(0.478125, 0.576971), -7.27116, -7.27116, 0, 0, Vector2(0.621875, 0.227159), 0.0, 0.0, 0, 0, Vector2(0.7625, 0.365457), 0.0, 0.0, 0, 0, Vector2(1, 0.04005), 0.0, 0.0, 0, 0] -point_count = 7 - -[sub_resource type="CurveTexture" id="CurveTexture_23r73"] -curve = SubResource("Curve_5r2bu") - -[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_p5fn2"] -emission_shape = 6 -emission_ring_axis = Vector3(0, 1, 0) -emission_ring_height = 1.0 -emission_ring_radius = 5.0 -emission_ring_inner_radius = 0.0 -emission_ring_cone_angle = 90.0 -direction = Vector3(0.2, -1, 0) -spread = 5.0 -initial_velocity_max = 10.0 -scale_min = 0.1 -alpha_curve = SubResource("CurveTexture_23r73") -collision_mode = 2 - -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_p5fn2"] -transparency = 1 -cull_mode = 2 -shading_mode = 0 -vertex_color_use_as_albedo = true -albedo_color = Color(1, 1, 1, 0.807843) -albedo_texture = ExtResource("23_23r73") -use_particle_trails = true - -[sub_resource type="RibbonTrailMesh" id="RibbonTrailMesh_5r2bu"] -material = SubResource("StandardMaterial3D_p5fn2") -size = 0.025 -sections = 2 -section_segments = 1 - [node name="Test3d" type="Node3D"] [node name="WorldEnvironment" type="WorldEnvironment" parent="."] @@ -761,31 +768,50 @@ shape = SubResource("BoxShape3D_tfa5t") [node name="VFX" type="Node3D" parent="SubViewportContainer/SubViewport"] -[node name="Fire" type="GPUParticles3D" parent="SubViewportContainer/SubViewport/VFX"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.08083, 0.0837402, 0.501403) -visible = false -amount = 50 -lifetime = 0.4 -speed_scale = 0.4 -process_material = SubResource("ParticleProcessMaterial_xvexm") -draw_pass_1 = SubResource("QuadMesh_hvb1l") +[node name="FloatingParticles" type="GPUParticles3D" parent="SubViewportContainer/SubViewport/VFX"] +script = ExtResource("9_oiyue") -[node name="OmniLight3D" type="OmniLight3D" parent="SubViewportContainer/SubViewport/VFX/Fire"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.000509977, 0.121094, -0.00151992) -light_color = Color(0.89, 0.461613, 0.2136, 1) -light_energy = 0.590552 -light_indirect_energy = 1.084 -light_volumetric_fog_energy = 3.764 -light_size = 0.105 -shadow_enabled = true -distance_fade_enabled = true -distance_fade_begin = 386.01 -distance_fade_shadow = 45.9 -distance_fade_length = 28.05 -script = ExtResource("22_ukp6m") +[node name="TileGround" type="Node3D" parent="SubViewportContainer/SubViewport"] +unique_name_in_owner = true +script = ExtResource("24_vyi1v") +ground_tile = ExtResource("25_caaui") -[node name="Rain" type="GPUParticles3D" parent="SubViewportContainer/SubViewport/VFX"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 10, 0) +[node name="Camp" type="Node3D" parent="SubViewportContainer/SubViewport"] +unique_name_in_owner = true + +[node name="Objects" type="Node3D" parent="SubViewportContainer/SubViewport/Camp"] + +[node name="tent-canvas2" parent="SubViewportContainer/SubViewport/Camp/Objects" instance=ExtResource("23_5r2bu")] +transform = Transform3D(0.964438, 0, -0.264311, 0, 1, 0, 0.264311, 0, 0.964438, -1.40178, 0, -1.67128) + +[node name="campfire_bricks2" parent="SubViewportContainer/SubViewport/Camp/Objects" instance=ExtResource("13_qasnx")] +transform = Transform3D(0.7, 0, 0, 0, 0.7, 0, 0, 0, 0.7, -0.93138, 0.05, -0.326702) + +[node name="campfire_logs2" parent="SubViewportContainer/SubViewport/Camp/Objects/campfire_bricks2" instance=ExtResource("14_2xm50")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.0053246, 0, 0.0117908) + +[node name="log2" parent="SubViewportContainer/SubViewport/Camp/Objects" instance=ExtResource("15_e0hgm")] +transform = Transform3D(0.440003, 0, 0.237482, 0, 0.5, 0, -0.237482, 0, 0.440003, -0.565749, 0.0532002, -0.598678) + +[node name="statue_column2" parent="SubViewportContainer/SubViewport/Camp/Objects" instance=ExtResource("16_ynokf")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2.654, 0, -2.707) + +[node name="statue_column3" parent="SubViewportContainer/SubViewport/Camp/Objects" instance=ExtResource("16_ynokf")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.589154, 0, -2.703) + +[node name="statue_column4" parent="SubViewportContainer/SubViewport/Camp/Objects" instance=ExtResource("16_ynokf")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2.727, 0, 0.611) + +[node name="statue_columnDamaged2" parent="SubViewportContainer/SubViewport/Camp/Objects" instance=ExtResource("17_pbfwi")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.609224, 0, 0.72) + +[node name="bed_floor2" parent="SubViewportContainer/SubViewport/Camp/Objects" instance=ExtResource("15_pbfwi")] +transform = Transform3D(0.72094, 0, -0.346764, 0, 0.8, 0, 0.346764, 0, 0.72094, -1.54675, 0.0359214, -1.37165) + +[node name="VFX" type="Node3D" parent="SubViewportContainer/SubViewport/Camp"] + +[node name="Rain" type="GPUParticles3D" parent="SubViewportContainer/SubViewport/Camp/VFX"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.545105, 10.1451, 0.937134) visible = false amount = 1000 preprocess = 10.0 @@ -795,16 +821,27 @@ trail_lifetime = 0.1 process_material = SubResource("ParticleProcessMaterial_p5fn2") draw_pass_1 = SubResource("RibbonTrailMesh_5r2bu") -[node name="FloatingParticles" type="GPUParticles3D" parent="SubViewportContainer/SubViewport/VFX"] -script = ExtResource("9_oiyue") +[node name="Fire" type="GPUParticles3D" parent="SubViewportContainer/SubViewport/Camp/VFX"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.923367, 0.0346675, -0.309572) +amount = 50 +lifetime = 0.4 +speed_scale = 0.4 +process_material = SubResource("ParticleProcessMaterial_xvexm") +draw_pass_1 = SubResource("QuadMesh_hvb1l") -[node name="TileGround" type="Node3D" parent="SubViewportContainer/SubViewport"] -unique_name_in_owner = true -script = ExtResource("24_vyi1v") -ground_tile = ExtResource("25_caaui") - -[node name="tent-canvas2" parent="." instance=ExtResource("23_5r2bu")] -transform = Transform3D(0.964438, 0, -0.264311, 0, 1, 0, 0.264311, 0, 0.964438, 1.49756, 1.86265e-09, -3.10828) +[node name="OmniLight3D" type="OmniLight3D" parent="SubViewportContainer/SubViewport/Camp/VFX/Fire"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.000509977, 0.121094, -0.00151992) +light_color = Color(0.89, 0.461613, 0.2136, 1) +light_energy = 0.716329 +light_indirect_energy = 1.084 +light_volumetric_fog_energy = 3.764 +light_size = 0.105 +shadow_enabled = true +distance_fade_enabled = true +distance_fade_begin = 386.01 +distance_fade_shadow = 45.9 +distance_fade_length = 28.05 +script = ExtResource("22_ukp6m") [node name="UISubViewportContainer" type="SubViewportContainer" parent="."] anchors_preset = 15 @@ -852,3 +889,6 @@ fit_content = true [node name="LoadedTreesLabel" type="RichTextLabel" parent="UISubViewportContainer/UISubViewport/UIContainer/PanelContainer/VBoxContainer"] layout_mode = 2 fit_content = true + +[node name="stone_smallC2" parent="." instance=ExtResource("19_ynokf")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.109824, 0.0499998, 1.05729)