feat: make pantry crises visible in the world
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
class_name PantryStockVisual
|
||||
extends Node3D
|
||||
|
||||
enum StockLevel { EMPTY, LOW, STOCKED }
|
||||
|
||||
const LOW_STOCK_THRESHOLD := 4.0
|
||||
const REFILL_RESPONSE_START := Vector3(0.0, 0.08, -0.5)
|
||||
const REFILL_RESPONSE_END := Vector3(0.0, 0.36, -0.5)
|
||||
|
||||
@onready var empty_root: Node3D = $EmptyStock
|
||||
@onready var low_stock_root: Node3D = $LowStock
|
||||
@onready var full_stock_root: Node3D = $FullStock
|
||||
@onready var refill_response_root: Node3D = $RefillResponse
|
||||
@onready var refill_response_visuals: Array[MeshInstance3D] = [
|
||||
$RefillResponse/Ring,
|
||||
$RefillResponse/MoteLeft,
|
||||
$RefillResponse/MoteCenter,
|
||||
$RefillResponse/MoteRight,
|
||||
]
|
||||
|
||||
var displayed_amount := -1.0
|
||||
var stock_level := StockLevel.EMPTY
|
||||
var transition_tween: Tween
|
||||
var refill_tween: Tween
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
refill_response_root.visible = false
|
||||
|
||||
|
||||
func set_food_amount(amount: float, animate: bool = true) -> void:
|
||||
var normalized_amount := maxf(amount, 0.0)
|
||||
var next_level := _get_stock_level(normalized_amount)
|
||||
if next_level == StockLevel.EMPTY:
|
||||
_stop_refill_response()
|
||||
var was_initialized := displayed_amount >= 0.0
|
||||
var was_empty := was_initialized and displayed_amount <= 0.001
|
||||
if was_initialized and next_level == stock_level:
|
||||
displayed_amount = normalized_amount
|
||||
return
|
||||
var should_animate := animate and was_initialized
|
||||
displayed_amount = normalized_amount
|
||||
stock_level = next_level
|
||||
if should_animate:
|
||||
_transition_to_level(next_level)
|
||||
else:
|
||||
_apply_level_immediately(next_level)
|
||||
if was_empty and normalized_amount > 0.001 and animate:
|
||||
_play_refill_response()
|
||||
|
||||
|
||||
func get_stock_level() -> StockLevel:
|
||||
return stock_level
|
||||
|
||||
|
||||
func _get_stock_level(amount: float) -> StockLevel:
|
||||
if amount <= 0.001:
|
||||
return StockLevel.EMPTY
|
||||
if amount < LOW_STOCK_THRESHOLD:
|
||||
return StockLevel.LOW
|
||||
return StockLevel.STOCKED
|
||||
|
||||
|
||||
func _apply_level_immediately(level: StockLevel) -> void:
|
||||
_stop_transition()
|
||||
_set_root_visible(empty_root, level == StockLevel.EMPTY)
|
||||
_set_root_visible(low_stock_root, level in [StockLevel.LOW, StockLevel.STOCKED])
|
||||
_set_root_visible(full_stock_root, level == StockLevel.STOCKED)
|
||||
|
||||
|
||||
func _transition_to_level(level: StockLevel) -> void:
|
||||
_stop_transition()
|
||||
transition_tween = create_tween().set_parallel(true)
|
||||
_transition_root(empty_root, level == StockLevel.EMPTY)
|
||||
_transition_root(low_stock_root, level in [StockLevel.LOW, StockLevel.STOCKED])
|
||||
_transition_root(full_stock_root, level == StockLevel.STOCKED)
|
||||
transition_tween.chain().tween_callback(_finish_transition.bind(level))
|
||||
|
||||
|
||||
func _transition_root(root: Node3D, should_show: bool) -> void:
|
||||
if should_show:
|
||||
if not root.visible:
|
||||
root.visible = true
|
||||
root.scale = Vector3.ONE * 0.62
|
||||
(
|
||||
transition_tween
|
||||
. tween_property(root, "scale", Vector3.ONE, 0.28)
|
||||
. set_trans(Tween.TRANS_BACK)
|
||||
. set_ease(Tween.EASE_OUT)
|
||||
)
|
||||
return
|
||||
if not root.visible:
|
||||
return
|
||||
(
|
||||
transition_tween
|
||||
. tween_property(root, "scale", Vector3.ONE * 0.18, 0.16)
|
||||
. set_trans(Tween.TRANS_SINE)
|
||||
. set_ease(Tween.EASE_IN)
|
||||
)
|
||||
|
||||
|
||||
func _finish_transition(level: StockLevel) -> void:
|
||||
transition_tween = null
|
||||
_set_root_visible(empty_root, level == StockLevel.EMPTY)
|
||||
_set_root_visible(low_stock_root, level in [StockLevel.LOW, StockLevel.STOCKED])
|
||||
_set_root_visible(full_stock_root, level == StockLevel.STOCKED)
|
||||
|
||||
|
||||
func _set_root_visible(root: Node3D, is_visible: bool) -> void:
|
||||
root.visible = is_visible
|
||||
root.scale = Vector3.ONE
|
||||
|
||||
|
||||
func _stop_transition() -> void:
|
||||
if transition_tween != null:
|
||||
transition_tween.kill()
|
||||
transition_tween = null
|
||||
|
||||
|
||||
func _play_refill_response() -> void:
|
||||
_stop_refill_response()
|
||||
refill_response_root.visible = true
|
||||
refill_response_root.position = REFILL_RESPONSE_START
|
||||
refill_response_root.scale = Vector3.ONE * 0.45
|
||||
_set_refill_transparency(0.0)
|
||||
refill_tween = create_tween()
|
||||
refill_tween.set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_OUT)
|
||||
refill_tween.tween_property(refill_response_root, "scale", Vector3.ONE, 0.24)
|
||||
refill_tween.parallel().tween_method(_set_refill_transparency, 0.0, 1.0, 0.18)
|
||||
refill_tween.tween_property(refill_response_root, "position", REFILL_RESPONSE_END, 0.5)
|
||||
refill_tween.parallel().tween_method(_set_refill_transparency, 1.0, 0.0, 0.5)
|
||||
refill_tween.tween_callback(_stop_refill_response)
|
||||
|
||||
|
||||
func _set_refill_transparency(value: float) -> void:
|
||||
for visual in refill_response_visuals:
|
||||
visual.transparency = clampf(1.0 - value, 0.0, 1.0)
|
||||
|
||||
|
||||
func _stop_refill_response() -> void:
|
||||
if refill_tween != null:
|
||||
refill_tween.kill()
|
||||
refill_tween = null
|
||||
if refill_response_root == null:
|
||||
return
|
||||
refill_response_root.visible = false
|
||||
refill_response_root.position = REFILL_RESPONSE_START
|
||||
refill_response_root.scale = Vector3.ONE * 0.45
|
||||
_set_refill_transparency(0.0)
|
||||
@@ -0,0 +1 @@
|
||||
uid://bj2aigpu1nug6
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=7 format=3]
|
||||
[gd_scene load_steps=6 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://world/storage/StorageNode.gd" id="1_storage"]
|
||||
|
||||
@@ -18,10 +18,6 @@ size = Vector3(1.6, 1.1, 1.6)
|
||||
material = SubResource("Material_cloth")
|
||||
size = Vector3(1.75, 0.12, 1.75)
|
||||
|
||||
[sub_resource type="BoxMesh" id="Mesh_sack"]
|
||||
material = SubResource("Material_cloth")
|
||||
size = Vector3(0.45, 0.65, 0.45)
|
||||
|
||||
[node name="StorageNode" type="Node3D"]
|
||||
script = ExtResource("1_storage")
|
||||
|
||||
@@ -35,10 +31,6 @@ mesh = SubResource("Mesh_crate")
|
||||
transform = Transform3D(1, 0, 0, 0, 0.7, 0.7173561, 0, -0.7173561, 0.7, 0, 1.15, -0.06)
|
||||
mesh = SubResource("Mesh_lid")
|
||||
|
||||
[node name="FoodSack" type="MeshInstance3D" parent="Visual"]
|
||||
transform = Transform3D(0.85, 0, 0, 0, 1, 0, 0, 0, 0.85, 0.8, 0.325, 0.55)
|
||||
mesh = SubResource("Mesh_sack")
|
||||
|
||||
[node name="InteractionPoint" type="Marker3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 2.0)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user