refactor node structure

This commit is contained in:
Antti Hakkarainen 2023-02-17 13:09:59 +02:00
parent 8189a16fee
commit f35d27b518
11 changed files with 311 additions and 233 deletions

View file

@ -1,3 +1,4 @@
class_name CameraMarker
extends Sprite2D
var size_multiplier:float
@ -26,3 +27,7 @@ func _on_camera_zoom_2d_camera_zoom_changed(new_zoom_factor):
func _on_main_worldgen_ready() -> void:
size_multiplier = Globals.map_size / 32
w_s = DisplayServer.window_get_size(0) / size_multiplier
func set_camera_marker_position(pos:Vector2) -> void:
self.position = pos

View file

@ -15,18 +15,6 @@ var x_min_limit:int = self.game_res.x/2 - chunk_in_px.x
#@onready var captured_image = $CapturedImage
func _on_main_worldgen_ready() -> void:
# set camera bounds to map size, with chunk_in_px room to go over
self.set_limit(SIDE_LEFT, -chunk_in_px.x)
self.set_limit(SIDE_RIGHT, Globals.map_size*Globals.TILE_SIZE_X + chunk_in_px.x)
self.set_limit(SIDE_TOP, -chunk_in_px.y)
self.set_limit(SIDE_BOTTOM, Globals.map_size*Globals.TILE_SIZE_Y + chunk_in_px.y)
func _on_set_camera_position(pos: Vector2) -> void:
self.position = pos
func _process(_delta) -> void:
Globals.CAMERA_POSITION = self.position
@ -142,5 +130,17 @@ func take_screenshot() -> void:
var captured_image:Image = get_viewport().get_texture().get_image()
captured_image.save_png(path)
func set_ready() -> void:
# set camera bounds to map size, with chunk_in_px room to go over
self.set_limit(SIDE_LEFT, -chunk_in_px.x)
self.set_limit(SIDE_RIGHT, Globals.map_size*Globals.TILE_SIZE_X + chunk_in_px.x)
self.set_limit(SIDE_TOP, -chunk_in_px.y)
self.set_limit(SIDE_BOTTOM, Globals.map_size*Globals.TILE_SIZE_Y + chunk_in_px.y)
func set_camera_position(pos: Vector2) -> void:
self.position = pos

View file

@ -37,56 +37,6 @@ func _exit_tree():
func _init() -> void:
self.name = "ChunkHandler"
func _on_main_worldgen_ready():
if !thread.is_started():
thread.start(start_chunkgen, Thread.PRIORITY_NORMAL)
clean_up_chunks()
func _ready():
mutex = Mutex.new()
semaphore = Semaphore.new()
exit_thread = false
if !thread:
thread = Thread.new()
process_delay_chunks()
process_delay_stats()
func process_delay_chunks() -> void:
while true:
update_chunks()
await get_tree().create_timer(0.05).timeout
func process_delay_stats() -> void:
# emit stats about chunk amounts every 0,5s
while true:
emit_signal("chunk_stats", self.chunks.size(), self.chunks_to_remove.size())
await get_tree().create_timer(0.5).timeout
func start_chunkgen():
while true:
semaphore.wait()
mutex.lock()
var should_exit = exit_thread # Protect with Mutex.
mutex.unlock()
if should_exit:
break
# work on emptying the generation queue
if not chunk_queue.is_empty():
mutex.lock()
var vars = chunk_queue.pop_front()
mutex.unlock()
load_chunk(vars[0].y, vars[0].x, vars[1])
func clean_up_chunks():
while true:
@ -98,6 +48,7 @@ func clean_up_chunks():
await get_tree().create_timer(0.02).timeout
func correction_factor(d) -> float:
if Globals.CAMERA_ZOOM_LEVEL < 0.6:
return d * 2.0
@ -122,6 +73,55 @@ func load_chunk(y:int, x:int, key):
chunks[key] = chunk
mutex.unlock()
func process_delay_chunks() -> void:
while true:
update_chunks()
await get_tree().create_timer(0.05).timeout
func process_delay_stats() -> void:
# emit stats about chunk amounts every 0,5s
while true:
emit_signal("chunk_stats", self.chunks.size(), self.chunks_to_remove.size())
await get_tree().create_timer(0.5).timeout
func set_ready():
mutex = Mutex.new()
semaphore = Semaphore.new()
exit_thread = false
if !thread:
thread = Thread.new()
if !thread.is_started():
thread.start(start_chunkgen, Thread.PRIORITY_NORMAL)
clean_up_chunks()
process_delay_chunks()
process_delay_stats()
func start_chunkgen():
while true:
semaphore.wait()
mutex.lock()
var should_exit = exit_thread # Protect with Mutex.
mutex.unlock()
if should_exit:
break
# work on emptying the generation queue
if not chunk_queue.is_empty():
mutex.lock()
var vars = chunk_queue.pop_front()
mutex.unlock()
load_chunk(vars[0].y, vars[0].x, vars[1])
func update_chunks():
var p_x:float = int(Globals.CAMERA_POSITION.x- Globals.CHUNK_SIZE.x) / Globals.TILE_SIZE_X / Globals.CHUNK_SIZE.x

