proto3 initial commit

This commit is contained in:
Segey Lapin
2020-04-13 12:45:25 +03:00
parent 69410badf6
commit 1084b6d5c3
1588 changed files with 368852 additions and 23 deletions

View File

@@ -0,0 +1,5 @@
extends BTBase
class_name BTAction
func tick(_tick: Tick) -> int:
return OK

View File

@@ -0,0 +1,30 @@
extends Node
class_name BehaviorTree
func tick(actor, blackboard, debug = false) -> int:
var tick := Tick.new()
tick.tree = self
tick.actor = actor
tick.blackboard = blackboard
tick.debug = debug
var result := FAILED
for child in get_children():
var _result = child._execute(tick)
assert(typeof(_result) == TYPE_INT)
result = _result
# Close nodes from last tick, if needed
var last_open_nodes: Array = tick.blackboard.get('openNodes', self)
var current_open_nodes := tick.open_nodes
# If node isn't currently open, but was open during last tick, close it
for node in last_open_nodes:
if (not current_open_nodes.has(node)
and tick.blackboard.get('isOpen', tick.tree, node)):
node._close(tick)
# Populate the blackboard
blackboard.set('openNodes', current_open_nodes, self)
return result

View File

@@ -0,0 +1,59 @@
extends Node
class_name Blackboard
var _base_memory: Dictionary #stores global info
var _tree_memory: Dictionary #store tree and node info
func _enter_tree() -> void:
_base_memory = {}
_tree_memory = {}
func set(key, value, behavior_tree = null, node_scope = null) -> void:
var memory := _get_memory(behavior_tree, node_scope)
memory[key] = value
func get(key, behavior_tree = null, node_scope = null):
var memory := _get_memory(behavior_tree, node_scope)
if memory.has(key):
return memory[key]
return null
func _get_memory(behavior_tree, node_scope) -> Dictionary:
var memory := _base_memory
if behavior_tree:
memory = _get_tree_memory(behavior_tree)
if node_scope:
memory = _get_node_memory(memory, node_scope)
return memory
func _get_tree_memory(behavior_tree) -> Dictionary:
if not _tree_memory.has(behavior_tree):
_tree_memory[behavior_tree] = {
'nodeMemory':{},
'openNodes':[]
}
return _tree_memory[behavior_tree]
func _get_node_memory(tree_memory: Dictionary, node_scope) -> Dictionary:
var memory: Dictionary = tree_memory['nodeMemory']
if not memory.has(node_scope):
memory[node_scope] = {}
return memory[node_scope]

View File

@@ -0,0 +1,66 @@
extends Node
class_name BTBase
func _execute(tick: Tick) -> int:
_enter(tick)
if not tick.blackboard.get('isOpen', tick.tree, self):
_open(tick)
var status := _tick(tick)
if status != ERR_BUSY:
_close(tick)
_exit(tick)
return status
func _enter(tick: Tick) -> void:
tick.enter_node(self) #debug call to be filled out in Tick object
enter(tick)
func _open(tick: Tick) -> void:
tick.open_node(self)
tick.blackboard.set('isOpen', true, tick.tree, self)
open(tick)
func _tick(tick: Tick) -> int:
tick.tick_node(self)
return tick(tick)
func _close(tick: Tick) -> void:
tick.close_node(self)
tick.blackboard.set('isOpen', false, tick.tree, self)
close(tick)
func _exit(tick: Tick) -> void:
tick.exit_node(self)
exit(tick)
# The following functions are to be overridden in extending nodes
func enter(_tick: Tick) -> void:
pass
func open(_tick: Tick) -> void:
pass
func tick(_tick: Tick) -> int:
return OK
func close(_tick: Tick) -> void:
pass
func exit(_tick: Tick) -> void:
pass

View File

