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.
103 lines
3.3 KiB
103 lines
3.3 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_sticky: AudioStream = load("res://Mods/copyThrower/Resources/sticky_randomizer.tres") |
|
|
|
# A cache of StandardMaterial3D materials created from colors and textures, with transparent variants. |
|
static var material_cache: Dictionary[Variant, Dictionary] |
|
|
|
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 |
|
$Model/Inner.visible = value |
|
if value: $AudioStreamPlayer3D.stream = stream_sticky |
|
|
|
func set_material(value: Variant) -> void: |
|
if not material_cache.has(value): |
|
var material_normal: StandardMaterial3D |
|
if value is Material: |
|
material_normal = value |
|
elif value is Color: |
|
material_normal = StandardMaterial3D.new() |
|
material_normal.albedo_color = value |
|
elif value is Texture2D: |
|
material_normal = StandardMaterial3D.new() |
|
material_normal.albedo_texture = value |
|
else: printerr("unsupported value type"); |
|
|
|
# Create an additional material that's semi-transparent. |
|
var material_sticky := material_normal.duplicate() |
|
material_sticky.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA |
|
material_sticky.albedo_color.a = 0.5 |
|
|
|
material_cache[value] = { normal = material_normal, sticky = material_sticky } |
|
|
|
var material := material_cache[value] |
|
# NOTE: Assuming this function is called after set_sticky. |
|
var sticky_str := "sticky" if sticky else "normal" |
|
$Model/Outer/Heart.material_override = material[sticky_str] |
|
$Model/Inner/Heart.material_override = material["normal"] |
|
|
|
|
|
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: |
|
reparent(original_parent) |
|
freeze = false |
|
|
|
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; |
|
reparent(body) |
|
freeze = true
|
|
|