95
scripts/EventBus.gd Normal file
View file

@ -0,0 +1,95 @@
class_name EventBus
extends Node
@onready var node_main = get_parent()
@onready var node_mainmenu = find_child("MainMenu")
@onready var node_game = find_child("Game")
# The idea is for the user to be able to choose the map from GUI later
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_10x10km_4096px.png"
]
var map_filename:String = map_filenames[3]
var _world_generator:WorldGenerator
func _ready():
node_mainmenu.set_ready()
func _unhandled_input(event) -> void:
if event.is_action_pressed("open_main_menu"):
# move mainmenu to current game camera position
var mainmenu_pos = Globals.CAMERA_POSITION
mainmenu_pos.x -= DisplayServer.window_get_size(0).x/2
mainmenu_pos.y -= DisplayServer.window_get_size(0).y/2
self.find_child("MainMenu").position = mainmenu_pos
# show the menu
toggle_main_menu_visibility()
#await get_tree().create_timer(0.2).timeout
self.find_child("Game").process_mode = PROCESS_MODE_DISABLED
func _on_mainmenu_button_pressed(button:int):
match button:
Globals.MAINMENU_NEW_GAME:
start_new_game()
node_mainmenu.find_child("Menu_NewGame").disabled = true
node_mainmenu.find_child("Menu_ResumeGame").disabled = false
toggle_main_menu_visibility()
Globals.MAINMENU_LOAD_GAME:
pass
Globals.MAINMENU_RESUME_GAME:
# TODO save camera position before opening menu, restore camera position when closing menu
node_game.process_mode = PROCESS_MODE_INHERIT
toggle_main_menu_visibility()
Globals.MAINMENU_OPTIONS:
pass
Globals.MAINMENU_CREDITS:
pass
Globals.MAINMENU_QUIT_GAME:
node_mainmenu.quit_game()
_:
push_error("Error: Main: unknown signal at _on_mainmenu_button_pressed: ", button)
func start_new_game():
# create a new world with worldgenerator
_world_generator = WorldGenerator.new()
if !_world_generator.generate_world(map_filename):
push_error("World generation failed :-(")
node_main.quit_game()
node_main.unpause_game()
node_game.set_ready()
self.set_camera_position(
Vector2(Globals.map_size / 2.0 * Globals.TILE_SIZE_X,
Globals.map_size / 2.0 * Globals.TILE_SIZE_Y)
)
func toggle_main_menu_visibility():
node_game.toggle_visibility()
if node_mainmenu.visible:
node_mainmenu.hide()
else:
node_mainmenu.show()
func set_camera_position(pos:Vector2):
node_game.set_camera_position(pos)

47
scripts/Game.gd Normal file
View file

