diff --git a/PlayerInput.gd b/PlayerInput.gd index a2076fc..428d9d6 100644 --- a/PlayerInput.gd +++ b/PlayerInput.gd @@ -1,18 +1,19 @@ extends Node var allow_joins = true -var players: Dictionary[int, PlayerInputData] +var players: Dictionary const DEADZONE = 0.2 signal player_join(data: PlayerInputData) + func _ready() -> void: Input.joy_connection_changed.connect(joy_connection_changed) -@warning_ignore("unused_parameter") func joy_connection_changed(device: int, connected: bool): - print("Connected ", device) + if not connected: + drop(device) func move_input(player: PlayerInputData, event: InputEvent, action: String): @@ -75,9 +76,13 @@ func join(who: int): players[who] = new_player player_join.emit(new_player) +func rejoin(who: PlayerInputData): + player_join.emit(who) + func drop(who: int): - players[who].drop.emit() - players.erase(who) + if players.has(who): + players[who].drop.emit() + players.erase(who) func get_action_name_all(event: InputEvent) -> String: @@ -123,7 +128,14 @@ func _input(event: InputEvent) -> void: if players.has(who): - game_input(players[who], event) + var data = players[who] + if not data.claimed: + rejoin(data) + else: + game_input(data, event) elif allow_joins and get_action_name(event): join(who) + +func restart(): + players = Dictionary() diff --git a/PlayerInputData.gd b/PlayerInputData.gd index ff8d4cf..d77c7a7 100644 --- a/PlayerInputData.gd +++ b/PlayerInputData.gd @@ -3,7 +3,10 @@ class_name PlayerInputData @warning_ignore("unused_signal") signal drop +@warning_ignore("unused_signal") +signal claim +var claimed := false var walk_dir: Vector3 = Vector3.ZERO var digging: bool = false var jumping: bool = false diff --git a/Pounce.res b/Pounce.res index 66d3f60..487a392 100644 Binary files a/Pounce.res and b/Pounce.res differ diff --git a/area_3d.gd b/area_3d.gd new file mode 100644 index 0000000..00cf90f --- /dev/null +++ b/area_3d.gd @@ -0,0 +1,25 @@ +extends Area3D +class_name VoleDetector + +signal on +signal off + +var intersect_count := 0 + +func _on_area_entered(area: Area3D) -> void: + if area is not VoleDetector: + return + if intersect_count == 0: + on.emit() + intersect_count += 1 + + +func _on_area_exited(area: Area3D) -> void: + if area is not VoleDetector: + return + intersect_count -= 1 + if intersect_count == 0: + off.emit() + +func vole(): + return owner diff --git a/area_3d.gd.uid b/area_3d.gd.uid new file mode 100644 index 0000000..72d7b7a --- /dev/null +++ b/area_3d.gd.uid @@ -0,0 +1 @@ +uid://bufpuqvrhkv8t diff --git a/blends/terrain.blend b/blends/terrain.blend new file mode 100644 index 0000000..541d545 Binary files /dev/null and b/blends/terrain.blend differ diff --git a/blends/terrain.blend1 b/blends/terrain.blend1 new file mode 100644 index 0000000..7c292a5 Binary files /dev/null and b/blends/terrain.blend1 differ diff --git a/box_art.tscn b/box_art.tscn new file mode 100644 index 0000000..519f154 --- /dev/null +++ b/box_art.tscn @@ -0,0 +1,27 @@ +[gd_scene load_steps=4 format=3 uid="uid://bcbgdhxac3ll5"] + +[ext_resource type="PackedScene" uid="uid://cj7l76arpv3ib" path="res://terrain.tscn" id="1_cw6mu"] +[ext_resource type="PackedScene" uid="uid://cg7vjpjmg60ti" path="res://vole.glb" id="2_cuf48"] + +[sub_resource type="Environment" id="Environment_cw6mu"] +background_mode = 1 +background_color = Color(0.56685, 0.797711, 1, 1) +volumetric_fog_density = 0.07 +volumetric_fog_emission = Color(1, 1, 1, 1) +volumetric_fog_length = 15.0 + +[node name="BoxArt" type="Node3D"] + +[node name="terrain" parent="." instance=ExtResource("1_cw6mu")] + +[node name="vole" parent="terrain" instance=ExtResource("2_cuf48")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5.56748, 12.0074, -0.381833) + +[node name="Camera3D" type="Camera3D" parent="terrain/vole"] +transform = Transform3D(1, 0, 0, 0, 0.992463, 0.122545, 0, -0.122545, 0.992463, 0, 0.493698, 1.15394) + +[node name="WorldEnvironment" type="WorldEnvironment" parent="terrain/vole/Camera3D"] +environment = SubResource("Environment_cw6mu") + +[node name="OmniLight3D" type="OmniLight3D" parent="terrain/vole"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.80256, 0) diff --git a/builds/avalanche_season.exe b/builds/avalanche_season.exe new file mode 100644 index 0000000..2953169 Binary files /dev/null and b/builds/avalanche_season.exe differ diff --git a/builds/avalanche_season.pck b/builds/avalanche_season.pck new file mode 100644 index 0000000..2ebaa5f Binary files /dev/null and b/builds/avalanche_season.pck differ diff --git a/builds/avalanche_season.x86_64 b/builds/avalanche_season.x86_64 new file mode 100755 index 0000000..b1a99a8 Binary files /dev/null and b/builds/avalanche_season.x86_64 differ diff --git a/button.gd b/button.gd new file mode 100644 index 0000000..98896ab --- /dev/null +++ b/button.gd @@ -0,0 +1,6 @@ +extends Button + + + +func _on_pressed() -> void: + get_tree().change_scene_to_file("res://main.tscn") diff --git a/button.gd.uid b/button.gd.uid new file mode 100644 index 0000000..ed66107 --- /dev/null +++ b/button.gd.uid @@ -0,0 +1 @@ +uid://co7lut3licn2s diff --git a/end_text.tscn b/end_text.tscn new file mode 100644 index 0000000..3d30d82 --- /dev/null +++ b/end_text.tscn @@ -0,0 +1,17 @@ +[gd_scene load_steps=3 format=3 uid="uid://bat5qdtcsb6kv"] + +[ext_resource type="PackedScene" uid="uid://wt0fxawif12f" path="res://text_scene.tscn" id="1_hbduh"] +[ext_resource type="Script" uid="uid://co7lut3licn2s" path="res://button.gd" id="2_17dmj"] + +[node name="TextScene" instance=ExtResource("1_hbduh")] + +[node name="Button" type="Button" parent="." index="2"] +layout_mode = 0 +offset_left = 441.0 +offset_top = 551.0 +offset_right = 506.0 +offset_bottom = 582.0 +text = "Restart" +script = ExtResource("2_17dmj") + +[connection signal="pressed" from="Button" to="Button" method="_on_pressed"] diff --git a/fox.gd b/fox.gd index 84f26fa..34d6072 100644 --- a/fox.gd +++ b/fox.gd @@ -17,3 +17,9 @@ func is_busy(): func root_motion(): return %AnimationTree.get_root_motion_position() + +func strike(): + for vole in %VoleCatcher.caught: + if vole.vole().visible: + vole.vole().caught() + %VoleCatcher.caught = Dictionary() diff --git a/fox.tscn b/fox.tscn index 40a755a..6589ace 100644 --- a/fox.tscn +++ b/fox.tscn @@ -1,7 +1,11 @@ -[gd_scene load_steps=13 format=3 uid="uid://dwm6v58p82b57"] +[gd_scene load_steps=15 format=3 uid="uid://dwm6v58p82b57"] [ext_resource type="PackedScene" uid="uid://bhhevwh2jipt7" path="res://fox.glb" id="1_8x0u3"] [ext_resource type="Script" uid="uid://8683t0qihiwq" path="res://fox.gd" id="2_kpck0"] +[ext_resource type="Script" uid="uid://cp541kkdti4y" path="res://vole_catcher.gd" id="3_k0xb2"] + +[sub_resource type="SphereShape3D" id="SphereShape3D_kpck0"] +radius = 1.32985 [sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_8x0u3"] animation = &"Idle" @@ -44,6 +48,19 @@ transitions = ["Start", "Idle", SubResource("AnimationNodeStateMachineTransition [node name="fox" instance=ExtResource("1_8x0u3")] script = ExtResource("2_kpck0") +[node name="BoneAttachment3D" type="BoneAttachment3D" parent="FoxRig/Skeleton3D" index="1"] +transform = Transform3D(1, 0, -8.74228e-08, -8.73917e-08, 0.0266449, -0.999645, 2.32937e-09, 0.999645, 0.0266449, 2.85687e-15, 2.29449, 1.46528) +bone_name = "head" +bone_idx = 4 + +[node name="VoleCatcher" type="Area3D" parent="FoxRig/Skeleton3D/BoneAttachment3D" index="0"] +unique_name_in_owner = true +script = ExtResource("3_k0xb2") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="FoxRig/Skeleton3D/BoneAttachment3D/VoleCatcher" index="0"] +transform = Transform3D(1, 4.44089e-16, -1.43704e-14, 0, 1, 0, -1.45717e-16, -3.72529e-09, 1, -2.30192e-08, 0.620525, -0.210184) +shape = SubResource("SphereShape3D_kpck0") + [node name="AnimationPlayer" parent="." index="1"] root_motion_track = NodePath("FoxRig/Skeleton3D:root") root_motion_local = false @@ -55,3 +72,6 @@ root_motion_track = NodePath("FoxRig/Skeleton3D:root") root_motion_local = false tree_root = SubResource("AnimationNodeStateMachine_k0xb2") anim_player = NodePath("../AnimationPlayer") + +[connection signal="area_entered" from="FoxRig/Skeleton3D/BoneAttachment3D/VoleCatcher" to="FoxRig/Skeleton3D/BoneAttachment3D/VoleCatcher" method="_on_area_entered"] +[connection signal="area_exited" from="FoxRig/Skeleton3D/BoneAttachment3D/VoleCatcher" to="FoxRig/Skeleton3D/BoneAttachment3D/VoleCatcher" method="_on_area_exited"] diff --git a/fox_win_text.tscn b/fox_win_text.tscn new file mode 100644 index 0000000..469564c --- /dev/null +++ b/fox_win_text.tscn @@ -0,0 +1,9 @@ +[gd_scene load_steps=2 format=3 uid="uid://unn34w22ob27"] + +[ext_resource type="PackedScene" uid="uid://bat5qdtcsb6kv" path="res://end_text.tscn" id="1_4cnm6"] + +[node name="TextScene" instance=ExtResource("1_4cnm6")] + +[node name="Label" parent="." index="1"] +text = "There are no voles left" +autowrap_mode = 1 diff --git a/intro_text.tscn b/intro_text.tscn new file mode 100644 index 0000000..ba5f41d --- /dev/null +++ b/intro_text.tscn @@ -0,0 +1,37 @@ +[gd_scene load_steps=3 format=3 uid="uid://bol2yxcuqnlco"] + +[ext_resource type="PackedScene" uid="uid://wt0fxawif12f" path="res://text_scene.tscn" id="1_gw8tw"] +[ext_resource type="Script" uid="uid://co7lut3licn2s" path="res://button.gd" id="2_0b7x6"] + +[node name="TextScene" instance=ExtResource("1_gw8tw")] + +[node name="Label" parent="." index="1"] +offset_left = -324.0 +offset_top = -284.0 +offset_right = 389.0 +offset_bottom = 181.0 +text = "Avalanche Season +(Game has no audio) + +The Winter is cold and the fox is hungry. The voles' only hope to foil the fox is gravity. With enough numbers and everyone squeaking at once, they can bring about an avalanche. It's a bit of a gamble, but it's their only hope! + +How to play: +This game is intended to be played with 2 or more players and supports arbitrarily many players. + +Join by pressing a button on a controller or WASD (and space) or arrow keys (and right shift) + +First player to join becomes the fox and can dive for voles. +Voles can make more voles by standing near other voles or press a button to switch the vole they control + +At least 20 voles are required to bring about an avalanche" + +[node name="Button" type="Button" parent="Label" index="0"] +layout_mode = 0 +offset_left = 280.0 +offset_top = 487.0 +offset_right = 359.0 +offset_bottom = 518.0 +text = "Continue" +script = ExtResource("2_0b7x6") + +[connection signal="pressed" from="Label/Button" to="Label/Button" method="_on_pressed"] diff --git a/main.gd b/main.gd new file mode 100644 index 0000000..f6cc5ca --- /dev/null +++ b/main.gd @@ -0,0 +1,5 @@ +extends Node3D + + +func _ready() -> void: + PlayerInput.restart() diff --git a/main.gd.uid b/main.gd.uid new file mode 100644 index 0000000..e9f9396 --- /dev/null +++ b/main.gd.uid @@ -0,0 +1 @@ +uid://d1hwmc7erkys0 diff --git a/main.tscn b/main.tscn index d952233..13546be 100644 --- a/main.tscn +++ b/main.tscn @@ -1,40 +1,81 @@ -[gd_scene load_steps=6 format=3 uid="uid://cgpuhiledvecy"] +[gd_scene load_steps=9 format=3 uid="uid://cgpuhiledvecy"] -[ext_resource type="PackedScene" uid="uid://bmt76eb0ke5fw" path="res://player_spawn.tscn" id="1_ig7tw"] +[ext_resource type="Script" uid="uid://d1hwmc7erkys0" path="res://main.gd" id="1_lquwl"] +[ext_resource type="PackedScene" uid="uid://cj7l76arpv3ib" path="res://terrain.tscn" id="2_0xm2m"] +[ext_resource type="PackedScene" uid="uid://cpap2mt61s2m" path="res://snow_particles.tscn" id="3_h2yge"] +[ext_resource type="PackedScene" uid="uid://2fdkfui13p2" path="res://player_manager.tscn" id="3_lquwl"] +[ext_resource type="PackedScene" uid="uid://54sf77urgp3h" path="res://player.tscn" id="4_1bvp3"] [sub_resource type="Environment" id="Environment_ig7tw"] - -[sub_resource type="BoxMesh" id="BoxMesh_7dm0k"] -size = Vector3(50, 0.5, 50) - -[sub_resource type="ConvexPolygonShape3D" id="ConvexPolygonShape3D_ig7tw"] -points = PackedVector3Array(25.3919, 0.940476, 25.3919, -25.3919, -0.646825, -25.3919, -25.3919, 0.940476, -25.3919, 25.3919, -0.646825, -25.3919, -25.3919, -0.646825, 25.3919, -25.3919, 0.940476, 25.3919, 25.3919, 0.940476, -25.3919, 25.3919, -0.646825, 25.3919) +background_mode = 1 +background_color = Color(0.56685, 0.797711, 1, 1) +volumetric_fog_enabled = true +volumetric_fog_density = 0.07 +volumetric_fog_emission = Color(1, 1, 1, 1) +volumetric_fog_length = 15.0 [sub_resource type="BoxMesh" id="BoxMesh_ig7tw"] +[sub_resource type="BoxShape3D" id="BoxShape3D_1bvp3"] +size = Vector3(35.0134, 9.75867, 0.249512) + [node name="Main" type="Node3D"] +script = ExtResource("1_lquwl") [node name="WorldEnvironment" type="WorldEnvironment" parent="."] environment = SubResource("Environment_ig7tw") [node name="DirectionalLight3D" type="DirectionalLight3D" parent="WorldEnvironment"] -transform = Transform3D(1, 0, 0, 0, 0.473074, 0.881023, 0, -0.881023, 0.473074, 0, 0, 0) - -[node name="MeshInstance3D" type="MeshInstance3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.694463, 0) -mesh = SubResource("BoxMesh_7dm0k") - -[node name="PlayerSpawn" parent="MeshInstance3D" instance=ExtResource("1_ig7tw")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.494699, 8.50994, 0.238789) - -[node name="StaticBody3D2" type="StaticBody3D" parent="MeshInstance3D"] - -[node name="CollisionShape3D" type="CollisionShape3D" parent="MeshInstance3D/StaticBody3D2"] -shape = SubResource("ConvexPolygonShape3D_ig7tw") +transform = Transform3D(0.273993, -0.45497, -0.847308, 0.961732, 0.129619, 0.241394, -1.15681e-10, -0.881023, 0.473074, 0, 17.9492, 0) [node name="Camera3D" type="Camera3D" parent="."] -transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 31.348, 0) +transform = Transform3D(1, 0, 0, 0, 0.995973, 0.0896594, 0, -0.0896594, 0.995973, 0, 11.4751, 48.7588) fov = 50.0 [node name="MeshInstance3D2" type="MeshInstance3D" parent="."] mesh = SubResource("BoxMesh_ig7tw") + +[node name="terrain" parent="." instance=ExtResource("2_0xm2m")] + +[node name="GPUParticles3D" parent="." instance=ExtResource("3_h2yge")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 14.0086, 44.111) + +[node name="StaticBody3D2" type="StaticBody3D" parent="."] + +[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D2"] +transform = Transform3D(5.09, 0, 0, 0, 5.09, 0, 0, 0, 5.09, 14.8539, 22.2908, -30.8631) +shape = SubResource("BoxShape3D_1bvp3") + +[node name="StaticBody3D3" type="StaticBody3D" parent="."] + +[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D3"] +transform = Transform3D(5.09, 0, 0, 0, 5.09, 0, 0, 0, 5.09, 14.8539, 22.2908, 30.3055) +shape = SubResource("BoxShape3D_1bvp3") + +[node name="StaticBody3D4" type="StaticBody3D" parent="."] +transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 23.5946, 0, 0) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D4"] +transform = Transform3D(4.32117, 0, -2.6899, 0, 5.09, 0, 2.6899, 0, 4.32117, 14.8539, 22.2908, 38.4117) +shape = SubResource("BoxShape3D_1bvp3") + +[node name="StaticBody3D5" type="StaticBody3D" parent="."] +transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -23.595, 0, 0) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D5"] +transform = Transform3D(4.74707, 0, 1.83669, 0, 5.09, 0, -1.83669, 0, 4.74707, 14.854, 22.291, -34.2884) +shape = SubResource("BoxShape3D_1bvp3") + +[node name="Player3" parent="." instance=ExtResource("4_1bvp3")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.72766, 4.42694, 16.2438) + +[node name="PlayerManager" parent="." node_paths=PackedStringArray("fox") instance=ExtResource("3_lquwl")] +fox = NodePath("../Player3") + +[node name="Player" parent="PlayerManager" instance=ExtResource("4_1bvp3")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.895613, 9.62245, -1.52932) +initial_model = 1 + +[node name="Player2" parent="PlayerManager" instance=ExtResource("4_1bvp3")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6.52864, 12.2658, -1.05488) +initial_model = 1 diff --git a/player.gd b/player.gd index 3c1e6cf..6044124 100644 --- a/player.gd +++ b/player.gd @@ -1,14 +1,56 @@ extends CharacterBody3D class_name Player -var input: PlayerInputData +var _input: PlayerInputData = null + +var input: PlayerInputData: + set(v): + if _input != null: + _input.drop.disconnect(drop) + _input.claimed = false + _input = v + if _input != null: + _input.drop.connect(drop) + _input.claimed = true + get: + return _input const SPEED = 5.0 const JUMP_VELOCITY = 4.5 -@onready var model = %fox +enum initial { + fox, + vole, +} +@export var initial_model: initial + +@onready var model = %vole if initial_model == initial.vole else %fox + + +func drop(): + _input = null + +func _ready() -> void: + %vole.visible = false + %fox.visible = false + model.visible = true + if model == %vole: + $VoleShape.visible = true + $FoxShape.visible = false + else: + $VoleShape.visible = false + $FoxShape.visible = true func _physics_process(delta: float) -> void: + if global_transform.origin.y < -100.0: + queue_free() + if not model.is_busy(): + if not is_on_floor(): + velocity.y = -10.0 + else: + velocity.y = 0.0 + if input == null: + return if not model.is_busy(): var direction := input.walk_dir if direction: diff --git a/player.tscn b/player.tscn index f4a39ca..b55bd13 100644 --- a/player.tscn +++ b/player.tscn @@ -1,19 +1,32 @@ -[gd_scene load_steps=4 format=3 uid="uid://54sf77urgp3h"] +[gd_scene load_steps=6 format=3 uid="uid://54sf77urgp3h"] [ext_resource type="Script" uid="uid://ccyxlwjirmyt0" path="res://player.gd" id="1_4flbx"] [ext_resource type="PackedScene" uid="uid://dwm6v58p82b57" path="res://fox.tscn" id="2_onrkg"] +[ext_resource type="PackedScene" uid="uid://dlpr8asp0m21a" path="res://vole.tscn" id="3_i3pqv"] + +[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_hqtel"] +radius = 0.762944 +height = 3.10227 [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_i3pqv"] -radius = 1.96912 -height = 5.13133 +radius = 0.451108 +height = 0.902216 [node name="Player" type="CharacterBody3D"] script = ExtResource("1_4flbx") [node name="FoxShape" type="CollisionShape3D" parent="."] -transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 1.9351, 0.152762) +transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0.508804, -0.199759) +shape = SubResource("CapsuleShape3D_hqtel") + +[node name="VoleShape" type="CollisionShape3D" parent="."] +transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0.346315, -0.203995) shape = SubResource("CapsuleShape3D_i3pqv") [node name="fox" parent="." instance=ExtResource("2_onrkg")] unique_name_in_owner = true transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, 0, 0) + +[node name="vole" parent="." instance=ExtResource("3_i3pqv")] +unique_name_in_owner = true +transform = Transform3D(-1, 0, 8.74228e-08, 0, 1, 0, -8.74228e-08, 0, -1, 0, 0, 0) diff --git a/player_manager.gd b/player_manager.gd new file mode 100644 index 0000000..d9bb2f6 --- /dev/null +++ b/player_manager.gd @@ -0,0 +1,59 @@ +extends Node3D +class_name PlayerManager + +@export var fox: Player + +func _ready() -> void: + PlayerInput.player_join.connect(player_join) + +func assign_unassigned(data: PlayerInputData) -> bool: + for child in get_children(): + if child.input == null: + child.input = data + return true + return false + +func is_assigned(data: PlayerInputData) -> bool: + for child in get_children(): + if child.input == data: + return true + return false + +func switch_player(data: PlayerInputData): + if fox.input == null: + data.drop.emit() + fox.input = data + return + if not is_assigned(data): + assign_unassigned(data) + else: + var children = get_children() + var i := 0 + while i < children.size(): + if children[i].input == data: + break + i += 1 + if i == children.size(): + return + var j := 0 + while j < children.size() - 1: + var ii := (i + 1 + j) % children.size() + if children[ii].input == null: + children[i].input = null + children[ii].input = data + return + j += 1 + + +func player_join(data: PlayerInputData): + if fox.input == null: + fox.input = data + return + assign_unassigned(data) + +func _process(_delta: float) -> void: + var count := get_children().size() + if count == 0: + get_tree().change_scene_to_file("res://fox_win_text.tscn") + elif count >= 20: + get_tree().change_scene_to_file("res://vole_win_text.tscn") diff --git a/player_manager.gd.uid b/player_manager.gd.uid new file mode 100644 index 0000000..270c4eb --- /dev/null +++ b/player_manager.gd.uid @@ -0,0 +1 @@ +uid://boqwl77kugp5o diff --git a/player_manager.tscn b/player_manager.tscn new file mode 100644 index 0000000..8a8e0a9 --- /dev/null +++ b/player_manager.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=3 uid="uid://2fdkfui13p2"] + +[ext_resource type="Script" uid="uid://boqwl77kugp5o" path="res://player_manager.gd" id="1_4ihkx"] + +[node name="PlayerManager" type="Node3D"] +script = ExtResource("1_4ihkx") diff --git a/project.godot b/project.godot index 30b0abe..5405edb 100644 --- a/project.godot +++ b/project.godot @@ -10,8 +10,8 @@ config_version=5 [application] -run/main_scene="uid://cgpuhiledvecy" -config/features=PackedStringArray("4.5") +run/main_scene="uid://bol2yxcuqnlco" +config/features=PackedStringArray("4.4") [autoload] diff --git a/snow_ground.gdshader b/snow_ground.gdshader new file mode 100644 index 0000000..0ae917b --- /dev/null +++ b/snow_ground.gdshader @@ -0,0 +1,23 @@ +shader_type spatial; + +varying vec3 pos; +varying vec3 norm; +uniform sampler2D space_color : source_color, repeat_disable; +uniform vec3 line_color : source_color; + +uniform float scale = 1000.0; + +#include "noise.gdshaderinc" + +void vertex() { + norm = NORMAL; + pos = VERTEX; +} + +void fragment() { + ALBEDO = line_color; + if (norm.y > 0.7 && mod(pos.y, 5) > 0.2) { + float f = shell_worley(pos, scale); + ALBEDO = texture(space_color, vec2(f)).rgb; + } +} diff --git a/snow_ground.gdshader.uid b/snow_ground.gdshader.uid new file mode 100644 index 0000000..91a4781 --- /dev/null +++ b/snow_ground.gdshader.uid @@ -0,0 +1 @@ +uid://h7lexcd2td6u diff --git a/snow_ground.material.depren b/snow_ground.material.depren new file mode 100644 index 0000000..a802a90 Binary files /dev/null and b/snow_ground.material.depren differ diff --git a/snow_ground.tres b/snow_ground.tres new file mode 100644 index 0000000..44f1005 --- /dev/null +++ b/snow_ground.tres @@ -0,0 +1,16 @@ +[gd_resource type="ShaderMaterial" load_steps=4 format=3 uid="uid://cuao3o0agwaei"] + +[ext_resource type="Shader" uid="uid://h7lexcd2td6u" path="res://snow_ground.gdshader" id="1_3o7ea"] + +[sub_resource type="Gradient" id="Gradient_j6wpu"] +colors = PackedColorArray(0.960784, 1, 1, 1, 0.541182, 0.877096, 0.999999, 1) + +[sub_resource type="GradientTexture1D" id="GradientTexture1D_6ccw5"] +gradient = SubResource("Gradient_j6wpu") + +[resource] +render_priority = 0 +shader = ExtResource("1_3o7ea") +shader_parameter/space_color = SubResource("GradientTexture1D_6ccw5") +shader_parameter/line_color = Color(0.871027, 0.999864, 1, 1) +shader_parameter/scale = 0.235 diff --git a/snow_particles.tscn b/snow_particles.tscn new file mode 100644 index 0000000..df3fede --- /dev/null +++ b/snow_particles.tscn @@ -0,0 +1,111 @@ +[gd_scene load_steps=7 format=3 uid="uid://cpap2mt61s2m"] + +[sub_resource type="Shader" id="Shader_opj16"] +code = "// NOTE: Shader automatically converted from Godot Engine 4.2.1.stable's StandardMaterial3D. + +shader_type spatial; +render_mode blend_mix,depth_draw_opaque,cull_back,unshaded; +uniform vec4 albedo : source_color; +uniform sampler2D texture_albedo : source_color,filter_linear_mipmap,repeat_enable; +uniform float point_size : hint_range(0,128); +uniform float roughness : hint_range(0,1); +uniform sampler2D texture_metallic : hint_default_white,filter_linear_mipmap,repeat_enable; +uniform vec4 metallic_texture_channel; +uniform sampler2D texture_roughness : hint_roughness_r,filter_linear_mipmap,repeat_enable; +uniform float specular; +uniform float metallic; +uniform int particles_anim_h_frames; +uniform int particles_anim_v_frames; +uniform bool particles_anim_loop; +uniform vec3 uv1_scale; +uniform vec3 uv1_offset; +uniform vec3 uv2_scale; +uniform vec3 uv2_offset; + +uniform sampler2D life_alpha : repeat_disable; + +varying float life; + +void vertex() { + life = INSTANCE_CUSTOM.y; + UV=UV*uv1_scale.xy+uv1_offset.xy; + mat4 mat_world = mat4(normalize(INV_VIEW_MATRIX[0]), normalize(INV_VIEW_MATRIX[1]) ,normalize(INV_VIEW_MATRIX[2]), MODEL_MATRIX[3]); + mat_world = mat_world * mat4(vec4(cos(INSTANCE_CUSTOM.x), -sin(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(sin(INSTANCE_CUSTOM.x), cos(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); + MODELVIEW_MATRIX = VIEW_MATRIX * mat_world; + MODELVIEW_NORMAL_MATRIX = mat3(MODELVIEW_MATRIX); + float h_frames = float(particles_anim_h_frames); + float v_frames = float(particles_anim_v_frames); + float particle_total_frames = float(particles_anim_h_frames * particles_anim_v_frames); + float particle_frame = floor(INSTANCE_CUSTOM.z * float(particle_total_frames)); + if (!particles_anim_loop) { + particle_frame = clamp(particle_frame, 0.0, particle_total_frames - 1.0); + } else { + particle_frame = mod(particle_frame, particle_total_frames); + } + UV /= vec2(h_frames, v_frames); + UV += vec2(mod(particle_frame, h_frames) / h_frames, floor((particle_frame + 0.5) / h_frames) / v_frames); +} + + + + + +void fragment() { + if (length(UV - vec2(0.5)) > 0.05) { + discard; + } + vec2 base_uv = UV; + vec4 albedo_tex = texture(texture_albedo,base_uv); + ALBEDO = albedo.rgb * albedo_tex.rgb; + float metallic_tex = dot(texture(texture_metallic,base_uv),metallic_texture_channel); + METALLIC = metallic_tex * metallic; + vec4 roughness_texture_channel = vec4(1.0,0.0,0.0,0.0); + float roughness_tex = dot(texture(texture_roughness,base_uv),roughness_texture_channel); + ROUGHNESS = roughness_tex * roughness; + SPECULAR = specular; + ALPHA = texture(life_alpha, vec2(life)).r; +} +" + +[sub_resource type="Curve" id="Curve_x40c4"] +_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(0.904632, 0.855861), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] +point_count = 3 + +[sub_resource type="CurveTexture" id="CurveTexture_j7b0c"] +curve = SubResource("Curve_x40c4") + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_cn13f"] +render_priority = 0 +shader = SubResource("Shader_opj16") +shader_parameter/albedo = Color(1, 1, 1, 1) +shader_parameter/point_size = 1.0 +shader_parameter/roughness = 1.0 +shader_parameter/metallic_texture_channel = Vector4(0, 0, 0, 0) +shader_parameter/specular = 0.5 +shader_parameter/metallic = 0.0 +shader_parameter/particles_anim_h_frames = 1 +shader_parameter/particles_anim_v_frames = 1 +shader_parameter/particles_anim_loop = false +shader_parameter/uv1_scale = Vector3(1, 1, 1) +shader_parameter/uv1_offset = Vector3(0, 0, 0) +shader_parameter/uv2_scale = Vector3(1, 1, 1) +shader_parameter/uv2_offset = Vector3(0, 0, 0) +shader_parameter/life_alpha = SubResource("CurveTexture_j7b0c") + +[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_c4a1g"] +emission_shape = 3 +emission_box_extents = Vector3(10, 0, 2) +turbulence_enabled = true +turbulence_noise_strength = 0.05 +turbulence_noise_scale = 2.756 + +[sub_resource type="QuadMesh" id="QuadMesh_sfy6f"] + +[node name="GPUParticles3D" type="GPUParticles3D"] +material_override = SubResource("ShaderMaterial_cn13f") +amount = 300 +lifetime = 10.0 +preprocess = 10.0 +local_coords = true +process_material = SubResource("ParticleProcessMaterial_c4a1g") +draw_pass_1 = SubResource("QuadMesh_sfy6f") diff --git a/terrain.glb b/terrain.glb new file mode 100644 index 0000000..890cf9c Binary files /dev/null and b/terrain.glb differ diff --git a/terrain.glb.import b/terrain.glb.import new file mode 100644 index 0000000..ab06cb4 --- /dev/null +++ b/terrain.glb.import @@ -0,0 +1,51 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://ryjsgbrkvv16" +path="res://.godot/imported/terrain.glb-b2160bb0ba4a5beeb4fac37d95b0a850.scn" + +[deps] + +source_file="res://terrain.glb" +dest_files=["res://.godot/imported/terrain.glb-b2160bb0ba4a5beeb4fac37d95b0a850.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +_subresources={ +"materials": { +"snow": { +"use_external/enabled": true, +"use_external/fallback_path": "res://snow_ground.tres", +"use_external/path": "uid://cuao3o0agwaei" +} +}, +"nodes": { +"PATH:Terrain": { +"generate/physics": true, +"physics/shape_type": 2 +} +} +} +gltf/naming_version=1 +gltf/embedded_image_handling=1 diff --git a/terrain.tscn b/terrain.tscn new file mode 100644 index 0000000..ba1ceac --- /dev/null +++ b/terrain.tscn @@ -0,0 +1,5 @@ +[gd_scene load_steps=2 format=3 uid="uid://cj7l76arpv3ib"] + +[ext_resource type="PackedScene" uid="uid://ryjsgbrkvv16" path="res://terrain.glb" id="1_206su"] + +[node name="terrain" instance=ExtResource("1_206su")] diff --git a/text_scene.tscn b/text_scene.tscn new file mode 100644 index 0000000..2e80d33 --- /dev/null +++ b/text_scene.tscn @@ -0,0 +1,35 @@ +[gd_scene format=3 uid="uid://wt0fxawif12f"] + +[node name="TextScene" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="ColorRect" type="ColorRect" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +color = Color(0, 0, 0, 1) + +[node name="Label" type="Label" parent="."] +layout_mode = 1 +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -155.0 +offset_top = -208.0 +offset_right = 181.0 +offset_bottom = 200.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_colors/font_color = Color(1, 1, 1, 1) +text = "This is text" +autowrap_mode = 3 diff --git a/thumbnail.png b/thumbnail.png new file mode 100644 index 0000000..c109929 Binary files /dev/null and b/thumbnail.png differ diff --git a/thumbnail.png.import b/thumbnail.png.import new file mode 100644 index 0000000..91821f5 --- /dev/null +++ b/thumbnail.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://caker2oony8dq" +path="res://.godot/imported/thumbnail.png-3f545d161fd110f6ef4e5b6d4c7c77a7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://thumbnail.png" +dest_files=["res://.godot/imported/thumbnail.png-3f545d161fd110f6ef4e5b6d4c7c77a7.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/vole.gd b/vole.gd index 09f107c..c06ffc7 100644 --- a/vole.gd +++ b/vole.gd @@ -3,6 +3,9 @@ extends Node3D @onready var playback: AnimationNodeStateMachinePlayback = %AnimationTree.get("parameters/playback") @export var pouncing := false +func _ready() -> void: + $Breed.paused = true + func idle(): playback.travel("Idle") @@ -17,3 +20,42 @@ func is_busy(): func root_motion(): return %AnimationTree.get_root_motion_position() + +func caught(): + var manager: PlayerManager = $"../.." + manager.switch_player($"..".input) + $"..".queue_free() + +var can_press: bool = true +func _process(_delta: float) -> void: + if not visible: + return + var input: PlayerInputData = $"..".input + if input == null: + $Breed.paused = true + return + $Breed.paused = not breeding + if input.raw_dig or input.raw_jump: + if can_press: + var manager: PlayerManager = $"../.." + manager.switch_player(input) + can_press = false + else: + can_press = true + + +var breeding = false +func _on_area_3d_on() -> void: + breeding = true + + +func _on_area_3d_off() -> void: + breeding = false + +func _on_breed_timeout() -> void: + if randi_range(0, 2) == 2 or true: + var new: Player = load("res://player.tscn").instantiate() + new.transform = get_parent().transform + new.transform.origin.y += 1. + new.initial_model = Player.initial.vole + get_parent().get_parent().add_child(new) diff --git a/vole.tscn b/vole.tscn index 2aea85e..a36d5c3 100644 --- a/vole.tscn +++ b/vole.tscn @@ -1,20 +1,55 @@ -[gd_scene load_steps=5 format=3 uid="uid://dlpr8asp0m21a"] +[gd_scene load_steps=11 format=3 uid="uid://dlpr8asp0m21a"] [ext_resource type="PackedScene" uid="uid://cg7vjpjmg60ti" path="res://vole.glb" id="1_fw737"] [ext_resource type="Script" uid="uid://dxdgep3hm0i8d" path="res://vole.gd" id="2_6xove"] +[ext_resource type="Script" uid="uid://bufpuqvrhkv8t" path="res://area_3d.gd" id="3_ldwnh"] -[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_fw737"] -animation = &"IDLE" +[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_6xove"] +animation = &"Idle" + +[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_ldwnh"] +animation = &"Walk2" + +[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_b8ce1"] +advance_mode = 2 + +[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_qawrn"] + +[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_xxacn"] [sub_resource type="AnimationNodeStateMachine" id="AnimationNodeStateMachine_fw737"] -states/IDLE/node = SubResource("AnimationNodeAnimation_fw737") -states/IDLE/position = Vector2(411, 153) +states/Idle/node = SubResource("AnimationNodeAnimation_6xove") +states/Idle/position = Vector2(532, 98) +states/Walk/node = SubResource("AnimationNodeAnimation_ldwnh") +states/Walk/position = Vector2(453, 50) +transitions = ["Start", "Idle", SubResource("AnimationNodeStateMachineTransition_b8ce1"), "Walk", "Idle", SubResource("AnimationNodeStateMachineTransition_qawrn"), "Idle", "Walk", SubResource("AnimationNodeStateMachineTransition_xxacn")] + +[sub_resource type="SphereShape3D" id="SphereShape3D_6xove"] +radius = 2.42109 [node name="vole" instance=ExtResource("1_fw737")] script = ExtResource("2_6xove") [node name="AnimationTree" type="AnimationTree" parent="." index="2"] +unique_name_in_owner = true +root_node = NodePath("%AnimationTree/..") root_motion_track = NodePath("VoleRig/Skeleton3D:root") root_motion_local = false tree_root = SubResource("AnimationNodeStateMachine_fw737") anim_player = NodePath("../AnimationPlayer") + +[node name="Area3D" type="Area3D" parent="." index="3"] +script = ExtResource("3_ldwnh") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Area3D" index="0"] +shape = SubResource("SphereShape3D_6xove") + +[node name="Breed" type="Timer" parent="." index="4"] +wait_time = 5.0 +autostart = true + +[connection signal="area_entered" from="Area3D" to="Area3D" method="_on_area_entered"] +[connection signal="area_exited" from="Area3D" to="Area3D" method="_on_area_exited"] +[connection signal="off" from="Area3D" to="." method="_on_area_3d_off"] +[connection signal="on" from="Area3D" to="." method="_on_area_3d_on"] +[connection signal="timeout" from="Breed" to="." method="_on_breed_timeout"] diff --git a/vole_catcher.gd b/vole_catcher.gd new file mode 100644 index 0000000..08fee14 --- /dev/null +++ b/vole_catcher.gd @@ -0,0 +1,11 @@ +extends Area3D + +var caught = Dictionary() + +func _on_area_entered(area: Area3D) -> void: + if area is VoleDetector: + caught[area as VoleDetector] = 0 + +func _on_area_exited(area: Area3D) -> void: + if area is VoleDetector: + caught.erase(area) diff --git a/vole_catcher.gd.uid b/vole_catcher.gd.uid new file mode 100644 index 0000000..987d8d8 --- /dev/null +++ b/vole_catcher.gd.uid @@ -0,0 +1 @@ +uid://cp541kkdti4y diff --git a/vole_win_text.tscn b/vole_win_text.tscn new file mode 100644 index 0000000..58672ac --- /dev/null +++ b/vole_win_text.tscn @@ -0,0 +1,9 @@ +[gd_scene load_steps=2 format=3 uid="uid://b6wak1fhycx13"] + +[ext_resource type="PackedScene" uid="uid://bat5qdtcsb6kv" path="res://end_text.tscn" id="1_ojax6"] + +[node name="TextScene" instance=ExtResource("1_ojax6")] + +[node name="Label" parent="." index="1"] +text = "The voles cover the mountain and squeak together bringing about a huge avalanche freezing the fox until Spring." +autowrap_mode = 1