Premier commit

This commit is contained in:
2026-09-01 22:41:37 +02:00
commit 7cff988739
133 changed files with 6412 additions and 0 deletions
+142
View File
@@ -0,0 +1,142 @@
extends Area3D
class_name Alien
const DEATH_SCENE : PackedScene = preload("res://entities/alien/alien_death_effect/alien_death_effect.tscn") as PackedScene
const DEATH_SCENE_TIME : float = 10.
const COLLISION_HEIGHT = 5
const COLLISION_RADIUS = 1.5
const NEIGHBOR_DETECTION_MARGIN = 0.5
const ATTACK_DISTANCE = 6.
const NEIGHBOR_ROTATION = 0.5
const NEIGHBOR_BUMP_FORCE = 4. * AlienHordeManager.CALCULATE_SCATTER_FREQUENCY
const NEIGHBOR_BLOCKED_SPEED_FACTOR = 0.5
const DIRECTION_DRIFT_RANGE = PI/8
const DAMAGE_EFFECT_DURATION : float = 0.5
const DEFAULT_HP : float = 20.
const DEFAULT_DAMAGE_RATE : float = 1.
signal died
enum State {RUNNING, ATTACKING, DEAD}
@export var size : float = 1.0
@export var speed : float = 10.
@export var turn_speed : float = 20.
@onready var damage_rate : float = size * DEFAULT_DAMAGE_RATE
@onready var hp : float = size * DEFAULT_HP
var state : State = State.RUNNING
var damage_effect_last : float = 0.
var id : int = 0
var target : Node3D
@onready var collision_shape : CollisionShape3D = generate_collision_shape()
func _ready():
monitoring = false
func generate_collision_shape() -> CollisionShape3D:
var new_collision_shape : CollisionShape3D= CollisionShape3D.new()
var cylinder_shape : CylinderShape3D = CylinderShape3D.new()
cylinder_shape.height = COLLISION_HEIGHT
cylinder_shape.radius = COLLISION_RADIUS
new_collision_shape.shape = cylinder_shape
new_collision_shape.position = Vector3(0,COLLISION_HEIGHT/2.,0)
add_child(new_collision_shape)
return new_collision_shape
func move(
delta: float,
calculate_direction: bool,
calculate_scatter : bool
):
var target_angle = rotation.y
var current_speed = speed
if calculate_direction and target:
target_angle = calculate_target_angle()
if calculate_scatter:
var collision_right = has_neighbor(1)
var collision_left = has_neighbor(-1)
if collision_left and not collision_right:
target_angle += - NEIGHBOR_ROTATION
position += Vector3.RIGHT.rotated(Vector3.UP, rotation.y) * NEIGHBOR_BUMP_FORCE * delta
elif collision_right and not collision_left:
target_angle += NEIGHBOR_ROTATION
position += Vector3.LEFT.rotated(Vector3.UP, rotation.y) * NEIGHBOR_BUMP_FORCE * delta
elif collision_left and collision_right:
current_speed = speed * get_random().randf_range(0., NEIGHBOR_BLOCKED_SPEED_FACTOR)
rotation.y = lerp_angle(
rotation.y,
target_angle,
min(1, delta*turn_speed)
)
position += Vector3.FORWARD.rotated(Vector3.UP, rotation.y) * current_speed * delta
func calculate_target_angle() -> float:
var target_angle : float = (
Vector2(global_position.z,global_position.x)
- Vector2(target.global_position.z,target.global_position.x)
).normalized().angle()
# Random drift in direction
target_angle += get_random().randf_range(-DIRECTION_DRIFT_RANGE, DIRECTION_DRIFT_RANGE)
return target_angle
func has_neighbor(direction = 1) -> bool:
var space_state = get_world_3d().direct_space_state
var query = PhysicsRayQueryParameters3D.create(
global_position,
global_position + Vector3(
direction * (COLLISION_RADIUS + NEIGHBOR_DETECTION_MARGIN), 0,0
).rotated(Vector3.UP, rotation.y)
)
query.collide_with_areas = true
query.exclude.append(get_rid())
var result = space_state.intersect_ray(query)
return result != {}
func attack_target(delta : float):
if target and target.has_method("hit"):
target.hit(delta * damage_rate)
func hit(damage = 1.):
hp = max(0, hp - damage)
damage_effect_last = DAMAGE_EFFECT_DURATION
if hp == 0:
die()
func die():
died.emit()
state = State.DEAD
collision_shape.disabled = true
add_child(DEATH_SCENE.instantiate())
await get_tree().create_timer(DEATH_SCENE_TIME).timeout
queue_free()
func get_random() -> RandomNumberGenerator:
var random : RandomNumberGenerator = RandomNumberGenerator.new()
random.seed = id
return random