@@ -0,0 +1,65 @@
extends BTAction
class_name BTBuildPath
func is_dynamic_target(npc):
var target_group = npc.has_meta("target_group")
if target_group in ["_player", "_away", "_enemy", "female", "male"]:
return true
return false
func tick(tick: Tick) -> int:
var npc = tick.actor
var bb = tick.blackboard
var npc_pos = npc.global_transform.origin
assert(npc.has_meta("target_loc"))
assert(npc.has_meta("target_group"))
var loc = npc.get_meta("target_loc")
var target_group = npc.get_meta("target_group")
if npc.has_meta("path_valid") && !is_dynamic_target(npc):
var valid = npc.get_meta("path_valid")
if valid > 0.0:
valid -= tick.blackboard.get("delta")
npc.set_meta("path_valid", valid)
return OK
# print("path no longer valid")
if loc:
var path = []
var target_result: Dictionary = bb.get("target_result").duplicate()
assert(typeof(target_result) == TYPE_DICTIONARY)
assert(target_result != null)
print(target_result)
var target_collider: PhysicsBody
var target_position: Vector3
if !target_result.has("collider"):
path = [npc_pos, loc]
if target_result.has("collider"):
target_collider = target_result.collider
target_position = target_result.position
if target_group == "_away":
if target_collider:
loc = target_position
path = [npc_pos, loc]
else:
var metaai = tick.blackboard.get("metaai")
var astar: AStar = metaai.astar
var start = astar.get_closest_point(npc_pos)
var end = astar.get_closest_point(loc)
path = astar.get_point_path(start, end)
if start == end && npc_pos.distance_to(loc) > 2.0:
path = []
if path.size() == 0:
path = [npc_pos, loc]
# assert(path.size() > 0)
# print("BTBuildPath: ", npc.name, " ", path.size(), ": ", path)
if path.size() == 0:
path = [npc_pos, loc]
npc.set_meta("path", path)
if !npc.get_meta("target_group") in ["_player", "_away", "female", "male"]:
npc.set_meta("path_valid", 1.0)
else:
npc.set_meta("path_valid", 0.3)
# if npc.get_meta("target_group") == "hide_spot":
# print("hide_spot: path: ", path)
return OK
# print("path failed")
return FAILED

View File

@@ -0,0 +1,26 @@
extends BTCondition
class_name BTCanGrab
func tick(tick: Tick) -> int:
var npc = tick.actor
var bb = tick.blackboard
if !npc.is_in_group("guard"):
return FAILED
if npc.get_meta("action") == "forcing":
return FAILED
var enemy = bb.get("closest_enemy")
if !enemy:
return FAILED
var enemy_pos = enemy.global_transform.origin
var npc_pos = npc.global_transform.origin
var space_state = npc.get_world().direct_space_state
var result
var up = npc.orientation.basis[1] * 0.9
var dir = (enemy_pos - npc_pos).normalized() * 1.2
result = space_state.intersect_ray(npc_pos + up, npc_pos + dir + up,
[npc], 0xffff)
if result.has("collider"):
if result.collider == enemy:
return OK
return FAILED

View File

@@ -0,0 +1,5 @@
extends BTCondition
class_name BTCanHide
func tick(tick: Tick) -> int:
return FAILED

View File

@@ -0,0 +1,28 @@
extends BTCondition
class_name BTCanThrow
func tick(tick: Tick) -> int:
var npc = tick.actor
var bb = tick.blackboard
var weapon = npc.get_meta("weapon")
if npc.is_in_group("guard"):
return FAILED
if !weapon && !npc.is_in_group("guard"):
return FAILED
var enemy = bb.get("closest_enemy")
if !enemy:
return FAILED
var enemy_pos = enemy.global_transform.origin
var npc_pos = npc.global_transform.origin
var space_state = npc.get_world().direct_space_state
var result
var up = npc.orientation.basis[1] * 0.9
var dir = (enemy_pos - npc_pos).normalized() * 10.0
result = space_state.intersect_ray(npc_pos + up, npc_pos + dir + up,
[npc], 0xffff)
if result.has("collider"):
if result.collider == enemy:
return OK
return FAILED

View File

@@ -0,0 +1,4 @@
extends BTBase
class_name BTCondition
func tick(_tick: Tick) -> int:
return OK

View File

@@ -0,0 +1,25 @@
extends BTAction
class_name BTFetchPathPoint
func tick(tick: Tick) -> int:
var npc = tick.actor
var path = Array(npc.get_meta("path"))
var valid = npc.get_meta("path_valid")
if valid <= 0.0:
# print("no valid path1")
npc.do_stop()
return FAILED
if path.size() == 0:
# print("no valid path2")
npc.do_stop()
return FAILED
var point = path[0]
var npc_pos = npc.global_transform.origin
if npc_pos.distance_to(point) < 0.5:
if path.size() > 0:
point = path.pop_front()
point.y = npc_pos.y
npc.set_meta("path_point", point)
npc.set_meta("path", path)
# print("fetched path point: ", point)
return OK

View File

@@ -0,0 +1,13 @@
extends BTAction
class_name BTGiveUp
func tick(tick: Tick) -> int:
var npc = tick.actor
# var bb = tick.blackboard
var p = []
p = [
["travel", "parameters/main/playback", "Motion"],
["travel", "parameters/main/Motion/playback", "kneel"]
]
npc.smart_obj(p)
return OK

16
proto3/godot/ai/grab.gd Normal file
View File

@@ -0,0 +1,16 @@
extends BTAction
class_name BTGrab
func tick(tick: Tick) -> int:
var npc = tick.actor
var bb = tick.blackboard
if npc.get_meta("agression") < 100.0:
return FAILED
var pattack = npc.get_meta("agression") / 1000.0
if pattack < randf():
return FAILED
if !npc.get_meta("grabbing"):
var best = bb.get("closest_enemy")
if !best:
return FAILED
grabbing.grab_character(npc, best)
return OK

