This commit is contained in:
Spencer Killen 2025-03-30 18:43:56 -06:00
parent 00c29e66fd
commit 46bc410f05
Signed by: sjkillen
GPG key ID: 3AF3117BA6FBB75B
43 changed files with 748 additions and 42 deletions

View file

@ -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()

View file

@ -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

Binary file not shown.

25
area_3d.gd Normal file
View file

@ -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

1
area_3d.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://bufpuqvrhkv8t

BIN
blends/terrain.blend Normal file

Binary file not shown.

BIN
blends/terrain.blend1 Normal file

Binary file not shown.

27
box_art.tscn Normal file
View file

@ -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)

BIN
builds/avalanche_season.exe Normal file

Binary file not shown.

BIN
builds/avalanche_season.pck Normal file

Binary file not shown.

BIN
builds/avalanche_season.x86_64 Executable file

Binary file not shown.

6
button.gd Normal file
View file

@ -0,0 +1,6 @@
extends Button
func _on_pressed() -> void:
get_tree().change_scene_to_file("res://main.tscn")

1
button.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://co7lut3licn2s

17
end_text.tscn Normal file
View file

@ -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"]

6
fox.gd
View file

@ -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()

View file

@ -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"]

9
fox_win_text.tscn Normal file
View file

@ -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

37
intro_text.tscn Normal file
View file

@ -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"]

5
main.gd Normal file
View file

@ -0,0 +1,5 @@
extends Node3D
func _ready() -> void:
PlayerInput.restart()

1
main.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://d1hwmc7erkys0

View file

@ -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

View file

@ -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:

View file

@ -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)

59
player_manager.gd Normal file
View file

@ -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")

1
player_manager.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://boqwl77kugp5o

6
player_manager.tscn Normal file
View file

@ -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")

View file

@ -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]

23
snow_ground.gdshader Normal file
View file

@ -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;
}
}

1
snow_ground.gdshader.uid Normal file
View file

@ -0,0 +1 @@
uid://h7lexcd2td6u

BIN
snow_ground.material.depren Normal file

Binary file not shown.

16
snow_ground.tres Normal file
View file

@ -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

111
snow_particles.tscn Normal file
View file

@ -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")

BIN
terrain.glb Normal file

Binary file not shown.

51
terrain.glb.import Normal file
View file

@ -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

5
terrain.tscn Normal file
View file

@ -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")]

35
text_scene.tscn Normal file
View file

@ -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

BIN
thumbnail.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

34
thumbnail.png.import Normal file
View file

@ -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

42
vole.gd
View file

@ -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)

View file

@ -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"]

11
vole_catcher.gd Normal file
View file

@ -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)

1
vole_catcher.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://cp541kkdti4y

9
vole_win_text.tscn Normal file
View file

@ -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