diff --git a/scenes/components/StoredSceneLoader.gd b/scenes/components/StoredSceneLoader.gd index 40fe56200..0ce147e52 100644 --- a/scenes/components/StoredSceneLoader.gd +++ b/scenes/components/StoredSceneLoader.gd @@ -10,7 +10,7 @@ func _ready(): if not stored_scenes: #Nothing was set here yet return if not stored_scenes is Dictionary: - push_error("DataStore.data[%s] exists but is not a dictionary.".format(stored_scene_key)) + push_error("DataStore.data[%s] exists but is not a dictionary." % stored_scene_key) else: for obj in stored_scenes.values(): var scene : PackedScene = obj diff --git a/scenes/friends/ScaredyCat.gd b/scenes/friends/ScaredyCat.gd new file mode 100644 index 000000000..a56c7517d --- /dev/null +++ b/scenes/friends/ScaredyCat.gd @@ -0,0 +1,71 @@ +extends KinematicBody2D + +export var velocity := Vector2.ZERO +export var jump_force := -300 +export var gravity_vec := Vector2.DOWN * 270 + +export var sound_db := -1 +export var sound_pitch_scale := 0.85 + +export var escape_time := 0.5 #The cat can not be recollected for this many seconds after it spawns, to avoid immediately recollecting it + +export(PackedScene) var cat_scene = preload("res://scenes/friends/Cat.tscn") + +var collected := false + +onready var escape_timer := $Timer +onready var audio_meow := $MeowStream + + +func _ready(): + escape_timer.start(escape_time) + + audio_meow.volume_db = sound_db + audio_meow.pitch_scale = sound_pitch_scale + + audio_meow.play() + + +func _physics_process(delta): + velocity += gravity_vec * delta + move_and_slide(velocity, Vector2.UP) + if is_on_floor(): + velocity.y = jump_force + audio_meow.play() + if is_on_wall(): + velocity.x *= -1 + if is_on_ceiling(): #BONK! You fall down now + velocity.y = max(0, velocity.y) + + +func collect(): + collected = true + + visible = false + set_physics_process(false) + + audio_meow.volume_db = 0 + audio_meow.pitch_scale = 1.05 + audio_meow.play() + + +func _on_PlayerHitbox_body_entered(body : KinematicBody2D): + if collected: + return + if escape_timer.time_left > 0: + return + if not body is Player: + return + + var cat = cat_scene.instance() + get_parent().call_deferred("add_child", cat) + cat.set_player(body) + cat.global_position = global_position + + collect() + + + +func _on_MeowStream_finished(): + if collected: + queue_free() diff --git a/scenes/friends/ScaredyCat.tscn b/scenes/friends/ScaredyCat.tscn new file mode 100644 index 000000000..15c42b464 --- /dev/null +++ b/scenes/friends/ScaredyCat.tscn @@ -0,0 +1,46 @@ +[gd_scene load_steps=6 format=2] + +[ext_resource path="res://sprites/cat-ears.png" type="Texture" id=1] +[ext_resource path="res://sprites/box-cat.png" type="Texture" id=2] +[ext_resource path="res://scenes/friends/ScaredyCat.gd" type="Script" id=3] +[ext_resource path="res://audio/sfx/meow.wav" type="AudioStream" id=4] + +[sub_resource type="RectangleShape2D" id=1] +extents = Vector2( 8, 8 ) + +[node name="ScaredyCat" type="KinematicBody2D"] +collision_layer = 0 +collision_mask = 2 +script = ExtResource( 3 ) + +[node name="PlayerHitbox" type="Area2D" parent="."] +collision_layer = 0 +collision_mask = 64 +monitorable = false + +[node name="CollisionShape2D" type="CollisionShape2D" parent="PlayerHitbox"] +shape = SubResource( 1 ) + +[node name="CollisionShape2D" type="CollisionShape2D" parent="."] +shape = SubResource( 1 ) + +[node name="Sprite" type="Sprite" parent="."] +scale = Vector2( 0.25, 0.25 ) +texture = ExtResource( 2 ) + +[node name="Sprite2" type="Sprite" parent="."] +position = Vector2( 0, -16 ) +scale = Vector2( 0.25, 0.25 ) +texture = ExtResource( 1 ) + +[node name="Timer" type="Timer" parent="."] +process_mode = 0 +one_shot = true + +[node name="MeowStream" type="AudioStreamPlayer2D" parent="."] +stream = ExtResource( 4 ) +bus = "sfx" +area_mask = 2 + +[connection signal="body_entered" from="PlayerHitbox" to="." method="_on_PlayerHitbox_body_entered"] +[connection signal="finished" from="MeowStream" to="." method="_on_MeowStream_finished"] diff --git a/scenes/platformer/characters/player_components/CatManager.gd b/scenes/platformer/characters/player_components/CatManager.gd index 3ee9fc2a7..e8ce9fb88 100644 --- a/scenes/platformer/characters/player_components/CatManager.gd +++ b/scenes/platformer/characters/player_components/CatManager.gd @@ -3,6 +3,10 @@ class_name CatManager export(PackedScene) var cat_scene = load("res://scenes/friends/Cat.tscn") export(PackedScene) var cat_manager_scene = load("res://scenes/platformer/characters/player_components/CatManager.tscn") +export(PackedScene) var scaredy_cat_scene = load("res://scenes/friends/ScaredyCat.tscn") + +export(Vector2) var min_scatter_velocity = Vector2(200, -20) +export(Vector2) var max_scatter_velocity = Vector2(300, -300) var cat_nodes := [] var cat_count_key = "CatCount" @@ -11,6 +15,8 @@ onready var _player : Player = get_parent() func _ready(): + EventBus.connect("heart_changed", self, "_on_Player_heart_changed") + var num_cats = DataStore.get_data_or_null(cat_count_key) if num_cats: for i in num_cats: @@ -21,13 +27,18 @@ func _ready(): DataStore.set_data_in_dict("PlayerStoredScenes", "CatManager", cat_manager_scene) -func get_cat_count(): +func get_cat_count() -> int: return cat_nodes.size() + + +func _on_Player_heart_changed(delta, _total): + if delta < 0: + scatter() #Returns the last cat that was added, or the player if this is the first cat. #This return value is used to tell a newly added cat what to follow. -func add_cat(cat_node : Node2D) -> Node2D: +func add_cat(cat_node : Node2D) -> Node2D: cat_nodes.append(cat_node) DataStore.set_data(cat_count_key, get_cat_count()) if get_cat_count() == 1: @@ -36,9 +47,9 @@ func add_cat(cat_node : Node2D) -> Node2D: return cat_nodes[-2] -func remove_cat(amount : int = 1): +func remove_cat(amount : int = 1) -> void: amount = min(amount, get_cat_count()) as int - for i in amount: + for i in range(1, amount+1): cat_nodes[-i].queue_free() cat_nodes.resize(cat_nodes.size() - amount) DataStore.set_data(cat_count_key, get_cat_count()) @@ -46,3 +57,17 @@ func remove_cat(amount : int = 1): DataStore.remove_data(cat_count_key) DataStore.remove_data_in_dict("PlayerStoredScenes", "CatManager") queue_free() + + +func scatter() -> void: + var count := get_cat_count() + remove_cat(count) + for i in count: + var cat : Node2D = scaredy_cat_scene.instance() + cat.velocity.x = rand_range(min_scatter_velocity.x, max_scatter_velocity.x) + cat.velocity.y = rand_range(min_scatter_velocity.y, max_scatter_velocity.y) + if randf() > 0.5: #Has an equal chance to run either left or right + cat.velocity.x *= -1 + cat.global_position = _player.global_position + _player.get_parent().call_deferred("add_child", cat) + diff --git a/scripts/autoload/DataStore.gd b/scripts/autoload/DataStore.gd index e1f20b340..f100fc984 100644 --- a/scripts/autoload/DataStore.gd +++ b/scripts/autoload/DataStore.gd @@ -69,7 +69,7 @@ func get_data_in_dict(key, inner_key): func remove_data_in_dict(key, inner_key, survive_level_restart = false, survive_respawn = false): var dict = get_data_or_null(key) if !dict: - push_error("DataStore.data[%s] does not exist.".format(key)) + push_error("DataStore.data[%s] does not exist." % key) else: assert(dict is Dictionary) dict.erase(inner_key)