diff --git a/scenes/Chunk.gd b/scenes/Chunk.gd index 33b6ef7..a979219 100644 --- a/scenes/Chunk.gd +++ b/scenes/Chunk.gd @@ -3,22 +3,39 @@ extends TileMap var x:int = -1 var y:int = -1 +var should_remove:bool = true # Called when the node enters the scene tree for the first time. func _init(xpos:int, ypos:int): self.x = xpos self.y = ypos + self.name = "Chunk [%d,%d]" % [x, y] self.set_tileset(Globals.TILESET_TERRAIN) self.position = Vector2i( - x*Globals.CHUNK_SIZE*Globals.TILE_SIZE_X, - y*Globals.CHUNK_SIZE*Globals.TILE_SIZE_Y + x*Globals.CHUNK_SIZE.x*Globals.TILE_SIZE_X, + y*Globals.CHUNK_SIZE.y*Globals.TILE_SIZE_Y + ) + +func _ready(): + generate_chunk() + +func _draw(): + self.draw_rect( + Rect2( + Vector2(0,0), + Vector2( + Globals.CHUNK_SIZE.x*Globals.TILE_SIZE_X, + Globals.CHUNK_SIZE.y*Globals.TILE_SIZE_Y) + ), + Color(0,0,0,0.5), + false ) func generate_chunk() -> void: - for row in Globals.CHUNK_SIZE: - for col in Globals.CHUNK_SIZE: - var tile_data: Array = Globals.map_tile_data[row+y*Globals.CHUNK_SIZE][col+x*Globals.CHUNK_SIZE] + for row in Globals.CHUNK_SIZE.y: + for col in Globals.CHUNK_SIZE.x: + var tile_data: Array = Globals.map_tile_data[row+y*Globals.CHUNK_SIZE.y][col+x*Globals.CHUNK_SIZE.x] # layer | tile coords at tilemap | tilemap id | coords of the tile at tileset | alternative tile self.set_cell( Globals.LAYER_TERRAIN, diff --git a/scenes/Chunk.tscn b/scenes/Chunk.tscn deleted file mode 100644 index 40efe6c..0000000 --- a/scenes/Chunk.tscn +++ /dev/null @@ -1,10 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://54iw2fjk2oth"] - -[ext_resource type="Script" path="res://scenes/Chunk.gd" id="1_lawsj"] -[ext_resource type="TileSet" uid="uid://cxiva1a6jdae2" path="res://scenes/Chunk.tres" id="1_x70ay"] - -[node name="Chunk" type="TileMap"] -tile_set = ExtResource("1_x70ay") -format = 2 -layer_0/tile_data = PackedInt32Array(0, 0, 65536, -1, 0, 65536) -script = ExtResource("1_lawsj") diff --git a/scripts/CameraZoom2D.gd b/scripts/CameraZoom2D.gd index 22a148e..b68eff4 100644 --- a/scripts/CameraZoom2D.gd +++ b/scripts/CameraZoom2D.gd @@ -10,7 +10,12 @@ func camera_zoom_in() -> void: func camera_zoom_out() -> void: _set_camera_zoom_level(Globals.CAMERA_ZOOM_LEVEL + Globals.CAMERA_ZOOM_DURATION) - + +func get_camera_position(): + return self.position + +func _process(delta) -> void: + Globals.CAMERA_POSITION = self.position func _set_camera_zoom_level(value: float) -> void: Globals.CAMERA_ZOOM_LEVEL = clamp(value, Globals.CAMERA_MIN_ZOOM_LEVEL, Globals.CAMERA_MAX_ZOOM_LEVEL) @@ -24,9 +29,8 @@ func _set_camera_zoom_level(value: float) -> void: Globals.CAMERA_ZOOM_DURATION ) -func _on_set_camera_position(_pos: Vector2) -> void: - #self.position = pos - pass +func _on_set_camera_position(pos: Vector2) -> void: + self.position = pos func _unhandled_input(event): if event.is_action_pressed("camera_zoom_in"): diff --git a/scripts/ChunkHandler.gd b/scripts/ChunkHandler.gd index fdcd0a6..c57a947 100644 --- a/scripts/ChunkHandler.gd +++ b/scripts/ChunkHandler.gd @@ -9,36 +9,74 @@ extends Node2D # This is done to speed up game loading and avoiding setting one large tilemap in one go # which is extremely slow in godot 4.0, 4096x4096 takes minutes to fill with set_cell() commands -var map_tiles:Array[Array] = [[]] var chunks:Dictionary = {} -var unused_chunks:Dictionary = {} +var unready_chunks:Dictionary = {} +var chunk_amount = 16 +var window_width = DisplayServer.window_get_size(0).x +var distance = abs((window_width/(Globals.CHUNK_SIZE.x*Globals.TILE_SIZE_X)) / 2 +1 ) func _init() -> void: self.name = "ChunkHandler" + +func _process(_delta): + update_chunks() + clean_up_chunks() + reset_chunks() func _ready(): #thread = Thread.new() + + + #print(distance) pass - - -func start_handler() -> void: - # Initialize the map tile array with enough chunks to cover the whole map - map_tiles.resize(Globals.map_size/Globals.CHUNK_SIZE) - for y in map_tiles.size(): - map_tiles[y].resize(Globals.map_size/Globals.CHUNK_SIZE) +func add_chunk(x:int, y:int) -> void: + var key = str(y) + "," + str(x) + if chunks.has(key): + return + + load_chunk(x, y, key) -func add_chunk(x:int, y:int): +func clean_up_chunks(): + for key in chunks: + var chunk = chunks[key] + if chunk.should_remove: + chunk.queue_free() + chunks.erase(key) + +func clear_chunk(pos:Vector2i) -> void: + self.chunks[pos.y][pos.x].clear() + +func get_chunk(x:int, y:int): + var key = str(y) + "," + str(x) + if self.chunks.has(key): + return chunks.get(key) + + return null + +func load_chunk(x:int, y:int, key:String): var chunk = Chunk.new(x,y) - - var start = Time.get_ticks_usec() - chunk.generate_chunk() self.add_child(chunk) - var end = Time.get_ticks_usec() - print("generate a chunk ", (end-start)/1000.0, "ms") + chunks[key] = chunk - - #chunk.set_position(Vector2(x*Globals.CHUNK_SIZE,y*Globals.CHUNK_SIZE)) + Globals.chunks_loaded += 1 - #map_tiles[chunk_pos.y][chunk_pos.x].clear() +func reset_chunks(): + for key in chunks: + chunks[key].should_remove = true + +func update_chunks(): + var p_x = int(Globals.CAMERA_POSITION.x- Globals.CHUNK_SIZE.x) / Globals.TILE_SIZE_X / Globals.CHUNK_SIZE.x + var p_y = int(Globals.CAMERA_POSITION.y- Globals.CHUNK_SIZE.y) / Globals.TILE_SIZE_Y / Globals.CHUNK_SIZE.y + + for y in Globals.map_size/Globals.CHUNK_SIZE.y: + for x in Globals.map_size/Globals.CHUNK_SIZE.x: + if (abs(x - p_x) <= distance && abs(y - p_y) <= distance): + add_chunk(x, y) + + var chunk = get_chunk(x,y) + if chunk != null: + chunk.should_remove = false + + diff --git a/scripts/Control.gd b/scripts/Control.gd index ab6a5db..757ebda 100644 --- a/scripts/Control.gd +++ b/scripts/Control.gd @@ -25,7 +25,9 @@ func _process(_delta): debug_info.set_text( str(get_viewport().get_mouse_position()) +"\n" + "FPS " + str(Engine.get_frames_per_second()) + "\n" + - "Zoom lvl: " + str(Globals.CAMERA_ZOOM_LEVEL) + "Zoom lvl: " + str(Globals.CAMERA_ZOOM_LEVEL) + "\n" + + "Chunks loaded: " + str(Globals.chunks_loaded) + "\n" + + "Camera pos: " + str(Globals.CAMERA_POSITION) ) # defines construction toolbar buttons diff --git a/scripts/Globals.gd b/scripts/Globals.gd index 2741e75..c51b51e 100644 --- a/scripts/Globals.gd +++ b/scripts/Globals.gd @@ -3,24 +3,18 @@ extends Node -# world map chunk size -const CHUNK_SIZE:int = 16 +var chunks_loaded:int = 0 +################################### +# CHUNK AND TERRAIN SETTINGS # +################################### +# world map chunk size +const CHUNK_SIZE:Vector2i = Vector2i(32,32) # tilemap tile types enum {TILE_WATER, TILE_TERRAIN, TILE_FOREST, TILE_BOG} - # tilemap layers enum {LAYER_TERRAIN, LAYER_BUILDINGS} - const TILESET_TERRAIN:TileSet = preload("res://scenes/Chunk.tres") - -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] - push_error(errmsg) - return false - - return true func choose_randomly(list_of_entries): return list_of_entries[randi() % list_of_entries.size()] @@ -34,8 +28,20 @@ var map_terrain_data:Array[Array] = [[]] # preprocess and store exact tile for every map cell to speed up setting tiles var map_tile_data:Array[Array] = [[]] +################################### +# CAMERA SETTINGS # +################################### + # current camera zoom level var CAMERA_ZOOM_LEVEL: float = 1.0 +var CAMERA_POSITION + +# camera movement settings +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 # FILE PATHS const SCENE_PATH:String = "res://scenes/" @@ -65,13 +71,6 @@ const TYPE_POWERPLANT:String = "powerplant" const TYPE_ROADS:String = "roads" const TYPE_DEMOLISH:String = "demolish" -# camera movement settings -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) diff --git a/scripts/Main.gd b/scripts/Main.gd index 25d8a4b..530ce78 100644 --- a/scripts/Main.gd +++ b/scripts/Main.gd @@ -16,11 +16,13 @@ var map_filenames:Array = [ "res://maps/tampere_10x10km_1000px.png", "res://maps/tampere_10x10km_1024px.png", "res://maps/varkaus_256x256px_test.png", - "res://maps/tampere_256px.png" + "res://maps/tampere_256px.png", + "res://maps/tampere_10x10km_4096px.png" ] -var map_filename:String = map_filenames[3] +var map_filename:String = map_filenames[1] var _world_generator:WorldGenerator var _chunk_handler:ChunkHandler +#var _2d_camera:CameraZoom2D func _init(): @@ -28,23 +30,27 @@ func _init(): # #Vector2i(Globals.DEFAULT_X_RES, Globals.DEFAULT_Y_RES) # Vector2i(3800,2000) # ) - pass - + Globals.CAMERA_POSITION = Vector2(16*256/2, 16*256/2) + +#func _process(_delta): +# Globals.CAMERA_POSITION = _2d_camera.position + # Called when the node enters the scene tree for the first time. func _ready(): # create a new world and worldgenerator _world_generator = WorldGenerator.new() - _chunk_handler = ChunkHandler.new() - add_child(_chunk_handler) + _chunk_handler = ChunkHandler.new() + #_2d_camera = CameraZoom2D.new() - var result = _world_generator.generate_world(map_filename) - - if result: - _chunk_handler.start_handler() - for y in Globals.map_size/Globals.CHUNK_SIZE: - for x in Globals.map_size/Globals.CHUNK_SIZE: - if (y + x) % 2 == 0: - _chunk_handler.add_chunk(x, y) + # add chunk handler if worldgen was successful + if _world_generator.generate_world(map_filename): + add_child(_chunk_handler) + #add_child(_2d_camera) + +# for y in Globals.map_size/Globals.CHUNK_SIZE.y: +# for x in Globals.map_size/Globals.CHUNK_SIZE.x: +# #if (y + x) % 2 == 0: +# _chunk_handler.load_chunk(x, y) else: push_error("World generation failed :-(") diff --git a/scripts/WorldGenerator.gd b/scripts/WorldGenerator.gd index 2d33cf6..9d079bc 100644 --- a/scripts/WorldGenerator.gd +++ b/scripts/WorldGenerator.gd @@ -9,6 +9,14 @@ var directions:Array = [ Vector2i(0,-1), # north Vector2i(-1,0) # west ] + +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] + push_error(errmsg) + return false + + return true func choose_tile(tile:Vector2i, selected, surrounding) -> Array: var surrounding_tiles:Array = [] @@ -249,13 +257,13 @@ func smooth_recursively(pos:Vector2i, selected:int, comp:int) -> void: smooth_recursively(pos, selected, comp) func validate_mapgen_params() -> bool: - if !Globals.are_coords_valid( + if !are_coords_valid( Globals.map_size, Vector2i(Globals.MAP_MIN_HEIGHT, Globals.MAP_MAX_HEIGHT), Globals.ERROR_IMAGE_HEIGHT_INCORRECT): return false - elif !Globals.are_coords_valid( + elif !are_coords_valid( Globals.map_size, Vector2i(Globals.MAP_MIN_WIDTH, Globals.MAP_MAX_WIDTH), Globals.ERROR_IMAGE_WIDTH_INCORRECT):