Files
godot-demo-projects/3d/platformer/enemy/enemy.gd
2022-12-13 16:51:20 +01:00

85 lines
2.4 KiB
GDScript

extends RigidBody3D
const ACCEL = 5.0
const DEACCEL = 20.0
const MAX_SPEED = 2.0
const ROT_SPEED = 1.0
var prev_advance := false
var dying := false
var rot_dir = 4
@onready var gravity = ProjectSettings.get_setting("physics/3d/default_gravity") \
* ProjectSettings.get_setting("physics/3d/default_gravity_vector")
@onready var _animation_player := $Enemy/AnimationPlayer as AnimationPlayer
@onready var _ray_floor := $Enemy/Skeleton/RayFloor as RayCast3D
@onready var _ray_wall := $Enemy/Skeleton/RayWall as RayCast3D
func _integrate_forces(state: PhysicsDirectBodyState3D):
var delta := state.get_step()
var lin_velocity := state.get_linear_velocity()
var grav := state.get_total_gravity()
# get_total_gravity returns zero for the first few frames, leading to errors.
if grav.is_zero_approx():
grav = self.gravity
lin_velocity += grav * delta # Apply gravity.
var up := -grav.normalized()
if dying:
state.set_linear_velocity(lin_velocity)
return
for i in state.get_contact_count():
var contact_collider := state.get_contact_collider_object(i)
var contact_normal := state.get_contact_local_normal(i)
if is_instance_valid(contact_collider):
if contact_collider is Bullet and contact_collider.enabled:
dying = true
axis_lock_angular_x = false
axis_lock_angular_y = false
axis_lock_angular_z = false
collision_layer = 0
state.set_angular_velocity(-contact_normal.cross(up).normalized() * 33.0)
_animation_player.play(&"impact")
_animation_player.queue(&"extra/explode")
contact_collider.enabled = false
$SoundWalkLoop.stop()
$SoundHit.play()
return
var advance := _ray_floor.is_colliding() and not _ray_wall.is_colliding()
var dir := ($Enemy/Skeleton as Node3D).get_transform().basis[2].normalized()
var deaccel_dir := dir
if advance:
if dir.dot(lin_velocity) < MAX_SPEED:
lin_velocity += dir * ACCEL * delta
deaccel_dir = dir.cross(gravity).normalized()
else:
if prev_advance:
rot_dir = 1
dir = Basis(up, rot_dir * ROT_SPEED * (delta)) * dir
$Enemy/Skeleton.set_transform(Transform3D().looking_at(-dir, up))
var dspeed := deaccel_dir.dot(lin_velocity)
dspeed -= DEACCEL * delta
if dspeed < 0:
dspeed = 0
lin_velocity = lin_velocity - deaccel_dir * deaccel_dir.dot(lin_velocity) \
+ deaccel_dir * dspeed
state.set_linear_velocity(lin_velocity)
prev_advance = advance
func _die():
queue_free()