extends Node3D @export var structures: Array[Structure] = [] var map:DataMap var index:int = 0 # Index of structure being built @export var selector:Node3D # The 'cursor' @export var selector_container:Node3D # Node that holds a preview of the structure @export var view_camera:Camera3D # Used for raycasting mouse @export var gridmap:GridMap @export var cash_display:Label var plane:Plane # Used for raycasting mouse func _ready(): map = DataMap.new() plane = Plane(Vector3.UP, Vector3.ZERO) # Create new MeshLibrary dynamically, can also be done in the editor # See: https://docs.godotengine.org/en/stable/tutorials/3d/using_gridmaps.html var mesh_library = MeshLibrary.new() for structure in structures: var id = mesh_library.get_last_unused_item_id() mesh_library.create_item(id) mesh_library.set_item_mesh(id, get_mesh(structure.model)) mesh_library.set_item_mesh_transform(id, Transform3D()) gridmap.mesh_library = mesh_library update_structure() update_cash() func _process(delta): # Controls action_rotate() # Rotates selection 90 degrees action_structure_toggle() # Toggles between structures action_save() # Saving action_load() # Loading # Map position based on mouse var world_position = plane.intersects_ray( view_camera.project_ray_origin(get_viewport().get_mouse_position()), view_camera.project_ray_normal(get_viewport().get_mouse_position())) var gridmap_position = Vector3(round(world_position.x), 0, round(world_position.z)) selector.position = lerp(selector.position, gridmap_position, delta * 40) action_build(gridmap_position) action_demolish(gridmap_position) # Retrieve the mesh from a PackedScene, used for dynamically creating a MeshLibrary func get_mesh(packed_scene): var scene_state:SceneState = packed_scene.get_state() for i in range(scene_state.get_node_count()): if(scene_state.get_node_type(i) == "MeshInstance3D"): for j in scene_state.get_node_property_count(i): var prop_name = scene_state.get_node_property_name(i, j) if prop_name == "mesh": var prop_value = scene_state.get_node_property_value(i, j) return prop_value.duplicate() # Build (place) a structure func action_build(gridmap_position): if Input.is_action_just_pressed("build"): var previous_tile = gridmap.get_cell_item(gridmap_position) gridmap.set_cell_item(gridmap_position, index, gridmap.get_orthogonal_index_from_basis(selector.basis)) if previous_tile != index: map.cash -= structures[index].price update_cash() # Demolish (remove) a structure func action_demolish(gridmap_position): if Input.is_action_just_pressed("demolish"): gridmap.set_cell_item(gridmap_position, -1) # Rotates the 'cursor' 90 degrees func action_rotate(): if Input.is_action_just_pressed("rotate"): selector.rotate_y(deg_to_rad(90)) # Toggle between structures to build func action_structure_toggle(): if Input.is_action_just_pressed("structure_next"): index = wrap(index + 1, 0, structures.size()) if Input.is_action_just_pressed("structure_previous"): index = wrap(index - 1, 0, structures.size()) update_structure() # Update the structure visual in the 'cursor' func update_structure(): # Clear previous structure preview in selector for n in selector_container.get_children(): selector_container.remove_child(n) # Create new structure preview in selector var _model = structures[index].model.instantiate() selector_container.add_child(_model) _model.position.y += 0.25 func update_cash(): cash_display.text = "$" + str(map.cash) # Saving/load func action_save(): if Input.is_action_just_pressed("save"): print("Saving map...") map.structures.clear() for cell in gridmap.get_used_cells(): var data_structure:DataStructure = DataStructure.new() data_structure.position = Vector2i(cell.x, cell.z) data_structure.orientation = gridmap.get_cell_item_orientation(cell) data_structure.structure = gridmap.get_cell_item(cell) map.structures.append(data_structure) ResourceSaver.save(map, "user://map.res") func action_load(): if Input.is_action_just_pressed("load"): print("Loading map...") gridmap.clear() map = ResourceLoader.load("user://map.res") if not map: map = DataMap.new() for cell in map.structures: gridmap.set_cell_item(Vector3i(cell.position.x, 0, cell.position.y), cell.structure, cell.orientation) update_cash()