reorganize everything
This commit is contained in:
27
scripts/entities/enemies/projectile_spawner.gd
Normal file
27
scripts/entities/enemies/projectile_spawner.gd
Normal file
@@ -0,0 +1,27 @@
|
||||
extends Node3D
|
||||
|
||||
@export var _velocity: Vector3 = Vector3.FORWARD
|
||||
@export var _spawn_rate: float = 2
|
||||
|
||||
@export_group("References")
|
||||
@export var _spawn_point: Node3D
|
||||
@export var _projectile_scene: PackedScene
|
||||
@export var _spawn_particles: GPUParticles3D
|
||||
|
||||
var _spawn_timer: float
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_spawn_timer = _spawn_rate
|
||||
_spawn_point.position.y = Projectile.HEIGHT
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if _spawn_timer <= 0:
|
||||
_spawn_timer = _spawn_rate
|
||||
var projectile := _projectile_scene.instantiate() as Projectile
|
||||
projectile.init(basis * _velocity, _spawn_point.global_position)
|
||||
add_child(projectile)
|
||||
_spawn_particles.emitting = true
|
||||
|
||||
_spawn_timer -= delta
|
||||
1
scripts/entities/enemies/projectile_spawner.gd.uid
Normal file
1
scripts/entities/enemies/projectile_spawner.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dbyq5apxmiosn
|
||||
93
scripts/entities/player/player.gd
Normal file
93
scripts/entities/player/player.gd
Normal file
@@ -0,0 +1,93 @@
|
||||
class_name Player
|
||||
extends CharacterBody3D
|
||||
|
||||
static var instances: Array[Player]
|
||||
|
||||
@export var cursor_color: Color
|
||||
|
||||
@export var _input_mode: Inputer.Mode = Inputer.Mode.KB_MOUSE
|
||||
@export var _device_index: int = 0
|
||||
|
||||
@export var _respawn_height: float = -5
|
||||
|
||||
@export_group("References")
|
||||
@export var attack: PlayerAttacker
|
||||
@export var stats: PlayerStats
|
||||
@export var mover: PlayerMover
|
||||
@export var aimer: PlayerAimer
|
||||
@export var _cursor: PlayerCursor
|
||||
|
||||
|
||||
var _respawn_point: Vector3
|
||||
|
||||
|
||||
static func is_single_player() -> bool:
|
||||
return instances.size() == 1
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_respawn_point = global_position
|
||||
instances.append(self)
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
var aim_pos := global_position + aimer.aim_offset
|
||||
Debugger.marker("aim", aim_pos + Vector3.UP)
|
||||
Debugger.vector("aimv", Vector3(aim_pos.x, 0, aim_pos.z), aim_pos + Vector3.UP)
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
_aiming()
|
||||
var can_move := not attack.is_hitting()
|
||||
velocity = mover.process_movement(velocity, delta, is_on_floor(), can_move)
|
||||
|
||||
move_and_slide()
|
||||
|
||||
if not attack.is_hitting() and aimer.aim_offset.length() > 0:
|
||||
look_at(global_position + aimer.aim_offset, Vector3.UP, true)
|
||||
|
||||
_process_respawning()
|
||||
_cursor.handle_cursor(self, delta)
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
var mode := Inputer.get_event_mode(event)
|
||||
if (
|
||||
not input_mode_is(mode)
|
||||
or (
|
||||
not Player.is_single_player()
|
||||
and _input_mode == Inputer.Mode.CONTROLLER
|
||||
and event.device != _device_index
|
||||
)
|
||||
):
|
||||
return
|
||||
|
||||
aimer.handle_input(event, mode)
|
||||
mover.handle_input(event, mode)
|
||||
|
||||
if event.is_action_pressed("attack"):
|
||||
attack.attack()
|
||||
|
||||
|
||||
func input_mode_is(mode: Inputer.Mode) -> bool:
|
||||
return (
|
||||
(Player.is_single_player() and mode == Inputer.mode)
|
||||
or (not Player.is_single_player() and _input_mode == mode)
|
||||
)
|
||||
|
||||
|
||||
func _aiming() -> void:
|
||||
if input_mode_is(Inputer.Mode.CONTROLLER):
|
||||
aimer.aim_controller(mover.move_input)
|
||||
|
||||
if input_mode_is(Inputer.Mode.KB_MOUSE):
|
||||
var mouse_pos := get_viewport().get_mouse_position()
|
||||
if get_viewport().get_visible_rect().has_point(mouse_pos):
|
||||
aimer.aim_mouse(mouse_pos, global_position, is_on_floor())
|
||||
|
||||
|
||||
func _process_respawning() -> void:
|
||||
if global_position.y < _respawn_height:
|
||||
global_position = _respawn_point
|
||||
velocity = Vector3.ZERO
|
||||
reset_physics_interpolation()
|
||||
1
scripts/entities/player/player.gd.uid
Normal file
1
scripts/entities/player/player.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bvvmaqn1fp6nq
|
||||
85
scripts/entities/player/player_aimer.gd
Normal file
85
scripts/entities/player/player_aimer.gd
Normal file
@@ -0,0 +1,85 @@
|
||||
class_name PlayerAimer
|
||||
extends Node
|
||||
|
||||
@export var _controller_aim_offset: float = 6
|
||||
@export var _vertical_aim_aspect: float = 1.5
|
||||
|
||||
var aim_offset: Vector3
|
||||
var aim_input: Vector2
|
||||
|
||||
var _floor_height: float
|
||||
|
||||
var _aim_left: float
|
||||
var _aim_right: float
|
||||
var _aim_up: float
|
||||
var _aim_down: float
|
||||
|
||||
|
||||
func handle_input(event: InputEvent, mode: Inputer.Mode) -> void:
|
||||
if Player.is_single_player():
|
||||
return
|
||||
|
||||
if mode == Inputer.Mode.CONTROLLER and event is InputEventJoypadMotion:
|
||||
var motion_event := event as InputEventJoypadMotion
|
||||
if motion_event.is_action("aim_left"):
|
||||
_aim_left = motion_event.get_action_strength("aim_left")
|
||||
if motion_event.is_action("aim_right"):
|
||||
_aim_right = motion_event.get_action_strength("aim_right")
|
||||
if motion_event.is_action("aim_up"):
|
||||
_aim_up = motion_event.get_action_strength("aim_up")
|
||||
if motion_event.is_action("aim_down"):
|
||||
_aim_down = motion_event.get_action_strength("aim_down")
|
||||
|
||||
|
||||
func aim_controller(move_input: Vector2) -> void:
|
||||
if Player.is_single_player():
|
||||
aim_input = Input.get_vector(
|
||||
"aim_left",
|
||||
"aim_right",
|
||||
"aim_up",
|
||||
"aim_down",
|
||||
Settings.aiming_stick_deadzone
|
||||
)
|
||||
else:
|
||||
aim_input = Inputer.get_vector_from_raw_strengths(
|
||||
_aim_left, _aim_right, _aim_up, _aim_down, Settings.aiming_stick_deadzone
|
||||
)
|
||||
|
||||
if aim_input.length() == 0 and move_input.length() == 0:
|
||||
return
|
||||
|
||||
var input := (aim_input if aim_input.length() > 0 else move_input).normalized()
|
||||
|
||||
var aim_direction := Vector3(input.x, 0, input.y * _vertical_aim_aspect)
|
||||
|
||||
aim_offset = (
|
||||
aim_direction.rotated(Vector3.UP, MainCamera.instance.rotation.y)
|
||||
* _controller_aim_offset
|
||||
)
|
||||
|
||||
|
||||
func aim_mouse(
|
||||
mouse_pos: Vector2, player_position: Vector3, is_on_floor: bool
|
||||
) -> void:
|
||||
var position_y := player_position.y
|
||||
if is_on_floor:
|
||||
_floor_height = player_position.y
|
||||
player_position.y = _floor_height
|
||||
|
||||
var aim_position := _mouse_project(mouse_pos, _floor_height + Projectile.HEIGHT)
|
||||
aim_offset = aim_position - player_position
|
||||
aim_offset.y = 0
|
||||
aim_position.y = position_y
|
||||
|
||||
|
||||
func _mouse_project(mouse_pos: Vector2, height: float) -> Vector3:
|
||||
var camera := MainCamera.instance
|
||||
|
||||
var from := camera.project_ray_origin(mouse_pos)
|
||||
var direction := camera.project_ray_normal(mouse_pos)
|
||||
var plane := Plane(Vector3.UP, height)
|
||||
|
||||
var intersection: Variant = plane.intersects_ray(from, direction)
|
||||
if not intersection:
|
||||
return Vector3.ZERO
|
||||
return intersection as Vector3
|
||||
1
scripts/entities/player/player_aimer.gd.uid
Normal file
1
scripts/entities/player/player_aimer.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c131c3hcbmu77
|
||||
117
scripts/entities/player/player_animator.gd
Normal file
117
scripts/entities/player/player_animator.gd
Normal file
@@ -0,0 +1,117 @@
|
||||
extends AnimationTree
|
||||
|
||||
@export_group("References")
|
||||
@export var _player: Player
|
||||
@export var _attack: PlayerAttacker
|
||||
@export var _bone_flipper: BoneFlipper
|
||||
@export var _sfx_audio_player: AudioStreamPlayer3D
|
||||
@export var _hurt_particles: GPUParticles3D
|
||||
@export var _footsteps_player: FootstepsPlayer
|
||||
|
||||
@export_group("Audio")
|
||||
@export var _hurt_sound: AudioStream
|
||||
@export var _hit_sounds: Array[AudioStream]
|
||||
@export var _swing_sounds: AudioStream
|
||||
|
||||
var _speed: float
|
||||
var _has_input: bool
|
||||
|
||||
var _queue_hit_sound: bool
|
||||
|
||||
@onready var _sfx_audio_playback_polyphonic := (
|
||||
_sfx_audio_player.get_stream_playback() as AudioStreamPlaybackPolyphonic
|
||||
)
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
assert(_player, "_player missing!")
|
||||
Music.track_started.connect(_on_music_track_started)
|
||||
_set_bpm()
|
||||
_attack.attacked.connect(_on_attack_attacked)
|
||||
_attack.did_hit.connect(_on_attack_did_hit)
|
||||
_player.stats.damaged.connect(_on_stats_damaged)
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
_footsteps_player.can_play = _player.is_on_floor()
|
||||
_bone_flipper.flip = _is_left()
|
||||
var has_input_prev := _has_input
|
||||
|
||||
_speed = _player.velocity.length() / _player.mover.move_speed
|
||||
_has_input = (
|
||||
_player.mover.move_input.length() > 0 and not _player.attack.is_hitting()
|
||||
)
|
||||
|
||||
var velocity_relative := _player.to_local(
|
||||
_player.global_position + _player.velocity
|
||||
)
|
||||
var velocity_blend := (
|
||||
Vector2(-velocity_relative.x, velocity_relative.z) / _player.mover.move_speed
|
||||
)
|
||||
|
||||
if _is_left():
|
||||
velocity_blend.x = -velocity_blend.x
|
||||
|
||||
Debugger.text("velocity_blend", velocity_blend, 2)
|
||||
set(&"parameters/locomotion/run/blend_position", velocity_blend)
|
||||
|
||||
if has_input_prev != _has_input:
|
||||
if _has_input:
|
||||
_abort_oneshots()
|
||||
else:
|
||||
_run_to_idle()
|
||||
|
||||
if _queue_hit_sound:
|
||||
_queue_hit_sound = false
|
||||
for stream in _hit_sounds:
|
||||
_play_sound(stream)
|
||||
|
||||
|
||||
func _is_left() -> bool:
|
||||
return _attack.side == PlayerAttacker.Side.LEFT
|
||||
|
||||
|
||||
func _play_sound(stream: AudioStream) -> void:
|
||||
_sfx_audio_playback_polyphonic.play_stream(stream)
|
||||
|
||||
|
||||
func _set_bpm() -> void:
|
||||
set(&"parameters/main_time_scale/scale", Music.bpm_factor)
|
||||
|
||||
|
||||
func _run_to_idle() -> void:
|
||||
set(
|
||||
&"parameters/run->idle_oneshot/request",
|
||||
AnimationNodeOneShot.ONE_SHOT_REQUEST_FIRE
|
||||
)
|
||||
|
||||
|
||||
func _abort_oneshots() -> void:
|
||||
set(&"parameters/hit_oneshot/request", AnimationNodeOneShot.ONE_SHOT_REQUEST_ABORT)
|
||||
set(
|
||||
&"parameters/run->idle_oneshot/request",
|
||||
AnimationNodeOneShot.ONE_SHOT_REQUEST_ABORT
|
||||
)
|
||||
|
||||
|
||||
func _on_attack_attacked() -> void:
|
||||
set(&"parameters/hit_oneshot/request", AnimationNodeOneShot.ONE_SHOT_REQUEST_FIRE)
|
||||
_play_sound(_swing_sounds)
|
||||
|
||||
|
||||
func _on_attack_did_hit() -> void:
|
||||
_queue_hit_sound = true
|
||||
|
||||
|
||||
func _on_stats_damaged() -> void:
|
||||
_play_sound(_hurt_sound)
|
||||
_hurt_particles.restart()
|
||||
_hurt_particles.emitting = true
|
||||
for node in _hurt_particles.get_children():
|
||||
if node is GPUParticles3D:
|
||||
(node as GPUParticles3D).restart()
|
||||
(node as GPUParticles3D).emitting = true
|
||||
|
||||
|
||||
func _on_music_track_started() -> void:
|
||||
_set_bpm()
|
||||
1
scripts/entities/player/player_animator.gd.uid
Normal file
1
scripts/entities/player/player_animator.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dqxvdi3i2ejs
|
||||
28
scripts/entities/player/player_attack_effect.gd
Normal file
28
scripts/entities/player/player_attack_effect.gd
Normal file
@@ -0,0 +1,28 @@
|
||||
extends MeshInstance3D
|
||||
|
||||
@export var _swoop_effect_time: float = 0.25
|
||||
|
||||
@export_group("References")
|
||||
@export var _attack: PlayerAttacker
|
||||
|
||||
var _swoop_effect_timer: float
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
mesh.radius = _attack.attack_radius
|
||||
mesh.height = _attack.attack_radius
|
||||
_attack.attacked.connect(_on_attack_attacked)
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if _swoop_effect_timer > 0:
|
||||
_swoop_effect_timer -= delta
|
||||
|
||||
(material_override as StandardMaterial3D).albedo_color = Color(
|
||||
1, 1, 1, _swoop_effect_timer / _swoop_effect_time
|
||||
)
|
||||
visible = _swoop_effect_timer > 0
|
||||
|
||||
|
||||
func _on_attack_attacked() -> void:
|
||||
_swoop_effect_timer = _swoop_effect_time
|
||||
1
scripts/entities/player/player_attack_effect.gd.uid
Normal file
1
scripts/entities/player/player_attack_effect.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bxsmma3kjo381
|
||||
161
scripts/entities/player/player_attacker.gd
Normal file
161
scripts/entities/player/player_attacker.gd
Normal file
@@ -0,0 +1,161 @@
|
||||
class_name PlayerAttacker
|
||||
extends Area3D
|
||||
|
||||
signal attacked
|
||||
signal did_hit
|
||||
|
||||
enum Side { RIGHT, LEFT }
|
||||
|
||||
@export_group("References")
|
||||
@export var _attack_shape_node: CollisionShape3D
|
||||
|
||||
@export_group("Collision")
|
||||
@export var _attack_max_angle: float = 2 * PI / 3
|
||||
@export var attack_radius: float = 2
|
||||
|
||||
@export_group("Timers")
|
||||
@export var _cooldown_time: float = 0.3
|
||||
@export var _hit_window_time: float = 0.15
|
||||
|
||||
@export_group("Hits")
|
||||
@export var _hit_projectile_speed: float = 35
|
||||
@export var _direction_angles: Dictionary[float, float] = {0.0: 0.0, PI: PI / 2.0}
|
||||
@export var _hit_stop_time_scale := 0.05
|
||||
@export var _hit_stop_duration := 0.25
|
||||
|
||||
var side := Side.RIGHT
|
||||
|
||||
var _cooldown_timer: float
|
||||
var _hit_window_timer: float
|
||||
var _queue_hit_stop: bool
|
||||
|
||||
@onready var _attack_shape: CylinderShape3D = _attack_shape_node.shape as CylinderShape3D
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
Debugger.add_event("attacked")
|
||||
attacked.connect(func() -> void: Debugger.event_emitted("attacked", []))
|
||||
area_entered.connect(_on_area_entered)
|
||||
|
||||
position.y = Projectile.HEIGHT
|
||||
_set_collision_size(attack_radius)
|
||||
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if _cooldown_timer > 0:
|
||||
_cooldown_timer -= delta
|
||||
|
||||
if _hit_window_timer > 0:
|
||||
_hit_window_timer -= delta
|
||||
|
||||
if _queue_hit_stop:
|
||||
_queue_hit_stop = false
|
||||
_hit_stop(_hit_stop_time_scale, _hit_stop_duration)
|
||||
|
||||
Debugger.text("_cooldown_timer", _cooldown_timer, 2)
|
||||
Debugger.text("_hit_window_timer", _hit_window_timer, 2)
|
||||
Debugger.vector(
|
||||
"fghdh",
|
||||
global_position,
|
||||
(
|
||||
global_position
|
||||
+ global_basis.z.rotated(Vector3.UP, _attack_max_angle) * attack_radius
|
||||
)
|
||||
)
|
||||
Debugger.vector(
|
||||
"fghdh2",
|
||||
global_position,
|
||||
(
|
||||
global_position
|
||||
+ global_basis.z.rotated(Vector3.UP, -_attack_max_angle) * attack_radius
|
||||
)
|
||||
)
|
||||
for dir_angle: float in _direction_angles.keys():
|
||||
Debugger.line(
|
||||
"fghdh3" + str(dir_angle),
|
||||
global_position,
|
||||
(
|
||||
global_position
|
||||
+ (
|
||||
global_basis.z.rotated(
|
||||
Vector3.UP, dir_angle * (-1.0 if side == Side.LEFT else 1.0)
|
||||
)
|
||||
* attack_radius
|
||||
)
|
||||
),
|
||||
Color.BLUE
|
||||
)
|
||||
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
monitoring = _hit_window_timer > 0
|
||||
|
||||
|
||||
func is_hitting() -> bool:
|
||||
return _cooldown_timer > 0
|
||||
|
||||
|
||||
func attack() -> void:
|
||||
if _cooldown_timer > 0:
|
||||
return
|
||||
|
||||
_cooldown_timer = _cooldown_time
|
||||
_hit_window_timer = _hit_window_time
|
||||
side = Side.LEFT if side == Side.RIGHT else Side.RIGHT
|
||||
attacked.emit()
|
||||
|
||||
|
||||
func _hit_projectile(projectile: Projectile) -> void:
|
||||
var diff := projectile.global_position - global_position
|
||||
diff.y = 0
|
||||
var angle := global_basis.z.signed_angle_to(diff, Vector3.UP)
|
||||
Debugger.vector("ASDSAD", global_position, global_position + global_basis.z)
|
||||
Debugger.vector("ASDSAD2", global_position, global_position + diff)
|
||||
Debugger.text("angle", rad_to_deg(angle), 2)
|
||||
if angle > _attack_max_angle or angle < -_attack_max_angle:
|
||||
return
|
||||
|
||||
var angle_sign := -1.0 if side == Side.RIGHT else 1.0
|
||||
|
||||
var angle_signed := angle * angle_sign
|
||||
Debugger.text("side", Side.find_key(side), 2)
|
||||
Debugger.text("angle_signed", rad_to_deg(angle_signed), 2)
|
||||
|
||||
var prev_dir_angle: float = -_attack_max_angle
|
||||
for dir_angle: float in _direction_angles.keys():
|
||||
if angle_signed > prev_dir_angle and angle_signed <= dir_angle:
|
||||
Debugger.text("prev_dir_angle", rad_to_deg(prev_dir_angle), 2)
|
||||
Debugger.text("dir_angle", rad_to_deg(dir_angle), 2)
|
||||
var new_direction := global_basis.z.rotated(
|
||||
Vector3.UP, (_direction_angles[dir_angle] as float) * angle_sign
|
||||
)
|
||||
Debugger.vector(
|
||||
"ASDSAD3",
|
||||
projectile.global_position,
|
||||
projectile.global_position + new_direction
|
||||
)
|
||||
projectile.hit(new_direction * _hit_projectile_speed)
|
||||
_queue_hit_stop = true
|
||||
break
|
||||
|
||||
prev_dir_angle = dir_angle
|
||||
|
||||
|
||||
func _set_collision_size(radius: float) -> void:
|
||||
_attack_shape.radius = radius
|
||||
|
||||
|
||||
func _hit_stop(time_scale: float, duration: float) -> void:
|
||||
Engine.time_scale = time_scale
|
||||
await get_tree().create_timer(time_scale * duration).timeout
|
||||
Engine.time_scale = 1
|
||||
|
||||
|
||||
func _on_area_entered(node: Node3D) -> void:
|
||||
if _hit_window_timer <= 0:
|
||||
return
|
||||
|
||||
if node is Projectile:
|
||||
_hit_projectile(node as Projectile)
|
||||
did_hit.emit()
|
||||
1
scripts/entities/player/player_attacker.gd.uid
Normal file
1
scripts/entities/player/player_attacker.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dmu2tkt0wo7d1
|
||||
50
scripts/entities/player/player_cursor.gd
Normal file
50
scripts/entities/player/player_cursor.gd
Normal file
@@ -0,0 +1,50 @@
|
||||
class_name PlayerCursor
|
||||
extends CanvasLayer
|
||||
|
||||
@export var _side_change_speed: float = 15
|
||||
@export var _screen_inset: float = 100
|
||||
|
||||
@export_group("References")
|
||||
@export var _base: Control
|
||||
@export var _bat: Control
|
||||
@export var _arrow: Control
|
||||
|
||||
var _side: float = 0
|
||||
|
||||
|
||||
func handle_cursor(player: Player, delta: float) -> void:
|
||||
var cursor_pos_world := player.attack.global_position + player.aimer.aim_offset
|
||||
var cursor_pos_screen := MainCamera.instance.unproject_position(cursor_pos_world)
|
||||
|
||||
var clamp_corner_min := Vector2.ZERO
|
||||
var clamp_corner_max := get_viewport().get_visible_rect().size
|
||||
if player.input_mode_is(Inputer.Mode.CONTROLLER):
|
||||
clamp_corner_min += Vector2(_screen_inset, _screen_inset)
|
||||
clamp_corner_max -= Vector2(_screen_inset, _screen_inset)
|
||||
|
||||
_base.position = (
|
||||
cursor_pos_screen.clamp(clamp_corner_min, clamp_corner_max) - _base.size / 2
|
||||
)
|
||||
|
||||
_side = lerpf(
|
||||
_side as float,
|
||||
(PI / 2.0) * (1.0 if player.attack.side == PlayerAttacker.Side.LEFT else -1.0),
|
||||
_side_change_speed * delta
|
||||
)
|
||||
|
||||
var aim_offset_normalized := player.aimer.aim_offset.normalized()
|
||||
var bat_rotation_point_screen := MainCamera.instance.unproject_position(
|
||||
cursor_pos_world + aim_offset_normalized.rotated(Vector3.UP, _side as float)
|
||||
)
|
||||
var arrow_rotation_point_screen := MainCamera.instance.unproject_position(
|
||||
cursor_pos_world + aim_offset_normalized
|
||||
)
|
||||
|
||||
_bat.rotation = cursor_pos_screen.angle_to_point(bat_rotation_point_screen)
|
||||
_arrow.rotation = (
|
||||
cursor_pos_screen.angle_to_point(arrow_rotation_point_screen) + PI / 2
|
||||
)
|
||||
|
||||
_base.modulate = player.cursor_color
|
||||
if player.input_mode_is(Inputer.Mode.KB_MOUSE):
|
||||
_base.position = (get_viewport().get_mouse_position() - _base.size / 2)
|
||||
1
scripts/entities/player/player_cursor.gd.uid
Normal file
1
scripts/entities/player/player_cursor.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://ddx56siie1sf4
|
||||
108
scripts/entities/player/player_mover.gd
Normal file
108
scripts/entities/player/player_mover.gd
Normal file
@@ -0,0 +1,108 @@
|
||||
class_name PlayerMover
|
||||
extends Node
|
||||
|
||||
@export var move_speed: float = 8
|
||||
|
||||
@export var move_acceleration: float = 100
|
||||
@export var move_deceleration: float = 50
|
||||
|
||||
@export var fall_speed: float = 20
|
||||
@export var fall_acceleration: float = 25
|
||||
|
||||
var move_input: Vector2
|
||||
|
||||
var _move_direction: Vector3
|
||||
|
||||
var _move_left: float
|
||||
var _move_right: float
|
||||
var _move_up: float
|
||||
var _move_down: float
|
||||
|
||||
|
||||
func handle_input(event: InputEvent, mode: Inputer.Mode) -> void:
|
||||
if Player.is_single_player():
|
||||
return
|
||||
|
||||
if mode == Inputer.Mode.KB_MOUSE and event is InputEventKey:
|
||||
var key_event := event as InputEventKey
|
||||
if key_event.is_action_pressed("move_left"):
|
||||
_move_left = 1
|
||||
elif key_event.is_action_released("move_left"):
|
||||
_move_left = 0
|
||||
if key_event.is_action_pressed("move_right"):
|
||||
_move_right = 1
|
||||
elif key_event.is_action_released("move_right"):
|
||||
_move_right = 0
|
||||
if key_event.is_action_pressed("move_up"):
|
||||
_move_up = 1
|
||||
elif key_event.is_action_released("move_up"):
|
||||
_move_up = 0
|
||||
if key_event.is_action_pressed("move_down"):
|
||||
_move_down = 1
|
||||
elif key_event.is_action_released("move_down"):
|
||||
_move_down = 0
|
||||
|
||||
if mode == Inputer.Mode.CONTROLLER and event is InputEventJoypadMotion:
|
||||
var motion_event := event as InputEventJoypadMotion
|
||||
if motion_event.is_action("move_left"):
|
||||
_move_left = motion_event.get_action_strength("move_left")
|
||||
if motion_event.is_action("move_right"):
|
||||
_move_right = motion_event.get_action_strength("move_right")
|
||||
if motion_event.is_action("move_up"):
|
||||
_move_up = motion_event.get_action_strength("move_up")
|
||||
if motion_event.is_action("move_down"):
|
||||
_move_down = motion_event.get_action_strength("move_down")
|
||||
|
||||
|
||||
func process_movement(
|
||||
velocity: Vector3, delta: float, is_on_floor: bool, can_move: bool
|
||||
) -> Vector3:
|
||||
velocity = _lateral_movement(velocity, delta, can_move)
|
||||
velocity = _vertical_movement(velocity, delta, is_on_floor)
|
||||
|
||||
return velocity
|
||||
|
||||
|
||||
func _lateral_movement(velocity: Vector3, delta: float, can_move: bool) -> Vector3:
|
||||
if Player.is_single_player():
|
||||
move_input = Input.get_vector(
|
||||
"move_left",
|
||||
"move_right",
|
||||
"move_up",
|
||||
"move_down",
|
||||
Settings.movement_stick_deadzone
|
||||
)
|
||||
else:
|
||||
move_input = Inputer.get_vector_from_raw_strengths(
|
||||
_move_left,
|
||||
_move_right,
|
||||
_move_up,
|
||||
_move_down,
|
||||
Settings.movement_stick_deadzone
|
||||
)
|
||||
Debugger.text("move_input" + str(get_instance_id()), move_input)
|
||||
|
||||
if move_input.length() > 0 and can_move:
|
||||
_move_direction = Vector3(move_input.x, 0, move_input.y).normalized().rotated(
|
||||
Vector3.UP, MainCamera.instance.rotation.y
|
||||
)
|
||||
var new_velocity := _move_direction * move_speed
|
||||
new_velocity.y = velocity.y
|
||||
velocity = velocity.move_toward(new_velocity, move_acceleration * delta)
|
||||
else:
|
||||
var new_velocity := Vector3.ZERO
|
||||
new_velocity.y = velocity.y
|
||||
velocity = velocity.move_toward(new_velocity, move_deceleration * delta)
|
||||
|
||||
return velocity
|
||||
|
||||
|
||||
func _vertical_movement(velocity: Vector3, delta: float, is_on_floor: bool) -> Vector3:
|
||||
if not is_on_floor:
|
||||
var new_velocity := velocity
|
||||
new_velocity.y = -fall_speed
|
||||
velocity = velocity.move_toward(new_velocity, fall_acceleration * delta)
|
||||
else:
|
||||
velocity.y = 0
|
||||
|
||||
return velocity
|
||||
1
scripts/entities/player/player_mover.gd.uid
Normal file
1
scripts/entities/player/player_mover.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://5vgfsrafb8ud
|
||||
11
scripts/entities/player/player_stats.gd
Normal file
11
scripts/entities/player/player_stats.gd
Normal file
@@ -0,0 +1,11 @@
|
||||
class_name PlayerStats
|
||||
extends Node
|
||||
|
||||
signal damaged
|
||||
|
||||
@export var health: int = 6
|
||||
|
||||
|
||||
func damage() -> void:
|
||||
health -= 1
|
||||
damaged.emit()
|
||||
1
scripts/entities/player/player_stats.gd.uid
Normal file
1
scripts/entities/player/player_stats.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://clks186ll0joi
|
||||
94
scripts/entities/projectiles/projectile.gd
Normal file
94
scripts/entities/projectiles/projectile.gd
Normal file
@@ -0,0 +1,94 @@
|
||||
class_name Projectile
|
||||
extends Area3D
|
||||
|
||||
const HEIGHT: float = 1
|
||||
const MAX_STRETCH: float = 0.75
|
||||
|
||||
@export var _speed_stretch_factor: float = 100
|
||||
|
||||
@export var _hit_particles_scene: PackedScene
|
||||
@export var _destroy_particles_scene: PackedScene
|
||||
|
||||
@export_group("References")
|
||||
@export var _model_base: Node3D
|
||||
@export var _model_mesh: MeshInstance3D
|
||||
|
||||
var _start_position: Vector3
|
||||
var _velocity: Vector3
|
||||
var _lifetime: float
|
||||
var _size: float = 0.25
|
||||
|
||||
var _life_timer: float
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_life_timer = _lifetime
|
||||
global_position = _start_position
|
||||
body_entered.connect(_on_body_entered)
|
||||
_model_mesh.rotation = Vector3(
|
||||
randf_range(0, TAU), randf_range(0, TAU), randf_range(0, TAU)
|
||||
)
|
||||
_model_mesh.scale = Vector3.ONE * _size
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if _life_timer <= 0:
|
||||
queue_free()
|
||||
|
||||
_life_timer -= delta
|
||||
global_position += _velocity * delta
|
||||
look_at(global_position + _velocity, Vector3.UP, true)
|
||||
|
||||
var speed_squash := clampf(
|
||||
_velocity.length() / _speed_stretch_factor, 0, MAX_STRETCH
|
||||
)
|
||||
_model_base.scale = Vector3(1 - speed_squash, 1 - speed_squash, 1 + speed_squash)
|
||||
|
||||
|
||||
func init(velocity: Vector3, start_position: Vector3, lifetime: float = 10) -> void:
|
||||
_velocity = velocity
|
||||
_start_position = start_position
|
||||
_lifetime = lifetime
|
||||
|
||||
|
||||
func hit(velocity: Vector3) -> void:
|
||||
var hit_particles := (
|
||||
_hit_particles_scene.instantiate() as Particles3DSelfDestructing
|
||||
)
|
||||
get_tree().get_root().add_child(hit_particles)
|
||||
hit_particles.init(global_position, velocity)
|
||||
set_velocity(velocity)
|
||||
|
||||
|
||||
func set_velocity(velocity: Vector3) -> void:
|
||||
_velocity = velocity
|
||||
_life_timer = _lifetime
|
||||
|
||||
|
||||
func _destroy() -> void:
|
||||
var destroy_particles := (
|
||||
_destroy_particles_scene.instantiate() as Particles3DSelfDestructing
|
||||
)
|
||||
get_tree().get_root().add_child(destroy_particles)
|
||||
destroy_particles.init(global_position)
|
||||
queue_free()
|
||||
|
||||
|
||||
func _on_body_entered(node: Node3D) -> void:
|
||||
if node is Player:
|
||||
queue_free()
|
||||
var player := node as Player
|
||||
player.stats.damage()
|
||||
return
|
||||
|
||||
if node is CollisionObject3D:
|
||||
var collision_node := node as CollisionObject3D
|
||||
if collision_node.collision_layer & 1:
|
||||
_destroy()
|
||||
return
|
||||
|
||||
if node is CSGCombiner3D:
|
||||
var collision_node := node as CSGCombiner3D
|
||||
if collision_node.collision_layer & 1:
|
||||
_destroy()
|
||||
return
|
||||
1
scripts/entities/projectiles/projectile.gd.uid
Normal file
1
scripts/entities/projectiles/projectile.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bbd22tc1scoom
|
||||
Reference in New Issue
Block a user