load and remove chunks around camera pos working

This commit is contained in:
Antti Hakkarainen 2023-02-12 22:17:21 +02:00
parent fccef57210
commit 0109934933
8 changed files with 137 additions and 73 deletions

View file

@ -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,

View file

@ -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")

View file

@ -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"):

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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 :-(")

View file

@ -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):