diff --git a/export_presets.cfg b/export_presets.cfg new file mode 100644 index 0000000..8521739 --- /dev/null +++ b/export_presets.cfg @@ -0,0 +1,66 @@ +[preset.0] + +name="Windows Desktop" +platform="Windows Desktop" +runnable=true +dedicated_server=false +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="" +encryption_include_filters="" +encryption_exclude_filters="" +encrypt_pck=false +encrypt_directory=false +script_encryption_key="" + +[preset.0.options] + +custom_template/debug="" +custom_template/release="" +debug/export_console_script=1 +binary_format/embed_pck=false +texture_format/bptc=false +texture_format/s3tc=true +texture_format/etc=false +texture_format/etc2=false +texture_format/no_bptc_fallbacks=true +binary_format/architecture="x86_64" +codesign/enable=false +codesign/identity_type=0 +codesign/identity="" +codesign/password="" +codesign/timestamp=true +codesign/timestamp_server_url="" +codesign/digest_algorithm=1 +codesign/description="" +codesign/custom_options=PackedStringArray() +application/modify_resources=true +application/icon="" +application/console_wrapper_icon="" +application/icon_interpolation=4 +application/file_version="" +application/product_version="" +application/company_name="" +application/product_name="" +application/file_description="" +application/copyright="" +application/trademarks="" +ssh_remote_deploy/enabled=false +ssh_remote_deploy/host="user@host_ip" +ssh_remote_deploy/port="22" +ssh_remote_deploy/extra_args_ssh="" +ssh_remote_deploy/extra_args_scp="" +ssh_remote_deploy/run_script="Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}' +$action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}' +$trigger = New-ScheduledTaskTrigger -Once -At 00:00 +$settings = New-ScheduledTaskSettingsSet +$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings +Register-ScheduledTask godot_remote_debug -InputObject $task -Force:$true +Start-ScheduledTask -TaskName godot_remote_debug +while (Get-ScheduledTask -TaskName godot_remote_debug | ? State -eq running) { Start-Sleep -Milliseconds 100 } +Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue" +ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue +Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue +Remove-Item -Recurse -Force '{temp_dir}'" diff --git a/maps/tampere_10x10km_1000px.png.import b/maps/tampere_10x10km_1000px.png.import index 8d5d39a..28ed209 100644 --- a/maps/tampere_10x10km_1000px.png.import +++ b/maps/tampere_10x10km_1000px.png.import @@ -1,34 +1,14 @@ [remap] -importer="texture" -type="CompressedTexture2D" +importer="image" +type="Image" uid="uid://b3c1bddo2an1c" -path="res://.godot/imported/tampere_10x10km_1000px.png-d109810aa82500564790bd9658dd33b4.ctex" -metadata={ -"vram_texture": false -} +path="res://.godot/imported/tampere_10x10km_1000px.png-d109810aa82500564790bd9658dd33b4.image" [deps] source_file="res://maps/tampere_10x10km_1000px.png" -dest_files=["res://.godot/imported/tampere_10x10km_1000px.png-d109810aa82500564790bd9658dd33b4.ctex"] +dest_files=["res://.godot/imported/tampere_10x10km_1000px.png-d109810aa82500564790bd9658dd33b4.image"] [params] -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -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=1 diff --git a/scenes/Main.tscn b/scenes/Main.tscn index 6ac5b6a..dec1fff 100644 --- a/scenes/Main.tscn +++ b/scenes/Main.tscn @@ -476,8 +476,8 @@ script = ExtResource("1_ysxum") [node name="World" type="TileMap" parent="."] tile_set = SubResource("TileSet_t3bbo") format = 2 -layer_0/name = "Buildings" -layer_1/name = "Terrain" +layer_0/name = "Terrain" +layer_1/name = "Buildings" layer_1/enabled = true layer_1/modulate = Color(1, 1, 1, 1) layer_1/y_sort_enabled = false @@ -554,6 +554,7 @@ offset_top = 24.0 offset_right = 928.0 offset_bottom = 280.0 +[connection signal="set_camera_position" from="World" to="World/CameraZoom2D" method="_on_world_set_camera_position"] [connection signal="button_pressed" from="UILayer/Control" to="World" method="_on_control_button_pressed"] [connection signal="pressed" from="UILayer/Control/ConstructionPanel/button_residental" to="UILayer/Control" method="_on_button_residental_pressed"] [connection signal="pressed" from="UILayer/Control/ConstructionPanel/button_commercial" to="UILayer/Control" method="_on_button_commercial_pressed"] diff --git a/scripts/CameraZoom2D.gd b/scripts/CameraZoom2D.gd index e505c99..652987f 100644 --- a/scripts/CameraZoom2D.gd +++ b/scripts/CameraZoom2D.gd @@ -5,6 +5,13 @@ extends Camera2D var is_panning_camera = false var tween +func camera_zoom_in() -> void: + _set_camera_zoom_level(Globals.CAMERA_ZOOM_LEVEL - Globals.CAMERA_ZOOM_FACTOR) + +func camera_zoom_out() -> void: + _set_camera_zoom_level(Globals.CAMERA_ZOOM_LEVEL + Globals.CAMERA_ZOOM_DURATION) + + func _set_camera_zoom_level(value: float) -> void: Globals.CAMERA_ZOOM_LEVEL = clamp(value, Globals.CAMERA_MIN_ZOOM_LEVEL, Globals.CAMERA_MAX_ZOOM_LEVEL) @@ -17,13 +24,10 @@ func _set_camera_zoom_level(value: float) -> void: Globals.CAMERA_ZOOM_DURATION ) -func camera_zoom_in() -> void: - _set_camera_zoom_level(Globals.CAMERA_ZOOM_LEVEL - Globals.CAMERA_ZOOM_FACTOR) - -func camera_zoom_out() -> void: - _set_camera_zoom_level(Globals.CAMERA_ZOOM_LEVEL + Globals.CAMERA_ZOOM_DURATION) - - +func _on_world_set_camera_position(pos: Vector2) -> void: + print("Setting camera pos:", pos) + self.position = pos + func _unhandled_input(event): if event.is_action_pressed("camera_zoom_in"): camera_zoom_in() @@ -39,3 +43,4 @@ func _unhandled_input(event): if event is InputEventMouseMotion and is_panning_camera: self.position -= event.relative * Globals.CAMERA_PAN_MULTI + diff --git a/scripts/Control.gd b/scripts/Control.gd index 0a6a9e5..a37abea 100644 --- a/scripts/Control.gd +++ b/scripts/Control.gd @@ -3,7 +3,7 @@ extends Control # var view = get_node("../View") signal button_pressed(button_name) -@onready var debug_info = get_node("DebugInfo") +@onready var debug_info = get_node(Globals.DEBUGINFO_NODE) # name, position var buttons = { @@ -28,10 +28,10 @@ func _process(_delta): func create_buttons(): for button in buttons: var values = buttons[button] - var node_path = get_node("ConstructionPanel/" + str(button)) + var node_path = get_node(Globals.CONSTRUCTION_PANEL_NODE + "/" + str(button)) if(!node_path): - push_error("Error: Button '" + button + "' not found when trying to set it's properties in Control.gd!") + push_error("Error: Button '%s' not found when trying to set it's properties in Control.gd!", button) node_path.set_size(Globals.GUI_BUILD_BUTTON_SIZE) node_path.set_position(values[0]) diff --git a/scripts/Globals.gd b/scripts/Globals.gd index 92a01f1..6a2e061 100644 --- a/scripts/Globals.gd +++ b/scripts/Globals.gd @@ -1,30 +1,67 @@ +# File contains global variables or constants so they all are in one place instead +# of a million files. So you can adjust them easily from one place if needed. + extends Node +var world_map: TileMap + +# FILE PATHS const SCENE_PATH:String = "res://scenes/" const ART_PATH:String = "res://art/" const SCRIPT_PATH:String = "res://scripts" +# NODE NAMES +const WORLD_NODE:String = "World" +const DEBUGINFO_NODE:String = "DebugInfo" +const CONSTRUCTION_PANEL_NODE:String = "ConstructionPanel" + const GUI_BUILD_BUTTON_SIZE_X: int = 50 const GUI_BUILD_BUTTON_SIZE_Y: int = 50 const GUI_BUILD_BUTTON_SIZE: Vector2i = Vector2i(GUI_BUILD_BUTTON_SIZE_X,GUI_BUILD_BUTTON_SIZE_Y) +# GAME WINDOW DEFAULT SIZE const DEFAULT_X_RES:int = 1920 const DEFAULT_Y_RES:int = 1080 -const TYPE_RESIDENTIAL = "residential" -const TYPE_COMMERCIAL = "commercial" -const TYPE_INDUSTRIAL = "industrial" -const TYPE_SERVICES = "services" -const TYPE_SOCIAL = "social" -const TYPE_POWERPLANT = "powerplant" -const TYPE_ROADS = "roads" -const TYPE_DEMOLISH = "demolish" +# maybe should use int for these instead for faster matching? +const TYPE_RESIDENTIAL:String = "residential" +const TYPE_COMMERCIAL:String = "commercial" +const TYPE_INDUSTRIAL:String = "industrial" +const TYPE_SERVICES:String = "services" +const TYPE_SOCIAL:String = "social" +const TYPE_POWERPLANT:String = "powerplant" +const TYPE_ROADS:String = "roads" +const TYPE_DEMOLISH:String = "demolish" + +# tilemap layers +const LAYER_TERRAIN:int = 0 +const LAYER_BUILDINGS:int = 1 # camera movement settings -var CAMERA_ZOOM_LEVEL : float = 1.0 +var CAMERA_ZOOM_LEVEL: float = 1.0 const CAMERA_MIN_ZOOM_LEVEL: float = 0.1 const CAMERA_MAX_ZOOM_LEVEL: float = 2.0 const CAMERA_ZOOM_FACTOR: float = 0.1 const CAMERA_ZOOM_DURATION: float = 0.1 const CAMERA_PAN_MULTI:float = 2.0 + +# city map generation file should have black ground (0,0,0) and white water (1,1,1) +const GROUND_TILE_COLOR_IN_MAP_FILE: Color = Color(0,0,0,1) +const WATER_TILE_COLOR_IN_MAP_FILE: Color = Color(1,1,1,1) + +# min and max sizes for a map so the map won't be unreasonably small or large +const MAP_MIN_HEIGHT:int = 100 +const MAP_MAX_HEIGHT:int = 1000 +const MAP_MIN_WIDTH:int = 100 +const MAP_MAX_WIDTH:int = 1000 + +# tile size +const TILE_SIZE_X:int = 16 +const TILE_SIZE_Y:int = 16 + +# error messages +const ERROR_IMAGE_WIDTH_INCORRECT:String = "Provided map image width '%s' too small or too large. Width should be between: '%s-%s'" +const ERROR_IMAGE_HEIGHT_INCORRECT:String = "Provided map image height '%s' too small or too large. Height should be between: '%s-%s'" +const ERROR_FAILED_TO_LOAD_FILE:String = "Failed to load image with filename: '%s'" + diff --git a/scripts/Main.gd b/scripts/Main.gd index a6ab5d6..e921740 100644 --- a/scripts/Main.gd +++ b/scripts/Main.gd @@ -8,7 +8,8 @@ extends Node -var world_map: TileMap +# The idea is for the user to be able to choose the map from GUI later +var map_file_name: String = "res://maps/tampere_10x10km_1000px.png" func _init(): DisplayServer.window_set_size( @@ -17,21 +18,22 @@ func _init(): # Called when the node enters the scene tree for the first time. func _ready(): - generate_terrain() - - + Globals.world_map = get_node("World") + if !Globals.world_map: + push_error("Error while making an instance of World node.") + quit_game() + + # generate terrain. quit game if generation fails. + if !Globals.world_map.generate_terrain(map_file_name): + push_error("Error in generating the map. Game won't start.") + quit_game() + #SceneTree.quit # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(_delta): pass + +func quit_game(): + get_tree().get_root().propagate_notification(NOTIFICATION_WM_CLOSE_REQUEST) + -func generate_terrain(): - world_map = get_node("World") - var image = Image.new() - image.load("res://maps/tampere_10x10km_1000px.png") - - for x in 1000: - for y in 1000: - # layer | position coords | tilemap id | coords of the tile at tilemap | alternative tile - if image.get_pixel(x, y) == Color(1,1,1,1): - world_map.set_cell(0, Vector2i(x, y), 2, Vector2i(0,0), 0) diff --git a/scripts/World.gd b/scripts/World.gd index abcb67f..929ab2a 100644 --- a/scripts/World.gd +++ b/scripts/World.gd @@ -1,8 +1,9 @@ extends TileMap +signal set_camera_position(pos:Vector2) + var building : bool = false var building_type: String -var tilemap: Vector2i #var scene # Called when the node enters the scene tree for the first time. @@ -31,41 +32,93 @@ func _input(event): # stop processing the sprite (fix it in place). no idea if it is a good idea yet.. #building.set_process(false) building = false - place_building_to_map() + place_building_to_map(event) # cancel placement if event.is_action_pressed("cancel"): if building != false: pass +func calculate_grid_coordinates(map_position: Vector2) -> Vector2: + return (map_position).floor() -func place_building_to_map(): - # layer | position coords | tilemap id | coords of the tile at tilemap | alternative tile - +func place_building_to_map(event): + var tileset_id = 0 # default value + var tilemap_tile_coords: Vector2i + + # layer | position coords | tileset id | coords of the tile at tilemap | alternative tile match building_type: Globals.TYPE_RESIDENTIAL: - tilemap = Vector2i(0,0) - set_cell(0, local_to_map(get_viewport().get_mouse_position()) , 0, tilemap, 0) + tilemap_tile_coords = Vector2i(0,0) + tileset_id = 0 Globals.TYPE_COMMERCIAL: - tilemap = Vector2i(4,12) - set_cell(0, local_to_map(get_viewport().get_mouse_position()) , 1, tilemap, 0) + tilemap_tile_coords = Vector2i(4,12) + tileset_id = 1 Globals.TYPE_INDUSTRIAL: - tilemap = Vector2i(4,20) - set_cell(0, local_to_map(get_viewport().get_mouse_position()) , 1, tilemap, 0) + tilemap_tile_coords = Vector2i(4,20) + tileset_id = 1 Globals.TYPE_ROADS: - tilemap = Vector2i(14,2) - set_cell(0, local_to_map(get_viewport().get_mouse_position()) , 1, tilemap, 0) + tilemap_tile_coords = Vector2i(14,2) + tileset_id = 1 Globals.TYPE_DEMOLISH: - tilemap = Vector2i(4,4) - set_cell(0, local_to_map(get_viewport().get_mouse_position()) , 1, tilemap, 0) + tilemap_tile_coords = Vector2i(4,4) + tileset_id = 1 Globals.TYPE_SERVICES: - tilemap = Vector2i(4,8) - set_cell(0, local_to_map(get_viewport().get_mouse_position()) , 1, tilemap, 0) + tilemap_tile_coords = Vector2i(4,8) + tileset_id = 1 Globals.TYPE_SOCIAL: - tilemap = Vector2i(4,0) - set_cell(0, local_to_map(get_viewport().get_mouse_position()) , 1, tilemap, 0) + tilemap_tile_coords = Vector2i(4,0) + tileset_id = 1 _: #default - tilemap = Vector2i(16,16) - set_cell(0, local_to_map(get_viewport().get_mouse_position()) , 1, tilemap, 0) + tilemap_tile_coords = Vector2i(16,16) + tileset_id = 1 - # set_cell(0, local_to_map(get_viewport().get_mouse_position()) , 1, tilemap, 0) + var mouse_pos = local_to_map(get_global_mouse_position()) + set_cell(Globals.LAYER_BUILDINGS, mouse_pos, tileset_id, tilemap_tile_coords, 0) + #print("cell set at layer ", Globals.LAYER_BUILDINGS) + #print("cellpos:", local_to_map(get_global_mouse_position())) + #print("event position:", event.position) + +func generate_terrain(filename) -> bool: + # Try to load the image which we used to place water & ground to world map + var image:Image = Image.new() + image = load(filename) + if image == null: + var errmsg = Globals.ERROR_FAILED_TO_LOAD_FILE + push_error(errmsg % filename) + return false + + var image_height:int = image.get_height() + var image_width:int = image.get_width() + + # Check if image is too small or too large + if Globals.MAP_MIN_HEIGHT > image_height or image_height > Globals.MAP_MAX_HEIGHT: + var errmsg = Globals.ERROR_IMAGE_HEIGHT_INCORRECT + errmsg = errmsg % [image_height, Globals.MAP_MIN_HEIGHT, Globals.MAP_MAX_HEIGHT] + push_error(errmsg) + return false + elif Globals.MAP_MIN_WIDTH > image_width or image_width > Globals.MAP_MAX_WIDTH: + var errmsg = Globals.ERROR_IMAGE_WIDTH_INCORRECT + errmsg = errmsg % [image_width, Globals.MAP_MIN_WIDTH, Globals.MAP_MAX_WIDTH] + push_error(errmsg) + return false + + # Try to load the world tilemap where we place the tiles + if (Globals.world_map == null): + print("World TileMap node missing or name is wrong.\n + Tried to load: '%s'", Globals.WORLD_NODE) + return false + + # Finally populate the world map with hopefully valid tiles! + for x in image_width: + for y in image_height: + # layer | position coords | tilemap id | coords of the tile at tilemap | alternative tile + if image.get_pixel(x, y) == Globals.WATER_TILE_COLOR_IN_MAP_FILE: + Globals.world_map.set_cell(Globals.LAYER_TERRAIN, Vector2i(x, y), 2, Vector2i(0,0), 0) + + # center camera to world map + emit_signal( + "set_camera_position", + Vector2(image_height/2.0*Globals.TILE_SIZE_X, image_width/2.0*Globals.TILE_SIZE_Y) + ) + return true