Merge pull request 'behavior-tree-implementation' (#2) from behavior-tree-implementation into main
Reviewed-on: #2pull/3/head
commit
208dfd20d5
|
@ -9,6 +9,8 @@
|
|||
- Temperature layer (normal and different levels of coldness, transparent solid color)
|
||||
- Design a tilemap for the game
|
||||
- Player (Dome)
|
||||
- As a layer in the tilemap
|
||||
- Implemented in the PlayerManager
|
||||
- Stats (see document)
|
||||
- Inventory
|
||||
- with one slot
|
||||
|
@ -18,7 +20,7 @@
|
|||
- Use tilemap layers to compute route
|
||||
- Support obstacles
|
||||
- Result must be an array of tile coordinates, length (array length) and the total cost (sum of weights)
|
||||
- Decision Tree (Classes, etc.) (Luca, Cool in)
|
||||
- Decision Tree (Classes, etc.) (Yan)
|
||||
- Reference Food Gatherer for implementation
|
||||
- Child of player, serves as controller
|
||||
- Script needs access to the scene, player and other objects/data
|
||||
|
|
|
@ -1,48 +1,48 @@
|
|||
{
|
||||
"filename": "tilemaps.aseprite",
|
||||
"height": 320,
|
||||
"width": 320,
|
||||
"layers": [
|
||||
{
|
||||
"name": "ground",
|
||||
"cels": [
|
||||
{
|
||||
"image": "tilemaps\\tilemap_ground.png",
|
||||
"frame": 0
|
||||
}
|
||||
],
|
||||
"name": "ground"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "objects",
|
||||
"cels": [
|
||||
{
|
||||
"image": "tilemaps\\tilemap_objects.png",
|
||||
"frame": 0
|
||||
}
|
||||
],
|
||||
"name": "objects"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "temperature",
|
||||
"cels": [
|
||||
{
|
||||
"image": "tilemaps\\tilemap_temperature.png",
|
||||
"frame": 0
|
||||
}
|
||||
],
|
||||
"name": "temperature"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "player",
|
||||
"cels": [
|
||||
{
|
||||
"image": "tilemaps\\tilemap_player.png",
|
||||
"frame": 0
|
||||
}
|
||||
],
|
||||
"name": "player"
|
||||
]
|
||||
}
|
||||
],
|
||||
"width": 320,
|
||||
"frames": [
|
||||
{
|
||||
"duration": 0.1
|
||||
}
|
||||
],
|
||||
"filename": "tilemaps.aseprite"
|
||||
]
|
||||
}
|
|
@ -1,10 +1,14 @@
|
|||
[gd_scene load_steps=6 format=4 uid="uid://b88asko1ugyd2"]
|
||||
[gd_scene load_steps=10 format=4 uid="uid://b88asko1ugyd2"]
|
||||
|
||||
[ext_resource type="Script" path="res://scripts/global/GameManager.gd" id="1_eeg2d"]
|
||||
[ext_resource type="Script" path="res://scripts/tilemap/World.gd" id="1_k0rw8"]
|
||||
[ext_resource type="TileSet" uid="uid://bi836ygcmyvhb" path="res://assets/tilemap/tileset.tres" id="1_vlccq"]
|
||||
[ext_resource type="Script" path="res://scripts/global/Camera.gd" id="2_1vbjl"]
|
||||
[ext_resource type="Script" path="res://scripts/player/PlayerManager.gd" id="4_1xqo1"]
|
||||
[ext_resource type="Script" path="res://scripts/player/tree/BehaviorTree.gd" id="6_efs30"]
|
||||
[ext_resource type="Script" path="res://scripts/player/tree/impl/base/TaskSelector.gd" id="7_1jajd"]
|
||||
[ext_resource type="Script" path="res://scripts/player/tree/impl/context/Task5050Success.gd" id="8_xrswf"]
|
||||
[ext_resource type="Script" path="res://scripts/player/tree/impl/context/Task5050Running.gd" id="9_r13cd"]
|
||||
|
||||
[node name="Island-scene" type="Node2D"]
|
||||
script = ExtResource("1_eeg2d")
|
||||
|
@ -33,3 +37,18 @@ tile_set = ExtResource("1_vlccq")
|
|||
|
||||
[node name="PlayerManager" type="Node" parent="."]
|
||||
script = ExtResource("4_1xqo1")
|
||||
|
||||
[node name="BehaviorTree" type="Node" parent="PlayerManager"]
|
||||
script = ExtResource("6_efs30")
|
||||
|
||||
[node name="sl_Root" type="Node" parent="PlayerManager/BehaviorTree"]
|
||||
script = ExtResource("7_1jajd")
|
||||
|
||||
[node name="Node" type="Node" parent="PlayerManager/BehaviorTree/sl_Root"]
|
||||
script = ExtResource("7_1jajd")
|
||||
|
||||
[node name="5050Success" type="Node" parent="PlayerManager/BehaviorTree/sl_Root/Node"]
|
||||
script = ExtResource("8_xrswf")
|
||||
|
||||
[node name="5050Running" type="Node" parent="PlayerManager/BehaviorTree/sl_Root/Node"]
|
||||
script = ExtResource("9_r13cd")
|
||||
|
|
|
@ -76,6 +76,11 @@ key_9={
|
|||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":57,"key_label":0,"unicode":57,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
force_game_tick={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":70,"key_label":0,"unicode":102,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
|
||||
[rendering]
|
||||
|
||||
|
|
|
@ -6,8 +6,7 @@ extends Node
|
|||
@onready var camera: Camera2D = $Camera2D
|
||||
|
||||
func _ready() -> void:
|
||||
player.world = world
|
||||
player.camera = camera
|
||||
player.game_manager = self
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if Input.is_action_just_pressed("key_1"):
|
||||
|
@ -16,3 +15,5 @@ func _process(delta: float) -> void:
|
|||
camera.go_to_zooming(Vector2(789.883972167969, 450.102813720703), 0.56015348434448)
|
||||
if Input.is_action_just_pressed("key_9"):
|
||||
camera.print_config()
|
||||
if Input.is_action_just_pressed("force_game_tick"):
|
||||
player.game_tick()
|
||||
|
|
|
@ -1,19 +1,32 @@
|
|||
class_name PlayerManager
|
||||
extends Node
|
||||
|
||||
var board_position: Vector2 = Vector2(0, 0)
|
||||
var world: World = null
|
||||
var camera: Camera2D = null
|
||||
#
|
||||
var tilemap_types: TileMapTileTypes = TileMapTileTypes.new()
|
||||
#
|
||||
var game_manager: GameManager = null
|
||||
var board_position: Vector2 = Vector2(0, 0)
|
||||
|
||||
@onready var behavior_tree: BehaviorTree = $BehaviorTree
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
call_deferred("update_board")
|
||||
call_deferred("defer_ready")
|
||||
|
||||
|
||||
func defer_ready() -> void:
|
||||
behavior_tree.game_manager = game_manager
|
||||
update_board()
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if Input.is_action_just_pressed("key_3"):
|
||||
camera.go_to_zooming(world.tilemap_player.cell_to_local(board_position), 2)
|
||||
game_manager.camera.go_to_zooming(game_manager.world.tilemap_player.cell_to_local(board_position), 2)
|
||||
|
||||
|
||||
func update_board() -> void:
|
||||
world.tilemap_player.clear_cells()
|
||||
world.tilemap_player.set_cell(board_position, tilemap_types.PLAYER)
|
||||
game_manager.world.tilemap_player.clear_cells()
|
||||
game_manager.world.tilemap_player.set_cell(board_position, tilemap_types.PLAYER)
|
||||
|
||||
|
||||
func game_tick() -> void:
|
||||
behavior_tree.game_tick()
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
class_name BehaviorTree
|
||||
extends Node
|
||||
|
||||
var game_manager: GameManager = null
|
||||
#
|
||||
var blackboard: Dictionary = {}
|
||||
var behavior_tree: Task = null
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
if get_child_count() == 0 or get_child_count() > 1:
|
||||
push_error("This controller needs exactly one Task child, got " + str(get_child_count()))
|
||||
|
||||
var child: Node = get_child(0)
|
||||
if not (child is Task):
|
||||
push_error("Child is not a task: " + child.name)
|
||||
|
||||
behavior_tree = child as Task
|
||||
|
||||
|
||||
func populate_blackboard():
|
||||
blackboard["world"] = game_manager.world
|
||||
blackboard["player"] = game_manager.player
|
||||
blackboard["camera"] = game_manager.camera
|
||||
|
||||
|
||||
func game_tick() -> void:
|
||||
print("game_tick:")
|
||||
populate_blackboard()
|
||||
behavior_tree.internal_run(blackboard)
|
||||
print(" ==> [active state=", blackboard["current_task"], "] [status=", behavior_tree.status, "]")
|
|
@ -0,0 +1,56 @@
|
|||
class_name Task
|
||||
extends Node
|
||||
|
||||
enum {FAILURE = -1, SUCCESS = 1, RUNNING = 0}
|
||||
var status: int = FAILURE
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
for c in get_children():
|
||||
if not c is Task:
|
||||
push_error("Child is not a task: " + c.name + " in " + name)
|
||||
return
|
||||
|
||||
|
||||
func internal_run(p_blackboard: Dictionary) -> void:
|
||||
p_blackboard["current_task"] = self
|
||||
|
||||
if status == RUNNING:
|
||||
var running_child: Task = find_running_child()
|
||||
if running_child != null:
|
||||
running_child.internal_run(p_blackboard)
|
||||
status = running_child.status
|
||||
return
|
||||
else:
|
||||
run(p_blackboard)
|
||||
else:
|
||||
run(p_blackboard)
|
||||
print(" - ", name, " ", status)
|
||||
|
||||
|
||||
func find_running_child() -> Task:
|
||||
for c in get_children():
|
||||
if c.status == RUNNING:
|
||||
return c
|
||||
return null
|
||||
|
||||
|
||||
func run_child(p_blackboard: Dictionary, p_child: Task) -> void:
|
||||
p_child.internal_run(p_blackboard)
|
||||
if p_child.status != RUNNING:
|
||||
status = RUNNING
|
||||
|
||||
|
||||
func run(p_blackboard: Dictionary) -> void:
|
||||
pass
|
||||
|
||||
|
||||
func cancel(p_blackboard: Dictionary):
|
||||
pass
|
||||
|
||||
|
||||
func get_first_child() -> Task:
|
||||
if get_child_count() == 0:
|
||||
push_error("Task does not have any children: " + name)
|
||||
return null
|
||||
return get_children()[0] as Task
|
|
@ -0,0 +1,11 @@
|
|||
class_name TaskSelector
|
||||
extends Task
|
||||
|
||||
func run(blackboard: Dictionary) -> void:
|
||||
for c in self.get_children():
|
||||
run_child(blackboard, c)
|
||||
if c.status != FAILURE:
|
||||
status = c.status
|
||||
return
|
||||
status = FAILURE
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
class_name TaskSequence
|
||||
extends Task
|
||||
|
||||
func run(blackboard: Dictionary) -> void:
|
||||
for c in self.get_children():
|
||||
run_child(blackboard, c)
|
||||
if c.status != SUCCESS:
|
||||
status = c.status
|
||||
return
|
||||
status = SUCCESS
|
|
@ -0,0 +1,9 @@
|
|||
class_name Task5050Running
|
||||
extends Task
|
||||
|
||||
func run(blackboard: Dictionary) -> void:
|
||||
var random: int = randi() % 2
|
||||
if random == 0:
|
||||
status = RUNNING
|
||||
else:
|
||||
status = SUCCESS
|
|
@ -0,0 +1,9 @@
|
|||
class_name Task5050Success
|
||||
extends Task
|
||||
|
||||
func run(blackboard: Dictionary) -> void:
|
||||
var random: int = randi() % 2
|
||||
if random == 0:
|
||||
status = SUCCESS
|
||||
else:
|
||||
status = FAILURE
|
Loading…
Reference in New Issue