224 lines
6.5 KiB
GDScript
224 lines
6.5 KiB
GDScript
extends CharacterBody3D
|
|
|
|
@export var speed = 100.0
|
|
@export var fall_acceleration = 75.0
|
|
@export var vertical_sensivity = 0.005
|
|
@export var horizontal_sensivity = 0.005
|
|
|
|
var queue: CommandQueue = CommandQueue.new()
|
|
var queue_data: Dictionary = {}
|
|
|
|
@onready var camera: Camera3D = $"Camera"
|
|
@onready var weapon_player: AnimationPlayer = $"HUD/Weapon/AnimationPlayer"
|
|
@onready var weapons: WeaponContainer = $"WeaponContainer"
|
|
|
|
# Placeholder UI
|
|
@onready var ammo_label: Label = $"HUD/Ammo"
|
|
|
|
var current_weapon:Weapon
|
|
|
|
var slot_actions: Array[StringName] = [ "slot_primary", "slot_secondary", "slot_tertiary" ]
|
|
|
|
func _ready() -> void:
|
|
queue.command_pushed.connect(on_queue_command_pushed)
|
|
queue.command_popped.connect(on_queue_command_popped)
|
|
queue.command_started.connect(on_queue_command_started)
|
|
|
|
weapons.slot_selected.connect(on_weapon_slot_selected)
|
|
|
|
get_tree().create_timer(0.02).timeout.connect(on_weapon_slot_selected)
|
|
|
|
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
|
|
|
func _process(_delta: float) -> void:
|
|
if current_weapon == null:
|
|
return
|
|
var weapon_sides = current_weapon.uses_hands
|
|
var weapon_sides_are_free = not queue.sides_are_busy(weapon_sides)
|
|
if weapon_sides_are_free:
|
|
# Fire logic
|
|
var fire_action = Input.is_action_just_pressed('shoot')
|
|
if fire_action:
|
|
push_copied_command(CommandQueue.Command.FIRE, weapon_sides)
|
|
|
|
|
|
# Reload logic
|
|
var reload_action = Input.is_action_just_pressed('reload')
|
|
if reload_action:
|
|
if not queue.has_command(CommandQueue.Command.RELOAD):
|
|
push_copied_command(CommandQueue.Command.RELOAD, weapon_sides)
|
|
|
|
# Slot changing logic
|
|
var slot_action = false
|
|
for slot in slot_actions.size():
|
|
if Input.is_action_just_pressed(slot_actions[slot]):
|
|
slot_action = true
|
|
queue_data['slot_id'] = slot
|
|
if slot_action:
|
|
push_copied_command(CommandQueue.Command.HOLSTER_WEAPON, weapon_sides)
|
|
|
|
# Stop firing logic
|
|
if not current_weapon.fire_mode is SingleFireMode:
|
|
var stop_firing_action = Input.is_action_just_released('shoot')
|
|
if stop_firing_action:
|
|
push_copied_command(CommandQueue.Command.STOP_FIRING, weapon_sides)
|
|
|
|
|
|
for side in CommandQueue.Side.values():
|
|
var command = queue.current_command(side)
|
|
match side:
|
|
CommandQueue.Side.LEFT:
|
|
handle_current_left_command(command)
|
|
CommandQueue.Side.RIGHT:
|
|
handle_current_right_command(command)
|
|
|
|
func _physics_process(delta: float) -> void:
|
|
var direction = Vector3.ZERO
|
|
direction.z = Input.get_axis("move_forward", "move_backward")
|
|
direction.x = Input.get_axis("move_left", "move_right")
|
|
var target_velocity = (transform.basis * direction).normalized() * speed * delta
|
|
|
|
if not is_on_floor():
|
|
target_velocity.y -= fall_acceleration * delta
|
|
|
|
velocity = target_velocity
|
|
move_and_slide()
|
|
|
|
func _input(event):
|
|
if event is InputEventMouseMotion:
|
|
var new_rotation = clamp(
|
|
camera.rotation.x - event.relative.y * vertical_sensivity,
|
|
-PI/2,
|
|
PI/2
|
|
)
|
|
camera.rotation.x = new_rotation
|
|
rotation.y -= event.relative.x * horizontal_sensivity
|
|
|
|
func on_weapon_slot_selected():
|
|
if current_weapon != null:
|
|
current_weapon.fired.disconnect(on_weapon_fired)
|
|
current_weapon.fire_failed.disconnect(finish_task)
|
|
current_weapon.fire_allowed.disconnect(finish_task)
|
|
|
|
weapon_player.remove_animation_library("current")
|
|
|
|
current_weapon = weapons.current_weapon
|
|
|
|
current_weapon.fired.connect(on_weapon_fired)
|
|
current_weapon.fire_failed.connect(finish_task)
|
|
current_weapon.fire_allowed.connect(finish_task)
|
|
|
|
weapon_player.add_animation_library("current", current_weapon.animation_library)
|
|
|
|
push_copied_command(CommandQueue.Command.DRAW_WEAPON, current_weapon.uses_hands)
|
|
|
|
update_ammo_label()
|
|
|
|
|
|
func on_queue_command_pushed(commands: Dictionary):
|
|
for side in commands:
|
|
match side:
|
|
CommandQueue.Side.LEFT:
|
|
handle_new_left_command(commands[side])
|
|
CommandQueue.Side.RIGHT:
|
|
handle_new_right_command(commands[side])
|
|
|
|
func push_copied_command(command: CommandQueue.Command, sides: Array[CommandQueue.Side]):
|
|
var commands = {}
|
|
for side in sides:
|
|
commands[side] = command
|
|
queue.push(commands)
|
|
|
|
func finish_task():
|
|
queue.pop()
|
|
|
|
func reset_animation_and_finish_task():
|
|
weapon_player.play("current/static")
|
|
queue.pop()
|
|
|
|
func on_queue_command_popped(commands):
|
|
for i in CommandQueue.Side.size():
|
|
match CommandQueue.Side.values()[i]:
|
|
CommandQueue.Side.LEFT:
|
|
handle_ended_left_command(commands[i])
|
|
CommandQueue.Side.RIGHT:
|
|
handle_ended_right_command(commands[i])
|
|
|
|
func on_queue_command_started(commands):
|
|
for i in CommandQueue.Side.size():
|
|
match CommandQueue.Side.values()[i]:
|
|
CommandQueue.Side.LEFT:
|
|
handle_started_left_command(commands[i])
|
|
CommandQueue.Side.RIGHT:
|
|
handle_started_right_command(commands[i])
|
|
|
|
func update_ammo_label():
|
|
ammo_label.text = "{ammo}/{max}".format({
|
|
ammo = current_weapon.ammo,
|
|
max = current_weapon.max_ammo
|
|
})
|
|
|
|
func on_weapon_fired():
|
|
weapon_player.stop()
|
|
weapon_player.play("current/fire")
|
|
update_ammo_label()
|
|
|
|
func on_weapon_reload():
|
|
weapon_player.play("current/reload")
|
|
|
|
func reset_animation():
|
|
weapon_player.play("current/static")
|
|
|
|
func handle_new_left_command(command: CommandQueue.Command):
|
|
match command:
|
|
pass
|
|
|
|
func handle_new_right_command(command: CommandQueue.Command):
|
|
match command:
|
|
CommandQueue.Command.RELOAD:
|
|
weapon_player.play('current/reload')
|
|
CommandQueue.Command.STOP_FIRING:
|
|
if queue.current_command(CommandQueue.Side.RIGHT) == CommandQueue.Command.FIRE:
|
|
current_weapon.end_fire()
|
|
|
|
func handle_ended_left_command(command: CommandQueue.Command):
|
|
match command:
|
|
pass
|
|
|
|
func handle_ended_right_command(command: CommandQueue.Command):
|
|
match command:
|
|
CommandQueue.Command.FIRE:
|
|
current_weapon.end_fire()
|
|
CommandQueue.Command.RELOAD:
|
|
weapon_player.play('current/static')
|
|
current_weapon.reload()
|
|
update_ammo_label()
|
|
CommandQueue.Command.HOLSTER_WEAPON:
|
|
weapons.select_slot(queue_data['slot_id'])
|
|
CommandQueue.Command.DRAW_WEAPON:
|
|
weapon_player.play('current/static')
|
|
|
|
func handle_started_left_command(command: CommandQueue.Command):
|
|
match command:
|
|
pass
|
|
|
|
func handle_started_right_command(command: CommandQueue.Command):
|
|
match command:
|
|
CommandQueue.Command.FIRE:
|
|
current_weapon.request_fire()
|
|
CommandQueue.Command.STOP_FIRING:
|
|
queue.pop()
|
|
CommandQueue.Command.DRAW_WEAPON:
|
|
weapon_player.play('current/draw')
|
|
CommandQueue.Command.HOLSTER_WEAPON:
|
|
weapon_player.play('current/holster')
|
|
|
|
func handle_current_left_command(command: CommandQueue.Command):
|
|
match command:
|
|
pass
|
|
|
|
func handle_current_right_command(command: CommandQueue.Command):
|
|
match command:
|
|
CommandQueue.Command.FIRE:
|
|
if not current_weapon.is_firing:
|
|
current_weapon.request_fire()
|