AI can 'die' now; blackboard work

This commit is contained in:
Segey Lapin
2022-01-04 06:45:16 +03:00
parent 2573492f59
commit fedb6a38e1
19 changed files with 120929 additions and 93123 deletions

View File

@@ -29,7 +29,7 @@ const guard_distance = 2.0
const engage_distance = 10.0
const flee_distance = 5.0
var blackboard = {
var init_blackboard = {
"stamina": 100.0,
"health": 100.0,
"melee_weapon_equipped": false,
@@ -62,7 +62,7 @@ func combat_event(ev, data):
var dst = where.distance_squared_to(curpos)
if dst < guard_distance * guard_distance:
if who == player:
blackboard.guard = true
blackboard_set("guard", true)
"damage":
var who = data[0]
var weapon = data[1]
@@ -72,13 +72,15 @@ func combat_event(ev, data):
var dst = where.distance_squared_to(curpos)
if dst < attack_distance * attack_distance:
if who == player:
blackboard.melee_damage = true
blackboard_set("melee_damage", true)
var initialized = false
func init():
func init(tick):
assert(!initialized)
name = "bandit_ai"
root = get_character()
for e in init_blackboard.keys():
blackboard_set(e, init_blackboard[e])
assert(root.has_meta("skeleton"))
rnd = RandomNumberGenerator.new()
rnd.randomize()
@@ -377,6 +379,39 @@ class rest extends base_bhv:
assert(root)
active = false
finished = false
class unconcious extends base_bhv:
var root
var anim1
var anim2
var state = 0
func start(root: Node, anim1: String, anim2: String):
self.root = root
self.anim1 = anim1
self.anim2 = anim2
active = true
state = 0
func run(delta: float, bb: Dictionary):
assert(active)
assert(root)
assert(anim1)
assert(anim2)
match state:
0:
characters.animation_node_travel(root, anim1)
state = 1
# if finished:
# return
# if bb.stamina < 100.0:
# print("rest: stamina: ", bb.stamina)
# bb.stamina += 15500.0 * delta
# else:
# finished = true
func stop():
assert(active)
assert(root)
active = false
finished = false
#var walk_to: walkto
#var flee_to: walkto
@@ -392,76 +427,78 @@ var conf_behaviors: = {
"melee_attack": attack,
"guard": guard,
"rest": rest,
"get_melee_damage": get_damage
"get_melee_damage": get_damage,
"unconcious": unconcious
}
var pdst = INF
static func calc_utility(utility: String, bb: Dictionary):
func calc_utility(utility: String):
match utility:
"take_melee_weapon":
if bb.health <= 0.0:
if blackboard_get("health") <= 0.0:
return 0.0
if bb.melee_weapon_equipped:
if blackboard_get("melee_weapon_equipped"):
return 0.0
else:
if bb.enemy_distance < engage_distance * engage_distance:
if blackboard_get("enemy_distance") < engage_distance * engage_distance:
return 110.0
"approach":
if bb.health <= 0.0:
if blackboard_get("health") <= 0.0:
return 0.0
if bb.enemy_distance < 1.6 * 1.6:
if blackboard_get("enemy_distance") < 1.6 * 1.6:
return 0.0
if bb.stamina > 50.0 && bb.enemy_distance < engage_distance * engage_distance:
return 10.0 + (bb.enemy_distance - 10.0) / 6.0
if blackboard_get("stamina") > 50.0 && blackboard_get("enemy_distance") < engage_distance * engage_distance:
return 10.0 + (blackboard_get("enemy_distance") - 10.0) / 6.0
"melee_attack":
if bb.health <= 0.0:
if blackboard_get("health") <= 0.0:
return 0.0
if bb.melee_weapon_equipped:
if bb.attack_cooldown <= 0.0:
if blackboard_get("melee_weapon_equipped"):
if blackboard_get("attack_cooldown") <= 0.0:
var d = attack_distance * attack_distance
if bb.stamina > 20.0 && bb.enemy_distance <= d:
if blackboard_get("stamina") > 20.0 && blackboard_get("enemy_distance") <= d:
return 50.0
"flee":
if bb.health <= 0.0:
if blackboard_get("health") <= 0.0:
return 0.0
if bb.flee_cooldown > 0.0:
if blackboard_get("flee_cooldown") > 0.0:
return 0.0
if bb.stamina <= 50.0 && bb.stamina > 10.0 && bb.enemy_distance < flee_distance * flee_distance:
return 100.0 + clamp((100.0 - bb.stamina), 0, 90.0) * 2.0
if bb.stamina <= 10.0 && bb.enemy_distance <= flee_distance * flee_distance * 0.5:
if blackboard_get("stamina") <= 50.0 && blackboard_get("stamina") > 10.0 && blackboard_get("enemy_distance") < flee_distance * flee_distance:
return 100.0 + clamp((100.0 - blackboard_get("stamina")), 0, 90.0) * 2.0
if blackboard_get("stamina") <= 10.0 && blackboard_get("enemy_distance") <= flee_distance * flee_distance * 0.5:
return 250.0
if bb.stamina <= 50.0 && bb.enemy_distance < engage_distance * engage_distance:
if bb.randf < 0.3:
if blackboard_get("stamina") <= 50.0 && blackboard_get("enemy_distance") < engage_distance * engage_distance:
if blackboard_get("randf") < 0.3:
return 100.0
if bb.enemy_distance < 1.4 * 1.4:
if blackboard_get("enemy_distance") < 1.4 * 1.4:
return 150.0
if bb.health < 50 && bb.health > 15:
if blackboard_get("health") < 50 && blackboard_get("health") > 15:
return 160
"guard":
if bb.health <= 0.0:
if blackboard_get("health") <= 0.0:
return 0.0
if bb.guard_cooldown > 0.0:
if blackboard_get("guard_cooldown") > 0.0:
return 0.0
elif bb.guard:
bb.guard = false
elif blackboard_get("guard"):
blackboard_set("guard", false)
return 300.0
# elif bb.enemy_distance < guard_distance * guard_distance * 0.3 && bb.stamina > 10.0:
# elif blackboard_get("enemy_distance") < guard_distance * guard_distance * 0.3 && blackboard_get("stamina") > 10.0:
# return 80
# elif bb.enemy_distance < attack_distance * attack_distance * 0.3:
# elif blackboard_get("enemy_distance") < attack_distance * attack_distance * 0.3:
# return 10.0
"rest":
if bb.stamina >= 100.0:
return 0.0
if bb.stamina <= 10.0 && bb.enemy_distance >= flee_distance * flee_distance:
return 100.0 + bb.enemy_distance / 10.0
if bb.health < 10:
"unconcious":
if blackboard_get("health") < 10:
return 2000
"get_melee_damage":
if bb.health <= 0.0:
"rest":
if blackboard_get("stamina") >= 100.0:
return 0.0
if bb.melee_damage:
bb.melee_damage = false
print("DAMAGE2 ", bb.health)
if blackboard_get("stamina") <= 10.0 && blackboard_get("enemy_distance") >= flee_distance * flee_distance:
return 100.0 + blackboard_get("enemy_distance") / 10.0
"get_melee_damage":
if blackboard_get("health") <= 0.0:
return 0.0
if blackboard_get("melee_damage"):
blackboard_set("melee_damage", false)
print("DAMAGE2 ", blackboard_get("health"))
return 1000
_:
assert(false)
@@ -473,7 +510,7 @@ func select_behavior():
best_behavior = "rest"
best_utility = 0.0
for e in conf_behaviors.keys():
var utility = calc_utility(e, blackboard)
var utility = calc_utility(e)
if e == last_behavior:
utility *= 2.0
if best_utility < utility:
@@ -486,7 +523,7 @@ var last_bhv
var last_running = []
var current_running = []
var run_behaviors = {}
func update_physics(delta):
func update_physics(tick, delta):
assert(initialized)
assert(root)
var cam = root.get_viewport().get_camera()
@@ -498,10 +535,10 @@ func update_physics(delta):
var o = root.global_transform.origin
var p = cam.get_meta("player").global_transform
pdst = o.distance_squared_to(p.origin)
blackboard.enemy_distance = pdst
blackboard.randf = rnd.randf()
blackboard.enemy_pos = p.origin
blackboard.space = space
blackboard_set("enemy_distance", pdst)
blackboard_set("randf", rnd.randf())
blackboard_set("enemy_pos", p.origin)
blackboard_set("space", space)
# var adest = o + (p.origin - o).normalized() * min(2.0, sqrt(pdst))
var adest = p.origin
var away = (o - p.origin).normalized()
@@ -511,7 +548,7 @@ func update_physics(delta):
var enemy_dir: Vector3 = Transform(p.basis, Vector3()).xform(Vector3(0, 0, -1))
var root_dir: Vector3 = Transform(root.global_transform.basis, Vector3()).xform(Vector3(0, 0, -1))
var dot = root_dir.dot(enemy_dir)
blackboard.dot = dot
blackboard_set("dot", dot)
var prev_state = state
match state:
@@ -544,6 +581,8 @@ func update_physics(delta):
run_behaviors[bhv].start(root, "guard-melee1", "guard-front-melee1")
"get_melee_damage":
run_behaviors[bhv].start(root, "guard-melee1", "guard-front-melee1", 10.0)
"unconcious":
run_behaviors[bhv].start(root, "fall-front", "fall-back")
_:
assert(false)
# print("adding behavior: ", bhv)
@@ -552,10 +591,10 @@ func update_physics(delta):
if !e in last_running:
if !e.active:
e.activate()
e.run(delta, blackboard)
e.run(delta, blackboard_get_dict())
#FIXME: mess :(
if e == run_behaviors["flee"]:
blackboard.flee_cooldown = 2.0 + rnd.randf() * 3.0
blackboard_set("flee_cooldown", 2.0 + rnd.randf() * 3.0)
if e.finished && e.active:
# print("in current run but finished")
e.stop()
@@ -570,18 +609,18 @@ func update_physics(delta):
state = 3
3:
state = 0
if blackboard.stamina < 100.0:
blackboard.stamina += delta
if blackboard.attack_cooldown > 0.0:
blackboard.attack_cooldown -= delta
if blackboard.guard_cooldown > 0.0:
blackboard.guard_cooldown -= delta
if blackboard.flee_cooldown > 0.0:
blackboard.flee_cooldown -= delta
blackboard.stamina = clamp(blackboard.stamina, 0, 100.0)
blackboard.health = clamp(blackboard.health, 0, 100.0)
if blackboard_get("stamina") < 100.0:
blackboard_set("stamina", blackboard_get("stamina") + delta)
if blackboard_get("attack_cooldown") > 0.0:
blackboard_set("attack_cooldown", blackboard_get("attack_cooldown") - delta)
if blackboard_get("guard_cooldown") > 0.0:
blackboard_set("guard_cooldown", blackboard_get("guard_cooldown") - delta)
if blackboard_get("flee_cooldown") > 0.0:
blackboard_set("flee_cooldown", blackboard_get("flee_cooldown") - delta)
blackboard_set("stamina", clamp(blackboard_get("stamina"), 0, 100.0))
blackboard_set("health", clamp(blackboard_get("health"), 0, 100.0))
return ERR_BUSY
func update(delta):
func update(tick, delta):
return ERR_BUSY
##