В скрипте у мобов есть два состояния: они бродят или атакуют персонажа, когда он находится в заданных пределах.
Любые переменные игрока, такие как хп и позиция на карте берутся из автолод скрипта global. Я не уверен, что такая архитектура в принципе является удачной, если я прав, был бы рад, если вы предложите новую.
extends KinematicBody2D
var player_is_attacked = false
var staying = true
var speed = 45
var speed_atack = 1
var range_atack = 40
var damage = 1
var detection_area = 200
var velocity = Vector2()
var destination = Vector2()
var prev_pos = Vector2()
var player_pos = Vector2()
export var x_zone = 0
export var y_zone = 0
func _ready():
$AnimatedSprite.speed_scale = speed_atack
func _process(delta):
if velocity:
prev_pos = position
select_walk_animation()
move_and_slide(velocity)
generate_destination()
if global.player_health != 0:
search_player()
else:
player_is_attacked = false
func generate_destination():
if staying:
randomize()
var x = rand_range(x_zone - 90, x_zone + 90) #x_zone и y_zone присваиваются в сцене карты
var y = rand_range(y_zone - 90, y_zone + 90)
get_destination(Vector2(x, y))
elif velocity != Vector2():
if not player_is_attacked:
if position.distance_to(destination) <= speed:
cancel_moving()
$NotMovTimer.start(1.5)
elif prev_pos.distance_to(position) <= 0.6:
cancel_moving()
$NotMovTimer.start(0.5)
func get_destination(dest):
destination = dest
velocity = (destination - position).normalized() * speed
staying = false
func search_player():
var pl_pos = Vector2(global.player_pos.x, global.player_pos.y)
if pl_pos.distance_to(position) <= detection_area: #игрок в заданой области
get_destination(pl_pos)
if pl_pos.distance_to(position) <= range_atack: #если до точки остался путь в range_atack
velocity = Vector2()
destination = Vector2()
select_attack_animation()
player_is_attacked = true
else:
player_is_attacked = false
func cancel_moving():
$AnimatedSprite.stop()
$AnimatedSprite.set_frame(0) # анимация в 0(спокойствии) и сохраняет свое направление после .stop()
velocity = Vector2()
destination = Vector2()
func select_walk_animation():
if abs(velocity.x) > abs(velocity.y):
if velocity.x < 0:
$AnimatedSprite.play("left")
else:
$AnimatedSprite.play("right")
elif abs(velocity.x) < abs(velocity.y):
if velocity.y < 0:
$AnimatedSprite.play("up")
else:
$AnimatedSprite.play("down")
func select_attack_animation():
if "atack" in $AnimatedSprite.animation: #анимации удара называются attack_направление
return #анимации передвижения left, right, up, down
else:
$AnimatedSprite.play("atack_" + $AnimatedSprite.animation)
func _on_NotMovTimer_timeout():
staying = true
func _on_AnimatedSprite_animation_finished():
if player_is_attacked and global.player_health >= 0:
global.player_health -= damage