Proper generation of the node graph for target selectors, refactored carrying logic
parent
7879bb4656
commit
b688b5c8f5
|
@ -201,7 +201,8 @@
|
|||
"ignore": [
|
||||
"RechargeBattery",
|
||||
"GoToBattery"
|
||||
]
|
||||
],
|
||||
"restore_transfer_variables": true
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
|
|
|
@ -14,8 +14,10 @@ const ROTATION_SPEED: float = 5.0 # adians per second
|
|||
signal waste_detected(waste)
|
||||
#
|
||||
var battery_charge: float = 100.0
|
||||
const battery_charge_drain_per_second: float = 4.0
|
||||
const battery_charge_recharge_per_second: float = 27.0
|
||||
const battery_charge_drain_per_second: float = 5.0
|
||||
const battery_charge_recharge_per_second: float = 30.0
|
||||
# carry item
|
||||
var carry_item: Node2D = null
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
|
@ -43,7 +45,11 @@ func _draw() -> void:
|
|||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
battery_charge -= battery_charge_drain_per_second * delta
|
||||
%StateMachineInfoPanel.values["battery_charge"] = battery_charge
|
||||
if carry_item:
|
||||
# put the carry_item on the character
|
||||
carry_item.position = position
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
|
@ -51,8 +57,6 @@ func _physics_process(delta: float) -> void:
|
|||
detect_waste()
|
||||
queue_redraw()
|
||||
|
||||
battery_charge -= battery_charge_drain_per_second * delta
|
||||
|
||||
|
||||
func detect_waste() -> void:
|
||||
var overlapping_bodies: Array[Node2D] = detection_area.get_overlapping_bodies()
|
||||
|
|
|
@ -17,7 +17,7 @@ func state_process(delta: float) -> void:
|
|||
pass
|
||||
|
||||
|
||||
func state_exit() -> void:
|
||||
func state_exit(new_state: State) -> void:
|
||||
pass
|
||||
|
||||
|
||||
|
|
|
@ -10,14 +10,13 @@ var state_machine_data: Dictionary = {}
|
|||
var received_signals: Array[Dictionary] = []
|
||||
# state change parameters ("transfer")
|
||||
var state_transfer_variables: Dictionary = {}
|
||||
|
||||
var state_history: Array = []
|
||||
|
||||
var current_state: State:
|
||||
set(value):
|
||||
if current_state:
|
||||
current_state.state_exit()
|
||||
state_history.append(value)
|
||||
current_state.state_exit(value)
|
||||
state_history.append({"state": value, "transfer": state_transfer_variables})
|
||||
current_state = value
|
||||
current_state.state_enter()
|
||||
|
||||
|
@ -95,16 +94,30 @@ func check_transitions() -> void:
|
|||
%StateMachineInfoPanel.values["transitioned to"] = transition["target"]
|
||||
|
||||
# evaluate transfer parameters if any
|
||||
state_transfer_variables = {}
|
||||
if transition.has("copy_transfer_variables") and transition["copy_transfer_variables"]:
|
||||
pass
|
||||
else:
|
||||
state_transfer_variables = {}
|
||||
|
||||
if "transfer" in transition and transition["transfer"]:
|
||||
for key in transition["transfer"]:
|
||||
state_transfer_variables[key] = transition_resolve_parameter(transition["transfer"][key])
|
||||
%StateMachineInfoPanel.values["transfer [" + key + "]"] = state_transfer_variables[key]
|
||||
|
||||
# allow current state to contribute to transfer variables
|
||||
current_state.contribute_transfer_variables(state_transfer_variables)
|
||||
|
||||
print("All criteria were met for switching to state ", transition["target"], " with transfer variables ", state_transfer_variables)
|
||||
print("All criteria were met for switching to state ", transition["target"])
|
||||
|
||||
if transition["target"] is Dictionary:
|
||||
if transition["target"].has("restore_transfer_variables") and transition["target"]["restore_transfer_variables"]:
|
||||
var transfer_variables: Dictionary = find_state_by_selector(transition["target"])["transfer"]
|
||||
for key in transfer_variables:
|
||||
state_transfer_variables[key] = transfer_variables[key]
|
||||
|
||||
print("Transfer variables: ", state_transfer_variables)
|
||||
for key in state_transfer_variables:
|
||||
%StateMachineInfoPanel.values["transfer [" + str(key) + "]"] = state_transfer_variables[key]
|
||||
|
||||
current_state = find_state(transition["target"])
|
||||
|
||||
|
||||
|
@ -233,7 +246,7 @@ func find_detected_signal(signal_name: String) -> Dictionary:
|
|||
# UTILITY FUNCTIONS
|
||||
func find_state(name) -> State:
|
||||
if name is Dictionary:
|
||||
return find_state_by_selector(name)
|
||||
return find_state_by_selector(name)["state"]
|
||||
return find_state_by_name(name)
|
||||
|
||||
|
||||
|
@ -242,10 +255,11 @@ func find_state_by_name(name: String) -> State:
|
|||
if child is State:
|
||||
if child.get_name() == name:
|
||||
return child
|
||||
return null
|
||||
# return the default state as a fallback
|
||||
return self.get_child(state_machine_data["start"]["state"])
|
||||
|
||||
|
||||
func find_state_by_selector(name: Dictionary) -> State:
|
||||
func find_state_by_selector(name: Dictionary) -> Dictionary:
|
||||
# {
|
||||
# "type": "history_first",
|
||||
# "ignore": [
|
||||
|
@ -256,10 +270,12 @@ func find_state_by_selector(name: Dictionary) -> State:
|
|||
if name["type"] == "history_first":
|
||||
var index: int = state_history.size() - 1
|
||||
while index >= 0:
|
||||
if not state_history[index].get_name() in name["ignore"]:
|
||||
if not state_history[index]["state"].get_name() in name["ignore"]:
|
||||
return state_history[index]
|
||||
index -= 1
|
||||
return null
|
||||
|
||||
# return the default state as a fallback
|
||||
return {"state": self.get_child(state_machine_data["start"]["state"]), "transfer": {}}
|
||||
|
||||
|
||||
func was_signal_received(signal_name: String) -> bool:
|
||||
|
|
|
@ -6,20 +6,23 @@ var carry_trash: Node2D = null
|
|||
|
||||
|
||||
func state_enter():
|
||||
carry_trash = state_machine.state_transfer_variables["waste"]
|
||||
# disable it's collision to avoid it from colliding with the character
|
||||
carry_trash.get_node("CollisionShape2D").disabled = true
|
||||
if state_machine.state_transfer_variables.has("waste"):
|
||||
carry_trash = state_machine.state_transfer_variables["waste"]
|
||||
character.carry_item = carry_trash
|
||||
# disable it's collision to avoid it from colliding with the character
|
||||
carry_trash.get_node("CollisionShape2D").disabled = true
|
||||
|
||||
print("Carry ", carry_trash, " to ", trash_bin.position)
|
||||
|
||||
|
||||
func state_process(delta: float) -> void:
|
||||
# put the trash on the character
|
||||
carry_trash.position = character.position
|
||||
# carry the trash to the trash bin
|
||||
var target_position: Vector2 = trash_bin.position
|
||||
character.move_towards(target_position, delta)
|
||||
character.move_and_slide()
|
||||
|
||||
|
||||
func state_exit() -> void:
|
||||
carry_trash.queue_free()
|
||||
func state_exit(new_state: State) -> void:
|
||||
if new_state.get_name() != "GoToBattery":
|
||||
character.carry_item = null
|
||||
carry_trash.queue_free()
|
||||
|
|
|
@ -59,12 +59,16 @@ func build_tree():
|
|||
# Set up labels (input and output)
|
||||
populate_node_labels(graph_node, state_name, state_data, all_node_names_to_nodes)
|
||||
|
||||
# Arrange nodes
|
||||
var idx: int = 0
|
||||
for graph_node in all_nodes:
|
||||
@warning_ignore("integer_division")
|
||||
var y_pos: int = randi() % (y_spacing * 2) - y_spacing
|
||||
var x_pos: int = x_spacing * i
|
||||
var x_pos: int = x_spacing * idx
|
||||
y_pos += randi() % 200 - 100
|
||||
graph_node.position_offset = Vector2(x_pos, y_pos)
|
||||
node_positions.append(graph_node)
|
||||
idx += 1
|
||||
|
||||
|
||||
func _on_graph_edit_connection_request(from_node: StringName, from_port: int, to_node: StringName, to_port: int) -> void:
|
||||
|
@ -82,7 +86,10 @@ func populate_node_labels(node: DTreeNode, state_name: String, state_data: Dicti
|
|||
|
||||
if not transition.has("target"):
|
||||
continue
|
||||
|
||||
if not transition['target'] is String:
|
||||
if transition['target'] is Dictionary:
|
||||
populate_node_labels_state_dict(node, state_name, node_names_to_nodes, transition, port_out)
|
||||
continue
|
||||
|
||||
var target_state_name: String = transition['target']
|
||||
|
@ -100,3 +107,39 @@ func populate_node_labels(node: DTreeNode, state_name: String, state_data: Dicti
|
|||
)
|
||||
print("Connecting %s [%d] to %s [%d]" % [node.get_name(), port_out, target_node.get_name(), port_in])
|
||||
|
||||
|
||||
func populate_node_labels_state_dict(node: DTreeNode, state_name: String, node_names_to_nodes: Dictionary, transition: Dictionary, port_out: Vector3i) -> void:
|
||||
# {
|
||||
# "type": "history_first",
|
||||
# "ignore": [
|
||||
# "RechargeBattery",
|
||||
# "GoToBattery"
|
||||
# ],
|
||||
# "restore_transfer_variables": true
|
||||
# }
|
||||
# display a new node for the target state with it's information
|
||||
var target_state_name: String = node.get_name() + "_" + transition['target']['type']
|
||||
var target_node: DTreeNode = null
|
||||
if node_names_to_nodes.has(target_state_name):
|
||||
target_node = node_names_to_nodes[target_state_name]
|
||||
else:
|
||||
target_node = D_TREE_NODE.instantiate()
|
||||
graph_edit.add_child(target_node)
|
||||
target_node.title = transition['target']['type']
|
||||
all_nodes.append(target_node)
|
||||
all_node_names_to_nodes[target_state_name] = target_node
|
||||
|
||||
# add the "ignore" states as input ports
|
||||
if transition['target'].has("ignore"):
|
||||
target_node.add_label("ignore:", false, false)
|
||||
for ignore_state in transition['target']['ignore']:
|
||||
target_node.add_label("- %s" % [ignore_state], false, false)
|
||||
|
||||
var port_in: Vector3i = target_node.add_label("%s" % [state_name], true, false)
|
||||
|
||||
# connect the nodes
|
||||
graph_edit.connect_node(
|
||||
node.get_name(), port_out.z,
|
||||
target_node.get_name(), port_in.y
|
||||
)
|
||||
print("Connecting %s [%d] to %s [%d]" % [node.get_name(), port_out, target_node.get_name(), port_in])
|
Loading…
Reference in New Issue