View File

@@ -0,0 +1,19 @@
extends BTCondition
class_name BTHasArrived
func tick(tick: Tick) -> int:
var npc = tick.actor
var tgt = npc.get_meta("target_loc")
var point = npc.get_meta("path_point")
var npc_pos = npc.global_transform.origin
# print("target: ", tgt, " point: ", point, " pos: ", npc_pos)
if point.distance_to(tgt) < 0.2:
# print("arrived1")
npc.set_meta("path_valid", 0.0)
return OK
if npc_pos.distance_to(tgt) < 0.4:
# print("arrived2")
npc.set_meta("path_valid", 0.0)
return OK
# print(npc.name, " distance: ", npc_pos.distance_to(tgt))
return FAILED

View File

@@ -0,0 +1,9 @@
extends BTCondition
class_name BTHasWeapon
func tick(tick: Tick) -> int:
assert(tick.actor.has_meta("weapon"))
var objmeta = tick.actor.get_meta("weapon")
if objmeta:
return OK
return FAILED

View File

@@ -0,0 +1,16 @@
extends BTCondition
class_name BTIsAction
export var action = "attack"
func tick(tick: Tick) -> int:
var npc = tick.actor
var ameta = npc.get_meta("action")
assert(ameta.length() > 0)
if action == ameta:
# print("is action:", action)
# if action == "hide":
# print("action = hide")
# print(npc.name, " action ok, ", ameta)
return OK
# print("not action: ", action, " action = ", ameta)
return FAILED

View File

@@ -0,0 +1,9 @@
extends BTCondition
class_name BTIsFree
func tick(tick: Tick) -> int:
var npc = tick.actor
if npc.get_meta("smart_object"):
return FAILED
if npc.get_meta("grabbed"):
return FAILED
return OK

View File

@@ -0,0 +1,11 @@
extends BTCondition
class_name BTIsPlayerNearby
export var min_distance = 6.0
func tick(tick: Tick) -> int:
var metaai = tick.blackboard.get("metaai")
var player = metaai.player
var npc = tick.actor
if combat.player_nearby(npc, min_distance):
return OK
return FAILED

View File

@@ -0,0 +1,105 @@
extends BTAction
class_name BTLookAtPath
func tick(tick: Tick) -> int:
var npc = tick.actor
var bb = tick.blackboard
var point = npc.get_meta("path_point")
# print("look path point: ", point)
# var space_state = npc.get_world().direct_space_state
var result
var correction = 0
var xf = Transform()
# var right = npc.orientation.basis[0] * 0.2
# var front = - npc.orientation.basis[2]* 1.2
# var up = npc.orientation.basis[1] * 0.9
var front_result = bb.get("front_result")
if front_result.has("collider"):
correction |= (1 << 0)
result = bb.get("front_right_result")
if result.has("collider"):
correction |= (1 << 1)
result = bb.get("front_left_result")
if result.has("collider"):
correction |= (1 << 2)
# if correction != 0:
# npc.do_stop()
# 1 = FRONT
# 2 = RIGHT
# 4 = LEFT
if !npc.has_meta("unp_c"):
npc.set_meta("unp_c", (PI/1.5 + PI / 4.0 * randf()) * sign(0.5 - randf()))
var c_angle = npc.get_meta("unp_c")
match(correction):
1, 6, 7:
xf = npc.orientation.rotated(Vector3(0, 1, 0), c_angle)
# npc.orientation.basis = xf.basis
if randf() > 0.6:
npc.smart_obj([["set", "parameters/unstuck1/active", "true"]])
elif randf() > 0.4:
npc.smart_obj([["set", "parameters/unstuck2/active", "true"]])
elif randf() > 0.2:
npc.smart_obj([["set", "parameters/turn_right/active", "true"]])
elif randf() > 0.1:
npc.smart_obj([["set", "parameters/turn_left/active", "true"]])
print("correction: ", correction)
# npc.do_stop()
npc.set_meta("walk_cooldown", 2.0)
# return FAILED
2, 3:
npc.smart_obj([["set", "parameters/turn_left/active", "true"]])
npc.set_meta("walk_cooldown", 0.5)
# return FAILED
4, 5:
npc.smart_obj([["set", "parameters/turn_right/active", "true"]])
npc.set_meta("walk_cooldown", 0.5)
# return FAILED
# 1, 2, 3, 4, 5, 6, 7:
# npc.orientation.basis = npc.orientation.interpolate_with(xf, tick.blackboard.get("delta")).basis
# if !npc.has_meta("path_point"):
# npc.do_stop()
if correction in [0, 1, 2, 3, 4, 5]:
var path = npc.get_meta("path")
var npc_pos = npc.global_transform.origin
point.y = npc_pos.y
var dir = Vector3()
if path.size() > 2:
var p1 = path[0]
var p2 = path[1]
p1.y = npc_pos.y
p2.y = npc_pos.y
var dir1 = (point - npc_pos).normalized()
var dir2 = (p1 - npc_pos).normalized()
var dir3 = (p2 - npc_pos).normalized()
dir = (dir1 * 0.9 + dir2 * 0.5 + dir3 * 0.5).normalized()
else:
dir = (point - npc_pos).normalized()
var npc_xform = npc.global_transform
# print("dir: ", dir)
if front_result.has("collider"):
var steer = front_result.normal * 1.5
steer.y = 0.0
dir = (dir + steer).normalized()
if dir.length() > 0:
xf = npc_xform.looking_at(npc_pos + dir, Vector3(0, 1, 0))
npc.orientation.basis = npc.orientation.basis.slerp(xf.basis, tick.blackboard.get("delta"))
# for k in get_tree().get_nodes_in_group("debug_cube"):
# k.queue_free()
# var cube = CubeMesh.new()
# cube.size = Vector3(0.5, 0.5, 0.5)
# var mi = MeshInstance.new()
# mi.mesh = cube
# var r = get_node("/root")
# r.add_child(mi)
# mi.global_transform.origin = point
# mi.add_to_group("debug_cube")
# if !correction in [0, 2, 4]:
# npc.remove_meta("path")
# npc.remove_meta("path_valid")
# npc.remove_meta("target_loc")
# npc.remove_meta("target_group")
# npc.set_meta("path_cooldown", 1.0)
# print("correction: ", correction)
return OK

