Personalized heart thrower mod for SnekStudio
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

93 lines
2.7 KiB

extends RigidBody3D
## If this heart were to exist for longer than 1 minute for some reason, destroy it.
## The heart should also disappear if it falls low enough.
var lifetime := 60.0 # 1 minute
## If this heart has impacted another object already.
## Prevents repeated impact sounds and sticking.
var impacted := false
## Relative size of the heart. Affects audio pitch.
## Used later to decide how impactful a collision was.
var size := 1.0
## Whether the heart will stick to avatars when colliding.
var sticky := false
## How long the heart will be sticking before falling off again.
@onready var sticky_timer := randf_range(3, 6) # 3 to 6 seconds
# Remember the original parent this node was created under, so if the
# heart sticks to a character, it can return here once it unsticks.
@onready var original_parent: Node = get_parent()
static var stream_normal: AudioStream = load("res://Mods/copyThrower/Resources/normal_randomizer.tres")
static var stream_sticky: AudioStream = load("res://Mods/copyThrower/Resources/sticky_randomizer.tres")
func _ready() -> void:
body_entered.connect(on_body_entered)
# Give it a little bit of random spin.
var random_vector := Vector3(randf() - 0.5, randf() - 0.5, randf() - 0.5).normalized()
angular_velocity = random_vector * randf_range(0, 25) * TAU
angular_damp = 5.0
func set_size(value: float) -> void:
size = value
$Model.scale *= value
$CollisionShape3D.scale *= value
$AudioStreamPlayer3D.pitch_scale = 1 / lerpf(1, value, 0.5)
func set_sticky(value: bool) -> void:
sticky = value
if value: $AudioStreamPlayer3D.stream = stream_sticky
else: $AudioStreamPlayer3D.stream = stream_normal
func set_material(material: StandardMaterial3D) -> void:
$Model/Heart.material_override = material
func _process(delta: float) -> void:
# Kill heart if it ever lives too long.
lifetime -= delta
if lifetime <= 0: queue_free(); return
# Kill heart if it falls too low.
if global_position.y < -10: queue_free(); return
# Unsticky heart after some time.
if get_parent() is CharacterBody3D:
sticky_timer -= delta
if sticky_timer <= 0:
set_physics_active(true)
reparent(original_parent)
func on_body_entered(body: Node) -> void:
if not (body is CharacterBody3D): return
if impacted: return
impacted = true
$AudioStreamPlayer3D.play()
original_parent.on_collide(self, body)
if sticky:
await get_tree().process_frame;
set_physics_active(false)
set_gravity_scale(0.0)
reparent(body)
func set_physics_active(active: bool) -> void:
if active:
sleeping = false
collision_mask = 1
set_gravity_scale(1.0)
else:
sleeping = true
linear_velocity = Vector3.ZERO
angular_velocity = Vector3.ZERO
collision_mask = 0
collision_layer = 0
set_gravity_scale(0.0)