Files
client/spacewar/ships/ship_movement.gd
T
anekdotin b55453d948 first commit
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-12 19:16:29 -04:00

141 lines
4.3 KiB
GDScript

extends CharacterBody2D
const BULLET_SCENE = preload("res://ships/bullet.tscn")
var _fire_cooldown: float = 0.0
var health: int = 0
var _dead: bool = false
var _invincible: bool = false
var _invincible_timer: float = 0.0
func _ready() -> void:
if GameConfig.player_ship_path.is_empty():
visible = false
set_physics_process(false)
GameConfig.team_selected.connect(_on_team_selected)
else:
_init_player()
func _on_team_selected() -> void:
_init_player()
func _init_player() -> void:
var sprite := get_node_or_null("Sprite2D")
if sprite and not GameConfig.player_ship_path.is_empty():
sprite.texture = load(GameConfig.player_ship_path)
sprite.scale = Vector2.ONE * GameConfig.player_ship_scale
set_physics_process(true)
_respawn()
func _physics_process(delta: float) -> void:
if _dead:
return
# 1. INVINCIBILITY BLINK
if _invincible:
_invincible_timer -= delta
modulate.a = 0.3 if int(_invincible_timer * 8) % 2 == 0 else 1.0
if _invincible_timer <= 0.0:
_invincible = false
modulate.a = 1.0
# 2. ROTATION
if Input.is_action_pressed("move_right"):
rotation += GameConfig.ship_rotation_speed * delta
if Input.is_action_pressed("move_left"):
rotation -= GameConfig.ship_rotation_speed * delta
# 3. THRUST
var thrust := GameConfig.ship_thrust * GameConfig.player_ship_speed_factor
var max_speed := GameConfig.ship_max_speed * GameConfig.player_ship_speed_factor
if Input.is_action_pressed("move_up"):
velocity += Vector2.UP.rotated(rotation) * thrust * delta
if Input.is_action_pressed("move_down"):
velocity += Vector2.DOWN.rotated(rotation) * thrust * delta
velocity = velocity.limit_length(max_speed)
var velocity_before_move := velocity
move_and_slide()
_handle_environment_collisions(velocity_before_move)
# 4. SHOOT
_fire_cooldown -= delta
if Input.is_action_pressed("shoot") and _fire_cooldown <= 0.0:
_fire_cooldown = GameConfig.ship_fire_rate
var bullet = BULLET_SCENE.instantiate()
bullet.global_position = global_position + Vector2.UP.rotated(rotation) * 40.0
bullet.velocity = Vector2.UP.rotated(rotation) * GameConfig.bullet_speed + velocity
bullet.source = self
get_parent().add_child(bullet)
# 5. WALL COLLISION
var bounds = GameConfig.world_bounds
if global_position.x < bounds.position.x or global_position.x > bounds.end.x:
velocity.x = 0
global_position.x = clamp(global_position.x, bounds.position.x, bounds.end.x)
if global_position.y < bounds.position.y or global_position.y > bounds.end.y:
velocity.y = 0
global_position.y = clamp(global_position.y, bounds.position.y, bounds.end.y)
func _handle_environment_collisions(previous_velocity: Vector2) -> void:
for i in get_slide_collision_count():
var collision := get_slide_collision(i)
var collider := collision.get_collider() as Node
if collider == null:
continue
var is_hazard: bool = collider.is_in_group("environment_hazard")
var is_wall: bool = collider.is_in_group("environment_wall")
if not (is_hazard or is_wall):
continue
var normal := collision.get_normal()
var impact_speed := -previous_velocity.dot(normal)
if impact_speed <= 0.0:
continue
velocity = previous_velocity.bounce(normal) * GameConfig.ship_bounce_restitution
if is_hazard:
var damage := int(impact_speed * GameConfig.ship_collision_damage_scale)
if damage > 0:
take_damage(damage)
func take_damage(amount: int) -> void:
if _invincible or _dead:
return
health = max(0, health - amount)
_update_hud()
if health == 0:
_die()
func _die() -> void:
_dead = true
visible = false
velocity = Vector2.ZERO
await get_tree().create_timer(GameConfig.ship_respawn_delay).timeout
_respawn()
func _respawn() -> void:
global_position = _get_spawn_position()
velocity = Vector2.ZERO
rotation = 0.0
health = GameConfig.ship_max_health
_dead = false
visible = true
_invincible = true
_invincible_timer = GameConfig.ship_invincibility_time
_update_hud()
func _get_spawn_position() -> Vector2:
var markers := get_tree().get_nodes_in_group("team_a_spawn") + get_tree().get_nodes_in_group("team_b_spawn")
if markers.size() > 0:
return markers[randi() % markers.size()].global_position
return GameConfig.world_bounds.get_center()
func _update_hud() -> void:
var label = get_node_or_null("/root/World/HUD/HealthLabel")
if label:
label.text = "HP: %d / %d" % [health, GameConfig.ship_max_health]