View File

@@ -0,0 +1,12 @@
extends BTBase
class_name BTParallel
func tick(tick: Tick) -> int:
var _result := OK #if we have no children, assume success
for child in get_children():
var x_result = child._execute(tick)
assert(typeof(x_result) == TYPE_INT)
_result = x_result
return OK

View File

@@ -0,0 +1,16 @@
extends BTBase
class_name BTSelector
func tick(tick: Tick) -> int:
var result := OK #if we have no children, assume success
for child in get_children():
var _result = child._execute(tick)
assert(typeof(_result) == TYPE_INT)
result = _result
if not result == FAILED:
break
return result

View File

@@ -0,0 +1,16 @@
extends BTBase
class_name BTSequence
func tick(tick: Tick) -> int:
var result := OK #if we have no children, assume success
for child in get_children():
var _result = child._execute(tick)
assert(typeof(_result) == TYPE_INT)
result = _result
if not result == OK:
break
return result

View File

@@ -0,0 +1,175 @@
extends BTAction
class_name BTSetAction
export var min_distance = 9.0
#func utility_player_nearby(tick):
# var player = global.player
# var npc = tick.actor
# if combat.player_nearby(npc, min_distance):
# var player_pos = player.global_transform.origin
# var npc_pos = npc.global_transform.origin
# var dst = player_pos.distance_to(npc_pos)
# if dst < min_distance:
# return 1.0 - dst / min_distance
# return 0.0
func utility_enemy_nearby(tick: Tick):
var bb = tick.blackboard
var npc = tick.actor
var enemy = bb.get("closest_enemy")
# var enemy_dist = bb.get("closest_enemy_distance")
if !enemy:
return 0.0
var enemy_pos = enemy.global_transform.origin
var npc_pos = npc.global_transform.origin
var dst = enemy_pos.distance_to(npc_pos)
if dst < min_distance:
# print("nearby: ", 1.0 - dst / min_distance)
return clamp(1.0 - dst / min_distance, 0.0, 1.0)
return clamp(1.0 / (1.0 + 10.0 * dst * dst), 0.0, 1.0)
func utility_attack(tick):
var npc = tick.actor
var ret = utility_enemy_nearby(tick) * npc.get_meta("agression") / 100.0
if npc.get_meta("weapon") == false:
ret = 0.0
if utility_enemy_nearby(tick) > 0.5:
ret *= 0.2
if utility_enemy_nearby(tick) > 0.5 && npc.is_in_group("guard"):
ret = 1.0
if npc.is_in_group("maid"):
ret = 0.0
return clamp(ret, 0.0, 1.0)
func utility_can_hide(tick):
var npc = tick.actor
var ret = 0.0
if rpg.get_stamina(npc) * rpg.get_health(npc) > 0.1:
ret = 1.0
if utility_enemy_nearby(tick) > 0.85:
ret = 0.1
return ret
func utility_hide(tick):
var npc = tick.actor
if npc.is_in_group("guard"):
return 0.0
if utility_enemy_nearby(tick) > 0.9:
return 0.0
return clamp(utility_can_hide(tick) * (0.1 + utility_enemy_nearby(tick)), 0.0, 1.0)
func utility_run_away(tick):
var npc = tick.actor
var ret = utility_enemy_nearby(tick) * (1.0 + npc.get_meta("panic"))
print(ret)
# if npc.is_in_group("maid"):
# ret = utility_player_nearby(tick) * 0.1 * npc.get_meta("panic")
if npc.get_meta("weapon") == false:
ret *= 2.5
if npc.is_in_group("guard"):
return 0.0
if npc.is_in_group("maid"):
return clamp(ret, 0.0, 0.1)
return clamp(ret, 0.0, 1.0)
func utility_find_weapon(tick):
var npc = tick.actor
if npc.get_meta("weapon") == true:
return 0.0
if get_tree().get_nodes_in_group("weapons").size() == 0:
return 0.0
if npc.is_in_group("guard"):
return 0.0
if npc.is_in_group("maid"):
return 0.0
return 1.0 / (1.0 + utility_enemy_nearby(tick))
func utility_wash_floor(tick):
var npc = tick.actor
if npc.is_in_group("maid"):
return 1.0
return 0.0
func utility_patrol(tick):
var npc = tick.actor
if npc.is_in_group("guard"):
return 1.0
return 0.0
func utility_unstuck(tick):
var npc = tick.actor
if npc.has_meta("stuck"):
var stuck = npc.get_meta("stuck")
if stuck > 0.0:
return 1.0
else:
npc.set_meta("stuck", null)
return 0.0
func utility_give_up(tick):
var npc = tick.actor
if npc.is_in_group("guard"):
return 0.0
elif npc.is_in_group("maid"):
return clamp(rpg.get_panic(npc) / 100.0, 0.0, 1.0)
else:
return clamp(rpg.get_panic(npc) / 1000.0, 0.0, 1.0)
func utility_deliver_captive(tick):
var npc = tick.actor
if npc.get_meta("grabbing"):
var item = grabbing.get_grabbed(npc)
if item.is_in_group("captive"):
return 1.0
else:
return 0.0
func utility_forcing(tick):
var npc = tick.actor
var bb = tick.blackboard
if npc.is_in_group("female"):
return 0.0
if npc.get_meta("grabbing"):
return 0.0
if npc.get_meta("grabbed"):
return 0.0
if !npc.is_in_group("guard"):
if utility_enemy_nearby(tick) * 100.0 > 1.0:
return 0.0
var closest_f = bb.get("closest_visible_female")
var xd = bb.get("closest_visible_female_distance")
if !closest_f:
closest_f = bb.get("closest_female")
xd = bb.get("closest_female_distance")
if !closest_f:
return 0.0
var d = (1.0 + 0.1 * rpg.get_lust(npc)) / (1.0 + xd)
return clamp(d, 0.0, 1.0)
var actions = {
"unstuck": 200.0,
"attack": 40.0,
"hide": 40.0,
"run_away": 6500.0,
"find_weapon": 30.0,
"wash_floor": 30.0,
"patrol": 20.0,
"deliver_captive": 20.0,
"forcing": 4000.0,
"give_up": 210.0
}
func tick(tick: Tick) -> int:
var npc = tick.actor
if !npc.has_meta("action"):
npc.set_meta("action", "")
var current_action = npc.get_meta("action")
var current_score = 0.0
# var old_action = current_action
# if actions.has(current_action):
# current_score = actions[current_action] * 1.5
if current_action == "":
print("score: ", current_score)
for k in actions.keys():
var score = call("utility_" + k, tick) * actions[k]
if k == current_action:
score *= 1.5
if current_score < score:
current_score = score
current_action = k
if current_action == "":
print("utility_" + k, " ", actions[k], " ", score)
npc.set_meta("action", current_action)
print(npc.name)
assert(npc.get_meta("action").length() > 0)
print(npc.name, " ", current_action)
assert(current_action.length() > 0)
return OK

