some shake
This commit is contained in:
90
addons/shaker/src/Vector2/ShakerBase2D.gd
Normal file
90
addons/shaker/src/Vector2/ShakerBase2D.gd
Normal file
@@ -0,0 +1,90 @@
|
||||
@tool
|
||||
extends Node2D
|
||||
|
||||
# Shake intensity
|
||||
@export_range(0.0, 1.0, 0.001, "or_greater") var intensity: float = 1.0:
|
||||
set = set_intensity,
|
||||
get = get_intensity
|
||||
|
||||
# Shake duration
|
||||
@export var duration: float = 0.00:
|
||||
set = set_duration,
|
||||
get = get_duration
|
||||
|
||||
# Shake speed
|
||||
@export_range(0.0, 1.0, 0.001, "or_greater") var shake_speed: float = 1.0:
|
||||
set = set_shake_speed,
|
||||
get = get_shake_speed
|
||||
|
||||
# Fade-in easing
|
||||
@export_exp_easing var fade_in: float = 0.25:
|
||||
set = set_fade_in,
|
||||
get = get_fade_in
|
||||
|
||||
# Fade-out easing
|
||||
@export_exp_easing("attenuation") var fade_out: float = 0.25:
|
||||
set = set_fade_out,
|
||||
get = get_fade_out
|
||||
|
||||
# Shaker preset
|
||||
@export var shakerPreset:ShakerPreset2D:
|
||||
set = set_shaker_preset,
|
||||
get = get_shaker_preset
|
||||
|
||||
# Timer for shake progress
|
||||
var timer: float = 0.0:
|
||||
set = _on_timeline_progress
|
||||
|
||||
# SIGNALS
|
||||
signal timeline_progress(progress: float)
|
||||
signal shake_started
|
||||
signal shake_finished
|
||||
signal shake_fading_out
|
||||
|
||||
func set_intensity(value: float) -> void:
|
||||
intensity = max(value, 0.0)
|
||||
|
||||
func get_intensity() -> float:
|
||||
return intensity
|
||||
|
||||
func set_duration(value: float) -> void:
|
||||
duration = max(value, 0.0)
|
||||
if shakerPreset != null:
|
||||
shakerPreset.component_duration = duration
|
||||
notify_property_list_changed()
|
||||
|
||||
func get_duration() -> float:
|
||||
return duration
|
||||
|
||||
func set_shake_speed(value: float) -> void:
|
||||
shake_speed = max(value, 0.001)
|
||||
notify_property_list_changed()
|
||||
|
||||
func get_shake_speed() -> float:
|
||||
return shake_speed
|
||||
|
||||
func set_fade_in(value: float) -> void:
|
||||
fade_in = value
|
||||
|
||||
func get_fade_in() -> float:
|
||||
return fade_in
|
||||
|
||||
func set_fade_out(value: float) -> void:
|
||||
fade_out = value
|
||||
|
||||
func get_fade_out() -> float:
|
||||
return fade_out
|
||||
|
||||
func set_shaker_preset(value: ShakerPreset2D) -> void:
|
||||
shakerPreset = value
|
||||
if shakerPreset != null:
|
||||
shakerPreset.parent = self
|
||||
shakerPreset.component_duration = duration
|
||||
|
||||
func get_shaker_preset() -> ShakerPreset2D:
|
||||
return shakerPreset
|
||||
|
||||
# Handles timeline progress
|
||||
func _on_timeline_progress(value: float) -> void:
|
||||
timer = value
|
||||
timeline_progress.emit(timer)
|
||||
1
addons/shaker/src/Vector2/ShakerBase2D.gd.uid
Normal file
1
addons/shaker/src/Vector2/ShakerBase2D.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c0tuadw5ygn6m
|
||||
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
|
||||
1
addons/shaker/src/Vector2/ShakerEmitter2D.gd.uid
Normal file
1
addons/shaker/src/Vector2/ShakerEmitter2D.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://ddpgk78xe5y4g
|
||||
148
addons/shaker/src/Vector2/ShakerReceiver2D.gd
Normal file
148
addons/shaker/src/Vector2/ShakerReceiver2D.gd
Normal file
@@ -0,0 +1,148 @@
|
||||
@icon("res://addons/shaker/assets/ShakerReceiver2D.svg")
|
||||
@tool
|
||||
class_name ShakerReceiver2D
|
||||
extends Node2D
|
||||
|
||||
## Transmits values from ShakerEmitter2D to ShakerComponent2D
|
||||
|
||||
# Fade-in easing
|
||||
@export_exp_easing var enter_fade_in: float = 0.1:
|
||||
set = set_fade_in,
|
||||
get = get_fade_in
|
||||
|
||||
# Fade-out easing
|
||||
@export_exp_easing("attenuation") var exit_fade_out: float = 3.0:
|
||||
set = set_fade_out,
|
||||
get = get_fade_out
|
||||
|
||||
# Private variables
|
||||
var area2D: Area2D
|
||||
var position_offset: Vector2 = Vector2.ZERO
|
||||
var rotation_offset:float = 0.0
|
||||
var scale_offset: Vector2 = Vector2.ZERO
|
||||
var emitter_list: Array[EmitterData]
|
||||
|
||||
# Called when the node enters the scene tree for the first time
|
||||
func _ready() -> void:
|
||||
_setup_area2D()
|
||||
if !Engine.is_editor_hint():
|
||||
add_to_group("ShakerReceiver")
|
||||
_connect_signals()
|
||||
|
||||
# Sets up the Area2D node
|
||||
func _setup_area2D() -> void:
|
||||
for child in get_children():
|
||||
if child is Area2D:
|
||||
area2D = child
|
||||
return
|
||||
|
||||
area2D = Area2D.new()
|
||||
var 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 = 0
|
||||
area2D.collision_mask = 1 << 9
|
||||
|
||||
# Connects signals
|
||||
func _connect_signals() -> void:
|
||||
area2D.area_entered.connect(on_area_entered)
|
||||
area2D.area_exited.connect(on_area_exited)
|
||||
|
||||
# Called every frame
|
||||
func _process(delta: float) -> void:
|
||||
position_offset = Vector2.ZERO
|
||||
rotation_offset = 0.0
|
||||
scale_offset = Vector2.ZERO
|
||||
|
||||
if emitter_list.size() > 0:
|
||||
for emitter_data in emitter_list:
|
||||
_process_emitter(emitter_data, delta)
|
||||
|
||||
# Processes each emitter
|
||||
func _process_emitter(emitter_data: EmitterData, delta: float) -> void:
|
||||
if emitter_data.emitter:
|
||||
var ease_in: float = ease(emitter_data.timer, enter_fade_in)
|
||||
var ease_out: float = ease(1.0 - (emitter_data.timer - emitter_data.fade_out_timer), exit_fade_out) if emitter_data.fade_out_timer != 0.0 else 1.0
|
||||
emitter_data.ease_out_intensity = move_toward(emitter_data.ease_out_intensity, ease_out, delta)
|
||||
ease_out = emitter_data.ease_out_intensity
|
||||
var max_distance: float = emitter_data.emitter.max_distance
|
||||
var distance: float = min(emitter_data.emitter.global_position.distance_to(global_position), max_distance) / max(max_distance, 0.001)
|
||||
var attenuation: float = ease(1.0 - distance, emitter_data.emitter.distance_attenuation)
|
||||
position_offset += emitter_data.emitter.shake_offset_position * ease_in * ease_out * attenuation
|
||||
rotation_offset += emitter_data.emitter.shake_offset_rotation * ease_in * ease_out * attenuation
|
||||
scale_offset += emitter_data.emitter.shake_offset_scale * ease_in * ease_out * attenuation
|
||||
|
||||
emitter_data.timer += delta
|
||||
if ease_out <= delta:
|
||||
emitter_list.erase(emitter_data)
|
||||
else:
|
||||
emitter_list.erase(emitter_data)
|
||||
# Returns the current shake values
|
||||
func get_value() -> Array[Vector2]:
|
||||
return [position_offset, Vector2(rotation_offset, 0.0), scale_offset]
|
||||
|
||||
# Returns configuration warnings
|
||||
func _get_configuration_warnings() -> PackedStringArray:
|
||||
if not get_parent() is ShakerComponent2D:
|
||||
return ["Parent must be ShakerComponent2D"]
|
||||
var _ex:bool = false
|
||||
for i in get_children():
|
||||
if i is Area2D:
|
||||
_ex = true
|
||||
break
|
||||
if !_ex:
|
||||
return ["ShakerReceiver2D needs Area2D to work"]
|
||||
return []
|
||||
|
||||
# Called when an area enters
|
||||
func on_area_entered(area: Area2D) -> void:
|
||||
var node = area.get_parent()
|
||||
if node is ShakerEmitter2D:
|
||||
var data = EmitterData.new(node)
|
||||
emitter_list.append(data)
|
||||
|
||||
# Called when an area exits
|
||||
func on_area_exited(area: Area2D) -> void:
|
||||
var node = area.get_parent()
|
||||
if node is ShakerEmitter2D:
|
||||
for index in emitter_list.size():
|
||||
var data = emitter_list[index]
|
||||
if data.emitter == node:
|
||||
data.fade_out_timer = data.timer
|
||||
break
|
||||
|
||||
# Setter for enter_fade_in
|
||||
func set_fade_in(value: float) -> void:
|
||||
enter_fade_in = value
|
||||
|
||||
# Getter for enter_fade_in
|
||||
func get_fade_in() -> float:
|
||||
return enter_fade_in
|
||||
|
||||
# Setter for exit_fade_out
|
||||
func set_fade_out(value: float) -> void:
|
||||
exit_fade_out = value
|
||||
|
||||
# Getter for exit_fade_out
|
||||
func get_fade_out() -> float:
|
||||
return exit_fade_out
|
||||
|
||||
# EmitterData inner class
|
||||
class EmitterData:
|
||||
var emitter: ShakerEmitter2D
|
||||
var timer: float = 0.0
|
||||
var fade_out_timer: float = 0.0
|
||||
var ease_out_intensity:float = 1.0
|
||||
|
||||
func _init(_emitter: ShakerEmitter2D) -> void:
|
||||
self.emitter = _emitter
|
||||
func is_playing() -> bool:
|
||||
for i:EmitterData in emitter_list:
|
||||
return i.emitter.emitting
|
||||
return false
|
||||
|
||||
1
addons/shaker/src/Vector2/ShakerReceiver2D.gd.uid
Normal file
1
addons/shaker/src/Vector2/ShakerReceiver2D.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://ca4ybjjck0t0a
|
||||
287
addons/shaker/src/Vector2/shaker_component2D.gd
Normal file
287
addons/shaker/src/Vector2/shaker_component2D.gd
Normal file
@@ -0,0 +1,287 @@
|
||||
@tool
|
||||
@icon("res://addons/shaker/assets/Shaker2D.svg")
|
||||
class_name ShakerComponent2D
|
||||
extends "res://addons/shaker/src/Vector2/ShakerBase2D.gd"
|
||||
|
||||
## Allows you to apply shake effect to any 2D node according to position, rotation, scale
|
||||
|
||||
enum ShakeAddMode {
|
||||
add,
|
||||
override
|
||||
}
|
||||
|
||||
# Custom target flag
|
||||
@export var custom_target: bool = false:
|
||||
set = set_custom_target,
|
||||
get = get_custom_target
|
||||
|
||||
# Array of target Node2D objects
|
||||
@export var Targets: Array[Node2D]
|
||||
|
||||
# Randomization flag
|
||||
@export var randomize: bool = false:
|
||||
set = set_randomize,
|
||||
get = get_randomize
|
||||
|
||||
# Playing state
|
||||
@export var is_playing: bool = false
|
||||
|
||||
@export var AutoPlay:bool = false
|
||||
|
||||
# Private variables
|
||||
var _last_position_shake: Array[Vector2] = [Vector2.ZERO]
|
||||
var _last_scale_shake: Array[Vector2] = [Vector2.ZERO]
|
||||
var _last_rotation_shake: Array[float] = [0]
|
||||
var _timer_offset: float = 0.0
|
||||
var _fading_out: bool = false
|
||||
var _seed: float = 203445
|
||||
var _external_shakes:Array[ExternalShake]
|
||||
|
||||
# Called when the node enters the scene tree for the first time
|
||||
func _ready() -> void:
|
||||
set_process_input(false)
|
||||
set_process_internal(false)
|
||||
set_process_shortcut_input(false)
|
||||
set_process_unhandled_input(false)
|
||||
set_physics_process(false)
|
||||
set_physics_process_internal(false)
|
||||
add_to_group("ShakerComponent")
|
||||
|
||||
if !Engine.is_editor_hint():
|
||||
if AutoPlay:
|
||||
play_shake()
|
||||
|
||||
# Resets the shaker to its initial state
|
||||
func _reset() -> void:
|
||||
_last_position_shake = [Vector2.ZERO]
|
||||
_last_scale_shake = [Vector2.ZERO]
|
||||
_last_rotation_shake = [0]
|
||||
_external_shakes.clear()
|
||||
_initalize_prev_positions()
|
||||
is_playing = false
|
||||
_initialize_timer_offset()
|
||||
_fading_out = false
|
||||
_initalize_target()
|
||||
|
||||
# Initializes previous positions for randomized shaking
|
||||
func _initalize_prev_positions() -> void:
|
||||
_last_position_shake.resize(Targets.size())
|
||||
_last_position_shake.fill(Vector2.ZERO)
|
||||
|
||||
_last_scale_shake.resize(Targets.size())
|
||||
_last_scale_shake.fill(Vector2.ZERO)
|
||||
|
||||
_last_rotation_shake.resize(Targets.size())
|
||||
_last_rotation_shake.fill(0)
|
||||
|
||||
# Called every frame
|
||||
func _process(delta: float) -> void:
|
||||
if is_playing:
|
||||
if shakerPreset != null || _external_shakes.size() > 0 || is_receiving_from_emitters():
|
||||
if timer <= duration || 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 && !_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 (!(duration > 0) || _fading_out) && is_playing:
|
||||
if _ease_out <= get_process_delta_time():
|
||||
force_stop_shake()
|
||||
|
||||
var _shake_position: Array[Vector2] = []
|
||||
var _shake_rotation: Array[float] = []
|
||||
var _shake_scale: Array[Vector2] = []
|
||||
|
||||
var _count:int =(Targets.size() if randomize else 1)
|
||||
|
||||
_shake_position.resize(_count)
|
||||
_shake_position.fill(Vector2.ZERO)
|
||||
_shake_rotation.resize(_count)
|
||||
_shake_rotation.fill(0)
|
||||
_shake_scale.resize(_count)
|
||||
_shake_scale.fill(Vector2.ZERO)
|
||||
|
||||
for _index in _count:
|
||||
var _randomized: float = (_seed * (float(_index+1) / Targets.size())) if randomize else 0.0
|
||||
if _last_position_shake.size() != _count: _initalize_prev_positions()
|
||||
|
||||
# Shaker Preset
|
||||
if shakerPreset != null:
|
||||
var _value:float = timer + _randomized
|
||||
var _strength:float = intensity * _ease_in * _ease_out
|
||||
|
||||
_shake_position[_index] += (shakerPreset.get_value(_value, ShakerPreset2D.Categories.POSITION) * _strength)
|
||||
_shake_rotation[_index] += (shakerPreset.get_value(_value, ShakerPreset2D.Categories.ROTATION) * _strength * (PI/2.0))
|
||||
_shake_scale[_index] += (shakerPreset.get_value(_value, ShakerPreset2D.Categories.SCALE) * _strength)
|
||||
|
||||
# External Shake Addition
|
||||
for external_shake:ExternalShake in _external_shakes:
|
||||
var _real_time:float = min(timer-external_shake.start_time, external_shake.duration)
|
||||
_ease_in = ease(_real_time/external_shake.duration, external_shake.fade_in)
|
||||
_ease_out = ease(1.0-(_real_time/external_shake.duration), external_shake.fade_out)
|
||||
var _value:float = (_real_time*external_shake.speed) + _randomized
|
||||
var _strength:float = external_shake.intensity * intensity * _ease_in * _ease_out
|
||||
var _mode_value:Array[Vector2] = [Vector2.ZERO, Vector2.ZERO, Vector2.ZERO]
|
||||
match external_shake.mode:
|
||||
ShakeAddMode.add:
|
||||
_mode_value = [_shake_position[_index], Vector2(_shake_rotation[_index], 0.0), _shake_scale[_index] ]
|
||||
_shake_position[_index] = _mode_value[0] + (external_shake.preset.get_value(_value, ShakerPreset2D.Categories.POSITION) * _strength)
|
||||
_shake_rotation[_index] = _mode_value[1].x +(external_shake.preset.get_value(_value, ShakerPreset2D.Categories.ROTATION).x * _strength * (PI/2.0))
|
||||
_shake_scale[_index] = _mode_value[2] + (external_shake.preset.get_value(_value, ShakerPreset2D.Categories.SCALE) * _strength)
|
||||
|
||||
if _real_time >= external_shake.duration:
|
||||
_external_shakes.erase(external_shake)
|
||||
|
||||
# Shake Emitter
|
||||
for _child in get_children():
|
||||
if _child is ShakerReceiver2D:
|
||||
_shake_position[_index] += _child.position_offset
|
||||
_shake_rotation[_index] += _child.rotation_offset
|
||||
_shake_scale[_index] += _child.scale_offset
|
||||
|
||||
for index: int in Targets.size():
|
||||
var target: Node2D = Targets[index]
|
||||
if !is_instance_valid(target):
|
||||
Targets.remove_at(index)
|
||||
index-=1
|
||||
if Targets.size() <= 0:
|
||||
shake_finished.emit()
|
||||
break
|
||||
var _i:int = fmod(index, _shake_position.size())
|
||||
target.position += -_last_position_shake[_i] + _shake_position[_i]
|
||||
target.rotation += -_last_rotation_shake[_i] + _shake_rotation[_i]
|
||||
target.scale += -_last_scale_shake[_i] + _shake_scale[_i]
|
||||
|
||||
_last_position_shake = _shake_position
|
||||
_last_rotation_shake = _shake_rotation
|
||||
_last_scale_shake = _shake_scale
|
||||
|
||||
# Stops the shake effect with a fade-out
|
||||
func stop_shake() -> void:
|
||||
if !_fading_out:
|
||||
_timer_offset = timer
|
||||
_fading_out = true
|
||||
shake_fading_out.emit()
|
||||
|
||||
# Immediately stops the shake effect
|
||||
func force_stop_shake() -> void:
|
||||
if is_playing || _fading_out:
|
||||
set_progress(0.0)
|
||||
_reset()
|
||||
shake_finished.emit()
|
||||
|
||||
# Starts the shake effect
|
||||
func play_shake() -> void:
|
||||
_initalize_target()
|
||||
randomize_shake()
|
||||
is_playing = !is_playing if Engine.is_editor_hint() else true
|
||||
_fading_out = false
|
||||
_initialize_timer_offset()
|
||||
shake_started.emit()
|
||||
|
||||
func randomize_shake() -> void:
|
||||
_seed = randf_range(10000, 99999)
|
||||
|
||||
func _initalize_target() -> void:
|
||||
if !custom_target:
|
||||
Targets.clear()
|
||||
if get_parent() is Node2D:
|
||||
Targets.append(get_parent())
|
||||
|
||||
# Placeholder for shake function
|
||||
func shake(shaker_preset:ShakerPreset2D, _mode:ShakeAddMode=ShakeAddMode.add, duration:float=1.0, speed:float=1.0, intensity:float=1.0, fade_in:float=.25, fade_out:float=.25) -> void:
|
||||
var external_shake:ExternalShake = ExternalShake.new()
|
||||
external_shake.preset = shaker_preset
|
||||
external_shake.duration = duration
|
||||
external_shake.speed = speed
|
||||
external_shake.intensity = intensity
|
||||
external_shake.start_time = timer
|
||||
external_shake.fade_in = fade_in
|
||||
external_shake.fade_out = fade_out
|
||||
external_shake.mode = _mode
|
||||
_external_shakes.append(external_shake)
|
||||
if Targets.is_empty():
|
||||
_initalize_target()
|
||||
is_playing = true
|
||||
|
||||
# Validates property visibility
|
||||
func _validate_property(property: Dictionary) -> void:
|
||||
if property.name == "Targets" || property.name == "randomize":
|
||||
if !custom_target:
|
||||
property.usage = PROPERTY_USAGE_NONE
|
||||
if property.name == "fade_time":
|
||||
if duration > 0:
|
||||
property.usage = PROPERTY_USAGE_NONE
|
||||
|
||||
# Get configuration warnings
|
||||
func _get_configuration_warnings() -> PackedStringArray:
|
||||
if !custom_target:
|
||||
if not get_parent() is Node2D:
|
||||
return ["Parent must be Node2D"]
|
||||
|
||||
return []
|
||||
|
||||
# Sets the shake progress
|
||||
func set_progress(value: float) -> void:
|
||||
timer = value
|
||||
_progress_shake()
|
||||
|
||||
|
||||
|
||||
# Custom setter and getter functions for @export variables
|
||||
func set_custom_target(value: bool) -> void:
|
||||
custom_target = value
|
||||
notify_property_list_changed()
|
||||
|
||||
func get_custom_target() -> bool:
|
||||
return custom_target
|
||||
|
||||
func set_randomize(value: bool) -> void:
|
||||
if custom_target && Targets.size() > 1:
|
||||
for index: int in Targets.size():
|
||||
var target: Node2D = Targets[index]
|
||||
var i = fmod(index, _last_position_shake.size())
|
||||
target.position += -_last_position_shake[i]
|
||||
target.rotation += -_last_rotation_shake[i]
|
||||
target.scale += -_last_scale_shake[i]
|
||||
_last_position_shake.fill(_last_position_shake[0])
|
||||
_last_rotation_shake.fill(_last_rotation_shake[0])
|
||||
_last_scale_shake.fill(_last_scale_shake[0])
|
||||
randomize = value
|
||||
randomize_shake()
|
||||
|
||||
func get_randomize() -> bool:
|
||||
return randomize
|
||||
|
||||
class ExternalShake:
|
||||
var preset:ShakerPreset2D
|
||||
var duration:float = 1.0
|
||||
var speed:float = 1.0
|
||||
var intensity:float = 1.0
|
||||
var start_time:float = 0.0
|
||||
var fade_in:float = 0.25
|
||||
var fade_out:float = 0.25
|
||||
var mode:ShakeAddMode=ShakeAddMode.add
|
||||
|
||||
func _initialize_timer_offset() -> void:
|
||||
if !(duration > 0): _timer_offset = 0x80000
|
||||
else: _timer_offset = 0.0
|
||||
|
||||
func is_receiving_from_emitters() -> bool:
|
||||
for _child in get_children():
|
||||
if _child is ShakerReceiver2D:
|
||||
return _child.is_playing()
|
||||
return false
|
||||
1
addons/shaker/src/Vector2/shaker_component2D.gd.uid
Normal file
1
addons/shaker/src/Vector2/shaker_component2D.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b78swtk5maey2
|
||||
Reference in New Issue
Block a user