load and remove chunks around camera pos working
This commit is contained in:
parent
fccef57210
commit
0109934933
8 changed files with 137 additions and 73 deletions
|
@ -3,22 +3,39 @@ extends TileMap
|
||||||
|
|
||||||
var x:int = -1
|
var x:int = -1
|
||||||
var y:int = -1
|
var y:int = -1
|
||||||
|
var should_remove:bool = true
|
||||||
|
|
||||||
# Called when the node enters the scene tree for the first time.
|
# Called when the node enters the scene tree for the first time.
|
||||||
func _init(xpos:int, ypos:int):
|
func _init(xpos:int, ypos:int):
|
||||||
self.x = xpos
|
self.x = xpos
|
||||||
self.y = ypos
|
self.y = ypos
|
||||||
|
|
||||||
self.name = "Chunk [%d,%d]" % [x, y]
|
self.name = "Chunk [%d,%d]" % [x, y]
|
||||||
self.set_tileset(Globals.TILESET_TERRAIN)
|
self.set_tileset(Globals.TILESET_TERRAIN)
|
||||||
self.position = Vector2i(
|
self.position = Vector2i(
|
||||||
x*Globals.CHUNK_SIZE*Globals.TILE_SIZE_X,
|
x*Globals.CHUNK_SIZE.x*Globals.TILE_SIZE_X,
|
||||||
y*Globals.CHUNK_SIZE*Globals.TILE_SIZE_Y
|
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:
|
func generate_chunk() -> void:
|
||||||
for row in Globals.CHUNK_SIZE:
|
for row in Globals.CHUNK_SIZE.y:
|
||||||
for col in Globals.CHUNK_SIZE:
|
for col in Globals.CHUNK_SIZE.x:
|
||||||
var tile_data: Array = Globals.map_tile_data[row+y*Globals.CHUNK_SIZE][col+x*Globals.CHUNK_SIZE]
|
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
|
# layer | tile coords at tilemap | tilemap id | coords of the tile at tileset | alternative tile
|
||||||
self.set_cell(
|
self.set_cell(
|
||||||
Globals.LAYER_TERRAIN,
|
Globals.LAYER_TERRAIN,
|
||||||
|
|
|
@ -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")
|
|
|
@ -10,7 +10,12 @@ func camera_zoom_in() -> void:
|
||||||
|
|
||||||
func camera_zoom_out() -> void:
|
func camera_zoom_out() -> void:
|
||||||
_set_camera_zoom_level(Globals.CAMERA_ZOOM_LEVEL + Globals.CAMERA_ZOOM_DURATION)
|
_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:
|
func _set_camera_zoom_level(value: float) -> void:
|
||||||
Globals.CAMERA_ZOOM_LEVEL = clamp(value, Globals.CAMERA_MIN_ZOOM_LEVEL, Globals.CAMERA_MAX_ZOOM_LEVEL)
|
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
|
Globals.CAMERA_ZOOM_DURATION
|
||||||
)
|
)
|
||||||
|
|
||||||
func _on_set_camera_position(_pos: Vector2) -> void:
|
func _on_set_camera_position(pos: Vector2) -> void:
|
||||||
#self.position = pos
|
self.position = pos
|
||||||
pass
|
|
||||||
|
|
||||||
func _unhandled_input(event):
|
func _unhandled_input(event):
|
||||||
if event.is_action_pressed("camera_zoom_in"):
|
if event.is_action_pressed("camera_zoom_in"):
|
||||||
|
|
|
@ -9,36 +9,74 @@ extends Node2D
|
||||||
# This is done to speed up game loading and avoiding setting one large tilemap in one go
|
# 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
|
# 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 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:
|
func _init() -> void:
|
||||||
self.name = "ChunkHandler"
|
self.name = "ChunkHandler"
|
||||||
|
|
||||||
|
func _process(_delta):
|
||||||
|
update_chunks()
|
||||||
|
clean_up_chunks()
|
||||||
|
reset_chunks()
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
#thread = Thread.new()
|
#thread = Thread.new()
|
||||||
|
|
||||||
|
|
||||||
|
#print(distance)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
func add_chunk(x:int, y:int) -> void:
|
||||||
|
var key = str(y) + "," + str(x)
|
||||||
func start_handler() -> void:
|
if chunks.has(key):
|
||||||
# Initialize the map tile array with enough chunks to cover the whole map
|
return
|
||||||
map_tiles.resize(Globals.map_size/Globals.CHUNK_SIZE)
|
|
||||||
for y in map_tiles.size():
|
load_chunk(x, y, key)
|
||||||
map_tiles[y].resize(Globals.map_size/Globals.CHUNK_SIZE)
|
|
||||||
|
|
||||||
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 chunk = Chunk.new(x,y)
|
||||||
|
|
||||||
var start = Time.get_ticks_usec()
|
|
||||||
chunk.generate_chunk()
|
|
||||||
self.add_child(chunk)
|
self.add_child(chunk)
|
||||||
var end = Time.get_ticks_usec()
|
chunks[key] = chunk
|
||||||
print("generate a chunk ", (end-start)/1000.0, "ms")
|
|
||||||
|
|
||||||
|
Globals.chunks_loaded += 1
|
||||||
#chunk.set_position(Vector2(x*Globals.CHUNK_SIZE,y*Globals.CHUNK_SIZE))
|
|
||||||
|
|
||||||
|
|
||||||
#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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,9 @@ func _process(_delta):
|
||||||
debug_info.set_text(
|
debug_info.set_text(
|
||||||
str(get_viewport().get_mouse_position()) +"\n" +
|
str(get_viewport().get_mouse_position()) +"\n" +
|
||||||
"FPS " + str(Engine.get_frames_per_second()) + "\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
|
# defines construction toolbar buttons
|
||||||
|
|
|
@ -3,24 +3,18 @@
|
||||||
|
|
||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
# world map chunk size
|
var chunks_loaded:int = 0
|
||||||
const CHUNK_SIZE:int = 16
|
|
||||||
|
|
||||||
|
###################################
|
||||||
|
# CHUNK AND TERRAIN SETTINGS #
|
||||||
|
###################################
|
||||||
|
# world map chunk size
|
||||||
|
const CHUNK_SIZE:Vector2i = Vector2i(32,32)
|
||||||
# tilemap tile types
|
# tilemap tile types
|
||||||
enum {TILE_WATER, TILE_TERRAIN, TILE_FOREST, TILE_BOG}
|
enum {TILE_WATER, TILE_TERRAIN, TILE_FOREST, TILE_BOG}
|
||||||
|
|
||||||
# tilemap layers
|
# tilemap layers
|
||||||
enum {LAYER_TERRAIN, LAYER_BUILDINGS}
|
enum {LAYER_TERRAIN, LAYER_BUILDINGS}
|
||||||
|
|
||||||
const TILESET_TERRAIN:TileSet = preload("res://scenes/Chunk.tres")
|
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):
|
func choose_randomly(list_of_entries):
|
||||||
return list_of_entries[randi() % list_of_entries.size()]
|
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
|
# preprocess and store exact tile for every map cell to speed up setting tiles
|
||||||
var map_tile_data:Array[Array] = [[]]
|
var map_tile_data:Array[Array] = [[]]
|
||||||
|
|
||||||
|
###################################
|
||||||
|
# CAMERA SETTINGS #
|
||||||
|
###################################
|
||||||
|
|
||||||
# current camera zoom level
|
# current camera zoom level
|
||||||
var CAMERA_ZOOM_LEVEL: float = 1.0
|
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
|
# FILE PATHS
|
||||||
const SCENE_PATH:String = "res://scenes/"
|
const SCENE_PATH:String = "res://scenes/"
|
||||||
|
@ -65,13 +71,6 @@ const TYPE_POWERPLANT:String = "powerplant"
|
||||||
const TYPE_ROADS:String = "roads"
|
const TYPE_ROADS:String = "roads"
|
||||||
const TYPE_DEMOLISH:String = "demolish"
|
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)
|
# 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 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)
|
const WATER_TILE_COLOR_IN_MAP_FILE: Color = Color(1,1,1,1)
|
||||||
|
|
|
@ -16,11 +16,13 @@ var map_filenames:Array = [
|
||||||
"res://maps/tampere_10x10km_1000px.png",
|
"res://maps/tampere_10x10km_1000px.png",
|
||||||
"res://maps/tampere_10x10km_1024px.png",
|
"res://maps/tampere_10x10km_1024px.png",
|
||||||
"res://maps/varkaus_256x256px_test.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 _world_generator:WorldGenerator
|
||||||
var _chunk_handler:ChunkHandler
|
var _chunk_handler:ChunkHandler
|
||||||
|
#var _2d_camera:CameraZoom2D
|
||||||
|
|
||||||
|
|
||||||
func _init():
|
func _init():
|
||||||
|
@ -28,23 +30,27 @@ func _init():
|
||||||
# #Vector2i(Globals.DEFAULT_X_RES, Globals.DEFAULT_Y_RES)
|
# #Vector2i(Globals.DEFAULT_X_RES, Globals.DEFAULT_Y_RES)
|
||||||
# Vector2i(3800,2000)
|
# 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.
|
# Called when the node enters the scene tree for the first time.
|
||||||
func _ready():
|
func _ready():
|
||||||
# create a new world and worldgenerator
|
# create a new world and worldgenerator
|
||||||
_world_generator = WorldGenerator.new()
|
_world_generator = WorldGenerator.new()
|
||||||
_chunk_handler = ChunkHandler.new()
|
_chunk_handler = ChunkHandler.new()
|
||||||
add_child(_chunk_handler)
|
#_2d_camera = CameraZoom2D.new()
|
||||||
|
|
||||||
var result = _world_generator.generate_world(map_filename)
|
# add chunk handler if worldgen was successful
|
||||||
|
if _world_generator.generate_world(map_filename):
|
||||||
if result:
|
add_child(_chunk_handler)
|
||||||
_chunk_handler.start_handler()
|
#add_child(_2d_camera)
|
||||||
for y in Globals.map_size/Globals.CHUNK_SIZE:
|
|
||||||
for x in Globals.map_size/Globals.CHUNK_SIZE:
|
# for y in Globals.map_size/Globals.CHUNK_SIZE.y:
|
||||||
if (y + x) % 2 == 0:
|
# for x in Globals.map_size/Globals.CHUNK_SIZE.x:
|
||||||
_chunk_handler.add_chunk(x, y)
|
# #if (y + x) % 2 == 0:
|
||||||
|
# _chunk_handler.load_chunk(x, y)
|
||||||
else:
|
else:
|
||||||
push_error("World generation failed :-(")
|
push_error("World generation failed :-(")
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,14 @@ var directions:Array = [
|
||||||
Vector2i(0,-1), # north
|
Vector2i(0,-1), # north
|
||||||
Vector2i(-1,0) # west
|
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:
|
func choose_tile(tile:Vector2i, selected, surrounding) -> Array:
|
||||||
var surrounding_tiles:Array = []
|
var surrounding_tiles:Array = []
|
||||||
|
@ -249,13 +257,13 @@ func smooth_recursively(pos:Vector2i, selected:int, comp:int) -> void:
|
||||||
smooth_recursively(pos, selected, comp)
|
smooth_recursively(pos, selected, comp)
|
||||||
|
|
||||||
func validate_mapgen_params() -> bool:
|
func validate_mapgen_params() -> bool:
|
||||||
if !Globals.are_coords_valid(
|
if !are_coords_valid(
|
||||||
Globals.map_size,
|
Globals.map_size,
|
||||||
Vector2i(Globals.MAP_MIN_HEIGHT, Globals.MAP_MAX_HEIGHT),
|
Vector2i(Globals.MAP_MIN_HEIGHT, Globals.MAP_MAX_HEIGHT),
|
||||||
Globals.ERROR_IMAGE_HEIGHT_INCORRECT):
|
Globals.ERROR_IMAGE_HEIGHT_INCORRECT):
|
||||||
return false
|
return false
|
||||||
|
|
||||||
elif !Globals.are_coords_valid(
|
elif !are_coords_valid(
|
||||||
Globals.map_size,
|
Globals.map_size,
|
||||||
Vector2i(Globals.MAP_MIN_WIDTH, Globals.MAP_MAX_WIDTH),
|
Vector2i(Globals.MAP_MIN_WIDTH, Globals.MAP_MAX_WIDTH),
|
||||||
Globals.ERROR_IMAGE_WIDTH_INCORRECT):
|
Globals.ERROR_IMAGE_WIDTH_INCORRECT):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue