mirror of
https://github.com/tonytins/citylimits
synced 2025-06-25 17:34:43 -04:00
Merge Kenny's City Builder Starter Kit
This commit is contained in:
parent
dd04a01651
commit
36edaaf17b
510 changed files with 2236 additions and 7925 deletions
156
scripts/3d/builder3d.gd
Normal file
156
scripts/3d/builder3d.gd
Normal file
|
@ -0,0 +1,156 @@
|
|||
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()
|
5
scripts/3d/data_map.gd
Normal file
5
scripts/3d/data_map.gd
Normal file
|
@ -0,0 +1,5 @@
|
|||
extends Resource
|
||||
class_name DataMap
|
||||
|
||||
@export var cash:int = 10000
|
||||
@export var structures:Array[DataStructure]
|
6
scripts/3d/data_structure.gd
Normal file
6
scripts/3d/data_structure.gd
Normal file
|
@ -0,0 +1,6 @@
|
|||
extends Resource
|
||||
class_name DataStructure
|
||||
|
||||
@export var position:Vector2i
|
||||
@export var orientation:int
|
||||
@export var structure:int
|
8
scripts/3d/structure.gd
Normal file
8
scripts/3d/structure.gd
Normal file
|
@ -0,0 +1,8 @@
|
|||
extends Resource
|
||||
class_name Structure
|
||||
|
||||
@export_subgroup("Model")
|
||||
@export var model:PackedScene # Model of the structure
|
||||
|
||||
@export_subgroup("Gameplay")
|
||||
@export var price:int # Price of the structure when building
|
49
scripts/3d/view.gd
Normal file
49
scripts/3d/view.gd
Normal file
|
@ -0,0 +1,49 @@
|
|||
extends Node3D
|
||||
|
||||
var camera_position:Vector3
|
||||
var camera_rotation:Vector3
|
||||
|
||||
@onready var camera = $Camera
|
||||
|
||||
func _ready():
|
||||
|
||||
camera_rotation = rotation_degrees # Initial rotation
|
||||
|
||||
pass
|
||||
|
||||
func _process(delta):
|
||||
|
||||
# Set position and rotation to targets
|
||||
|
||||
position = position.lerp(camera_position, delta * 8)
|
||||
rotation_degrees = rotation_degrees.lerp(camera_rotation, delta * 6)
|
||||
|
||||
handle_input(delta)
|
||||
|
||||
# Handle input
|
||||
|
||||
func handle_input(_delta):
|
||||
|
||||
# Rotation
|
||||
|
||||
var input := Vector3.ZERO
|
||||
|
||||
input.x = Input.get_axis("camera_left", "camera_right")
|
||||
input.z = Input.get_axis("camera_forward", "camera_back")
|
||||
|
||||
input = input.rotated(Vector3.UP, rotation.y).normalized()
|
||||
|
||||
camera_position += input / 4
|
||||
|
||||
# Back to center
|
||||
|
||||
if Input.is_action_pressed("camera_center"):
|
||||
camera_position = Vector3()
|
||||
|
||||
func _input(event):
|
||||
|
||||
# Rotate camera using mouse (hold 'middle' mouse button)
|
||||
|
||||
if event is InputEventMouseMotion:
|
||||
if Input.is_action_pressed("camera_rotate"):
|
||||
camera_rotation += Vector3(0, -event.relative.x / 10, 0)
|
Loading…
Add table
Add a link
Reference in a new issue