133 lines
4.1 KiB
GDScript
133 lines
4.1 KiB
GDScript
extends KinematicBody2D
|
|
signal arrived
|
|
|
|
enum {STATE_IDLE, STATE_WALKTO, STATE_DIALOGUE, STATE_FOLLOW, STATE_CONTROL}
|
|
var destination = Vector2()
|
|
var state = STATE_IDLE
|
|
var velocity = Vector2()
|
|
var next_dst = Vector2()
|
|
var nav: Navigation2D
|
|
var arrived = false
|
|
var dst_node
|
|
|
|
func _ready():
|
|
nav = get_node("/root/main/nav")
|
|
add_to_group("npc")
|
|
func calc_next_dst():
|
|
var path = nav.get_simple_path(nav.get_closest_point(global_position), nav.get_closest_point(destination))
|
|
if path.size() > 1:
|
|
var ok = false
|
|
for p in path:
|
|
if global_position.distance_squared_to(p) >= 25.0:
|
|
next_dst = p
|
|
ok = true
|
|
break
|
|
if !ok:
|
|
if global_position.distance_squared_to(destination) < 25.0:
|
|
next_dst = destination
|
|
else:
|
|
next_dst = global_position + (destination - global_position).normalized() * 20.0 + Vector2(randf() - 0.5, randf() - 0.5) * 40.0
|
|
else:
|
|
next_dst = destination
|
|
func update_destination():
|
|
destination = dst_node.global_position
|
|
func walkto(p: Vector2):
|
|
arrived = false
|
|
destination = p
|
|
state = STATE_WALKTO
|
|
calc_next_dst()
|
|
func follow(n: Node2D):
|
|
arrived = false
|
|
state = STATE_FOLLOW
|
|
dst_node = n
|
|
update_destination()
|
|
calc_next_dst()
|
|
func avoidance(delta):
|
|
var avdst = 800.0
|
|
var velsum = Vector2()
|
|
for n in get_tree().get_nodes_in_group("npc"):
|
|
if n == self:
|
|
continue
|
|
var dist = n.global_position.distance_squared_to(global_position)
|
|
if dist < avdst:
|
|
var d = global_position - n.global_position
|
|
velsum += d
|
|
velocity = velocity.linear_interpolate(velsum.normalized() * velocity.length() + Vector2(randf() - 0.5, randf() - 0.5) * velocity.length() * 0.3, delta)
|
|
func flock(delta):
|
|
var avdst = 3600.0
|
|
var maxdst = 10000.0
|
|
var velsum = Vector2()
|
|
for n in get_tree().get_nodes_in_group("npc"):
|
|
if n == self:
|
|
continue
|
|
var dist = n.global_position.distance_squared_to(global_position)
|
|
if dist > avdst && dist < maxdst:
|
|
var d = global_position - n.global_position
|
|
velsum += -d
|
|
velocity = velocity.linear_interpolate(velsum.normalized() * velocity.length() + Vector2(randf() - 0.5, randf() - 0.5) * velocity.length() * 0.3, delta)
|
|
func attack():
|
|
var bodies = $capture.get_overlapping_bodies()
|
|
for b in bodies:
|
|
if b is RigidBody2D:
|
|
var e = velocity
|
|
if e.length() == 0:
|
|
e = Vector2(randf() - 0.5, randf() - 0.5)
|
|
b.apply_impulse(Vector2(), e.normalized() * (100.0 + 100.0 * randf()))
|
|
elif b.is_in_group("npc"):
|
|
var e = velocity * 2.0
|
|
if e.length() == 0:
|
|
e = Vector2(randf() - 0.5, randf() - 0.5) * 5000.0
|
|
b.velocity = e
|
|
b.move_and_slide(e)
|
|
func _process(delta):
|
|
match(state):
|
|
STATE_IDLE:
|
|
if randf() > 0.99:
|
|
velocity = velocity.linear_interpolate(Vector2(randf() * 300.0 - 150.0, randf() * 300.0 - 150.0), 0.1 + delta * 0.9)
|
|
else:
|
|
velocity = velocity.linear_interpolate(Vector2(), delta)
|
|
avoidance(delta)
|
|
flock(delta)
|
|
velocity = move_and_slide(velocity)
|
|
STATE_WALKTO:
|
|
var vel_base = 540.0
|
|
if global_position.distance_squared_to(next_dst) < 25.0:
|
|
calc_next_dst()
|
|
if global_position.distance_squared_to(next_dst) < 900.0:
|
|
vel_base = 160.0
|
|
var dir = (next_dst - position).normalized()
|
|
velocity = velocity.linear_interpolate(dir * vel_base, 0.3 * delta)
|
|
avoidance(delta)
|
|
flock(delta)
|
|
if velocity.length() < 3.0:
|
|
velocity += Vector2(randf() - 0.5, randf() - 0.5) * 6.0
|
|
attack()
|
|
velocity = move_and_slide(velocity)
|
|
if global_position.distance_squared_to(destination) < 25.0:
|
|
emit_signal("arrived", destination)
|
|
state = STATE_IDLE
|
|
arrived = true
|
|
STATE_FOLLOW:
|
|
var vel_base = 540.0
|
|
update_destination()
|
|
calc_next_dst()
|
|
if global_position.distance_squared_to(next_dst) < 900.0:
|
|
vel_base = 160.0
|
|
var dir = (next_dst - position).normalized()
|
|
velocity = velocity.linear_interpolate(dir * vel_base, 0.3 * delta)
|
|
avoidance(delta)
|
|
flock(delta)
|
|
if velocity.length() < 3.0:
|
|
velocity += Vector2(randf() - 0.5, randf() - 0.5) * 6.0
|
|
attack()
|
|
velocity = move_and_slide(velocity)
|
|
if global_position.distance_squared_to(destination) < 25.0:
|
|
emit_signal("arrived", destination)
|
|
state = STATE_IDLE
|
|
arrived = true
|
|
STATE_DIALOGUE:
|
|
pass
|
|
STATE_CONTROL:
|
|
pass
|
|
|