View File

@@ -0,0 +1,85 @@
extends BTAction
class_name BTSetDestinationGroup
export var dst_group: String = ""
#func add_loc_marker(tgt):
# for k in get_tree().get_nodes_in_group("debug_loc_marker"):
# k.queue_free()
# var cube = CubeMesh.new()
# cube.size = Vector3(0.2, 3.0, 0.2)
# var mi = MeshInstance.new()
# mi.mesh = cube
# get_node("/root").add_child(mi)
# mi.global_transform.origin = tgt
# mi.add_to_group("debug_loc_marker")
func tick(tick: Tick) -> int:
var dst = INF
var tgt = Vector3()
var npc = tick.actor
var bb = tick.blackboard
var npc_pos = npc.global_transform.origin
var player_pos = global.player.global_transform.origin
var enemy
enemy = bb.get("closest_enemy")
if !enemy:
enemy = bb.get("last_enemy")
var enemy_pos = Vector3()
if enemy:
enemy_pos = enemy.global_transform.origin
if dst_group == "_away":
assert(enemy)
var dir = (npc_pos - enemy_pos).normalized() * 80.0
tgt = npc_pos + dir
npc.set_meta("target_group", dst_group)
npc.set_meta("target_loc", tgt)
# print("run away ", npc.get_meta("action"))
# add_loc_marker(tgt)
return OK
elif dst_group == "_player":
# print("dst group player ", npc.name)
tgt = player_pos
npc.set_meta("target_group", dst_group)
npc.set_meta("target_loc", tgt)
# add_loc_marker(tgt)
# print("chase player ", npc.get_meta("action"))
return OK
elif dst_group == "_enemy":
# print("dst group enemy ", npc.name)
tgt = enemy_pos
npc.set_meta("target_group", dst_group)
npc.set_meta("target_loc", tgt)
# add_loc_marker(tgt)
# print("chase player ", npc.get_meta("action"))
return OK
elif dst_group == "_patrol":
var points = get_tree().get_nodes_in_group("patrol")
if points.size() > 0:
var c = points[randi() % points.size()]
var tpos = c.global_transform.origin
var ndst = tpos.distance_squared_to(npc_pos)
dst = ndst
tgt = tpos
# print("set target: ", tgt)
npc.set_meta("target_group", dst_group)
npc.set_meta("target_loc", tgt)
# add_loc_marker(tgt)
return OK
# print("dst ", npc.get_meta("action"), " ", dst_group)
for c in get_tree().get_nodes_in_group(dst_group):
if c is Spatial:
# print(c.name)
var tpos = c.global_transform.origin
var ndst = tpos.distance_squared_to(npc_pos)
if dst > ndst:
dst = ndst
tgt = tpos
# print("dst: ", dst)
if dst < 100000.0:
# print("set target: ", tgt)
npc.set_meta("target_group", dst_group)
npc.set_meta("target_loc", tgt)
# add_loc_marker(tgt)
# print("set to: ", dst_group)
# if dst_group == "hide_spot":
# print("hiding to ", tgt)
return OK
return FAILED

