157 lines
4.1 KiB
GDScript
157 lines
4.1 KiB
GDScript
class_name PlayerAttack
|
|
extends Area3D
|
|
|
|
signal attacked
|
|
|
|
enum Side { RIGHT, LEFT }
|
|
|
|
@export_group("Collision")
|
|
@export var _collision_debug_material: Material
|
|
@export var _attack_max_angle: float = PI / 2
|
|
@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 var _swoop_effect_time: float = 0.25
|
|
|
|
@export_group("Hits")
|
|
@export var _hit_projectile_speed: float = 25
|
|
@export var _direction_angles: Dictionary = {PI / 3: 0, 2 * PI / 3: PI / 4, PI: PI / 2}
|
|
|
|
var _side := Side.RIGHT
|
|
|
|
var _debug_collision_shapes := DebugCollisionShapes.new()
|
|
|
|
var _cooldown_timer: float
|
|
var _hit_window_timer: float
|
|
var _swoop_effect_timer: float
|
|
|
|
@onready var _attack_shape_node: CollisionShape3D = $AttackShape
|
|
@onready var _swoop_mesh_node: MeshInstance3D = $SwoopMesh
|
|
|
|
@onready var _attack_shape: CylinderShape3D = _attack_shape_node.shape as CylinderShape3D
|
|
@onready var _swoop_mesh: SphereMesh = _swoop_mesh_node.mesh as SphereMesh
|
|
|
|
|
|
func _ready() -> void:
|
|
Debugger.add_event("attacked")
|
|
attacked.connect(func() -> void: Debugger.event_emitted("attacked", []))
|
|
body_entered.connect(_on_body_entered)
|
|
|
|
position.y = Projectile.HEIGHT
|
|
_set_collision_size(_attack_radius)
|
|
|
|
_debug_collision_shapes.init(get_children(), self, _collision_debug_material)
|
|
|
|
|
|
func _unhandled_input(event: InputEvent) -> void:
|
|
if event.is_action_pressed("attack"):
|
|
_attack()
|
|
|
|
|
|
func _process(delta: float) -> void:
|
|
if _cooldown_timer > 0:
|
|
_cooldown_timer -= delta
|
|
|
|
if _hit_window_timer > 0:
|
|
_hit_window_timer -= delta
|
|
elif _debug_collision_shapes.is_visible:
|
|
_debug_collision_shapes.set_visibility(false)
|
|
|
|
if _swoop_effect_timer > 0:
|
|
_swoop_effect_timer -= delta
|
|
|
|
(_swoop_mesh_node.material_override as StandardMaterial3D).albedo_color = Color(
|
|
1, 1, 1, _swoop_effect_timer / _swoop_effect_time
|
|
)
|
|
_swoop_mesh_node.visible = _swoop_effect_timer > 0
|
|
|
|
Debugger.text("_cooldown_timer", _cooldown_timer, 2)
|
|
Debugger.text("_hit_window_timer", _hit_window_timer, 2)
|
|
Debugger.text("_swoop_effect_timer", _swoop_effect_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
|
|
)
|
|
)
|
|
|
|
|
|
func _physics_process(_delta: float) -> void:
|
|
monitoring = _hit_window_timer > 0
|
|
|
|
|
|
func is_hitting() -> bool:
|
|
return _hit_window_timer > 0
|
|
|
|
|
|
func _attack() -> void:
|
|
if _cooldown_timer > 0:
|
|
return
|
|
|
|
attacked.emit()
|
|
_cooldown_timer = _cooldown_time
|
|
_hit_window_timer = _hit_window_time
|
|
_swoop_effect_timer = _swoop_effect_time
|
|
_debug_collision_shapes.set_visibility(true)
|
|
_side = Side.LEFT if _side == Side.RIGHT else Side.RIGHT
|
|
|
|
|
|
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 side_angle := (
|
|
(angle + _attack_max_angle)
|
|
if _side == Side.RIGHT
|
|
else (-angle + _attack_max_angle)
|
|
)
|
|
Debugger.text("side_angle", rad_to_deg(side_angle), 2)
|
|
|
|
var prev_dir_angle: float = 0
|
|
for dir_angle: float in _direction_angles.keys():
|
|
if side_angle > prev_dir_angle and side_angle <= dir_angle:
|
|
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)
|
|
* (1.0 if _side == Side.RIGHT else -1.0)
|
|
)
|
|
)
|
|
projectile.set_velocity(new_direction * _hit_projectile_speed)
|
|
break
|
|
|
|
prev_dir_angle = dir_angle
|
|
|
|
|
|
func _set_collision_size(radius: float) -> void:
|
|
_attack_shape.radius = radius
|
|
_swoop_mesh.radius = radius
|
|
_swoop_mesh.height = radius
|
|
|
|
|
|
func _on_body_entered(node: Node3D) -> void:
|
|
if _hit_window_timer <= 0:
|
|
return
|
|
|
|
if node is Projectile:
|
|
_hit_projectile(node as Projectile)
|