@ -0,0 +1,47 @@
class_name Game
extends Node2D
@onready var node_camera:CameraZoom2D
@onready var node_chunkhandler:ChunkHandler
@onready var node_minimap:Minimap
@onready var node_mapbackground:MapBackground
@onready var node_uilayer
func _ready() -> void:
node_camera = find_child("CameraZoom2D")
node_chunkhandler = find_child("ChunkHandler")
node_minimap = find_child("Minimap")
node_mapbackground = find_child("MapBackground")
node_uilayer = find_child("UILayer")
# sets the minimap texture as map background to avoid jarring transitions
func _on_minimap_set_map_background_texture(sprite, scaling:Vector2) -> void:
self.set_map_background_texture(sprite, scaling)
func set_ready() -> void:
node_camera.set_ready()
node_chunkhandler.set_ready()
node_minimap.set_ready()
func set_map_background_texture(sprite, scaling:Vector2) -> void:
node_mapbackground.set_map_background_texture(sprite, scaling)
func set_camera_position(pos:Vector2):
node_camera.set_camera_position(pos)
func toggle_visibility():
if self.visible:
self.hide()
else:
self.show()
if node_uilayer.visible:
node_uilayer.hide()
else:
node_uilayer.show()

View file

@ -1,107 +1,33 @@
# OK - "Cube Clicker 2000" where you click a spot and a cube appears there.
# OK - Then add different shapes or colors of cubes.
# OK - Then clamp their positions to be on a grid.
# - Then make it so that when you add yellow cubes, yellow desire meter goes down and green meter goes up.
# - Then click a bunch of grey cubes in a row and have them automatically flatten out into flat grey cubes (roads).
# - Then click and drag to draw the lines of grey cubes.
# - etc.
# https://github.com/dfloer/SC2k-docs
class_name Main
extends Node2D
signal worldgen_ready
signal set_camera_position(pos:Vector2)
var start_new_game_pressed:bool = false
var bus:EventBus
# The idea is for the user to be able to choose the map from GUI later
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_10x10km_4096px.png"
]
var map_filename:String = map_filenames[3]
var _world_generator:WorldGenerator
func _init():
func _init() -> void:
# DisplayServer.window_set_size(
# #Vector2i(Globals.DEFAULT_X_RES, Globals.DEFAULT_Y_RES)
# Vector2i(3800,2000)
# )
Globals.CAMERA_POSITION = Vector2(16*256/2, 16*256/2)
pass
func start_new_game():
# create a new world with worldgenerator
_world_generator = WorldGenerator.new()
if !_world_generator.generate_world(map_filename):
push_error("World generation failed :-(")
quit_game()
# connections are made from GUI
# tell other classes they can start working after loading is done
emit_signal("worldgen_ready")
self.find_child("MainMenu").hide()
self.find_child("Game").show()
self.find_child("UILayer").show()
# center camera to world map
emit_signal(
"set_camera_position",
Vector2(Globals.map_size / 2.0 * Globals.TILE_SIZE_X,
Globals.map_size / 2.0 * Globals.TILE_SIZE_Y)
)
func _on_mainmenu_button_pressed(button:int):
match button:
Globals.MAINMENU_NEW_GAME:
start_new_game()
self.find_child("Menu_NewGame").disabled = true
self.find_child("Menu_ResumeGame").disabled = false
Globals.MAINMENU_LOAD_GAME:
pass
Globals.MAINMENU_RESUME_GAME:
# TODO save camera position before opening menu, restore camera position when closing menu
self.find_child("Game").process_mode = PROCESS_MODE_INHERIT
toggle_main_menu_visibility()
Globals.MAINMENU_QUIT_GAME:
quit_game()
_:
push_error("Error: Main: unknown signal at _on_mainmenu_button_pressed: ", button)
func _unhandled_input(event) -> void:
if event.is_action_pressed("open_main_menu"):
# move mainmenu to current game camera position
var mainmenu_pos = Globals.CAMERA_POSITION
mainmenu_pos.x -= DisplayServer.window_get_size(0).x/2
mainmenu_pos.y -= DisplayServer.window_get_size(0).y/2
self.find_child("MainMenu").position = mainmenu_pos
# show the menu
toggle_main_menu_visibility()
#await get_tree().create_timer(0.2).timeout
self.find_child("Game").process_mode = PROCESS_MODE_DISABLED
func _ready() -> void:
pause_game()
bus = find_child("EventBus")
bus.set_camera_position(Vector2(16*256/2, 16*256/2))
func toggle_main_menu_visibility():
var items = [find_child("Game"), find_child("UILayer"), find_child("MainMenu")]
func pause_game() -> void:
get_tree().paused = true
func unpause_game() -> void:
get_tree().paused = false
for item in items:
if !item:
push_error("Error: While toggling main menu visibility. Missing UI element " + item)
if item.visible:
item.hide()
continue
item.show()
func quit_game():
get_tree().get_root().propagate_notification(NOTIFICATION_WM_CLOSE_REQUEST)