View File

@@ -0,0 +1,19 @@
extends BTAction
class_name BTSpawnSmartObj
export(String, MULTILINE) var animation_script = ""
func tick(tick: Tick) -> int:
var npc = tick.actor
var bb = tick.blackboard
var s = bb.get("closest_female")
var root = get_node("/root")
var so = SmartObject.new()
root.add_child(so)
var npc_pos = npc.global_transform.origin
so.global_transform = npc.global_transform
var other_pos = s.global_transform.origin
if npc_pos.distance_to(other_pos) > 0.5:
return FAILED
so.activate2(npc, s, animation_script)
return OK

7
proto3/godot/ai/stop.gd Normal file
View File

@@ -0,0 +1,7 @@
extends BTAction
class_name BTStop
func tick(tick: Tick) -> int:
var npc = tick.actor
npc.do_stop()
# print(npc.name, " stand")
return OK

View File

@@ -0,0 +1,21 @@
extends BTAction
class_name BTThrowWeapon
func tick(tick: Tick) -> int:
var npc = tick.actor
if npc.get_meta("agression") < 100.0:
return FAILED
var pattack = npc.get_meta("agression") / 1000.0
if pattack < randf():
return FAILED
npc.set_meta("weapon", false)
var dir = (global.player.global_transform.origin - npc.global_transform.origin).normalized()
var look = npc.global_transform.looking_at(global.player.global_transform.origin, Vector3(0, 1, 0))
npc.orientation.basis = npc.orientation.basis.slerp(look.basis, 3.0 * get_process_delta_time())
var v1 = Vector2(npc.orientation.basis[2].x, npc.orientation.basis[2].z).normalized()
var v2 = -Vector2(dir.x, dir.z).normalized()
if abs(v1.angle_to(v2)) < PI / 9.00:
npc.do_attack()
return OK
else:
return ERR_BUSY

46
proto3/godot/ai/tick.gd Normal file
View File

@@ -0,0 +1,46 @@
#Created by the tree and passed to nodes, this lets nodes know which tree they belong to, and gives them a reference to the blackboard being used for this tick.
#It also holds the list of currently open nodes
#Can be extended to do nodeCount and send debug info
extends Node
class_name Tick
var tree
var open_nodes := []
#var node_count
var debug: bool
var actor
var blackboard: Blackboard
func open_node(node) -> void:
if debug:
print("Opening node '%s'" % node.name)
func enter_node(node) -> void:
open_nodes.push_back(node)
if debug:
print("Entering node '%s'" % node.name)
func tick_node(node) -> void:
if debug:
print("Ticking node '%s'" % node.name)
func close_node(node) -> void:
if open_nodes.has(node):
open_nodes.remove(open_nodes.find(node))
if debug:
print("Closing node '%s'" % node.name)
func exit_node(node) -> void:
if debug:
print("Exiting node '%s'" % node.name)

View File

