some shake
This commit is contained in:
172
addons/shaker/src/Vector2/ShakerEmitter2D.gd
Normal file
172
addons/shaker/src/Vector2/ShakerEmitter2D.gd
Normal file
@@ -0,0 +1,172 @@
|
||||
@icon("res://addons/shaker/assets/ShakerEmitter2D.svg")
|
||||
@tool
|
||||
class_name ShakerEmitter2D
|
||||
extends "res://addons/shaker/src/Vector2/ShakerBase2D.gd"
|
||||
|
||||
## It emits shake values and is received by ShakeEmitter2D.
|
||||
|
||||
# Exported variables
|
||||
@export var emit: bool:
|
||||
set = set_emit,
|
||||
get = get_emit
|
||||
|
||||
@export var max_distance: float = 0.0:
|
||||
set = set_max_distance,
|
||||
get = get_max_distance
|
||||
|
||||
@export_exp_easing("attenuation") var distance_attenuation: float = 0.5:
|
||||
set = set_distance_attenuation,
|
||||
get = get_distance_attenuation
|
||||
|
||||
# Private variables
|
||||
var emitting: bool = false
|
||||
var _timer_offset: float = 0.0
|
||||
var _fading_out: bool = false
|
||||
var shake_offset_position: Vector2 = Vector2.ZERO
|
||||
var shake_offset_rotation:float = 0.0
|
||||
var shake_offset_scale: Vector2 = Vector2.ZERO
|
||||
var area2d: Area2D
|
||||
var collision:CollisionShape2D
|
||||
|
||||
# Called when the node enters the scene tree for the first time
|
||||
func _ready() -> void:
|
||||
add_to_group("ShakerEmitter")
|
||||
|
||||
for child in get_children():
|
||||
if child is Area2D:
|
||||
area2d = child
|
||||
|
||||
if not area2d:
|
||||
_create_Area2D()
|
||||
|
||||
set_emit(emit)
|
||||
|
||||
# Creates an Area2D child node if one doesn't exist
|
||||
func _create_Area2D() -> void:
|
||||
area2d = Area2D.new()
|
||||
collision = CollisionShape2D.new()
|
||||
add_child(area2d)
|
||||
area2d.add_child(collision)
|
||||
area2d.set_owner(get_tree().edited_scene_root)
|
||||
collision.set_owner(get_tree().edited_scene_root)
|
||||
area2d.name = "Area2D"
|
||||
collision.name = "CollisionShape2D"
|
||||
|
||||
area2d.collision_layer = 1 << 9
|
||||
area2d.collision_mask = 0
|
||||
|
||||
# Called every frame
|
||||
func _process(delta: float) -> void:
|
||||
if emitting:
|
||||
if shakerPreset != null:
|
||||
if timer <= duration or duration == 0.0:
|
||||
_progress_shake()
|
||||
timer += delta * shake_speed
|
||||
else:
|
||||
force_stop_shake()
|
||||
else:
|
||||
if timer > 0:
|
||||
force_stop_shake()
|
||||
|
||||
# Progresses the shake effect
|
||||
func _progress_shake() -> void:
|
||||
var _ease_in: float = 1.0
|
||||
var _ease_out: float = 1.0
|
||||
var _final_duration: float = duration if (duration > 0 and not _fading_out) else 1.0
|
||||
|
||||
_ease_in = ease(timer/_final_duration, fade_in)
|
||||
_ease_out = ease(1.0 - (max((timer - _timer_offset), 0.0))/_final_duration, fade_out)
|
||||
|
||||
if not (duration > 0) or _fading_out:
|
||||
if _ease_out <= get_process_delta_time():
|
||||
force_stop_shake()
|
||||
|
||||
var _shake_position: Vector2 = Vector2.ZERO
|
||||
var _shake_rotation:float = 0.0
|
||||
var _shake_scale: Vector2 = Vector2.ZERO
|
||||
|
||||
if shakerPreset != null:
|
||||
var _value: float = timer
|
||||
var _strength: float = intensity * _ease_in * _ease_out
|
||||
|
||||
_shake_position += (shakerPreset.get_value(_value, ShakerPreset2D.Categories.POSITION) * _strength)
|
||||
_shake_rotation += (shakerPreset.get_value(_value, ShakerPreset2D.Categories.ROTATION) * _strength * (PI/2.0))
|
||||
_shake_scale += (shakerPreset.get_value(_value, ShakerPreset2D.Categories.SCALE) * _strength)
|
||||
|
||||
shake_offset_position = _shake_position
|
||||
shake_offset_rotation = _shake_rotation
|
||||
shake_offset_scale = _shake_scale
|
||||
|
||||
# Starts the shake effect
|
||||
func play_shake() -> void:
|
||||
if shakerPreset != null:
|
||||
emitting = true
|
||||
_fading_out = false
|
||||
_initialize_timer_offset()
|
||||
shake_started.emit()
|
||||
|
||||
func _initialize_timer_offset() -> void:
|
||||
if !(duration > 0): _timer_offset = 0x80000
|
||||
else: _timer_offset = 0.0
|
||||
|
||||
# Stops the shake effect with a fade-out
|
||||
func stop_shake() -> void:
|
||||
if not _fading_out:
|
||||
_timer_offset = timer
|
||||
_fading_out = true
|
||||
shake_fading_out.emit()
|
||||
|
||||
# Immediately stops the shake effect
|
||||
func force_stop_shake() -> void:
|
||||
if emitting:
|
||||
if emit: emit = false
|
||||
_fading_out = false
|
||||
emitting = false
|
||||
set_progress(0.0)
|
||||
shake_finished.emit()
|
||||
|
||||
# Returns configuration warnings
|
||||
func _get_configuration_warnings() -> PackedStringArray:
|
||||
if not get_children().any(func(child): return child is Area2D):
|
||||
return ["First child must be Area2D"]
|
||||
return []
|
||||
|
||||
# Sets the shake progress
|
||||
func set_progress(value: float) -> void:
|
||||
timer = value
|
||||
_progress_shake()
|
||||
|
||||
# Setter for emit property
|
||||
func set_emit(value: bool) -> void:
|
||||
emit = value
|
||||
if value:
|
||||
play_shake()
|
||||
elif timer > 0:
|
||||
force_stop_shake()
|
||||
|
||||
# Getter for emit property
|
||||
func get_emit() -> bool:
|
||||
return emit
|
||||
|
||||
# Setter for max_distance property
|
||||
func set_max_distance(value: float) -> void:
|
||||
max_distance = value
|
||||
notify_property_list_changed()
|
||||
|
||||
# Getter for max_distance property
|
||||
func get_max_distance() -> float:
|
||||
return max_distance
|
||||
|
||||
# Setter for distance_attenuation property
|
||||
func set_distance_attenuation(value: float) -> void:
|
||||
distance_attenuation = value
|
||||
|
||||
# Getter for distance_attenuation property
|
||||
func get_distance_attenuation() -> float:
|
||||
return distance_attenuation
|
||||
|
||||
# Validates properties
|
||||
func _validate_property(property: Dictionary) -> void:
|
||||
if property.name == "distance_attenuation":
|
||||
if not (max_distance > 0):
|
||||
property.usage = PROPERTY_USAGE_NONE
|
||||
Reference in New Issue
Block a user