View file

@ -1,12 +1,13 @@
extends GridContainer
class_name MainMenu
extends Control
signal button_pressed(button_name)
# Connect main menu to Main game
func _ready():
self.connect("button_pressed", self.find_parent("Main")._on_mainmenu_button_pressed, CONNECT_PERSIST)
self.find_child("Menu_ResumeGame").disabled = true
func set_ready():
self.connect("button_pressed", self.get_parent()._on_mainmenu_button_pressed, CONNECT_PERSIST)
self.find_child("Menu_ResumeGame").disabled = true
func _on_menu_new_game_pressed():
emit_signal("button_pressed", Globals.MAINMENU_NEW_GAME)

View file

@ -1,7 +1,8 @@
class_name MapBackground
extends Sprite2D
# sets the minimap texture as map background to avoid jarring transitions
func _on_minimap_set_map_background_texture(sprite) -> void:
func set_map_background_texture(sprite, scaling:Vector2) -> void:
self.texture = sprite
self.scale = Vector2(16, 16)
self.scale = scaling

View file

@ -2,13 +2,14 @@ class_name Minimap
extends Control
signal set_camera_position(pos:Vector2)
signal set_map_background_texture(texture)
signal set_map_background_texture(texture, scaling)
@onready var minimap_texture:ImageTexture = null
@onready var sprite:Sprite2D
@onready var is_mouse_inside_minimap:bool = false
@onready var position_multiplier:float
@onready var area_size:Vector2
@onready var node_camera_marker:CameraMarker
var observe_mouse_inside_minimap:bool = false
@ -22,27 +23,14 @@ func _draw():
pass
func _process(_delta):
if !is_mouse_inside_minimap and observe_mouse_inside_minimap:
Globals.camera_marker.position = Vector2(
Globals.CAMERA_POSITION.x / position_multiplier,
Globals.CAMERA_POSITION.y / position_multiplier,
)
#func _process(_delta):
# if !is_mouse_inside_minimap and observe_mouse_inside_minimap:
# node_camera_marker.set_position(Vector2(
# Globals.CAMERA_POSITION.x / position_multiplier,
# Globals.CAMERA_POSITION.y / position_multiplier,
# ))
func _on_main_worldgen_ready():
# Assuming the area has a child CollisionShape2D with a RectangleShape resource
self.set_process(true)
observe_mouse_inside_minimap = true
area_size = self.get_rect().size
position_multiplier = Globals.map_size / 32
self.generate_minimap()
self.set_minimap()
self.setup_camera_marker()
func _on_mouse_entered():
is_mouse_inside_minimap = true
@ -53,10 +41,10 @@ func _on_mouse_exited():
func _unhandled_input(event) -> void:
if is_mouse_inside_minimap:
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
Globals.camera_marker.position = get_local_mouse_position()
node_camera_marker.set_camera_marker_position(get_local_mouse_position())
emit_signal(
"set_camera_position",
get_local_mouse_position() * position_multiplier # 8 on 256 size map. need a forumla to calculate this
get_local_mouse_position() * position_multiplier
)
@ -83,6 +71,10 @@ func generate_minimap() -> void:
minimap_texture = ImageTexture.create_from_image(image)
func set_camera_marker() -> void:
node_camera_marker = self.find_child("CameraMarker")
func set_minimap() -> void:
self.sprite = self.find_child("MinimapSprite")
@ -97,12 +89,23 @@ func set_minimap() -> void:
sprite.scale = Vector2(sx, sy)
emit_signal("set_map_background_texture", sprite.texture)
emit_signal("set_map_background_texture", sprite.texture, Vector2(16, 16))
func set_ready() -> void:
# Assuming the area has a child CollisionShape2D with a RectangleShape resource
self.set_process(true)
observe_mouse_inside_minimap = true
area_size = self.get_rect().size
position_multiplier = Globals.map_size / 32
self.generate_minimap()
self.set_minimap()
self.set_camera_marker()
func setup_camera_marker() -> void:
Globals.camera_marker = self.find_child("CameraMarker")