diff --git a/project.godot b/project.godot index 0ae5a04..ab7ce6c 100644 --- a/project.godot +++ b/project.godot @@ -21,8 +21,8 @@ Globals="*res://scripts/Globals.gd" [display] -window/size/viewport_width=1920 window/size/viewport_height=1080 +window/size/mode=2 window/size/resizable=false [input] diff --git a/scenes/Main.tscn b/scenes/Main.tscn index 58ec049..acab0fd 100644 --- a/scenes/Main.tscn +++ b/scenes/Main.tscn @@ -470,7 +470,14 @@ texture = ExtResource("5_bqev6") 0:0/2/flip_v = true 0:0/3 = 3 0:0/3/transpose = true +1:0/next_alternative_id = 4 1:0/0 = 0 +1:0/1 = 1 +1:0/1/flip_h = true +1:0/2 = 2 +1:0/2/flip_v = true +1:0/3 = 3 +1:0/3/transpose = true 2:0/0 = 0 3:0/0 = 0 4:0/0 = 0 @@ -1528,6 +1535,7 @@ offset_right = 936.0 offset_bottom = 256.0 horizontal_alignment = 2 +[connection signal="set_camera_position" from="." to="World/CameraZoom2D" method="_on_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 cc2c2db..ae73441 100644 --- a/scripts/CameraZoom2D.gd +++ b/scripts/CameraZoom2D.gd @@ -24,7 +24,7 @@ func _set_camera_zoom_level(value: float) -> void: Globals.CAMERA_ZOOM_DURATION ) -func _on_world_set_camera_position(pos: Vector2) -> void: +func _on_set_camera_position(pos: Vector2) -> void: self.position = pos func _unhandled_input(event): diff --git a/scripts/Globals.gd b/scripts/Globals.gd index b1c0227..dd5fd1b 100644 --- a/scripts/Globals.gd +++ b/scripts/Globals.gd @@ -3,8 +3,12 @@ extends Node +# tilemap tile types enum {TILE_WATER, TILE_TERRAIN, TILE_FOREST, TILE_BOG} +# tilemap layers +enum {LAYER_TERRAIN, LAYER_BUILDINGS} + func are_coords_valid(value:int, bounds:Vector2i, errmsg:String) -> bool: if bounds.x > value or value > bounds.y: errmsg = errmsg % [value, bounds.x, bounds.y] @@ -12,6 +16,9 @@ func are_coords_valid(value:int, bounds:Vector2i, errmsg:String) -> bool: return false return true + +func choose_randomly(list_of_entries): + return list_of_entries[randi() % list_of_entries.size()] var world_map: TileMap var map_image_size:Vector2i @@ -44,10 +51,6 @@ 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 @@ -71,6 +74,56 @@ const MAP_MAX_WIDTH:int = 1000 const TILE_SIZE_X:int = 16 const TILE_SIZE_Y:int = 16 +# tile dict to tilemap +var td = { + TILE_WATER: { + "default": [Vector2i(1,0)] + }, + TILE_TERRAIN: { + "default": [Vector2i(0,0)], + # 4 land tiles around water + [1,1,1,1]: [Vector2i(0,0)], + # 3 land tiles around water + [1,1,1,0]: [Vector2i(0,0)], + [1,1,0,1]: [Vector2i(0,0)], + [1,0,1,1]: [Vector2i(0,0)], + [0,1,1,1]: [Vector2i(0,0)], + # 2 land tiles around water + [1,1,0,0]: [Vector2i(11,0), Vector2i(12,0)], + [0,1,1,0]: [Vector2i(7,0), Vector2i(8,0)], + [0,0,1,1]: [Vector2i(19,0), Vector2i(20,0)], + [1,0,0,1]: [Vector2i(15,0), Vector2i(16,0)], + # 1 land tile around water + [0,0,0,1]: [Vector2i(17,0), Vector2i(18,0)], + [0,0,1,0]: [Vector2i(5,0), Vector2i(6,0)], + [0,1,0,0]: [Vector2i(9,0), Vector2i(10,0)], + [1,0,0,0]: [Vector2i(13,0), Vector2i(14,0)], + }, + TILE_FOREST: { + "default": [Vector2i(5,1)], + # 4 forest tiles around land + [2,2,2,2]: [Vector2i(5,1)], + # 3 forest tiles around land + [2,2,2,1]: [Vector2i(5,1)], + [2,2,1,2]: [Vector2i(5,1)], + [2,1,2,2]: [Vector2i(5,1)], + [1,2,2,2]: [Vector2i(5,1)], + # 2 forest tiles around land + [2,2,1,1]: [Vector2i(28,0)], + [1,2,2,1]: [Vector2i(26,0)], + [1,1,2,2]: [Vector2i(24,0)], + [2,1,1,2]: [Vector2i(22,0)], + # 1 forest tile around land + [1,1,1,2]: [Vector2i(23,0)], + [1,1,2,1]: [Vector2i(25,0)], + [1,2,1,1]: [Vector2i(27,0)], + [2,1,1,1]: [Vector2i(29,0)], + }, + TILE_BOG: { + "key": [Vector2i(0,0)] + } + } + # error messages const ERROR_BUILDING_TYPE_NOT_SET:String = "Building type not set, while trying to place building." const ERROR_BUTTON_NOT_FOUND:String = "Button '%s' not found when trying to set it's properties in Control.gd!" diff --git a/scripts/Main.gd b/scripts/Main.gd index a98b34c..13241f7 100644 --- a/scripts/Main.gd +++ b/scripts/Main.gd @@ -9,16 +9,20 @@ class_name Main extends Node +signal set_camera_position(pos:Vector2) + # The idea is for the user to be able to choose the map from GUI later -var map_filename: String = "res://maps/varkaus_256x256px_test.png" +#var map_filename: String = "res://maps/tampere_10x10km_1000px.png" +var map_filename:String = "res://maps/tampere_200px_crop.png" var _world := World.new() var _world_generator := WorldGeneration.new() func _init(): - DisplayServer.window_set_size( - #Vector2i(Globals.DEFAULT_X_RES, Globals.DEFAULT_Y_RES) - Vector2i(3800,2000) - ) +# DisplayServer.window_set_size( +# #Vector2i(Globals.DEFAULT_X_RES, Globals.DEFAULT_Y_RES) +# Vector2i(3800,2000) +# ) + pass # Called when the node enters the scene tree for the first time. func _ready(): @@ -30,6 +34,13 @@ func _ready(): if !_world_generator.generate_world(map_filename): push_error(Globals.ERROR_WHILE_GENERATING_MAP) quit_game() + + # center camera to world map + emit_signal( + "set_camera_position", + Vector2(Globals.map_image_size.x / 2.0 * Globals.TILE_SIZE_X, + Globals.map_image_size.y / 2.0 * Globals.TILE_SIZE_Y) + ) # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(_delta): diff --git a/scripts/WorldGeneration.gd b/scripts/WorldGeneration.gd index 854a61b..fb27efd 100644 --- a/scripts/WorldGeneration.gd +++ b/scripts/WorldGeneration.gd @@ -1,8 +1,6 @@ class_name WorldGeneration extends RefCounted -signal set_camera_position(pos:Vector2) - var image:Image = Image.new() var map_tile_data:Array[Array] = [[]] # store map tile info to a 2d array var directions:Array = [ @@ -11,57 +9,45 @@ var directions:Array = [ Vector2i(0,-1), # north Vector2i(-1,0) # west ] - -var count:int = 0 -func choose_forest_tile(tile:Vector2i) -> Vector2i: - var surrounding_tiles:Array = [] - - # determine which directions have forest around the tile - for dir in directions: - # avoid index out of bounds - if (tile.y+dir.y >= Globals.map_image_size.y) or (tile.x+dir.x >= Globals.map_image_size.x): - surrounding_tiles.append(Globals.TILE_TERRAIN) - elif map_tile_data[tile.y+dir.y][tile.x+dir.x] == Globals.TILE_FOREST: - surrounding_tiles.append(Globals.TILE_FOREST) - continue - surrounding_tiles.append(Globals.TILE_TERRAIN) - - var selected_tile = match_forest_tile(surrounding_tiles) - if selected_tile.x == -1 or selected_tile.y == -1: - selected_tile = Vector2i(0,0) - - return selected_tile - -func choose_tile(tile:Vector2i) -> Vector2i: +func choose_tile(tile:Vector2i, selected, surrounding) -> void: var surrounding_tiles:Array = [] # determine which directions have land around the tile for dir in directions: # avoid index out of bounds if (tile.y+dir.y >= Globals.map_image_size.y) or (tile.x+dir.x >= Globals.map_image_size.x): - surrounding_tiles.append(Globals.TILE_WATER) - elif map_tile_data[tile.y+dir.y][tile.x+dir.x] == Globals.TILE_TERRAIN: - surrounding_tiles.append(Globals.TILE_TERRAIN) - continue - surrounding_tiles.append(Globals.TILE_WATER) + surrounding_tiles.append(surrounding) + elif map_tile_data[tile.y+dir.y][tile.x+dir.x] == surrounding: + surrounding_tiles.append(surrounding) + else: + surrounding_tiles.append(selected) - var selected_tile = match_tile(surrounding_tiles) - if selected_tile.x == -1 or selected_tile.y == -1: - selected_tile = Vector2i(1,0) + # this is because a tile can have more than 1 option + var selected_tile = Globals.td[surrounding].get(surrounding_tiles) + var tile_coords:Vector2i + if selected_tile == null: + tile_coords = Globals.td[selected].get("default")[0] + elif selected_tile.size() > 1: + tile_coords = Globals.choose_randomly(selected_tile) + else: + tile_coords = selected_tile[0] - return selected_tile - -func choose_randomly(list_of_entries:Array[int]) -> int: - return list_of_entries[randi() % list_of_entries.size()] + # layer | position coords | tilemap id | coords of the tile at tilemap | alternative tile + Globals.world_map.set_cell( + Globals.LAYER_TERRAIN, + Vector2i(tile.x, tile.y), + 2, + tile_coords, + 0 if selected_tile else Globals.choose_randomly([0,1,2,3]) + ) # Generates biomes, like forest and bog func generate_biomes() -> void: - - print("biome generation") + # generate a new noisemap which should emulate forest-looking areas var fnl = FastNoiseLite.new() fnl.noise_type = FastNoiseLite.TYPE_PERLIN - fnl.seed = randi() + fnl.seed = 69 #randi() fnl.frequency = 0.1 fnl.fractal_type = FastNoiseLite.FRACTAL_FBM fnl.fractal_octaves = 3 @@ -69,14 +55,14 @@ func generate_biomes() -> void: fnl.fractal_gain = 1.746 var water_next_to_tile:bool = false - - #var noise_img = Image.new() - #noise_img = fnl.get_image(Globals.map_image_size.x, Globals.map_image_size.y) + for y in map_tile_data.size(): - for x in map_tile_data[y].size(): + for x in map_tile_data[y].size(): + # replace non-water with biomes if map_tile_data[y][x] > 0: water_next_to_tile = false + # don't put forest next to water for dir in directions: if (y+dir.y >= Globals.map_image_size.y) or (x+dir.x >= Globals.map_image_size.x): @@ -84,13 +70,12 @@ func generate_biomes() -> void: if map_tile_data[y+dir.y][x+dir.x] == Globals.TILE_WATER: water_next_to_tile = true + # if there's no water next to a land tile, it can be replaced with forest if !water_next_to_tile: var noise_sample = fnl.get_noise_2d(x,y) if noise_sample < 0.1: - count += 1 map_tile_data[y][x] = Globals.TILE_FOREST - - print("maata korvattu ", count) + # can add other tresholds here for other biomes func generate_world(filename) -> bool: # Try to load the image which we used to place water & ground to world map @@ -106,95 +91,12 @@ func generate_world(filename) -> bool: return false read_image_pixel_data() - smooth_land_features() + smooth_land_features(Globals.TILE_WATER) # smooth water generate_biomes() - set_tilemap_tiles() - - # center camera to world map - emit_signal( - "set_camera_position", - Vector2(Globals.map_image_size.x / 2.0 * Globals.TILE_SIZE_X, - Globals.map_image_size.y / 2.0 * Globals.TILE_SIZE_Y) - ) + smooth_land_features(Globals.TILE_FOREST) # smooth out forest + set_tilemap_tiles() + return true - -func match_forest_tile(surrounding_tiles) -> Vector2i: - match surrounding_tiles: - # 4 forest tiles around land - [2,2,2,2]: - return Vector2i(5,1) # forest tile - - # 3 forest tiles around land - [2,2,2,1]: - return Vector2i(5,1) # forest tile - [2,2,1,2]: - return Vector2i(5,1) # forest tile - [2,1,2,2]: - return Vector2i(5,1) # forest tile - [1,2,2,2]: - return Vector2i(5,1) # forest tile - - # 2 forest tiles around land - [2,2,1,1]: # south & east - return Vector2i(28,0) - [1,2,2,1]: # north & east - return Vector2i(26,0) - [1,1,2,2]: # north & west - return Vector2i(24,0) - [2,1,1,2]: # south & west - return Vector2i(22,0) - - # 1 forest tile around land - [1,1,1,2]: # west only - return Vector2i(23,0) - [1,1,2,1]: # north only - return Vector2i(25,0) - [1,2,1,1]: # east only - return Vector2i(27,0) - [2,1,1,1]: # south only - return Vector2i(29,0) - - _: # otherwise skip drawing - return Vector2i(-1,-1) - -func match_tile(surrounding_tiles) -> Vector2i: - match surrounding_tiles: - # 4 land tiles around water - [1,1,1,1]: - return Vector2i(0,0) # land tile - - # 3 land tiles around water - [1,1,1,0]: - return Vector2i(0,0) # land tile - [1,1,0,1]: - return Vector2i(0,0) # land tile - [1,0,1,1]: - return Vector2i(0,0) # land tile - [0,1,1,1]: - return Vector2i(0,0) # land tile - - # 2 land tiles around water - [1,1,0,0]: # south & east - return Vector2i(choose_randomly([11,12]),0) - [0,1,1,0]: # north & east - return Vector2i(choose_randomly([7,8]),0) - [0,0,1,1]: # north & west - return Vector2i(choose_randomly([19,20]),0) - [1,0,0,1]: # south & west - return Vector2i(choose_randomly([15,16]),0) - - # 1 land tile around water - [0,0,0,1]: # west only - return Vector2i(choose_randomly([17,18]),0) - [0,0,1,0]: # north only - return Vector2i(choose_randomly([5,6]),0) - [0,1,0,0]: # east only - return Vector2i(choose_randomly([9,10]),0) - [1,0,0,0]: # south only - return Vector2i(choose_randomly([13,14]),0) - - _: # otherwise skip drawing - return Vector2i(-1,-1) func read_image_pixel_data(): # initialize the array to have enough rows @@ -212,77 +114,119 @@ func read_image_pixel_data(): func set_tilemap_tiles() -> void: for y in map_tile_data.size(): - for x in map_tile_data[y].size(): + for x in map_tile_data[y].size(): # layer | position coords | tilemap id | coords of the tile at tilemap | alternative tile match map_tile_data[y][x]: - Globals.TILE_WATER: - Globals.world_map.set_cell( - Globals.LAYER_TERRAIN, - Vector2i(x, y), - 2, - choose_tile(Vector2i(x, y)), # choose tile based on surrounding tiles - 0 - ) - Globals.TILE_TERRAIN: - Globals.world_map.set_cell( - Globals.LAYER_TERRAIN, - Vector2i(x, y), - 2, - choose_forest_tile(Vector2i(x,y)), - 0 - ) - Globals.TILE_FOREST: + Globals.TILE_WATER: # water or shoreline + choose_tile(Vector2i(x, y), Globals.TILE_WATER, Globals.TILE_TERRAIN) + + Globals.TILE_TERRAIN: #terrain or forest edge +# Globals.world_map.set_cell( +# Globals.LAYER_TERRAIN, +# Vector2i(x, y), +# 2, +# Vector2i(0,0), +# Globals.choose_randomly([0,1,2,3]) +# ) + choose_tile(Vector2i(x,y), Globals.TILE_TERRAIN, Globals.TILE_FOREST) + + Globals.TILE_FOREST: Globals.world_map.set_cell( Globals.LAYER_TERRAIN, Vector2i(x, y), 2, Vector2i(5,1), - choose_randomly([0,1,2,3]) - ) + Globals.choose_randomly([0,1,2,3]) + ) + _: #default pass # Fill water tiles, surrounded in 3-4 sides by land, with land. # Do it recursively with limit of n recursions! -func smooth_land_features() -> void: +func smooth_land_features(tile_type:int) -> void: # TODO for testing avoid map borders to make it simpler to implement for y in range(1, Globals.map_image_size.y-1): for x in range(1, Globals.map_image_size.x-1): - if map_tile_data[y][x] != Globals.TILE_WATER: + if map_tile_data[y][x] != tile_type: continue - smooth_recursively(Vector2i(x, y)) - -func smooth_recursively(pos:Vector2i) -> void: + match tile_type: + Globals.TILE_WATER: + smooth_recursively( + Vector2i(x, y), + Globals.TILE_WATER, + Globals.TILE_TERRAIN + ) + Globals.TILE_FOREST: + smooth_forest_recursively( + Vector2i(x, y), + Globals.TILE_FOREST, + Globals.TILE_TERRAIN + ) + +# TEMP SPAGHETTI SOLUTION +func smooth_forest_recursively(pos:Vector2i, selected:int, comp:int) -> void: # now we are supposed to be inspecting a tile with land - # 1 = water 0 = land var surrounding_tiles:Array = [] # determine which directions have land around the tile for dir in directions: - if map_tile_data[pos.y+dir.y][pos.x+dir.x] == Globals.TILE_TERRAIN: - surrounding_tiles.append(Globals.TILE_TERRAIN) - elif map_tile_data[pos.y+dir.y][pos.x+dir.x] == Globals.TILE_WATER: - surrounding_tiles.append(Globals.TILE_WATER) + if map_tile_data[pos.y+dir.y][pos.x+dir.x] == comp: + surrounding_tiles.append(comp) + elif map_tile_data[pos.y+dir.y][pos.x+dir.x] == selected: + surrounding_tiles.append(selected) + + match surrounding_tiles: + [1,1,1,2]: #west + map_tile_data[pos.y][pos.x] = comp + pos.x -= 1 + [1,1,2,1]: #north + map_tile_data[pos.y][pos.x] = comp + pos.y -= 1 + [1,2,1,1]: #east + map_tile_data[pos.y][pos.x] = comp + pos.x += 1 + [2,1,1,1]: #south + map_tile_data[pos.y][pos.x] = comp + pos.y += 1 + [1,1,1,1]: # remove solo forests + map_tile_data[pos.y][pos.x] = comp + return + _: + return + + #smooth_forest_recursively(pos, selected, comp) + +func smooth_recursively(pos:Vector2i, selected:int, comp:int) -> void: + # now we are supposed to be inspecting a tile with land + var surrounding_tiles:Array = [] + + # determine which directions have land around the tile + for dir in directions: + if map_tile_data[pos.y+dir.y][pos.x+dir.x] == comp: + surrounding_tiles.append(comp) + elif map_tile_data[pos.y+dir.y][pos.x+dir.x] == selected: + surrounding_tiles.append(selected) match surrounding_tiles: [1,1,1,0]: #west - map_tile_data[pos.y][pos.x] = Globals.TILE_TERRAIN + map_tile_data[pos.y][pos.x] = comp pos.x -= 1 [1,1,0,1]: #north - map_tile_data[pos.y][pos.x] = Globals.TILE_TERRAIN + map_tile_data[pos.y][pos.x] = comp pos.y -= 1 [1,0,1,1]: #east - map_tile_data[pos.y][pos.x] = Globals.TILE_TERRAIN + map_tile_data[pos.y][pos.x] = comp pos.x += 1 [0,1,1,1]: #south - map_tile_data[pos.y][pos.x] = Globals.TILE_TERRAIN + map_tile_data[pos.y][pos.x] = comp pos.y += 1 _: return - smooth_recursively(pos) + smooth_recursively(pos, selected, comp) func validate_mapgen_params() -> bool: if !Globals.are_coords_valid(