@@ -0,0 +1,62 @@
extends BTAction
class_name BTUnstuck
func npc_stuck(npc, cond):
if cond:
if npc.has_meta("stuck"):
var stuck = npc.get_meta("stuck")
stuck += 2.0 * get_process_delta_time()
npc.set_meta("stuck", stuck)
else:
npc.set_meta("stuck", 2.0 * get_process_delta_time())
print(npc.name, " stuck ", npc.get_meta("stuck"))
else:
if npc.has_meta("stuck"):
var stuck = npc.get_meta("stuck")
stuck -= 3.0 * get_process_delta_time()
print(npc.name, " unstucking: ", stuck)
if stuck > 0.01:
npc.set_meta("stuck", stuck)
else:
npc.set_meta("stuck", null)
func tick(tick: Tick) -> int:
var npc = tick.actor
var bb = tick.blackboard
var p = []
return FAILED
if randf() > 0.5:
p = [
["set", "parameters/main/Motion/walk/walking/blend_position", 1.0],
["set", "parameters/unstuck1/active", true]
]
else:
p = [
["set", "parameters/main/Motion/walk/walking/blend_position", 1.0],
["set", "parameters/unstuck2/active", true]
]
npc.smart_obj(p)
var front_result = bb.get("front_result")
var front_left_result = bb.get("front_left_result")
var front_right_result = bb.get("front_right_result")
var front_col = false
var left_col = false
var right_col = false
if front_result.has("collider"):
var col = front_result.collider
if !col.is_in_group("entry"):
front_col = true
if front_left_result.has("collider"):
var col = front_left_result.collider
if !col.is_in_group("entry"):
left_col = true
if front_right_result.has("collider"):
var col = front_right_result.collider
if !col.is_in_group("entry"):
right_col = true
if right_col && left_col || front_col:
npc_stuck(npc, true)
else:
npc_stuck(npc, false)
return OK

View File

@@ -0,0 +1,20 @@
extends BTCondition
class_name BTIsPathValid
func tick(tick: Tick) -> int:
var npc = tick.actor
if npc.has_meta("path"):
var path = npc.get_meta("path")
if path:
var valid = npc.get_meta("path_valid")
var delta = tick.blackboard.get("delta")
valid -= delta
if valid <= 0.0:
npc.remove_meta("path")
npc.remove_meta("path_valid")
return FAILED
npc.set_meta("path_valid", valid)
# print("path valid: ", valid, " path:", path)
return OK
npc.do_stop()
# print("invalid path: ", npc.name, ", action = ", npc.get_meta("action"))
return FAILED

174
proto3/godot/ai/walk.gd Normal file
View File

