Added job component and queue system
- Introduced a new JobComponent and JobQueue to manage jobs in the game. - Created two new jobs: DigJob and InfectJob with their respective scripts. - Updated CrystalGlowComponent, FreeCameraComponent, MushroomGlowComponent, WaterEffectComponent to improve logging messages. - Adjusted camera movement limits in FreeCameraGameCameraComponent for better control. - Added FiniteStateMachine class for managing states of entities. - Implemented GlowingIdle state as an example of using the state machine. - Included a utility function to fetch file paths by extension from a directory.
This commit is contained in:
parent
fc896925d6
commit
bb5724429a
23 changed files with 311 additions and 29 deletions
10
components/JobComponent.tscn
Normal file
10
components/JobComponent.tscn
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[gd_scene load_steps=3 format=3 uid="uid://buadlj7sbutdh"]
|
||||
|
||||
[ext_resource type="Script" path="res://components/scripts/job_component.gd" id="1_lsesq"]
|
||||
[ext_resource type="Script" path="res://components/scripts/job_queue.gd" id="2_tal7p"]
|
||||
|
||||
[node name="JobComponent" type="Node"]
|
||||
script = ExtResource("1_lsesq")
|
||||
|
||||
[node name="JobQueue" type="Node" parent="."]
|
||||
script = ExtResource("2_tal7p")
|
||||
6
components/jobs/Dig.tscn
Normal file
6
components/jobs/Dig.tscn
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
[gd_scene load_steps=2 format=3 uid="uid://bypebl5w1aivf"]
|
||||
|
||||
[ext_resource type="Script" path="res://components/jobs/scripts/dig.gd" id="1_my7sj"]
|
||||
|
||||
[node name="Dig" type="Node"]
|
||||
script = ExtResource("1_my7sj")
|
||||
6
components/jobs/Infect.tscn
Normal file
6
components/jobs/Infect.tscn
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
[gd_scene load_steps=2 format=3 uid="uid://pbnva2nkgral"]
|
||||
|
||||
[ext_resource type="Script" path="res://components/jobs/scripts/infect.gd" id="1_xpq3i"]
|
||||
|
||||
[node name="Infect" type="Node"]
|
||||
script = ExtResource("1_xpq3i")
|
||||
10
components/jobs/scripts/dig.gd
Normal file
10
components/jobs/scripts/dig.gd
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
extends Job
|
||||
class_name DigJob
|
||||
|
||||
func _init() -> void:
|
||||
job_name = "Dig"
|
||||
job_description = "Dig some stuff!"
|
||||
super._init()
|
||||
|
||||
func _ready() -> void:
|
||||
Log.pr("Dig job added to the scene...")
|
||||
10
components/jobs/scripts/infect.gd
Normal file
10
components/jobs/scripts/infect.gd
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
extends Job
|
||||
class_name InfectJob
|
||||
|
||||
func _init() -> void:
|
||||
job_name = "Infect"
|
||||
job_description = "Infect some roots"
|
||||
super._init()
|
||||
|
||||
func _ready() -> void:
|
||||
Log.pr("Infect job added to the scene...")
|
||||
11
components/jobs/scripts/job.gd
Normal file
11
components/jobs/scripts/job.gd
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
extends Node
|
||||
class_name Job
|
||||
|
||||
signal job_completed
|
||||
signal job_failed
|
||||
|
||||
var job_name : String
|
||||
var job_description : String
|
||||
|
||||
func _init() -> void:
|
||||
pass
|
||||
|
|
@ -16,13 +16,13 @@ func _ready() -> void:
|
|||
if !tile_map:
|
||||
Log.err("CrystalGlowComponent: TileMap not set")
|
||||
|
||||
Log.pr("CrystalGlowComponent ready")
|
||||
|
||||
tile_size = tile_map.get_tileset().tile_size
|
||||
tilemap_size = tile_map.get_used_rect().end - tile_map.get_used_rect().position
|
||||
|
||||
crystal_layer = tile_map.get_layer_id_by_name('Crystals')
|
||||
Log.pr(crystal_layer)
|
||||
|
||||
Log.pr("CrystalGlowComponent ready, working on layer: ", crystal_layer)
|
||||
|
||||
add_crystal_glow()
|
||||
|
||||
## Look for crystals in the scene and add the glow to the approprirate angle and colour
|
||||
|
|
@ -46,5 +46,3 @@ func add_crystal_glow() -> void:
|
|||
glow.orientation = orientation
|
||||
crystal_glow_container.add_child(glow)
|
||||
glowing_crystals.append(coords)
|
||||
|
||||
Log.pr("Glowing crystals: ", glowing_crystals)
|
||||
|
|
@ -9,20 +9,12 @@ func _ready() -> void:
|
|||
if !tile_map:
|
||||
Log.err("FreeCameraComponent: tile_map is not set")
|
||||
|
||||
## Set the limits for the camera based on the tilemap
|
||||
#camera.set_limits(0, tile_map.)
|
||||
|
||||
# Stop the camera scrolling out of bounds of the map
|
||||
var tile_size : Vector2i = tile_map.get_tileset().tile_size
|
||||
var tilemap_size : Vector2i = tile_map.get_used_rect().end - tile_map.get_used_rect().position
|
||||
var map_size_x : int = tile_size.x * tilemap_size.x
|
||||
var map_size_y : int = tile_size.y * tilemap_size.y
|
||||
|
||||
Log.pr("Size Y", map_size_y, get_viewport().size.y)
|
||||
Log.pr("Size X", map_size_x, get_viewport().size.x)
|
||||
|
||||
#Log.pr(map_size - get_viewport().size.x)
|
||||
|
||||
camera.set_limit(SIDE_LEFT, 0)
|
||||
camera.set_limit(SIDE_TOP, 0)
|
||||
camera.set_limit(SIDE_RIGHT, map_size_x)
|
||||
|
|
|
|||
|
|
@ -64,12 +64,12 @@ func _physics_process(delta : float) -> void:
|
|||
# If this movement would take us out of clamp we don't want to do it:
|
||||
var position_change : Vector2 = camera_movement * get_zoom()
|
||||
|
||||
if (position.x + position_change.x) <= limit_left or\
|
||||
(position.x + position_change.x) >= limit_right:
|
||||
if (position.x + position_change.x) < limit_left or\
|
||||
(position.x + position_change.x) > limit_right:
|
||||
camera_movement.x = 0
|
||||
|
||||
if (position.y + position_change.y) <= limit_top or\
|
||||
(position.y + position_change.y) >= limit_bottom:
|
||||
if (position.y + position_change.y) < limit_top or\
|
||||
(position.y + position_change.y) > limit_bottom:
|
||||
camera_movement.y = 0
|
||||
|
||||
if camera_movement.y != 0 or camera_movement.x != 0:
|
||||
|
|
|
|||
57
components/scripts/job_component.gd
Normal file
57
components/scripts/job_component.gd
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
extends Node
|
||||
class_name JobComponent
|
||||
|
||||
## Constants
|
||||
const JOB_FOLDER = "res://components/jobs/"
|
||||
|
||||
## Variables
|
||||
var job_types : Dictionary = {}
|
||||
|
||||
@onready var queue : JobQueue = $JobQueue
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
|
||||
## Get the list of job types from the job folder
|
||||
load_jobs()
|
||||
add_jobs_to_queue()
|
||||
add_jobs_to_queue()
|
||||
add_jobs_to_queue()
|
||||
|
||||
Log.pr("I am the job component, and I am ready.")
|
||||
|
||||
|
||||
# Look in the JOB_FOLDER and preload all scenes into a dictionary
|
||||
func load_jobs() -> void:
|
||||
var job_files : Array = FileUtil.get_file_paths_by_extension(JOB_FOLDER, "tscn")
|
||||
|
||||
#Log.pr("Job files: ", job_files)
|
||||
|
||||
for file : String in job_files:
|
||||
#Log.pr("Loading job: ", file)
|
||||
var job_scene : PackedScene = load(file)
|
||||
var job_instance : Job = job_scene.instantiate()
|
||||
|
||||
#Log.pr("⚒️ Job Name:", job_instance.job_name, "-- Description:", job_instance.job_description)
|
||||
|
||||
var job_details : Dictionary = {
|
||||
'job_name': job_instance.job_name,
|
||||
'job_description': job_instance.job_description,
|
||||
'job_instance': job_scene
|
||||
}
|
||||
|
||||
job_types[job_instance.job_name] = job_details
|
||||
|
||||
#Log.pr(job_details)
|
||||
|
||||
Log.pr("Job types: ", job_types)
|
||||
|
||||
func add_jobs_to_queue() -> void:
|
||||
#Log.pr("This is a debug function!")
|
||||
|
||||
for job : String in job_types.keys():
|
||||
#Log.pr("Adding job to queue: ", job)
|
||||
if job_types[job].job_instance != null:
|
||||
var job_scene : PackedScene = job_types[job].job_instance
|
||||
var job_instance : Node = job_scene.instantiate()
|
||||
queue.add_child(job_instance)
|
||||
5
components/scripts/job_queue.gd
Normal file
5
components/scripts/job_queue.gd
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
extends Node
|
||||
class_name JobQueue
|
||||
|
||||
func _ready() -> void:
|
||||
Log.pr("Job Queue ready...")
|
||||
|
|
@ -15,7 +15,7 @@ func _ready() -> void:
|
|||
if !tile_map:
|
||||
Log.err("MushroomGlowComponent: TileMap not set")
|
||||
|
||||
Log.pr("MushroomGlowComponent ready")
|
||||
|
||||
|
||||
tile_map.tilemap_updated.connect(add_mushroom_glow)
|
||||
|
||||
|
|
@ -23,7 +23,9 @@ func _ready() -> void:
|
|||
tilemap_size = tile_map.get_used_rect().end - tile_map.get_used_rect().position
|
||||
|
||||
mushroom_layer = tile_map.get_layer_id_by_name('Mushrooms')
|
||||
Log.pr(mushroom_layer)
|
||||
|
||||
Log.pr("MushroomGlowComponent ready, working on layer:", mushroom_layer)
|
||||
|
||||
add_mushroom_glow()
|
||||
|
||||
## Look for crystals in the scene and add the glow to the approprirate angle and colour
|
||||
|
|
|
|||
|
|
@ -18,13 +18,15 @@ func _ready() -> void:
|
|||
if !tile_map:
|
||||
Log.err("WaterEffectComponent: TileMap not set")
|
||||
|
||||
Log.pr("WaterEffectComponent ready")
|
||||
|
||||
|
||||
tile_size = tile_map.get_tileset().tile_size
|
||||
tilemap_size = tile_map.get_used_rect().end - tile_map.get_used_rect().position
|
||||
|
||||
water_layer = tile_map.get_layer_id_by_name('Water')
|
||||
Log.pr(water_layer)
|
||||
|
||||
Log.pr("WaterEffectComponent ready, working on layer:", water_layer)
|
||||
|
||||
add_water_effects()
|
||||
|
||||
## Look for crystals in the scene and add the glow to the approprirate angle and colour
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
[gd_scene load_steps=5 format=3 uid="uid://ddwnkcnncxmjv"]
|
||||
[gd_scene load_steps=7 format=3 uid="uid://ddwnkcnncxmjv"]
|
||||
|
||||
[ext_resource type="Script" path="res://entities/scripts/glowling.gd" id="1_aq1kk"]
|
||||
[ext_resource type="Texture2D" uid="uid://b0v24ggq57237" path="res://resources/particles/smallcircle.png" id="2_s3xbi"]
|
||||
[ext_resource type="Script" path="res://entities/scripts/finite_state_machine.gd" id="3_vqtdm"]
|
||||
[ext_resource type="Script" path="res://entities/states/glowling/glowling_idle.gd" id="4_2l3e6"]
|
||||
|
||||
[sub_resource type="Animation" id="Animation_01nc3"]
|
||||
resource_name = "GlowingPulse"
|
||||
|
|
@ -63,3 +65,10 @@ energy = 0.7
|
|||
shadow_filter = 2
|
||||
shadow_filter_smooth = 7.5
|
||||
texture = ExtResource("2_s3xbi")
|
||||
|
||||
[node name="StateMachine" type="Node" parent="." node_paths=PackedStringArray("initial_state")]
|
||||
script = ExtResource("3_vqtdm")
|
||||
initial_state = NodePath("Idle")
|
||||
|
||||
[node name="Idle" type="Node" parent="StateMachine"]
|
||||
script = ExtResource("4_2l3e6")
|
||||
|
|
|
|||
75
entities/scripts/finite_state_machine.gd
Normal file
75
entities/scripts/finite_state_machine.gd
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
@icon("res://resources/icons/fsm.png")
|
||||
extends Node
|
||||
class_name FiniteStateMachine
|
||||
|
||||
var states : Dictionary = {}
|
||||
var current_state : State
|
||||
@export var initial_state : State
|
||||
|
||||
#NOTE This is a generic finite_state_machine, it handles all states, changes to this code will affect
|
||||
# everything that uses a state machine!
|
||||
|
||||
func _ready() -> void:
|
||||
for child : State in get_children():
|
||||
states[child.name.to_lower()] = child
|
||||
child.state_transition.connect(change_state)
|
||||
|
||||
if initial_state:
|
||||
initial_state.enter()
|
||||
current_state = initial_state
|
||||
|
||||
# Call the current states update function
|
||||
func _process(delta : float) -> void:
|
||||
if current_state:
|
||||
current_state.update(delta)
|
||||
|
||||
func _physics_process(delta : float) -> void:
|
||||
if current_state:
|
||||
current_state.physics_update(delta)
|
||||
|
||||
func get_current_state_name() -> String:
|
||||
if current_state:
|
||||
return current_state.name.to_lower()
|
||||
else:
|
||||
return ""
|
||||
|
||||
# Use force_change_state cautiously, it immediately switches to a state regardless of any transitions.
|
||||
# This is used to force us into a 'death state' when killed
|
||||
func force_change_state(new_state : String) -> void:
|
||||
var newState : State = states.get(new_state.to_lower())
|
||||
|
||||
if !newState:
|
||||
print(new_state + " does not exist in the dictionary of states")
|
||||
return
|
||||
|
||||
if current_state == newState:
|
||||
print("State is same, aborting")
|
||||
return
|
||||
|
||||
# NOTE Calling exit like so: (current_state.Exit()) may cause warnings when flushing queries, like when the enemy is being removed after death.
|
||||
# call_deferred is safe and prevents this from occuring. We get the Exit function from the state as a callable and then call it in a thread-safe manner
|
||||
if current_state:
|
||||
var exit_callable : Callable = Callable(current_state, "exit")
|
||||
exit_callable.call_deferred()
|
||||
|
||||
newState.enter()
|
||||
|
||||
current_state = newState
|
||||
|
||||
func change_state(source_state : State, new_state_name : String) -> void:
|
||||
if source_state != current_state:
|
||||
#print("Invalid change_state trying from: " + source_state.name + " but currently in: " + current_state.name)
|
||||
#This typically only happens when trying to switch from death state following a force_change
|
||||
return
|
||||
|
||||
var new_state : State = states.get(new_state_name.to_lower())
|
||||
if !new_state:
|
||||
print("New state is empty")
|
||||
return
|
||||
|
||||
if current_state:
|
||||
current_state.exit()
|
||||
|
||||
new_state.enter()
|
||||
|
||||
current_state = new_state
|
||||
|
|
@ -8,12 +8,9 @@ class_name MushroomGlow
|
|||
@export var colour_name : String = "blue"
|
||||
|
||||
func _ready() -> void:
|
||||
Log.pr("And dog said let their be light...")
|
||||
Log.pr(position, global_position)
|
||||
set_light_colour(colour_name)
|
||||
animation.play("GlowFlicker")
|
||||
|
||||
|
||||
func set_light_colour(colour : String) -> void:
|
||||
if colour == "blue":
|
||||
inner_glow.color = "4cc5fa"
|
||||
|
|
|
|||
18
entities/scripts/state.gd
Normal file
18
entities/scripts/state.gd
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
@icon("res://resources/icons/fsm.png")
|
||||
extends Node
|
||||
class_name State
|
||||
|
||||
signal state_transition
|
||||
|
||||
func enter(_msg : Dictionary = {}) -> void:
|
||||
pass
|
||||
|
||||
func exit() -> void :
|
||||
pass
|
||||
|
||||
func update(_delta : float) -> void:
|
||||
pass
|
||||
|
||||
func physics_update(_delate : float) -> void:
|
||||
pass
|
||||
|
||||
5
entities/states/glowling/glowling_idle.gd
Normal file
5
entities/states/glowling/glowling_idle.gd
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
extends State
|
||||
class_name GlowingIdle
|
||||
|
||||
func enter(_msg : Dictionary = {}) -> void:
|
||||
Log.pr("I am a glowling and I am idle...")
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
[gd_scene load_steps=115 format=3 uid="uid://cbiwnafhckchl"]
|
||||
[gd_scene load_steps=116 format=3 uid="uid://cbiwnafhckchl"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://cwkjk7hh7csea" path="res://resources/sCaveTile.png" id="1_au2ii"]
|
||||
[ext_resource type="Material" uid="uid://bpverily2kmvm" path="res://levels/resources/material_desaturate_tileset.tres" id="1_iph1s"]
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
[ext_resource type="PackedScene" uid="uid://c87qvtq8ho3bb" path="res://components/MushroomGlowComponent.tscn" id="13_uwl47"]
|
||||
[ext_resource type="PackedScene" uid="uid://mawos5ss1cod" path="res://components/WaterEffectComponent.tscn" id="14_x3ue3"]
|
||||
[ext_resource type="PackedScene" uid="uid://htaqjgupmiiu" path="res://components/FreeCameraComponent.tscn" id="15_xajk3"]
|
||||
[ext_resource type="PackedScene" uid="uid://buadlj7sbutdh" path="res://components/JobComponent.tscn" id="16_qq30h"]
|
||||
|
||||
[sub_resource type="Environment" id="Environment_ct14l"]
|
||||
background_mode = 3
|
||||
|
|
@ -4000,6 +4001,9 @@ shader_parameter/noise_scroll_direction = Vector2(1, 0)
|
|||
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
||||
environment = SubResource("Environment_ct14l")
|
||||
|
||||
[node name="FreeCameraComponent" parent="." node_paths=PackedStringArray("tile_map") instance=ExtResource("15_xajk3")]
|
||||
tile_map = NodePath("../TileMap")
|
||||
|
||||
[node name="TileMap" type="TileMap" parent="."]
|
||||
tile_set = SubResource("TileSet_lsdax")
|
||||
format = 2
|
||||
|
|
@ -4035,5 +4039,4 @@ position = Vector2(2167, 319)
|
|||
[node name="CanvasModulate" type="CanvasModulate" parent="."]
|
||||
color = Color(0.301961, 0.45098, 1, 1)
|
||||
|
||||
[node name="FreeCameraComponent" parent="." node_paths=PackedStringArray("tile_map") instance=ExtResource("15_xajk3")]
|
||||
tile_map = NodePath("../TileMap")
|
||||
[node name="JobComponent" parent="." instance=ExtResource("16_qq30h")]
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ config/icon="res://icon.svg"
|
|||
[autoload]
|
||||
|
||||
GridUtil="*res://utilities/GridUtilitiesClass.gd"
|
||||
FileUtil="*res://utilities/FileUtilitiesClass.gd"
|
||||
|
||||
[debug]
|
||||
|
||||
|
|
|
|||
BIN
resources/icons/fsm.png
Normal file
BIN
resources/icons/fsm.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
34
resources/icons/fsm.png.import
Normal file
34
resources/icons/fsm.png.import
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bdibamw1s2nel"
|
||||
path="res://.godot/imported/fsm.png-8987802cee881c94358eee3cb13f0556.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://resources/icons/fsm.png"
|
||||
dest_files=["res://.godot/imported/fsm.png-8987802cee881c94358eee3cb13f0556.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
31
utilities/FileUtilitiesClass.gd
Normal file
31
utilities/FileUtilitiesClass.gd
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
extends Node
|
||||
class_name FileUtilitiesClass
|
||||
|
||||
func get_file_paths_by_extension(directoryPath: String, extension: String, recursive: bool = false) -> Array:
|
||||
|
||||
var dir : DirAccess = DirAccess.open(directoryPath)
|
||||
|
||||
if !dir:
|
||||
printerr("Warning: could not open directory: ", directoryPath)
|
||||
return []
|
||||
|
||||
if dir.list_dir_begin() != OK:
|
||||
printerr("Warning: could not list contents of: ", directoryPath)
|
||||
return []
|
||||
|
||||
var filePaths := []
|
||||
var fileName := dir.get_next()
|
||||
|
||||
while fileName != "":
|
||||
if dir.current_is_dir():
|
||||
if recursive:
|
||||
var dirPath : String = dir.get_current_dir() + "/" + fileName
|
||||
filePaths += get_file_paths_by_extension(dirPath, extension, recursive)
|
||||
else:
|
||||
if fileName.get_extension() == extension:
|
||||
var filePath : String = dir.get_current_dir() + "/" + fileName
|
||||
filePaths.append(filePath)
|
||||
|
||||
fileName = dir.get_next()
|
||||
|
||||
return filePaths
|
||||
Loading…
Add table
Add a link
Reference in a new issue