road-rage-tank/enemies/enemy.gd

93 lines
2.2 KiB
GDScript

class_name PoliceCar
extends CharacterBody3D
const FRAME_IDXS := 10
@export var dot_curve: Curve
@export var max_speed := 8.
@export var health := 10.
@export var knockback_mul := 1.
@export var invulnerable := false
var frame_idx := 0
var frame_count := 0
var knockback := Vector3.ZERO
var default_movement := true
var stunned := false
func set_rotation_to_velocity() -> void:
rotation.y = Vector2(velocity.x, -velocity.z).angle()
func exp_lerp(a: Variant, b: Variant, decay: float, dt: float) -> Variant:
return lerp(a, b, 1 - exp(-decay * dt))
func _ready() -> void:
frame_idx = randi() % FRAME_IDXS
func _update_nav_agent() -> void:
%NavAgent.target_position = Player.instance.global_position
func _process_movement(delta: float) -> void:
var dir := global_position.direction_to(%NavAgent.get_next_path_position())
dir.y = 0
var dot := dir.dot(velocity.normalized())
var dot_power := dot_curve.sample(dot)
velocity += dir * 8. * delta * dot_power
velocity = velocity.limit_length(max_speed)
func _process(delta: float) -> void:
if not default_movement: return
if stunned: return
frame_count = (frame_count + 1) % FRAME_IDXS
if frame_count == frame_idx:
_update_nav_agent()
if knockback.length() < 0.1:
_process_movement(delta)
set_rotation_to_velocity()
position.y = 0.01
else:
velocity = knockback
knockback = exp_lerp(knockback, Vector3.ZERO, 15., delta)
move_and_slide()
func kill() -> void:
queue_free()
var siren: AudioStreamPlayer3D = %Siren
siren.reparent(get_tree().current_scene)
var t := siren.create_tween()
if randf() < .25:
t.tween_property(siren, "pitch_scale", .25, .5)
t.tween_property(siren, "pitch_scale", .35, .25)
t.tween_property(siren, "pitch_scale", .0, .25)
else:
t.tween_property(siren, "pitch_scale", .0, .5)
t.finished.connect(siren.queue_free)
SignalBus.enemy_destroyed.emit()
func hit(proj: Node3D, damage: float) -> bool:
if invulnerable: return true
health -= damage
if health <= 0:
kill()
else:
if proj is PlayerProjectile:
knockback = proj.velocity * 2. * knockback_mul * proj.knockback_mul
return true
func _on_hurtbox_body_entered(body: Node3D) -> void:
if body is Player:
body.damage(self)