@@ -0,0 +1,174 @@
extends BTAction
class_name BTWalk
#func npc_stuck(npc, cond):
# if cond:
# if npc.has_meta("stuck"):
# var stuck = npc.get_meta("stuck")
# stuck += 2.0 * get_process_delta_time()
# npc.set_meta("stuck", stuck)
# else:
# npc.set_meta("stuck", 0.4 * get_process_delta_time())
# print(npc.name, " stuck ", npc.get_meta("stuck"))
# else:
# if npc.has_meta("stuck"):
# var stuck = npc.get_meta("stuck")
# stuck -= 0.1 * get_process_delta_time()
# print(npc.name, " unstucking: ", stuck)
# if stuck > 0.0:
# npc.set_meta("stuck", stuck)
# else:
# npc.set_meta("stuck", null)
#func is_npc_stuck(npc):
# if npc.has_meta("stuck"):
# var stuck = npc.get_meta("stuck")
# if stuck > 0.0:
# return true
# return false
func tick(tick: Tick) -> int:
var npc = tick.actor
var bb = tick.blackboard
# npc.disable_gravity = false
if npc.has_meta("walk_cooldown"):
var cd = npc.get_meta("walk_cooldown")
if cd >= 0.0:
cd -= get_process_delta_time()
npc.set_meta("walk_cooldown", cd)
return FAILED
else:
npc.remove_meta("walk_cooldown")
if npc.has_meta("action"):
if npc.get_meta("action") == "run_away":
var p = [["set", "parameters/main/Motion/walk/walking/blend_position", 1.0]]
npc.smart_obj(p)
elif npc.get_meta("action") == "unstuck":
return OK
else:
var p = [["set", "parameters/main/Motion/walk/walking/blend_position", 0.0]]
npc.smart_obj(p)
# var front = - npc.orientation.basis[2]* 0.6
# var up = npc.orientation.basis[1]
# var npc_pos = npc.global_transform.origin
# var space_state = npc.get_world().direct_space_state
# var front_result = space_state.intersect_ray(npc_pos + up, npc_pos + up + front,
# [npc], 0xffff)
var front_result = bb.get("front_result")
# var front_left_result = bb.get("front_left_result")
# var front_right_result = bb.get("front_right_result")
var low_obstacle_result: = {}
for k in ["low_obstacle_result"]:
low_obstacle_result = bb.get("low_obstacle_result")
if low_obstacle_result.has("collider"):
break
var front_col = false
# var left_col = false
# var right_col = false
var low_obstacle = false
if front_result.has("collider"):
var col = front_result.collider
if !col.is_in_group("entry"):
front_col = true
front_col = true
# if front_left_result.has("collider"):
# var col = front_left_result.collider
# if !col.is_in_group("entry"):
# left_col = true
# left_col = true
# if front_right_result.has("collider"):
# var col = front_right_result.collider
# if !col.is_in_group("entry"):
# right_col = true
# right_col = true
if !front_col:
if low_obstacle_result.has("collider"):
var col = low_obstacle_result.collider
if !col.is_in_group("entry"):
low_obstacle = true
if low_obstacle:
# npc.disable_gravity = true
var c = [["set", "parameters/climb_low_obstacle/active", true]]
npc.smart_obj(c)
else:
npc.do_walk()
# if !low_obstacle && !front_col:
## npc_stuck(npc, false)
# npc.do_walk()
## if npc.has_meta("stuck"):
## npc.set_meta("stuck", null)
# return OK
# elif !low_obstacle && front_col:
# var normal = front_result.normal
# var xnormal = npc.global_transform.xform_inv(normal)
# print("xnormal ", xnormal)
# var rot: Basis = npc.orientation.basis
# var ok = false
# if xnormal.z < 0:
# rot = rot.rotated(Vector3(0, 1, 0), deg2rad(-20 + 3.0 * (0.5 - randf())))
# ok = true
# elif xnormal.z > 0:
# rot = rot.rotated(Vector3(0, 1, 0), deg2rad(20 + 3.0 * (0.5 - randf())))
# ok = true
## else:
## rot = rot.rotated(Vector3(0, 1, 0), deg2rad(10 + 10.0 * (0.5 - randf())))
# var cur: Basis = npc.orientation.basis
# cur = cur.slerp(rot, get_process_delta_time())
# npc.orientation.basis = cur
# if ok:
# npc.do_walk()
# return OK
# elif !low_obstacle && left_col && !right_col:
# var rot: Basis = npc.orientation.basis.rotated(Vector3(0, 1, 0), deg2rad(-30))
# var cur: Basis = npc.orientation.basis
# cur = cur.slerp(rot, get_process_delta_time())
# npc.orientation.basis = cur
# npc_stuck(npc, false)
# if !is_npc_stuck(npc):
# npc.do_walk()
# return OK
# elif !low_obstacle && !left_col && right_col:
# var rot: Basis = npc.orientation.basis.rotated(Vector3(0, 1, 0), deg2rad(30))
# var cur: Basis = npc.orientation.basis
# cur = cur.slerp(rot, get_process_delta_time())
# npc.orientation.basis = cur
# npc_stuck(npc, false)
# if !is_npc_stuck(npc):
# npc.do_walk()
# return OK
# elif !low_obstacle && left_col && right_col:
# var rot: Basis = npc.orientation.basis.rotated(Vector3(0, 1, 0), deg2rad(100))
# var cur: Basis = npc.orientation.basis
# cur = cur.slerp(rot, get_process_delta_time())
# npc.orientation.basis = cur
# npc_stuck(npc, false)
# print("correction")
# npc.do_stop()
# if !is_npc_stuck(npc):
# npc.do_walk()
# return OK
# elif !low_obstacle && left_col && right_col:
# var rot: Basis = npc.orientation.basis.rotated(Vector3(0, 1, 0), deg2rad(90))
# var cur: Basis = npc.orientation.basis
# cur = cur.slerp(rot, get_process_delta_time())
# npc.orientation.basis = cur
# npc.do_walk()
# npc_stuck(npc, true)
# return FAILED
# elif !low_obstacle:
# var rot: Basis = npc.orientation.basis.rotated(Vector3(0, 1, 0), deg2rad(-45))
# var cur: Basis = npc.orientation.basis
# cur = cur.slerp(rot, get_process_delta_time())
# npc.orientation.basis = cur
# npc.do_walk()
# if npc.has_meta("stuck"):
# var stuck = npc.get_meta("stuck")
# stuck += 2.0 * get_process_delta_time()
# npc.set_meta("stuck", stuck)
# else:
# npc.set_meta("stuck", 0.0)
# npc_stuck(npc, true)
# return FAILED
return OK
# print(npc.name, " walk")

View File

@@ -0,0 +1,13 @@
extends BTAction
class_name BTWashFloor
func tick(tick: Tick) -> int:
var npc = tick.actor
# var bb = tick.blackboard
var p = []
p = [
["travel", "parameters/main/playback", "Motion"],
["travel", "parameters/main/Motion/playback", "wash_floor"]
]
npc.smart_obj(p)
return OK