Compare commits

...

20 commits

Author SHA1 Message Date
2f646169fb
initial ring map support (#2) 2025-05-04 00:36:12 +02:00
edf99640cf
Fix memory leak and save file deletion + other stuff
might also be the commit where timer starts only when you move
2025-05-03 14:33:49 +02:00
709ce8eea3
split gravity logic, various bug fixes
fixed gravity strength being possibly strong at level beginning
fixed restarting being allowed after getting the last ring
fixed save file's "played_for" being reset or set to another file's
fixed the displayed save file total play time not being updated on main menu

maybe there's other stuff
2025-04-29 21:18:04 +02:00
38897c706a
"save" & animate main menu, fix pause menu & restart (#3)
pause menu had classic issues of mouse inputs being eaten by something else (gravity)
restart didn't have working code anymore because of level logic changes
also remove the demo scene which I believe is unused beyond the jam version
2025-04-27 21:30:03 +02:00
71441a9335
show level name, best time, and thumbnail (#3)
now thumbnails need to be made
2025-04-25 16:03:36 +02:00
59bed24acd
simple level selection menu, change level logic (#3) 2025-04-24 14:54:54 +02:00
9890e0a625
new ring counter, move some logic away from main scene 2025-04-23 15:37:03 +02:00
b81eb08e05
new speed display + save best level times (#3) 2025-04-21 16:06:56 +02:00
ac1f29d111
new timer + save times to save files (#3) 2025-04-20 23:25:51 +02:00
7ae566720c
integrate a semi-working manager for save files (#3) 2025-04-16 00:16:39 +02:00
18dae312eb
sound effects for the main menu
started working on this like 2 weeks ago

then stuff happened and now I forgot what I was doing 👍
2025-04-14 23:07:52 +02:00
ff8bd770d2 preliminary support for controllers 2025-03-31 17:57:54 +02:00
8f18e43af7 implement the new main menu into the actual game 2025-03-30 15:40:22 +02:00
a73b32610e working settings menu
includes audio sliders, fullscreen, disabling gravity change sound
2025-03-28 13:42:53 +01:00
eefda9e2bd start creating the framework for menus (#3)
all very experimental so it'll see lots of changes
2025-03-27 16:00:39 +01:00
f7e85724b3 reduce video memory usage by orders of magnitude
big fonts use lots of big lumalpha8, so just scale up small fonts
2025-03-25 23:18:33 +01:00
df7736a9d1 better in-game timer
as in, use `_process()` and add a number
could you lag on purpose before finishing to cut time? probably not
2025-03-25 17:48:00 +01:00
4afec6386c graphics update: forest level 2025-03-25 13:39:03 +01:00
c0aed38065 properly fade out the music when finishing a level 2025-03-24 18:13:08 +01:00
a3e0c4d82d move to Godot 4.4 (from Godot 4.3) 2025-03-23 14:48:54 +01:00
56 changed files with 2332 additions and 802 deletions

9
default_bus_layout.tres Normal file
View file

@ -0,0 +1,9 @@
[gd_resource type="AudioBusLayout" format=3 uid="uid://bgs4iykhuoux0"]
[resource]
bus/1/name = &"Sounds"
bus/1/solo = false
bus/1/mute = false
bus/1/bypass_fx = false
bus/1/volume_db = 0.00282288
bus/1/send = &"Master"

View file

@ -1,43 +1,80 @@
[gd_scene load_steps=4 format=3 uid="uid://cnnvwotv33u1b"] [gd_scene load_steps=11 format=3 uid="uid://cnnvwotv33u1b"]
[ext_resource type="PackedScene" uid="uid://dw0xl8644x166" path="res://elements/gravity.tscn" id="1_h0h2o"]
[ext_resource type="PackedScene" uid="uid://df5m716pd6mej" path="res://elements/sphere.tscn" id="2_ophnk"]
[sub_resource type="GDScript" id="GDScript_bnqcw"] [sub_resource type="GDScript" id="GDScript_bnqcw"]
script/source = "extends Node3D script/source = "class_name Player
extends Node3D
func _process(_delta: float) -> void: signal velocity_change
var velocity := 0.0:
get: return velocity
set(value):
if value != velocity:
velocity_change.emit(value)
velocity = value
@onready var ball_position: Vector3 = $Sphere.position
func _physics_process(_delta: float) -> void:
ball_position = $Sphere.position
$SpotLightMain.position = $Sphere.position + Vector3(0, 5, 0) $SpotLightMain.position = $Sphere.position + Vector3(0, 5, 0)
$SpotLightTop.position = $Sphere.position $SpotLightTop.position = $Sphere.position
$SpotLightLeft.position = $Sphere.position $SpotLightLeft.position = $Sphere.position
$SpotLightRight.position = $Sphere.position $SpotLightRight.position = $Sphere.position
$SpotLightBottom.position = $Sphere.position $SpotLightBottom.position = $Sphere.position
## Keep the ball at the center of the camera, at a distance # Keep the ball at the center of the camera, at a distance
$Camera.position = $Sphere.position + Vector3(0, 0, 15) $Camera.position = $Sphere.position + Vector3(0, 0, 15)
## Angle of the camera, so the player can see where the ball is going # Angle of the camera, so the player can see where the ball is going
var velocity: Vector3 = $Sphere.linear_velocity velocity = abs($Sphere.linear_velocity.x) + abs($Sphere.linear_velocity.y)
var desired_x = max(min(velocity.y, 35), -35) var desired_x = max(min($Sphere.linear_velocity.y, 35), -35)
var desired_y = max(min(-velocity.x, 50), -50) var desired_y = max(min(-$Sphere.linear_velocity.x, 50), -50)
var difference_x = $Camera.rotation_degrees.x - desired_x var difference_x = $Camera.rotation_degrees.x - desired_x
var difference_y = $Camera.rotation_degrees.y - desired_y var difference_y = $Camera.rotation_degrees.y - desired_y
$Camera.rotation_degrees.x -= max(min(difference_x / 2, 3), -3) $Camera.rotation_degrees.x -= max(min(difference_x / 2, 3), -3)
$Camera.rotation_degrees.y -= max(min(difference_y / 2, 3), -3) $Camera.rotation_degrees.y -= max(min(difference_y / 2, 3), -3)
## FOV of the camera, so it unzooms more at higher velocities # FOV of the camera, so it unzooms more at higher velocities
const default_fov = 75 const default_fov = 75
var total_velocity = abs(velocity.x) + abs(velocity.y) $Camera.fov = default_fov + (velocity / 12)
$Camera.fov = default_fov + (total_velocity / 12)
" "
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_vumbr"]
bounce = 0.2
[sub_resource type="SphereShape3D" id="SphereShape3D_xfgrm"]
[sub_resource type="Gradient" id="Gradient_bgp4x"]
colors = PackedColorArray(0.942957, 7.89344e-06, 0.597148, 1, 0, 0.9912, 0.9912, 1)
[sub_resource type="GradientTexture2D" id="GradientTexture2D_5d6uk"]
gradient = SubResource("Gradient_bgp4x")
fill_from = Vector2(0.504951, 0.00495049)
fill_to = Vector2(0.549505, 1)
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_qcgmu"]
albedo_texture = SubResource("GradientTexture2D_5d6uk")
[sub_resource type="SphereMesh" id="SphereMesh_bor8g"]
material = SubResource("StandardMaterial3D_qcgmu")
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_4tofj"]
direction = Vector3(0, 0, 0)
gravity = Vector3(0, 0, 0)
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_2ybet"]
vertex_color_use_as_albedo = true
albedo_color = Color(0, 0.734117, 0.734117, 1)
[sub_resource type="SphereMesh" id="SphereMesh_1m3ut"]
material = SubResource("StandardMaterial3D_2ybet")
radius = 0.2
height = 0.4
radial_segments = 8
rings = 4
[node name="Player" type="Node3D"] [node name="Player" type="Node3D"]
script = SubResource("GDScript_bnqcw") script = SubResource("GDScript_bnqcw")
[node name="Gravity" parent="." instance=ExtResource("1_h0h2o")]
[node name="Sphere" parent="." instance=ExtResource("2_ophnk")]
[node name="Camera" type="Camera3D" parent="."] [node name="Camera" type="Camera3D" parent="."]
current = true current = true
@ -61,3 +98,21 @@ spot_range = 50.0
[node name="SpotLightBottom" type="SpotLight3D" parent="."] [node name="SpotLightBottom" type="SpotLight3D" parent="."]
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 0, 0) transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 0, 0)
spot_range = 50.0 spot_range = 50.0
[node name="Sphere" type="RigidBody3D" parent="."]
collision_priority = 100.0
axis_lock_linear_z = true
physics_material_override = SubResource("PhysicsMaterial_vumbr")
can_sleep = false
contact_monitor = true
[node name="CollisionShape3D" type="CollisionShape3D" parent="Sphere"]
shape = SubResource("SphereShape3D_xfgrm")
[node name="MeshInstance3D" type="MeshInstance3D" parent="Sphere"]
mesh = SubResource("SphereMesh_bor8g")
[node name="GPUParticles3D" type="GPUParticles3D" parent="Sphere"]
amount = 16
process_material = SubResource("ParticleProcessMaterial_4tofj")
draw_pass_1 = SubResource("SphereMesh_1m3ut")

14
elements/ring.gd Normal file
View file

@ -0,0 +1,14 @@
class_name Ring
extends CSGTorus3D
var happy_material = preload("res://graphics/happy_material.tres")
var collected = false
signal collect_signal
func _on_area_3d_body_entered(body: Node3D) -> void:
if collected == false and body.name == "Sphere":
self.material = happy_material
collected = true
$AudioStreamPlayer.play()
collect_signal.emit()

1
elements/ring.gd.uid Normal file
View file

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

View file

@ -2,24 +2,9 @@
[ext_resource type="Material" uid="uid://brwwlwb1rpro7" path="res://graphics/unhappy_material.tres" id="1_48h5f"] [ext_resource type="Material" uid="uid://brwwlwb1rpro7" path="res://graphics/unhappy_material.tres" id="1_48h5f"]
[ext_resource type="AudioStream" uid="uid://b0cl5v6q1ocbv" path="res://sounds/ring1.ogg" id="2_2so43"] [ext_resource type="AudioStream" uid="uid://b0cl5v6q1ocbv" path="res://sounds/ring1.ogg" id="2_2so43"]
[ext_resource type="Script" uid="uid://d1tdcd6b2bp05" path="res://elements/ring.gd" id="2_288uq"]
[ext_resource type="AudioStream" uid="uid://cvvs74ep5d4wt" path="res://sounds/ring2.ogg" id="3_lkqw0"] [ext_resource type="AudioStream" uid="uid://cvvs74ep5d4wt" path="res://sounds/ring2.ogg" id="3_lkqw0"]
[sub_resource type="GDScript" id="GDScript_86vhg"]
script/source = "extends CSGTorus3D
var happy_material = preload(\"res://graphics/happy_material.tres\")
var collected = false
signal collect_signal
func _on_area_3d_body_entered(body: Node3D) -> void:
if collected == false and body.name == \"Sphere\":
self.material = happy_material
collected = true
$AudioStreamPlayer.play()
collect_signal.emit()
"
[sub_resource type="CylinderShape3D" id="CylinderShape3D_tgirv"] [sub_resource type="CylinderShape3D" id="CylinderShape3D_tgirv"]
radius = 4.0 radius = 4.0
@ -33,10 +18,11 @@ stream_1/stream = ExtResource("3_lkqw0")
use_collision = true use_collision = true
inner_radius = 4.0 inner_radius = 4.0
outer_radius = 8.0 outer_radius = 8.0
sides = 16 sides = 32
ring_sides = 8 ring_sides = 16
material = ExtResource("1_48h5f") material = ExtResource("1_48h5f")
script = SubResource("GDScript_86vhg") script = ExtResource("2_288uq")
metadata/_custom_type_script = "uid://d1tdcd6b2bp05"
[node name="Area3D" type="Area3D" parent="."] [node name="Area3D" type="Area3D" parent="."]
@ -45,5 +31,6 @@ shape = SubResource("CylinderShape3D_tgirv")
[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."] [node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."]
stream = SubResource("AudioStreamRandomizer_251sn") stream = SubResource("AudioStreamRandomizer_251sn")
bus = &"Sounds"
[connection signal="body_entered" from="Area3D" to="." method="_on_area_3d_body_entered"] [connection signal="body_entered" from="Area3D" to="." method="_on_area_3d_body_entered"]

View file

@ -4,7 +4,7 @@
[node name="Text" type="Label3D" parent="."] [node name="Text" type="Label3D" parent="."]
text = "Sample text" text = "Sample text"
font_size = 1024 font_size = 64
[node name="CSGBox3D" type="CSGBox3D" parent="."] [node name="CSGBox3D" type="CSGBox3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -5.1) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -5.1)

View file

@ -1,52 +0,0 @@
[gd_scene load_steps=10 format=3 uid="uid://df5m716pd6mej"]
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_vumbr"]
bounce = 0.2
[sub_resource type="SphereShape3D" id="SphereShape3D_xfgrm"]
[sub_resource type="Gradient" id="Gradient_bgp4x"]
colors = PackedColorArray(0.942957, 7.89344e-06, 0.597148, 1, 0, 0.9912, 0.9912, 1)
[sub_resource type="GradientTexture2D" id="GradientTexture2D_5d6uk"]
gradient = SubResource("Gradient_bgp4x")
fill_from = Vector2(0.504951, 0.00495049)
fill_to = Vector2(0.549505, 1)
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_qcgmu"]
albedo_texture = SubResource("GradientTexture2D_5d6uk")
[sub_resource type="SphereMesh" id="SphereMesh_bor8g"]
material = SubResource("StandardMaterial3D_qcgmu")
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_4tofj"]
direction = Vector3(0, 0, 0)
gravity = Vector3(0, 0, 0)
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_2ybet"]
vertex_color_use_as_albedo = true
albedo_color = Color(0, 0.734117, 0.734117, 1)
[sub_resource type="SphereMesh" id="SphereMesh_1m3ut"]
material = SubResource("StandardMaterial3D_2ybet")
radius = 0.2
height = 0.4
radial_segments = 8
rings = 4
[node name="Sphere" type="RigidBody3D"]
collision_priority = 100.0
axis_lock_linear_z = true
physics_material_override = SubResource("PhysicsMaterial_vumbr")
contact_monitor = true
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
shape = SubResource("SphereShape3D_xfgrm")
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
mesh = SubResource("SphereMesh_bor8g")
[node name="GPUParticles3D" type="GPUParticles3D" parent="."]
amount = 16
process_material = SubResource("ParticleProcessMaterial_4tofj")
draw_pass_1 = SubResource("SphereMesh_1m3ut")

View file

@ -29,6 +29,7 @@ vertex_color_use_as_albedo = true
albedo_color = Color(0.212217, 0.468618, 0, 1) albedo_color = Color(0.212217, 0.468618, 0, 1)
[node name="Tree" type="Node3D"] [node name="Tree" type="Node3D"]
physics_interpolation_mode = 2
script = SubResource("GDScript_tbkod") script = SubResource("GDScript_tbkod")
[node name="Dirt" type="CSGBox3D" parent="."] [node name="Dirt" type="CSGBox3D" parent="."]

View file

@ -9,9 +9,11 @@ custom_features=""
export_filter="all_resources" export_filter="all_resources"
include_filter="" include_filter=""
exclude_filter="exports/*" exclude_filter="exports/*"
export_path="exports/AlakajamEntry.x86_64" export_path="exports/DreamBall.x86_64"
patches=PackedStringArray()
encryption_include_filters="" encryption_include_filters=""
encryption_exclude_filters="" encryption_exclude_filters=""
seed=0
encrypt_pck=false encrypt_pck=false
encrypt_directory=false encrypt_directory=false
script_export_mode=2 script_export_mode=2
@ -49,9 +51,11 @@ custom_features=""
export_filter="all_resources" export_filter="all_resources"
include_filter="" include_filter=""
exclude_filter="exports/*" exclude_filter="exports/*"
export_path="exports/AlakajamEntry.exe" export_path="exports/DreamBall.exe"
patches=PackedStringArray()
encryption_include_filters="" encryption_include_filters=""
encryption_exclude_filters="" encryption_exclude_filters=""
seed=0
encrypt_pck=false encrypt_pck=false
encrypt_directory=false encrypt_directory=false
script_export_mode=2 script_export_mode=2
@ -114,9 +118,11 @@ custom_features=""
export_filter="all_resources" export_filter="all_resources"
include_filter="" include_filter=""
exclude_filter="exports/*" exclude_filter="exports/*"
export_path="exports/web/AlakajamEntry.html" export_path="exports/web/DreamBall.html"
patches=PackedStringArray()
encryption_include_filters="" encryption_include_filters=""
encryption_exclude_filters="" encryption_exclude_filters=""
seed=0
encrypt_pck=false encrypt_pck=false
encrypt_directory=false encrypt_directory=false
script_export_mode=2 script_export_mode=2

Binary file not shown.

View file

@ -0,0 +1,35 @@
[remap]
importer="font_data_dynamic"
type="FontFile"
uid="uid://c3fsj6knyiuhl"
path="res://.godot/imported/Knewave-Regular.ttf-621ce63e5403426c07f1520fe86b0560.fontdata"
[deps]
source_file="res://fonts/Knewave/Knewave-Regular.ttf"
dest_files=["res://.godot/imported/Knewave-Regular.ttf-621ce63e5403426c07f1520fe86b0560.fontdata"]
[params]
Rendering=null
antialiasing=1
generate_mipmaps=false
disable_embedded_bitmaps=true
multichannel_signed_distance_field=false
msdf_pixel_range=8
msdf_size=48
allow_system_fallback=true
force_autohinter=false
hinting=1
subpixel_positioning=4
keep_rounding_remainders=true
oversampling=0.0
Fallbacks=null
fallbacks=[]
Compress=null
compress=true
preload=[]
language_support={}
script_support={}
opentype_features={}

93
fonts/Knewave/OFL.txt Normal file
View file

@ -0,0 +1,93 @@
Copyright (c) 2010, Tyler Finck <hello@sursly.com>, with Reserved Font Name: "Knewave".
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://openfontlicense.org
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

View file

@ -1,5 +1,5 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://df0n6u78ylb4h"] [gd_resource type="StandardMaterial3D" format=3 uid="uid://df0n6u78ylb4h"]
[resource] [resource]
albedo_color = Color(1, 0, 1, 1) albedo_color = Color(6.73831e-07, 0.700198, 0.789641, 1)
metallic_specular = 0.0 metallic_specular = 1.0

View file

@ -1,4 +1,6 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://brwwlwb1rpro7"] [gd_resource type="StandardMaterial3D" format=3 uid="uid://brwwlwb1rpro7"]
[resource] [resource]
albedo_color = Color(1, 0.32686, 0.232259, 1)
metallic = 1.0 metallic = 1.0
metallic_specular = 0.0

View file

@ -1,4 +1,4 @@
[gd_scene load_steps=8 format=3 uid="uid://dw0xl8644x166"] [gd_scene load_steps=7 format=3 uid="uid://dw0xl8644x166"]
[ext_resource type="Texture2D" uid="uid://ctjugvy1v3y6b" path="res://graphics/arrow.svg" id="1_4mbho"] [ext_resource type="Texture2D" uid="uid://ctjugvy1v3y6b" path="res://graphics/arrow.svg" id="1_4mbho"]
[ext_resource type="AudioStream" uid="uid://dmdbharecy448" path="res://sounds/gravity.ogg" id="2_5uwlw"] [ext_resource type="AudioStream" uid="uid://dmdbharecy448" path="res://sounds/gravity.ogg" id="2_5uwlw"]
@ -6,60 +6,35 @@
[sub_resource type="GDScript" id="GDScript_3yq1l"] [sub_resource type="GDScript" id="GDScript_3yq1l"]
script/source = "extends Control script/source = "extends Control
var player_ready = false @onready var direction_node: TextureRect = $Direction
const normal = 7 @onready var animation: AnimationPlayer = $Direction/AnimationPlayer
const stronger = normal * 3 @onready var audio: AudioStreamPlayer = $Direction/AudioStreamPlayer
func _input(_event: InputEvent) -> void:
if player_ready:
var grav = stronger if Input.is_key_pressed(KEY_SHIFT) else normal
PhysicsServer3D.area_set_param(get_viewport().find_world_3d().space, PhysicsServer3D.AREA_PARAM_GRAVITY, grav)
"
[sub_resource type="GDScript" id="GDScript_my602"]
script/source = "extends TextureRect
func _ready() -> void: func _ready() -> void:
# set the indicator to be fully transparent when it first spawns # set the indicator to be fully transparent when it first spawns
self.self_modulate = Color(1, 1, 1, 0) direction_node.self_modulate = Color(1, 1, 1, 0)
func _input(ev: InputEvent) -> void: func react_to_gravity_change(direction: Vector3) -> void:
if ev is InputEventKey and ev.is_pressed(): if direction == Vector3.UP:
var k = ev.keycode direction_node.rotation_degrees = -90
if k == KEY_UP or k == KEY_RIGHT or k == KEY_LEFT or k == KEY_DOWN: audio.pitch_scale = 1.05
var direction = Vector3() elif direction == Vector3.LEFT:
if k == KEY_UP: direction_node.rotation_degrees = -180
direction = Vector3.UP audio.pitch_scale = 1.02
self.rotation_degrees = -90 elif direction == Vector3.RIGHT:
$AudioStreamPlayer.pitch_scale = 1.05
elif k == KEY_LEFT:
direction = Vector3.LEFT
self.rotation_degrees = -180
$AudioStreamPlayer.pitch_scale = 1.02
elif k == KEY_RIGHT:
direction = Vector3.RIGHT direction = Vector3.RIGHT
self.rotation_degrees = 0 direction_node.rotation_degrees = 0
$AudioStreamPlayer.pitch_scale = 0.98 audio.pitch_scale = 0.98
elif k == KEY_DOWN: elif direction == Vector3.DOWN:
direction = Vector3.DOWN direction_node.rotation_degrees = 90
self.rotation_degrees = 90 audio.pitch_scale = 0.95
$AudioStreamPlayer.pitch_scale = 0.95
if get_parent().player_ready == false or direction != PhysicsServer3D.area_get_param( if animation.is_playing():
get_viewport().find_world_3d().space, animation.stop()
PhysicsServer3D.AREA_PARAM_GRAVITY_VECTOR animation.play(\"grow_fadeout\")
):
get_parent().player_ready = true
PhysicsServer3D.area_set_param(
get_viewport().find_world_3d().space,
PhysicsServer3D.AREA_PARAM_GRAVITY_VECTOR,
direction
)
if $AnimationPlayer.is_playing(): if Settings.sound_on_gravity_change:
$AnimationPlayer.stop() audio.play()
$AudioStreamPlayer.play()
$AnimationPlayer.play(\"grow_fadeout\")
" "
[sub_resource type="Animation" id="Animation_6rwl4"] [sub_resource type="Animation" id="Animation_6rwl4"]
@ -120,8 +95,8 @@ tracks/1/keys = {
[sub_resource type="AnimationLibrary" id="AnimationLibrary_0w0ne"] [sub_resource type="AnimationLibrary" id="AnimationLibrary_0w0ne"]
_data = { _data = {
"RESET": SubResource("Animation_6rwl4"), &"RESET": SubResource("Animation_6rwl4"),
"grow_fadeout": SubResource("Animation_ll6d0") &"grow_fadeout": SubResource("Animation_ll6d0")
} }
[node name="Gravity" type="Control"] [node name="Gravity" type="Control"]
@ -131,6 +106,7 @@ anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
mouse_filter = 2
script = SubResource("GDScript_3yq1l") script = SubResource("GDScript_3yq1l")
[node name="Direction" type="TextureRect" parent="."] [node name="Direction" type="TextureRect" parent="."]
@ -149,15 +125,16 @@ grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
scale = Vector2(0.3, 0.3) scale = Vector2(0.3, 0.3)
pivot_offset = Vector2(400, 400) pivot_offset = Vector2(400, 400)
mouse_filter = 2
texture = ExtResource("1_4mbho") texture = ExtResource("1_4mbho")
script = SubResource("GDScript_my602")
[node name="AnimationPlayer" type="AnimationPlayer" parent="Direction"] [node name="AnimationPlayer" type="AnimationPlayer" parent="Direction"]
libraries = { libraries = {
"": SubResource("AnimationLibrary_0w0ne") &"": SubResource("AnimationLibrary_0w0ne")
} }
[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="Direction"] [node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="Direction"]
stream = ExtResource("2_5uwlw") stream = ExtResource("2_5uwlw")
volume_db = -6.0 volume_db = -6.0
mix_target = 2 mix_target = 2
bus = &"Sounds"

66
gui/map.tscn Normal file
View file

@ -0,0 +1,66 @@
[gd_scene load_steps=2 format=3 uid="uid://bcxbw6wd54ksv"]
[sub_resource type="GDScript" id="GDScript_r4thc"]
script/source = "extends Control
func _ready() -> void:
$TemplateRing.hide()
func display_rings(player: Node3D, rings: Array[Ring]) -> void:
var old_rings_display := $Rings.get_children()
var difference := len(rings) - len(old_rings_display)
# Too many displayed, free them
for i in -difference:
old_rings_display[-(1 + i)].queue_free()
# Not enough displayed, create some
for i in difference:
var new_child := $TemplateRing.duplicate()
new_child.name = \"Ring\" + str(i + 1)
new_child.show()
$Rings.add_child(new_child)
var rings_display := $Rings.get_children()
var center: Vector2i = get_viewport().size / 2
for i in len(rings):
rings_display[i].color = rings[i].material.albedo_color
rings_display[i].rotation = rings[i].rotation.z
rings_display[i].position.x = center.x + rings[i].position.x - player.ball_position.x
rings_display[i].position.y = center.y - rings[i].position.y + player.ball_position.y
if rings[i].collected:
rings_display[i].scale = $TemplateRing.scale * 2 * min(4, max(1, rings[i].scale.x))
else:
rings_display[i].scale = $TemplateRing.scale * 3 * min(4, max(1, rings[i].scale.x))
"
[node name="Map" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = SubResource("GDScript_r4thc")
[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(1, 0, 1, 0.0392157)
[node name="Rings" type="Control" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="TemplateRing" type="ColorRect" parent="."]
layout_mode = 0
offset_right = 2.0
offset_bottom = 2.0

33
gui/rings.tscn Normal file
View file

@ -0,0 +1,33 @@
[gd_scene load_steps=4 format=3 uid="uid://cn55m5dqo3m6u"]
[ext_resource type="FontFile" uid="uid://c3fsj6knyiuhl" path="res://fonts/Knewave/Knewave-Regular.ttf" id="1_nja12"]
[sub_resource type="LabelSettings" id="LabelSettings_cnn6y"]
font = ExtResource("1_nja12")
font_size = 32
outline_size = 8
outline_color = Color(0, 0, 0, 1)
shadow_size = 8
shadow_color = Color(0, 0, 0, 1)
[sub_resource type="GDScript" id="GDScript_nja12"]
script/source = "extends Label
var remaining_rings := 0:
get: return remaining_rings
set(value):
remaining_rings = value
if value >= 1:
var rings_word := \"rings\" if value != 1 else \"ring\"
self.text = str(value) + \" \" + rings_word + \" to go!\"
else:
self.text = \"You did it!!\"
"
[node name="Rings" type="Label"]
offset_right = 109.0
offset_bottom = 23.0
text = "69 rings to go!"
label_settings = SubResource("LabelSettings_cnn6y")
horizontal_alignment = 2
script = SubResource("GDScript_nja12")

34
gui/speed.tscn Normal file
View file

@ -0,0 +1,34 @@
[gd_scene load_steps=4 format=3 uid="uid://cckeamgkt8bqo"]
[ext_resource type="FontFile" uid="uid://c3fsj6knyiuhl" path="res://fonts/Knewave/Knewave-Regular.ttf" id="1_xaun4"]
[sub_resource type="LabelSettings" id="LabelSettings_8g5s8"]
font = ExtResource("1_xaun4")
font_size = 32
font_color = Color(1, 0, 0, 1)
outline_size = 8
shadow_size = 8
shadow_color = Color(0, 0, 0, 1)
[sub_resource type="GDScript" id="GDScript_xaun4"]
script/source = "extends Label
var ball_velocity := 0.0:
get: return ball_velocity
set(value):
ball_velocity = value
var rounded: float = floor(value)
self.text = str(int(rounded)) + \" km/h\"
const min_px = 32.0
const max_px = 56.0
self.label_settings.font_size = min(max(rounded / 3, min_px), max_px)
self.label_settings.outline_size = min(max(rounded / 12, min_px / 4), max_px / 4)
self.label_settings.shadow_size = min(max(rounded / 12, min_px / 4), max_px / 4)
"
[node name="Speed" type="Label"]
text = "0 km/h"
label_settings = SubResource("LabelSettings_8g5s8")
horizontal_alignment = 2
script = SubResource("GDScript_xaun4")

142
gui/timer.tscn Normal file
View file

@ -0,0 +1,142 @@
[gd_scene load_steps=9 format=3 uid="uid://xd3nsiglcdfc"]
[ext_resource type="FontFile" uid="uid://c3fsj6knyiuhl" path="res://fonts/Knewave/Knewave-Regular.ttf" id="1_m1tld"]
[sub_resource type="GDScript" id="GDScript_q235s"]
script/source = "extends VBoxContainer
var enabled := false:
get: return enabled
set(value):
if enabled == value:
return
enabled = value
if value == false:
$AnimationPlayer.play(\"scale_linear\")
await get_tree().create_timer($AnimationPlayer.current_animation_length).timeout
$AnimationPlayer.play_backwards(\"scale_cubic\")
var seconds_spent_total := 0.0:
get: return seconds_spent_total
set(value):
seconds_spent_total = value
$Total.text = \"Total: \" + seconds_to_readable(seconds_spent_total)
var seconds_spent_level_attempt := 0.0:
get: return seconds_spent_level_attempt
set(value):
seconds_spent_level_attempt = value
$Level.text = \"Level: \" + seconds_to_readable(seconds_spent_level_attempt)
func _on_visibility_changed() -> void:
if self.visible and len(SaveFiles.selected_file):
var save_file = SaveFiles.read(SaveFiles.selected_file)
if save_file.has(\"played_for\") and save_file.played_for is float:
seconds_spent_total = save_file.played_for
else:
seconds_spent_total = 0.0
func seconds_to_readable(seconds: float) -> String:
var minutes: int = floor(seconds / 60)
return (\"%0*d\" % [2, minutes]) + \":\" + (\"%0*.3f\" % [6, seconds - (minutes * 60)])
func _physics_process(delta: float) -> void:
if enabled:
seconds_spent_total += delta
seconds_spent_level_attempt += delta
"
[sub_resource type="LabelSettings" id="LabelSettings_m1tld"]
font = ExtResource("1_m1tld")
font_size = 32
outline_size = 8
outline_color = Color(1, 0, 1, 1)
shadow_size = 8
shadow_color = Color(0, 0, 0, 1)
[sub_resource type="LabelSettings" id="LabelSettings_2a86r"]
font = ExtResource("1_m1tld")
font_size = 24
outline_size = 8
outline_color = Color(0, 0, 1, 1)
shadow_size = 8
shadow_color = Color(0, 0, 0, 1)
[sub_resource type="Animation" id="Animation_m1tld"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:scale")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(1, 1)]
}
[sub_resource type="Animation" id="Animation_houb3"]
resource_name = "scale_cubic"
length = 0.25
step = 0.25
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:scale")
tracks/0/interp = 2
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.25),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector2(1, 1), Vector2(1.2, 1.2)]
}
[sub_resource type="Animation" id="Animation_2a86r"]
resource_name = "scale_linear"
length = 0.25
step = 0.25
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:scale")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.25),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector2(1, 1), Vector2(1.2, 1.2)]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_jmgpn"]
_data = {
&"RESET": SubResource("Animation_m1tld"),
&"scale_cubic": SubResource("Animation_houb3"),
&"scale_linear": SubResource("Animation_2a86r")
}
[node name="Timer" type="VBoxContainer"]
process_mode = 3
offset_right = 315.0
offset_bottom = 85.0
theme_override_constants/separation = -5
script = SubResource("GDScript_q235s")
[node name="Total" type="Label" parent="."]
layout_mode = 2
text = "Total: 0:00.000"
label_settings = SubResource("LabelSettings_m1tld")
[node name="Level" type="Label" parent="."]
layout_mode = 2
text = "Level: 0:00.000"
label_settings = SubResource("LabelSettings_2a86r")
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
libraries = {
&"": SubResource("AnimationLibrary_jmgpn")
}
[connection signal="visibility_changed" from="." to="." method="_on_visibility_changed"]

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg>

Before

Width:  |  Height:  |  Size: 994 B

View file

@ -1,105 +1,125 @@
[gd_scene load_steps=11 format=3 uid="uid://ccgnnif026wb4"] [gd_scene load_steps=8 format=3 uid="uid://ccgnnif026wb4"]
[ext_resource type="PackedScene" uid="uid://n40mg5tc3bnv" path="res://levels/demo_level.tscn" id="1_08svf"] [ext_resource type="PackedScene" uid="uid://xd3nsiglcdfc" path="res://gui/timer.tscn" id="1_356j3"]
[ext_resource type="PackedScene" uid="uid://dw0xl8644x166" path="res://gui/gravity.tscn" id="1_ir7so"]
[ext_resource type="PackedScene" uid="uid://cckeamgkt8bqo" path="res://gui/speed.tscn" id="2_2gn6w"]
[ext_resource type="PackedScene" uid="uid://bcxbw6wd54ksv" path="res://gui/map.tscn" id="2_d1yoc"]
[ext_resource type="PackedScene" uid="uid://cn55m5dqo3m6u" path="res://gui/rings.tscn" id="3_mbj17"]
[ext_resource type="PackedScene" uid="uid://dkxtwpcy4moyo" path="res://menus/pause_menu.tscn" id="4_3bfj3"]
[sub_resource type="GDScript" id="GDScript_8n212"] [sub_resource type="GDScript" id="GDScript_8n212"]
script/source = "extends Node script/source = "extends Node
var seconds_spent: float = 0.0 var playing := false
var changing_level: bool = false var changing_level := false
var base = preload(\"res://levels/base/level.tscn\")
var forest = preload(\"res://levels/forest/level.tscn\") var main_menu: Node
var night = preload(\"res://levels/night/level.tscn\") var current_level: Level
var current_level_scene: PackedScene
const res_main_menu = preload(\"res://menus/main/main_menu.tscn\")
@onready var gui_gravity := $GUI/Gravity
@onready var gui_map := $GUI/Map
@onready var gui_timer := $GUI/TopLeft/Timer
@onready var gui_speed := $GUI/TopRight/Speed
@onready var gui_rings := $GUI/BottomRight/Rings
@onready var pause_menu := $PauseMenu
func _ready() -> void: func _ready() -> void:
var os_name = OS.get_name()
if os_name == \"Web\": ## we can't quit the game on web
$PauseMenu/VBoxContainer/Btn_Quit.hide()
$VictoryScreen.hide()
$Informations.hide()
$PauseMenu.hide()
## Add the version of the game and the name of the OS to the footer of the start menu ## Add the version of the game and the name of the OS to the footer of the start menu
$StartMenu/VBoxContainer/MarginContainer2/Notice.text += \" - build \" + ProjectSettings.get_setting(\"application/config/version\") + \" (\" + os_name + \")\" if OS.has_feature(\"editor\"):
$DevInfos.text = \"dev \"
$DevInfos.text += \"build \" + ProjectSettings.get_setting(\"application/config/version\") + \" (\" + OS.get_name() + \")\"
func start_level(level_scene: PackedScene) -> void: ## Hide UI stuff that shouldn't be visible until later in the game
$VictoryScreen.hide() pause_menu.hide()
if level_scene and level_scene.can_instantiate():
var level = level_scene.instantiate() ## Connect to necessary signals
$Levels.add_child(level) pause_menu.connect(\"request_pause\", pause_game)
$Timer.paused = false pause_menu.connect(\"request_fullscreen\", fullscreen_game)
AudioServer.set_bus_volume_db(0, 0) pause_menu.connect(\"request_restart\", restart_level)
PhysicsServer3D.area_set_param(
get_viewport().find_world_3d().space, set_main_menu()
PhysicsServer3D.AREA_PARAM_GRAVITY_VECTOR,
Vector3.DOWN func set_main_menu() -> void:
)
changing_level = false
else:
$VictoryScreen.show()
await get_tree().create_timer(2).timeout
$StartMenu/AnimationPlayer.play_backwards(\"fadeout\")
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
await get_tree().create_timer(1).timeout $GUI.hide()
$StartMenu.modulate = Color(1,1,1,1)
func stop_level() -> void: ## If no main menu exists yet, create one
PhysicsServer3D.area_set_param(get_viewport().find_world_3d().space, PhysicsServer3D.AREA_PARAM_GRAVITY, 1) if !is_instance_valid(main_menu):
$Timer.paused = true main_menu = res_main_menu.instantiate()
main_menu.connect(\"request_play_level\", start_level)
add_child(main_menu)
func start_level(level: Level, scene: PackedScene) -> void:
if is_instance_valid(current_level):
current_level.queue_free()
if is_instance_valid(main_menu) and self.is_ancestor_of(main_menu):
self.remove_child(main_menu)
current_level = level
current_level_scene = scene
add_child(current_level)
current_level.connect(\"started_playing\", func(): gui_timer.enabled = true)
current_level.connect(\"gravity_change\", gui_gravity.react_to_gravity_change)
current_level.connect(\"completed\", finish_current_level)
current_level.connect(\"ring_collected\", func():
gui_rings.remaining_rings = len(current_level.rings) - current_level.finished_rings_count
)
gui_rings.remaining_rings = len(current_level.rings) - current_level.finished_rings_count
$GUI.show()
Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)
pause_game(false)
playing = true
changing_level = false
gui_timer.seconds_spent_level_attempt = 0.0
func finish_current_level() -> void:
gui_timer.enabled = false
PhysicsServer3D.area_set_param(get_viewport().find_world_3d().space, PhysicsServer3D.AREA_PARAM_GRAVITY, 0.5)
playing = false
changing_level = true changing_level = true
AudioServer.set_bus_volume_db(0, -5) SaveFiles.change_property(\"played_for\", gui_timer.seconds_spent_total, SaveFiles.selected_file)
await get_tree().create_timer(0.5).timeout var save_file_data = SaveFiles.read(SaveFiles.selected_file)
AudioServer.set_bus_volume_db(0, -10) var property_name := current_level.id + \"_best_time\"
await get_tree().create_timer(0.5).timeout if !save_file_data.has(property_name) or save_file_data[property_name] is not float or save_file_data[property_name] > gui_timer.seconds_spent_level_attempt:
AudioServer.set_bus_volume_db(0, -30) SaveFiles.change_property(property_name, gui_timer.seconds_spent_level_attempt, SaveFiles.selected_file)
await get_tree().create_timer(0.5).timeout
AudioServer.set_bus_volume_db(0, -50)
await get_tree().create_timer(0.5).timeout
var next_level: PackedScene current_level.music.fadeOut(2)
var current_levels = $Levels.get_children(true) await get_tree().create_timer(2).timeout
if len(current_levels): current_level.queue_free()
var current_level = current_levels[0]
if current_level.get_meta(\"name\") == \"Base\":
next_level = forest
elif current_level.get_meta(\"name\") == \"Forest\":
next_level = night
for level in current_levels: set_main_menu()
level.queue_free()
start_level(next_level)
func restart_level() -> void: func restart_level() -> void:
if changing_level == false: gui_timer.enabled = false
var current_levels = $Levels.get_children(true) if !current_level or changing_level:
if len(current_levels): return
pause_game() if current_level_scene is not PackedScene:
changing_level = true print(\"Tried to restart the level despite not having the level scene\")
var current_level = current_levels[0] return
SaveFiles.change_property(\"played_for\", gui_timer.seconds_spent_total, SaveFiles.selected_file)
start_level(current_level_scene.instantiate(), current_level_scene)
var next_level: PackedScene = base func pause_game(to_pause: bool) -> void:
if current_level.get_meta(\"name\") == \"Forest\": if !is_instance_valid(current_level) or changing_level:
next_level = forest return
elif current_level.get_meta(\"name\") == \"Night\":
next_level = night
for level in current_levels: if to_pause:
level.queue_free() SaveFiles.change_property(\"played_for\", gui_timer.seconds_spent_total, SaveFiles.selected_file)
current_level.process_mode = Node.PROCESS_MODE_DISABLED
start_level(next_level) playing = false
pause_menu.show()
func pause_game() -> void:
if $Levels.process_mode == PROCESS_MODE_INHERIT:
$Levels.process_mode = Node.PROCESS_MODE_DISABLED
$Timer.paused = true
$PauseMenu.show()
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
else: else:
$Levels.process_mode = Node.PROCESS_MODE_INHERIT current_level.process_mode = Node.PROCESS_MODE_INHERIT
$Timer.paused = false playing = true
$PauseMenu.hide() pause_menu.hide()
Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN) Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)
func fullscreen_game() -> void: func fullscreen_game() -> void:
@ -109,390 +129,94 @@ func fullscreen_game() -> void:
else: else:
DisplayServer.window_set_mode(DisplayServer.WindowMode.WINDOW_MODE_WINDOWED) DisplayServer.window_set_mode(DisplayServer.WindowMode.WINDOW_MODE_WINDOWED)
func _on_btn_fullscreen_pressed() -> void:
fullscreen_game()
func _on_btn_start_pressed() -> void:
seconds_spent = 0.0
var current_levels = $Levels.get_children(true)
for level in current_levels:
level.queue_free()
$Informations.show()
$StartMenu/AnimationPlayer.play(\"fadeout\")
Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)
start_level(base)
$Timer.start(0)
func _on_animation_player_animation_finished(_anim_name: StringName) -> void:
if $StartMenu.modulate == Color(1,1,1,1):
$StartMenu.show()
else:
$StartMenu.hide()
func _on_timer_timeout() -> void:
seconds_spent = snapped(seconds_spent + 0.10, 0.01)
var minutes = floor(seconds_spent / 60)
$Informations/MarginContainer/Timer.text = (\"%0*d\" % [2, minutes]) + \":\" + (\"%0*.1f\" % [4, seconds_spent - (minutes * 60)])
func _process(_delta: float) -> void: func _process(_delta: float) -> void:
var current_levels = $Levels.get_children(true)
if len(current_levels):
var current_level = current_levels[0]
if is_instance_valid(current_level): if is_instance_valid(current_level):
if \"velocity\" in current_level: gui_speed.ball_velocity = current_level.velocity
$Informations/MarginContainer/VBoxContainer/Speed.text = str(floor(current_level.velocity)) + \" km/h\" if Input.is_action_pressed(\"display_map\"):
if \"rings_count\" in current_level and \"finished_rings_count\" in current_level: gui_map.display_rings(current_level.player, current_level.rings)
$Informations/MarginContainer/VBoxContainer/Rings.text = str(current_level.finished_rings_count) + \"/\" + str(current_level.rings_count)
func _unhandled_key_input(event: InputEvent) -> void: func _input(_event: InputEvent) -> void:
if event.is_pressed() and event is InputEventKey: if Input.is_action_just_released(\"display_map\"):
if $StartMenu.visible == false and changing_level == false: gui_map.hide()
if event.keycode == KEY_ESCAPE: if Input.is_action_just_pressed(\"display_map\"):
pause_game() gui_map.show()
elif event.keycode == KEY_R: if Input.is_action_just_pressed(\"restart_level\"):
pause_game()
restart_level()
func _on_btn_resume_pressed() -> void:
pause_game()
func _on_btn_fullscreen_2_pressed() -> void:
fullscreen_game()
func _on_btn_restart_pressed() -> void:
restart_level() restart_level()
func _on_btn_quit_pressed() -> void: func _on_btn_quit_pressed() -> void:
get_tree().quit() get_tree().quit()
" "
[sub_resource type="LabelSettings" id="LabelSettings_0s07t"]
font_size = 32
outline_size = 10
outline_color = Color(0, 0, 0, 1)
[sub_resource type="LabelSettings" id="LabelSettings_1bs00"]
font_size = 160
outline_size = 20
outline_color = Color(0, 0, 0, 1)
[sub_resource type="LabelSettings" id="LabelSettings_0jegv"]
font_size = 32
shadow_size = 2
shadow_color = Color(0, 0, 0, 1)
shadow_offset = Vector2(0, 0)
[sub_resource type="LabelSettings" id="LabelSettings_nbp4i"]
font_size = 24
shadow_size = 2
shadow_color = Color(0, 0, 0, 1)
shadow_offset = Vector2(0, 0)
[sub_resource type="LabelSettings" id="LabelSettings_5jdmh"]
font_size = 20
shadow_size = 2
shadow_color = Color(0, 0, 0, 1)
shadow_offset = Vector2(0, 0)
[sub_resource type="Animation" id="Animation_glb01"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:modulate")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Color(1, 1, 1, 1)]
}
[sub_resource type="Animation" id="Animation_75r06"]
resource_name = "fadeout"
step = 0.5
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:modulate")
tracks/0/interp = 2
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 1),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Color(1, 1, 1, 1), Color(1, 1, 1, 0)]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_5cb2g"]
_data = {
"RESET": SubResource("Animation_glb01"),
"fadeout": SubResource("Animation_75r06")
}
[node name="Game" type="Node"] [node name="Game" type="Node"]
script = SubResource("GDScript_8n212") script = SubResource("GDScript_8n212")
[node name="Informations" type="Control" parent="."] [node name="GUI" type="Control" parent="."]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
[node name="Gravity" parent="GUI" instance=ExtResource("1_ir7so")]
layout_mode = 1
[node name="Map" parent="GUI" instance=ExtResource("2_d1yoc")]
visible = false visible = false
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 1
[node name="MarginContainer" type="MarginContainer" parent="Informations"]
layout_mode = 1 layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_constants/margin_left = 10
theme_override_constants/margin_right = 10
[node name="Timer" type="Label" parent="Informations/MarginContainer"] [node name="TopLeft" type="MarginContainer" parent="GUI"]
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 8
text = "00:00.0"
label_settings = SubResource("LabelSettings_0s07t")
vertical_alignment = 2
[node name="VBoxContainer" type="VBoxContainer" parent="Informations/MarginContainer"]
layout_mode = 2
theme_override_constants/separation = -5
alignment = 2
[node name="Rings" type="Label" parent="Informations/MarginContainer/VBoxContainer"]
layout_mode = 2
text = "0/0"
label_settings = SubResource("LabelSettings_0s07t")
horizontal_alignment = 2
vertical_alignment = 2
[node name="Speed" type="Label" parent="Informations/MarginContainer/VBoxContainer"]
layout_mode = 2
text = "0 km/h"
label_settings = SubResource("LabelSettings_0s07t")
horizontal_alignment = 2
vertical_alignment = 2
[node name="VictoryScreen" type="Control" parent="."]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="Label" type="Label" parent="VictoryScreen"]
layout_mode = 1 layout_mode = 1
anchors_preset = 15 offset_right = 160.0
anchor_right = 1.0 offset_bottom = 85.0
anchor_bottom = 1.0 rotation = 0.0523599
grow_horizontal = 2 theme_override_constants/margin_left = 15
grow_vertical = 2
text = "YOU WON!"
label_settings = SubResource("LabelSettings_1bs00")
horizontal_alignment = 1
vertical_alignment = 1
[node name="Levels" type="Node" parent="."] [node name="Timer" parent="GUI/TopLeft" instance=ExtResource("1_356j3")]
layout_mode = 2
[node name="Demo" parent="Levels" instance=ExtResource("1_08svf")] [node name="TopRight" type="MarginContainer" parent="GUI"]
[node name="Timer" type="Timer" parent="."]
wait_time = 0.1
[node name="StartMenu" type="Control" parent="."]
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="StartMenu"]
layout_mode = 1 layout_mode = 1
anchors_preset = 15 anchors_preset = 1
anchor_left = 1.0
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 offset_left = -106.0
grow_horizontal = 2 offset_bottom = 51.0
grow_vertical = 2 grow_horizontal = 0
color = Color(0.522749, 0.477374, 0.510111, 0.501961) rotation = -0.0523599
theme_override_constants/margin_top = 5
theme_override_constants/margin_right = 15
[node name="VBoxContainer" type="VBoxContainer" parent="StartMenu"] [node name="Speed" parent="GUI/TopRight" instance=ExtResource("2_2gn6w")]
layout_mode = 2
[node name="BottomRight" type="MarginContainer" parent="GUI"]
layout_mode = 1 layout_mode = 1
anchors_preset = 15 anchors_preset = 3
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
offset_left = -222.0
offset_top = -51.0
grow_horizontal = 0
grow_vertical = 0
rotation = 0.0523599
theme_override_constants/margin_right = 15
theme_override_constants/margin_bottom = 15
[node name="Rings" parent="GUI/BottomRight" instance=ExtResource("3_mbj17")]
layout_mode = 2
[node name="DevInfos" type="Label" parent="."]
anchors_preset = 12
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_top = -23.0
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 2 grow_vertical = 0
[node name="Presentation" type="MarginContainer" parent="StartMenu/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 3
theme_override_constants/margin_left = 20
theme_override_constants/margin_top = 20
theme_override_constants/margin_right = 20
theme_override_constants/margin_bottom = 20
[node name="VBoxContainer" type="VBoxContainer" parent="StartMenu/VBoxContainer/Presentation"]
layout_mode = 2
[node name="Title" type="Label" parent="StartMenu/VBoxContainer/Presentation/VBoxContainer"]
layout_mode = 2
text = "DreamBall"
label_settings = SubResource("LabelSettings_0jegv")
horizontal_alignment = 1 horizontal_alignment = 1
[node name="Title2" type="Label" parent="StartMenu/VBoxContainer/Presentation/VBoxContainer"] [node name="PauseMenu" parent="." instance=ExtResource("4_3bfj3")]
layout_mode = 2
text = "A game about changing gravity to make a ball fly through the air"
label_settings = SubResource("LabelSettings_nbp4i")
horizontal_alignment = 1
[node name="MarginContainer" type="MarginContainer" parent="StartMenu/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 3
theme_override_constants/margin_left = 20
theme_override_constants/margin_top = 20
theme_override_constants/margin_right = 20
theme_override_constants/margin_bottom = 20
[node name="HBoxContainer" type="HBoxContainer" parent="StartMenu/VBoxContainer/MarginContainer"]
layout_mode = 2
size_flags_vertical = 3
[node name="Rules" type="VBoxContainer" parent="StartMenu/VBoxContainer/MarginContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
alignment = 2
[node name="Label" type="Label" parent="StartMenu/VBoxContainer/MarginContainer/HBoxContainer/Rules"]
layout_mode = 2
text = "- Change the direction of the gravity with the ARROW KEYS"
[node name="Label2" type="Label" parent="StartMenu/VBoxContainer/MarginContainer/HBoxContainer/Rules"]
layout_mode = 2
text = "- Keep LEFT SHIFT pressed to make the gravity stronger"
[node name="Label3" type="Label" parent="StartMenu/VBoxContainer/MarginContainer/HBoxContainer/Rules"]
layout_mode = 2
text = "- Press ESCAPE to pause and unpause the game at any point"
[node name="Label4" type="Label" parent="StartMenu/VBoxContainer/MarginContainer/HBoxContainer/Rules"]
layout_mode = 2
text = "- Press R to restart the current level from the beginning
(note that it won't reset the timer!)"
[node name="Buttons" type="VBoxContainer" parent="StartMenu/VBoxContainer/MarginContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
alignment = 2
[node name="Label5" type="Label" parent="StartMenu/VBoxContainer/MarginContainer/HBoxContainer/Buttons"]
layout_mode = 2
text = "Do your best to make the ball go through all the rings!"
horizontal_alignment = 1
[node name="HBoxContainer" type="HBoxContainer" parent="StartMenu/VBoxContainer/MarginContainer/HBoxContainer/Buttons"]
layout_mode = 2
theme_override_constants/separation = 20
alignment = 1
[node name="Btn_Fullscreen" type="Button" parent="StartMenu/VBoxContainer/MarginContainer/HBoxContainer/Buttons/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 4
action_mode = 0
text = "Toggle FULLSCREEN"
[node name="Btn_Start" type="Button" parent="StartMenu/VBoxContainer/MarginContainer/HBoxContainer/Buttons/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 4
text = "START the game!"
[node name="MarginContainer2" type="MarginContainer" parent="StartMenu/VBoxContainer"]
layout_mode = 2
theme_override_constants/margin_left = 20
theme_override_constants/margin_top = 20
theme_override_constants/margin_right = 20
theme_override_constants/margin_bottom = 20
[node name="Notice" type="Label" parent="StartMenu/VBoxContainer/MarginContainer2"]
layout_mode = 2
text = "Made during the 21st edition of Alakajam!"
label_settings = SubResource("LabelSettings_5jdmh")
horizontal_alignment = 1
[node name="AnimationPlayer" type="AnimationPlayer" parent="StartMenu"]
libraries = {
"": SubResource("AnimationLibrary_5cb2g")
}
[node name="PauseMenu" type="Control" parent="."]
visible = false
z_index = 2
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 1
[node name="ColorRect" type="ColorRect" parent="PauseMenu"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
color = Color(1, 0.54902, 1, 0.109804)
[node name="VBoxContainer" type="VBoxContainer" parent="PauseMenu"]
layout_mode = 1
anchors_preset = 14
anchor_top = 0.5
anchor_right = 1.0
anchor_bottom = 0.5
offset_top = -50.5
offset_bottom = 50.5
grow_horizontal = 2
grow_vertical = 2
theme_override_constants/separation = 10
[node name="Btn_Resume" type="Button" parent="PauseMenu/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 6
text = "RESUME game"
[node name="Btn_Fullscreen2" type="Button" parent="PauseMenu/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 6
text = "Toggle FULLSCREEN"
[node name="Btn_Restart" type="Button" parent="PauseMenu/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 6
text = "RESTART the level"
[node name="Btn_Quit" type="Button" parent="PauseMenu/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 6
text = "QUIT game"
[connection signal="timeout" from="Timer" to="." method="_on_timer_timeout"]
[connection signal="pressed" from="StartMenu/VBoxContainer/MarginContainer/HBoxContainer/Buttons/HBoxContainer/Btn_Fullscreen" to="." method="_on_btn_fullscreen_pressed"]
[connection signal="pressed" from="StartMenu/VBoxContainer/MarginContainer/HBoxContainer/Buttons/HBoxContainer/Btn_Start" to="." method="_on_btn_start_pressed"]
[connection signal="animation_finished" from="StartMenu/AnimationPlayer" to="." method="_on_animation_player_animation_finished"]
[connection signal="pressed" from="PauseMenu/VBoxContainer/Btn_Resume" to="." method="_on_btn_resume_pressed"]
[connection signal="pressed" from="PauseMenu/VBoxContainer/Btn_Fullscreen2" to="." method="_on_btn_fullscreen_2_pressed"]
[connection signal="pressed" from="PauseMenu/VBoxContainer/Btn_Restart" to="." method="_on_btn_restart_pressed"]
[connection signal="pressed" from="PauseMenu/VBoxContainer/Btn_Quit" to="." method="_on_btn_quit_pressed"]

View file

@ -1,26 +0,0 @@
[gd_scene load_steps=6 format=3 uid="uid://ygvokp5f78i5"]
[sub_resource type="Gradient" id="Gradient_hs6gw"]
[sub_resource type="GradientTexture2D" id="GradientTexture2D_hyysp"]
gradient = SubResource("Gradient_hs6gw")
fill_from = Vector2(0.536082, 1)
fill_to = Vector2(0.536082, 0)
[sub_resource type="PanoramaSkyMaterial" id="PanoramaSkyMaterial_g3k38"]
panorama = SubResource("GradientTexture2D_hyysp")
[sub_resource type="Sky" id="Sky_du8e4"]
sky_material = SubResource("PanoramaSkyMaterial_g3k38")
radiance_size = 1
[sub_resource type="Environment" id="Environment_y0yoy"]
background_mode = 2
background_color = Color(0.758192, 0.758192, 0.758192, 1)
sky = SubResource("Sky_du8e4")
ambient_light_source = 3
ambient_light_color = Color(1, 1, 1, 1)
reflected_light_source = 2
[node name="Environment" type="WorldEnvironment"]
environment = SubResource("Environment_y0yoy")

View file

@ -1,19 +1,49 @@
[gd_scene load_steps=8 format=3 uid="uid://b0mhosbyt1fit"] [gd_scene load_steps=11 format=3 uid="uid://ovtknjyj83gh"]
[ext_resource type="Material" uid="uid://brwwlwb1rpro7" path="res://graphics/unhappy_material.tres" id="1_dwsqy"]
[ext_resource type="PackedScene" uid="uid://ygvokp5f78i5" path="res://levels/base/environment.tscn" id="1_n7fd8"]
[ext_resource type="Script" path="res://levels/level.gd" id="1_rj40i"]
[ext_resource type="PackedScene" uid="uid://cnnvwotv33u1b" path="res://elements/player.tscn" id="2_b00jj"] [ext_resource type="PackedScene" uid="uid://cnnvwotv33u1b" path="res://elements/player.tscn" id="2_b00jj"]
[ext_resource type="PackedScene" uid="uid://cpm3laywhlbq5" path="res://elements/ring.tscn" id="3_hel5x"] [ext_resource type="PackedScene" uid="uid://cpm3laywhlbq5" path="res://elements/ring.tscn" id="3_hel5x"]
[ext_resource type="PackedScene" uid="uid://c77bli40240nk" path="res://elements/sign.tscn" id="4_atq6y"] [ext_resource type="PackedScene" uid="uid://c77bli40240nk" path="res://elements/sign.tscn" id="4_atq6y"]
[ext_resource type="PackedScene" uid="uid://cgt5st4qacruw" path="res://levels/base/music.tscn" id="4_uq42r"] [ext_resource type="PackedScene" uid="uid://dnuakh7n3fuij" path="res://levels/base/music.tscn" id="4_uq42r"]
[sub_resource type="GDScript" id="GDScript_1yugx"]
script/source = "extends Level
func _init() -> void:
self.id = \"base\"
func _on_player_velocity_change(new_velocity: float) -> void:
self.velocity = new_velocity
self.music.adaptInstrumentsToVelocity(new_velocity * 1.5)
"
[sub_resource type="Gradient" id="Gradient_hs6gw"]
[sub_resource type="GradientTexture2D" id="GradientTexture2D_hyysp"]
gradient = SubResource("Gradient_hs6gw")
fill_from = Vector2(0.536082, 1)
fill_to = Vector2(0.536082, 0)
[sub_resource type="PanoramaSkyMaterial" id="PanoramaSkyMaterial_g3k38"]
panorama = SubResource("GradientTexture2D_hyysp")
[sub_resource type="Sky" id="Sky_du8e4"]
sky_material = SubResource("PanoramaSkyMaterial_g3k38")
radiance_size = 1
[sub_resource type="Environment" id="Environment_y0yoy"]
background_mode = 2
background_color = Color(0.758192, 0.758192, 0.758192, 1)
sky = SubResource("Sky_du8e4")
ambient_light_source = 3
ambient_light_color = Color(1, 1, 1, 1)
reflected_light_source = 2
[node name="Base" type="Node3D"] [node name="Base" type="Node3D"]
script = ExtResource("1_rj40i") script = SubResource("GDScript_1yugx")
metadata/material = ExtResource("1_dwsqy") metadata/_custom_type_script = "uid://w3fetao1pegm"
metadata/name = "Base"
[node name="Environment" parent="." instance=ExtResource("1_n7fd8")] [node name="Environment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_y0yoy")
[node name="Music" parent="." instance=ExtResource("4_uq42r")] [node name="Music" parent="." instance=ExtResource("4_uq42r")]
@ -27,6 +57,7 @@ transform = Transform3D(-1, 8.74228e-08, 0, -8.74228e-08, -1, 0, 0, 0, 1, -366.4
transform = Transform3D(-1, -8.74228e-08, 0, 8.74228e-08, -1, 0, 0, 0, 1, -366.478, 3.24249e-05, 0) transform = Transform3D(-1, -8.74228e-08, 0, 8.74228e-08, -1, 0, 0, 0, 1, -366.478, 3.24249e-05, 0)
[node name="Text" parent="Signs/Sign" index="0"] [node name="Text" parent="Signs/Sign" index="0"]
transform = Transform3D(20, 0, 0, 0, 20, 0, 0, 0, 20, 0, 0, 0)
text = "Press the arrow keys text = "Press the arrow keys
to change the gravity!" to change the gravity!"
@ -34,13 +65,14 @@ to change the gravity!"
transform = Transform3D(4.37114e-08, -7.10543e-15, -1, -8.74228e-08, -1, 0, -1, 8.74228e-08, -4.37114e-08, 150, 40, 61) transform = Transform3D(4.37114e-08, -7.10543e-15, -1, -8.74228e-08, -1, 0, -1, 8.74228e-08, -4.37114e-08, 150, 40, 61)
[node name="Text" parent="Signs/Sign7" index="0"] [node name="Text" parent="Signs/Sign7" index="0"]
transform = Transform3D(30, 0, 0, 0, 30, 0, 0, 0, 30, 0, 0, 0)
text = "SLOW DOWN!!" text = "SLOW DOWN!!"
font_size = 2056
[node name="Sign2" parent="Signs" instance=ExtResource("4_atq6y")] [node name="Sign2" parent="Signs" instance=ExtResource("4_atq6y")]
transform = Transform3D(-1, -8.74228e-08, 0, 8.74228e-08, -1, 0, 0, 0, 1, -234.9, 2.09808e-05, 0) transform = Transform3D(-1, -8.74228e-08, 0, 8.74228e-08, -1, 0, 0, 0, 1, -234.9, 2.09808e-05, 0)
[node name="Text" parent="Signs/Sign2" index="0"] [node name="Text" parent="Signs/Sign2" index="0"]
transform = Transform3D(15, 0, 0, 0, 15, 0, 0, 0, 15, 0, 0, 0)
text = "While the shift key is pressed, text = "While the shift key is pressed,
the gravity is much stronger!" the gravity is much stronger!"
@ -48,6 +80,7 @@ the gravity is much stronger!"
transform = Transform3D(-1, -8.74228e-08, 0, 8.74228e-08, -1, 0, 0, 0, 1, -131.629, 81.2564, 0) transform = Transform3D(-1, -8.74228e-08, 0, 8.74228e-08, -1, 0, 0, 0, 1, -131.629, 81.2564, 0)
[node name="Text" parent="Signs/Sign4" index="0"] [node name="Text" parent="Signs/Sign4" index="0"]
transform = Transform3D(20, 0, 0, 0, 20, 0, 0, 0, 20, 0, 0, 0)
text = "You can take the rings text = "You can take the rings
in any order!" in any order!"
@ -55,6 +88,7 @@ in any order!"
transform = Transform3D(-4.37114e-08, 8.74228e-08, 1, 0, -1, 8.74228e-08, 1, 3.82137e-15, 4.37114e-08, -490.634, 50.3763, 34.0693) transform = Transform3D(-4.37114e-08, 8.74228e-08, 1, 0, -1, 8.74228e-08, 1, 3.82137e-15, 4.37114e-08, -490.634, 50.3763, 34.0693)
[node name="Text" parent="Signs/Sign5" index="0"] [node name="Text" parent="Signs/Sign5" index="0"]
transform = Transform3D(20, 0, 0, 0, 20, 0, 0, 0, 20, 0, 0, 0)
text = "The level is over once text = "The level is over once
you get all the rings!" you get all the rings!"
@ -62,13 +96,13 @@ you get all the rings!"
transform = Transform3D(-0.707107, 6.18172e-08, 0.707107, -8.74228e-08, -1, 0, 0.707107, -6.18172e-08, 0.707107, -532.475, 18.0064, 60) transform = Transform3D(-0.707107, 6.18172e-08, 0.707107, -8.74228e-08, -1, 0, 0.707107, -6.18172e-08, 0.707107, -532.475, 18.0064, 60)
[node name="Text" parent="Signs/Sign6" index="0"] [node name="Text" parent="Signs/Sign6" index="0"]
transform = Transform3D(30, 0, 0, 0, 30, 0, 0, 0, 30, 0, 0, 0)
text = "Have fun!" text = "Have fun!"
font_size = 2048
[node name="Sign3" parent="Signs" instance=ExtResource("4_atq6y")] [node name="Sign3" parent="Signs" instance=ExtResource("4_atq6y")]
[node name="Text" parent="Signs/Sign3" index="0"] [node name="Text" parent="Signs/Sign3" index="0"]
transform = Transform3D(-1, 8.74228e-08, 0, -8.74228e-08, -1, 0, 0, 0, 1, 0, 0, 0) transform = Transform3D(-20, 3.01992e-06, 0, -3.01992e-06, -20, 0, 0, 0, 20, 0, 0, 0)
text = "The less time you take, text = "The less time you take,
the more you can flex!" the more you can flex!"
@ -128,6 +162,8 @@ transform = Transform3D(0.0172464, 0.899835, 0, -0.899835, 0.0172464, 0, 0, 0, 0
[node name="Ring13" parent="Rings" instance=ExtResource("3_hel5x")] [node name="Ring13" parent="Rings" instance=ExtResource("3_hel5x")]
transform = Transform3D(0.0114976, 0.59989, 0, -0.59989, 0.0114976, 0, 0, 0, 0.6, -414.274, 8.64172, 0) transform = Transform3D(0.0114976, 0.59989, 0, -0.59989, 0.0114976, 0, 0, 0, 0.6, -414.274, 8.64172, 0)
[connection signal="velocity_change" from="Player" to="." method="_on_player_velocity_change"]
[editable path="Signs/Sign"] [editable path="Signs/Sign"]
[editable path="Signs/Sign7"] [editable path="Signs/Sign7"]
[editable path="Signs/Sign2"] [editable path="Signs/Sign2"]

View file

@ -1,7 +1,7 @@
[gd_scene load_steps=8 format=3 uid="uid://cgt5st4qacruw"] [gd_scene load_steps=8 format=3 uid="uid://dnuakh7n3fuij"]
[ext_resource type="AudioStream" uid="uid://b46a7y6vdqd4n" path="res://levels/base/music/hihat-closed.ogg" id="1_shxcq"] [ext_resource type="AudioStream" uid="uid://b46a7y6vdqd4n" path="res://levels/base/music/hihat-closed.ogg" id="1_shxcq"]
[ext_resource type="Script" path="res://levels/music.gd" id="1_y1f1r"] [ext_resource type="Script" uid="uid://dgpjhli3hpn0u" path="res://levels/music.gd" id="1_y1f1r"]
[ext_resource type="AudioStream" uid="uid://buag3j2s22jpo" path="res://levels/base/music/hihat-open.ogg" id="3_xb717"] [ext_resource type="AudioStream" uid="uid://buag3j2s22jpo" path="res://levels/base/music/hihat-open.ogg" id="3_xb717"]
[ext_resource type="AudioStream" uid="uid://djmbrvp7k263k" path="res://levels/base/music/kick2.ogg" id="4_1da6f"] [ext_resource type="AudioStream" uid="uid://djmbrvp7k263k" path="res://levels/base/music/kick2.ogg" id="4_1da6f"]
[ext_resource type="AudioStream" uid="uid://dma7btls87mg4" path="res://levels/base/music/kick.ogg" id="5_7thjx"] [ext_resource type="AudioStream" uid="uid://dma7btls87mg4" path="res://levels/base/music/kick.ogg" id="5_7thjx"]
@ -10,6 +10,7 @@
[node name="Music" type="Node"] [node name="Music" type="Node"]
script = ExtResource("1_y1f1r") script = ExtResource("1_y1f1r")
metadata/_custom_type_script = "uid://dgpjhli3hpn0u"
[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."] [node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."]
stream = ExtResource("1_shxcq") stream = ExtResource("1_shxcq")

View file

@ -1,29 +0,0 @@
[gd_scene load_steps=6 format=3 uid="uid://n40mg5tc3bnv"]
[ext_resource type="Script" path="res://levels/level.gd" id="1_ifscd"]
[ext_resource type="PackedScene" uid="uid://b6gnffoboc5j5" path="res://levels/night/environment.tscn" id="2_v6rg2"]
[ext_resource type="PackedScene" uid="uid://q7frlnx37gv6" path="res://levels/night/music.tscn" id="3_fb0ct"]
[ext_resource type="PackedScene" uid="uid://cnnvwotv33u1b" path="res://elements/player.tscn" id="4_ge8id"]
[ext_resource type="PackedScene" uid="uid://cpm3laywhlbq5" path="res://elements/ring.tscn" id="5_j060p"]
[node name="Demo" type="Node3D"]
script = ExtResource("1_ifscd")
metadata/name = "Demo"
[node name="Environment" parent="." instance=ExtResource("2_v6rg2")]
[node name="Music" parent="." instance=ExtResource("3_fb0ct")]
[node name="Player" parent="." instance=ExtResource("4_ge8id")]
[node name="Rings" type="Node3D" parent="."]
[node name="Ring" parent="Rings" instance=ExtResource("5_j060p")]
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 15.6731, -50)
visible = false
[node name="Ring2" parent="Rings" instance=ExtResource("5_j060p")]
transform = Transform3D(-4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0, 1, 10, -10, 0)
[node name="Ring3" parent="Rings" instance=ExtResource("5_j060p")]
transform = Transform3D(-4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0, 1, -10, -10, 0)

View file

@ -1,24 +0,0 @@
[gd_scene load_steps=4 format=3 uid="uid://w4h8ip754qnb"]
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_clvpw"]
sky_top_color = Color(0, 0.504542, 0.579919, 1)
sky_horizon_color = Color(9.62615e-08, 0.776269, 0.496436, 1)
sky_curve = 0.219613
ground_bottom_color = Color(0.078119, 0.275869, 4.81308e-08, 1)
ground_horizon_color = Color(0.300489, 0.406247, 0.0024617, 1)
sun_angle_max = 224.83
sun_curve = 0.212132
[sub_resource type="Sky" id="Sky_8w3rf"]
sky_material = SubResource("ProceduralSkyMaterial_clvpw")
[sub_resource type="Environment" id="Environment_nda78"]
background_mode = 2
sky = SubResource("Sky_8w3rf")
sky_rotation = Vector3(0.0872665, 0.698132, 0.0872665)
ambient_light_source = 3
ambient_light_color = Color(1, 1, 1, 1)
reflected_light_source = 2
[node name="Environment" type="WorldEnvironment"]
environment = SubResource("Environment_nda78")

View file

@ -1,18 +1,63 @@
[gd_scene load_steps=8 format=3 uid="uid://dfvuxfxc6ooya"] [gd_scene load_steps=10 format=3 uid="uid://e1761h6d522a"]
[ext_resource type="PackedScene" uid="uid://w4h8ip754qnb" path="res://levels/forest/environment.tscn" id="1_7clrg"]
[ext_resource type="Script" path="res://levels/level.gd" id="1_fdxcj"]
[ext_resource type="PackedScene" uid="uid://cnnvwotv33u1b" path="res://elements/player.tscn" id="2_mjogx"] [ext_resource type="PackedScene" uid="uid://cnnvwotv33u1b" path="res://elements/player.tscn" id="2_mjogx"]
[ext_resource type="PackedScene" uid="uid://dp8nvfm55te85" path="res://levels/forest/music.tscn" id="3_n1xsx"] [ext_resource type="PackedScene" uid="uid://cakmsiye3hjfe" path="res://levels/forest/music.tscn" id="3_n1xsx"]
[ext_resource type="PackedScene" uid="uid://cpm3laywhlbq5" path="res://elements/ring.tscn" id="4_p8yhq"] [ext_resource type="PackedScene" uid="uid://cpm3laywhlbq5" path="res://elements/ring.tscn" id="4_p8yhq"]
[ext_resource type="PackedScene" uid="uid://da6lkdiskdh8v" path="res://elements/tree.tscn" id="6_1e514"] [ext_resource type="PackedScene" uid="uid://da6lkdiskdh8v" path="res://elements/tree.tscn" id="6_1e514"]
[ext_resource type="PackedScene" uid="uid://c77bli40240nk" path="res://elements/sign.tscn" id="6_ifogr"] [ext_resource type="PackedScene" uid="uid://c77bli40240nk" path="res://elements/sign.tscn" id="6_ifogr"]
[node name="Forest" type="Node3D"] [sub_resource type="GDScript" id="GDScript_mqwxc"]
script = ExtResource("1_fdxcj") script/source = "extends Level
metadata/name = "Forest"
[node name="Environment" parent="." instance=ExtResource("1_7clrg")] var cycle := 0
func _init() -> void:
self.id = \"forest\"
self.thumbnail = load(\"res://levels/forest/thumbnail.png\")
func _process(_delta: float) -> void:
var moving_ring: Ring = $Rings/Ring18
if !moving_ring.collected:
if moving_ring.position.y < 55 or moving_ring.position.y > 65:
cycle += 1
moving_ring.position.y += 0.5 if cycle % 2 else -0.5
func _on_player_velocity_change(new_velocity: float) -> void:
self.velocity = new_velocity
self.music.adaptInstrumentsToVelocity(new_velocity)
"
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_grcut"]
sky_top_color = Color(0, 0.504542, 0.579919, 1)
sky_horizon_color = Color(9.62615e-08, 0.776269, 0.496436, 1)
sky_curve = 0.219613
ground_bottom_color = Color(0.078119, 0.275869, 4.81308e-08, 1)
ground_horizon_color = Color(0.300489, 0.406247, 0.0024617, 1)
sun_angle_max = 224.83
sun_curve = 0.212132
[sub_resource type="Sky" id="Sky_gxmta"]
sky_material = SubResource("ProceduralSkyMaterial_grcut")
[sub_resource type="Environment" id="Environment_y3whn"]
background_mode = 2
sky = SubResource("Sky_gxmta")
sky_rotation = Vector3(0.0872665, 0.698132, 0.0872665)
ambient_light_source = 3
ambient_light_color = Color(1, 1, 1, 1)
reflected_light_source = 2
[node name="Forest" type="Node3D"]
script = SubResource("GDScript_mqwxc")
metadata/_custom_type_script = "uid://w3fetao1pegm"
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(-0.920505, 0.195366, -0.338383, 0, 0.866025, 0.5, 0.390731, 0.460252, -0.797181, 0, 0, 0)
shadow_enabled = true
directional_shadow_mode = 0
[node name="Environment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_y3whn")
[node name="Music" parent="." instance=ExtResource("3_n1xsx")] [node name="Music" parent="." instance=ExtResource("3_n1xsx")]
@ -22,9 +67,8 @@ metadata/name = "Forest"
transform = Transform3D(-4.37114e-08, 8.74228e-08, 1, 0, -1, 8.74228e-08, 1, 3.82137e-15, 4.37114e-08, -450, 132.977, 0) transform = Transform3D(-4.37114e-08, 8.74228e-08, 1, 0, -1, 8.74228e-08, 1, 3.82137e-15, 4.37114e-08, -450, 132.977, 0)
[node name="Text" parent="Sign" index="0"] [node name="Text" parent="Sign" index="0"]
transform = Transform3D(-1, 8.74228e-08, 0, -8.74228e-08, -1, 0, 0, 0, 1, 0, 0, 0) transform = Transform3D(-35, 5.28485e-06, 0, -5.28485e-06, -35, 0, 0, 0, 35, 0, 0, 0)
text = "Watch out!" text = "Watch out!"
font_size = 2048
[node name="Trees" type="Node3D" parent="."] [node name="Trees" type="Node3D" parent="."]
@ -110,7 +154,7 @@ transform = Transform3D(-49.1471, 0, -9.19585, 0, 50, 0, 9.19585, 0, -49.1471, -
transform = Transform3D(-28.781, 0, 40.8859, 0, 50, 0, -40.8859, 0, -28.781, -460.677, -329.892, 361.614) transform = Transform3D(-28.781, 0, 40.8859, 0, 50, 0, -40.8859, 0, -28.781, -460.677, -329.892, 361.614)
[node name="Tree28" parent="Trees" instance=ExtResource("6_1e514")] [node name="Tree28" parent="Trees" instance=ExtResource("6_1e514")]
transform = Transform3D(-28.781, 0, 40.8859, 0, 50, 0, -40.8859, 0, -28.781, -643.482, -296.989, 101.924) transform = Transform3D(-28.781, 0, 40.8859, 0, 50, 0, -40.8859, 0, -28.781, -643.482, -296.989, 139.279)
[node name="Tree29" parent="Trees" instance=ExtResource("6_1e514")] [node name="Tree29" parent="Trees" instance=ExtResource("6_1e514")]
transform = Transform3D(-29.5106, 0, 40.3624, 0, 50, 0, -40.3624, 0, -29.5106, -418.092, -296.989, 136.2) transform = Transform3D(-29.5106, 0, 40.3624, 0, 50, 0, -40.3624, 0, -29.5106, -418.092, -296.989, 136.2)
@ -234,4 +278,6 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -218.208, 206.247, 0)
[node name="Ring23" parent="Rings" instance=ExtResource("4_p8yhq")] [node name="Ring23" parent="Rings" instance=ExtResource("4_p8yhq")]
transform = Transform3D(0.939693, 0.34202, 0, -0.34202, 0.939693, 0, 0, 0, 1, -1018.15, -96.9134, 0) transform = Transform3D(0.939693, 0.34202, 0, -0.34202, 0.939693, 0, 0, 0, 1, -1018.15, -96.9134, 0)
[connection signal="velocity_change" from="Player" to="." method="_on_player_velocity_change"]
[editable path="Sign"] [editable path="Sign"]

View file

@ -1,6 +1,6 @@
[gd_scene load_steps=8 format=3 uid="uid://dp8nvfm55te85"] [gd_scene load_steps=8 format=3 uid="uid://cakmsiye3hjfe"]
[ext_resource type="Script" path="res://levels/music.gd" id="1_whsrg"] [ext_resource type="Script" uid="uid://dgpjhli3hpn0u" path="res://levels/music.gd" id="1_whsrg"]
[ext_resource type="AudioStream" uid="uid://pn2b2f3egpck" path="res://levels/forest/music/dong2.ogg" id="2_pm2p2"] [ext_resource type="AudioStream" uid="uid://pn2b2f3egpck" path="res://levels/forest/music/dong2.ogg" id="2_pm2p2"]
[ext_resource type="AudioStream" uid="uid://dghw6a7i3adcu" path="res://levels/forest/music/dong.ogg" id="3_1eawt"] [ext_resource type="AudioStream" uid="uid://dghw6a7i3adcu" path="res://levels/forest/music/dong.ogg" id="3_1eawt"]
[ext_resource type="AudioStream" uid="uid://bu4kmowmputnr" path="res://levels/forest/music/hihat-closed.ogg" id="4_kv4yx"] [ext_resource type="AudioStream" uid="uid://bu4kmowmputnr" path="res://levels/forest/music/hihat-closed.ogg" id="4_kv4yx"]
@ -10,6 +10,7 @@
[node name="Music" type="Node"] [node name="Music" type="Node"]
script = ExtResource("1_whsrg") script = ExtResource("1_whsrg")
metadata/_custom_type_script = "uid://dgpjhli3hpn0u"
[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."] [node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."]
stream = ExtResource("2_pm2p2") stream = ExtResource("2_pm2p2")

BIN
levels/forest/thumbnail.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

View file

@ -2,16 +2,16 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://c4nwhhum2vht5" uid="uid://dhyxogc13hnbe"
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex" path="res://.godot/imported/thumbnail.png-6909560b6205778a3cb325a584af7ca5.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://icon.svg" source_file="res://levels/forest/thumbnail.png"
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"] dest_files=["res://.godot/imported/thumbnail.png-6909560b6205778a3cb325a584af7ca5.ctex"]
[params] [params]
@ -32,6 +32,3 @@ process/hdr_as_srgb=false
process/hdr_clamp_exposure=false process/hdr_clamp_exposure=false
process/size_limit=0 process/size_limit=0
detect_3d/compress_to=1 detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View file

@ -1,51 +1,104 @@
class_name Level
extends Node3D extends Node3D
signal started_playing
signal gravity_change
signal ring_collected
signal completed
const gravity_strength_normal = 7
const gravity_strength_strong = gravity_strength_normal * 3
## Lowercase, spaceless name of the level
var id: String
var thumbnail: CompressedTexture2D
var player: Node3D
var music: Music
var rings: Array[Ring] = []
var finished_rings_count: int = 0
var velocity: float = 0.0 var velocity: float = 0.0
var has_started_playing: bool = false
var rings_count = 72727 func _init() -> void:
var finished_rings_count = 0 assert(len(id) > 0, self.name + " has no id!")
var rings: Array[Node] = []
var stream_players: Array[AudioStreamPlayer] = []
func _ready() -> void: func _ready() -> void:
var music_node = get_node("Music") PhysicsServer3D.area_set_param(
assert(is_instance_valid(music_node), self.name + " has no music!") get_viewport().find_world_3d().space,
var music = music_node.get_children() PhysicsServer3D.AREA_PARAM_GRAVITY_VECTOR,
for music_player in music: Vector3(0, 0, 0)
if music_player is AudioStreamPlayer: )
stream_players.push_back(music_player)
PhysicsServer3D.area_set_param(
get_viewport().find_world_3d().space,
PhysicsServer3D.AREA_PARAM_GRAVITY,
0
)
var children = get_children()
for child in children:
if is_instance_of(child, Music):
music = child
if child.name == "Player" and is_instance_of(child, Node3D):
player = child
assert(is_instance_valid(music), self.name + " has no music!")
var rings_node = get_node("Rings") var rings_node = get_node("Rings")
assert(is_instance_valid(rings_node), self.name + " has no rings!") assert(is_instance_valid(rings_node), self.name + " has no Rings node!")
rings = rings_node.get_children() var rings_node_children = rings_node.get_children()
rings_count = len(rings) for ring in rings_node_children:
for ring in rings: if is_instance_of(ring, Ring):
ring.connect("collect_signal", do_we_end_yet) rings.push_back(ring)
ring.connect("collect_signal", collect_ring)
func do_we_end_yet(): func collect_ring():
finished_rings_count += 1 finished_rings_count = len(rings.filter(func(ring: Ring): return ring.collected))
if finished_rings_count >= rings_count: ring_collected.emit()
var game = get_parent().get_parent()
if is_instance_valid(game) and game.has_method("stop_level"):
game.stop_level()
func _process(delta: float) -> void: if finished_rings_count >= len(rings):
var sphere = $Player/Sphere completed.emit()
velocity = abs(sphere.linear_velocity.x) + abs(sphere.linear_velocity.y)
var instruments_needed = floor(velocity / 8)
var instruments_playing = stream_players.filter(func(p: AudioStreamPlayer): return p.volume_db > -50)
for index_p in len(instruments_playing): func _input(_event: InputEvent) -> void:
var playing = instruments_playing[index_p] if Input.is_action_pressed("gravity_strong") or Input.is_action_just_released("gravity_strong"):
if index_p + 1 > instruments_needed: PhysicsServer3D.area_set_param(
playing.volume_db = max(playing.volume_db - (delta * 32), -50) get_viewport().find_world_3d().space,
elif playing.volume_db <= 0: PhysicsServer3D.AREA_PARAM_GRAVITY,
playing.volume_db = min(playing.volume_db + (delta * 8), 0) gravity_strength_strong if Input.is_action_pressed("gravity_strong") else gravity_strength_normal
)
if instruments_needed > len(instruments_playing): var up := Input.is_action_just_pressed("gravity_up")
var instruments_not_playing = stream_players.filter(func(p: AudioStreamPlayer): return p.volume_db <= -50) var left := Input.is_action_just_pressed("gravity_left")
if len(instruments_not_playing): var right := Input.is_action_just_pressed("gravity_right")
var to_play = instruments_not_playing.pick_random() var down := Input.is_action_just_pressed("gravity_down")
if is_instance_valid(to_play):
to_play.volume_db = min(to_play.volume_db + (delta * 16), 0) if up or left or right or down:
if !has_started_playing:
has_started_playing = true
started_playing.emit()
PhysicsServer3D.area_set_param(
get_viewport().find_world_3d().space,
PhysicsServer3D.AREA_PARAM_GRAVITY,
gravity_strength_strong if Input.is_action_pressed("gravity_strong") else gravity_strength_normal
)
var direction: Vector3
if up:
direction = Vector3.UP
elif left:
direction = Vector3.LEFT
elif right:
direction = Vector3.RIGHT
elif down:
direction = Vector3.DOWN
if direction && direction != PhysicsServer3D.area_get_param(
get_viewport().find_world_3d().space,
PhysicsServer3D.AREA_PARAM_GRAVITY_VECTOR
):
PhysicsServer3D.area_set_param(
get_viewport().find_world_3d().space,
PhysicsServer3D.AREA_PARAM_GRAVITY_VECTOR,
direction
)
gravity_change.emit(direction)

1
levels/level.gd.uid Normal file
View file

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

View file

@ -1,15 +1,69 @@
class_name Music
extends Node extends Node
## While the instruments are manipulated individually to match the gameplay,
## they are all regrouped in a single bus dedicated to this specific music.
## So we also manipulate the bus itself for the purposes of applying
## audio balance and settings and the such more efficiently.
var bus_index: int = -1
var instruments: Array[AudioStreamPlayer] = []
func _ready() -> void: func _ready() -> void:
var players = get_children() bus_index = AudioServer.get_bus_index(self.name)
for player in players: if bus_index == -1:
if player is AudioStreamPlayer: AudioServer.add_bus()
player.volume_db = -50 AudioServer.set_bus_name(AudioServer.bus_count - 1, self.name)
var stream: AudioStreamOggVorbis = player.stream bus_index = AudioServer.get_bus_index(self.name)
changeVolume(0)
var current_effects = AudioServer.get_bus_effect_count(bus_index)
for i in current_effects:
AudioServer.remove_bus_effect(bus_index, i)
var children = get_children()
for child in children:
if child is AudioStreamPlayer:
instruments.push_back(child)
child.bus = AudioServer.get_bus_name(bus_index)
child.volume_db = -50
var stream: AudioStreamOggVorbis = child.stream
if stream is AudioStreamOggVorbis: if stream is AudioStreamOggVorbis:
stream.loop = true stream.loop = true
stream.bpm = 124 stream.bpm = 124
for player in players: for instrument in instruments:
if player is AudioStreamPlayer: if instrument is AudioStreamPlayer:
player.play() instrument.play()
func changeVolume(db: float) -> void:
AudioServer.set_bus_volume_db(bus_index, db + Settings.volume_music)
AudioServer.set_bus_mute(bus_index, Settings.volume_music <= -15.0)
func adaptInstrumentsToVelocity(velocity: float) -> void:
## temp
const delta = 0.00833333333333
var instruments_needed = floor(velocity / 8)
var instruments_playing = instruments.filter(func(i: AudioStreamPlayer): return i.volume_db > -50)
for index_p in len(instruments_playing):
var playing = instruments_playing[index_p]
if index_p + 1 > instruments_needed:
playing.volume_db = max(playing.volume_db - (delta * 32), -50)
elif playing.volume_db <= 0:
playing.volume_db = min(playing.volume_db + (delta * 8), 0)
if instruments_needed > len(instruments_playing):
var instruments_not_playing = instruments.filter(func(i: AudioStreamPlayer): return i.volume_db <= -50)
if len(instruments_not_playing):
var to_play = instruments_not_playing.pick_random()
if is_instance_valid(to_play):
to_play.volume_db = min(to_play.volume_db + (delta * 16), 0)
func fadeOut(seconds: float) -> void:
var tween: Tween = create_tween()
# https://github.com/godotengine/godot/issues/32882
AudioServer.add_bus_effect(bus_index, AudioEffectAmplify.new())
var effect_index: int = AudioServer.get_bus_effect_count(bus_index) - 1
var effect: AudioEffectAmplify = AudioServer.get_bus_effect(bus_index, effect_index)
tween.tween_property(effect, "volume_linear", 0, seconds)

1
levels/music.gd.uid Normal file
View file

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

View file

@ -1,22 +0,0 @@
[gd_scene load_steps=6 format=3 uid="uid://b6gnffoboc5j5"]
[sub_resource type="Gradient" id="Gradient_x6q8u"]
[sub_resource type="GradientTexture1D" id="GradientTexture1D_lu6nv"]
gradient = SubResource("Gradient_x6q8u")
[sub_resource type="PanoramaSkyMaterial" id="PanoramaSkyMaterial_4yv3y"]
panorama = SubResource("GradientTexture1D_lu6nv")
[sub_resource type="Sky" id="Sky_ys2yp"]
sky_material = SubResource("PanoramaSkyMaterial_4yv3y")
[sub_resource type="Environment" id="Environment_8o42c"]
background_mode = 1
sky = SubResource("Sky_ys2yp")
ambient_light_source = 2
ambient_light_color = Color(1, 1, 1, 1)
reflected_light_source = 2
[node name="Environment" type="WorldEnvironment"]
environment = SubResource("Environment_8o42c")

View file

@ -1,19 +1,51 @@
[gd_scene load_steps=9 format=3 uid="uid://c2rlx31om4gey"] [gd_scene load_steps=13 format=3 uid="uid://drnqmu4lka22d"]
[ext_resource type="Script" path="res://levels/level.gd" id="1_3m1pa"] [ext_resource type="PackedScene" uid="uid://drfy3vhe6skp1" path="res://levels/night/music.tscn" id="1_npc74"]
[ext_resource type="PackedScene" uid="uid://q7frlnx37gv6" path="res://levels/night/music.tscn" id="1_npc74"]
[ext_resource type="PackedScene" uid="uid://cnnvwotv33u1b" path="res://elements/player.tscn" id="2_bc1ig"] [ext_resource type="PackedScene" uid="uid://cnnvwotv33u1b" path="res://elements/player.tscn" id="2_bc1ig"]
[ext_resource type="PackedScene" uid="uid://b6gnffoboc5j5" path="res://levels/night/environment.tscn" id="2_wintp"]
[ext_resource type="PackedScene" uid="uid://cpm3laywhlbq5" path="res://elements/ring.tscn" id="4_brcr0"] [ext_resource type="PackedScene" uid="uid://cpm3laywhlbq5" path="res://elements/ring.tscn" id="4_brcr0"]
[ext_resource type="PackedScene" uid="uid://c77bli40240nk" path="res://elements/sign.tscn" id="6_36yav"] [ext_resource type="PackedScene" uid="uid://c77bli40240nk" path="res://elements/sign.tscn" id="6_36yav"]
[ext_resource type="PackedScene" uid="uid://b4jtpua36m6b1" path="res://elements/star.tscn" id="7_ltcl0"] [ext_resource type="PackedScene" uid="uid://b4jtpua36m6b1" path="res://elements/star.tscn" id="7_ltcl0"]
[ext_resource type="PackedScene" uid="uid://da6lkdiskdh8v" path="res://elements/tree.tscn" id="8_kgstj"] [ext_resource type="PackedScene" uid="uid://da6lkdiskdh8v" path="res://elements/tree.tscn" id="8_kgstj"]
[node name="Night" type="Node3D"] [sub_resource type="GDScript" id="GDScript_akhnt"]
script = ExtResource("1_3m1pa") script/source = "extends Level
metadata/name = "Night"
[node name="Environment" parent="." instance=ExtResource("2_wintp")] func _init() -> void:
self.id = \"night\"
func _process(delta: float) -> void:
$Tree.rotate_x(delta / 3)
$Tree.rotate_y(delta)
func _on_player_velocity_change(new_velocity: float) -> void:
self.velocity = new_velocity
self.music.adaptInstrumentsToVelocity(new_velocity * 2)
"
[sub_resource type="Gradient" id="Gradient_x6q8u"]
[sub_resource type="GradientTexture1D" id="GradientTexture1D_lu6nv"]
gradient = SubResource("Gradient_x6q8u")
[sub_resource type="PanoramaSkyMaterial" id="PanoramaSkyMaterial_4yv3y"]
panorama = SubResource("GradientTexture1D_lu6nv")
[sub_resource type="Sky" id="Sky_ys2yp"]
sky_material = SubResource("PanoramaSkyMaterial_4yv3y")
[sub_resource type="Environment" id="Environment_8o42c"]
background_mode = 1
sky = SubResource("Sky_ys2yp")
ambient_light_source = 2
ambient_light_color = Color(1, 1, 1, 1)
reflected_light_source = 2
[node name="Night" type="Node3D"]
script = SubResource("GDScript_akhnt")
metadata/_custom_type_script = "uid://w3fetao1pegm"
[node name="Environment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_8o42c")
[node name="Music" parent="." instance=ExtResource("1_npc74")] [node name="Music" parent="." instance=ExtResource("1_npc74")]
@ -171,40 +203,42 @@ transform = Transform3D(-1.31134e-07, -3, 0, 3, -1.31134e-07, 0, 0, 0, 3, -104.2
[node name="Ring2" parent="Rings" instance=ExtResource("4_brcr0")] [node name="Ring2" parent="Rings" instance=ExtResource("4_brcr0")]
transform = Transform3D(0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, -12.3896, -2, 0) transform = Transform3D(0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, -12.3896, -2, 0)
[node name="Tree" parent="." instance=ExtResource("8_kgstj")]
transform = Transform3D(-3.79271, -7.04382, 0, 7.04382, -3.79271, 0, 0, 0, 8, 28.958, -413.185, -93.8242)
[node name="Signs" type="Node3D" parent="."] [node name="Signs" type="Node3D" parent="."]
[node name="Sign" parent="Signs" instance=ExtResource("6_36yav")] [node name="Sign" parent="Signs" instance=ExtResource("6_36yav")]
transform = Transform3D(0.843785, 0, 0.536681, 0, 1, 0, -0.536681, 0, 0.843785, -159.605, -62.9326, 0) transform = Transform3D(0.843785, 0, 0.536681, 0, 1, 0, -0.536681, 0, 0.843785, -159.605, -62.9326, 0)
[node name="Text" parent="Signs/Sign" index="0"] [node name="Text" parent="Signs/Sign" index="0"]
transform = Transform3D(37, 0, 0, 0, 37, 0, 0, 0, 37, 0, 0, 0)
text = "^^^ text = "^^^
Go UP!!" Go UP!!"
font_size = 2048
[node name="Sign4" parent="Signs" instance=ExtResource("6_36yav")] [node name="Sign4" parent="Signs" instance=ExtResource("6_36yav")]
transform = Transform3D(0.965926, 0, 0.258819, 0, 1, 0, -0.258819, 0, 0.965926, 231.92, -32.6467, 0) transform = Transform3D(0.965926, 0, 0.258819, 0, 1, 0, -0.258819, 0, 0.965926, 231.92, -32.6467, 0)
[node name="Text" parent="Signs/Sign4" index="0"] [node name="Text" parent="Signs/Sign4" index="0"]
transform = Transform3D(22, 0, 0, 0, 22, 0, 0, 0, 22, 0, 0, 0)
text = "^^ text = "^^
Don't forget Don't forget
that one!" that one!"
font_size = 1500
[node name="Sign2" parent="Signs" instance=ExtResource("6_36yav")] [node name="Sign2" parent="Signs" instance=ExtResource("6_36yav")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -159.605, -30.0117, -45.6318) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -159.605, -30.0117, -45.6318)
[node name="Text" parent="Signs/Sign2" index="0"] [node name="Text" parent="Signs/Sign2" index="0"]
transform = Transform3D(30, 0, 0, 0, 30, 0, 0, 0, 30, 0, 0, 0)
text = "After taking this, text = "After taking this,
go RIGHT!" go RIGHT!"
font_size = 1600
[node name="Sign3" parent="Signs" instance=ExtResource("6_36yav")] [node name="Sign3" parent="Signs" instance=ExtResource("6_36yav")]
transform = Transform3D(-1, -8.74228e-08, 0, 8.74228e-08, -1, 0, 0, 0, 1, -64.0671, 131.627, -45.6318) transform = Transform3D(-1, -8.74228e-08, 0, 8.74228e-08, -1, 0, 0, 0, 1, -64.0671, 131.627, -45.6318)
[node name="Text" parent="Signs/Sign3" index="0"] [node name="Text" parent="Signs/Sign3" index="0"]
transform = Transform3D(-1, 8.74228e-08, 0, -8.74228e-08, -1, 0, 0, 0, 1, 0, 0, 0) transform = Transform3D(-30, 4.52987e-06, 0, -4.52987e-06, -30, 0, 0, 0, 30, 0, 0, 0)
text = "Go RIGHT!" text = "Go RIGHT!"
font_size = 2048
[node name="Stars" type="Node3D" parent="."] [node name="Stars" type="Node3D" parent="."]
transform = Transform3D(4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 37.5124, -255.888) transform = Transform3D(4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 37.5124, -255.888)
@ -304,8 +338,7 @@ transform = Transform3D(-0.99693, 0.0731445, -0.0279554, -0.0555776, -0.912445,
[node name="Star32" parent="Stars" instance=ExtResource("7_ltcl0")] [node name="Star32" parent="Stars" instance=ExtResource("7_ltcl0")]
transform = Transform3D(-0.99693, 0.0731445, -0.0279554, -0.0555776, -0.912445, -0.405407, -0.055161, -0.402609, 0.913709, 0.952739, 0.24193, 7.10684) transform = Transform3D(-0.99693, 0.0731445, -0.0279554, -0.0555776, -0.912445, -0.405407, -0.055161, -0.402609, 0.913709, 0.952739, 0.24193, 7.10684)
[node name="Tree" parent="." instance=ExtResource("8_kgstj")] [connection signal="velocity_change" from="Player" to="." method="_on_player_velocity_change"]
transform = Transform3D(-3.79443, -7.04289, 0, 7.04289, -3.79443, 0, 0, 0, 8, 28.958, -413.185, -93.8242)
[editable path="Signs/Sign"] [editable path="Signs/Sign"]
[editable path="Signs/Sign4"] [editable path="Signs/Sign4"]

View file

@ -1,6 +1,6 @@
[gd_scene load_steps=8 format=3 uid="uid://q7frlnx37gv6"] [gd_scene load_steps=8 format=3 uid="uid://drfy3vhe6skp1"]
[ext_resource type="Script" path="res://levels/music.gd" id="1_ok6lg"] [ext_resource type="Script" uid="uid://dgpjhli3hpn0u" path="res://levels/music.gd" id="1_ok6lg"]
[ext_resource type="AudioStream" uid="uid://dcgmuddvkcw6" path="res://levels/night/music/hihat-closed.ogg" id="2_oeg0c"] [ext_resource type="AudioStream" uid="uid://dcgmuddvkcw6" path="res://levels/night/music/hihat-closed.ogg" id="2_oeg0c"]
[ext_resource type="AudioStream" uid="uid://deqxl1qmwu51s" path="res://levels/night/music/hihat-open.ogg" id="3_olgpr"] [ext_resource type="AudioStream" uid="uid://deqxl1qmwu51s" path="res://levels/night/music/hihat-open.ogg" id="3_olgpr"]
[ext_resource type="AudioStream" uid="uid://028dtbgdh0os" path="res://levels/night/music/kick.ogg" id="4_utlv1"] [ext_resource type="AudioStream" uid="uid://028dtbgdh0os" path="res://levels/night/music/kick.ogg" id="4_utlv1"]
@ -10,6 +10,7 @@
[node name="Music" type="Node"] [node name="Music" type="Node"]
script = ExtResource("1_ok6lg") script = ExtResource("1_ok6lg")
metadata/_custom_type_script = "uid://dgpjhli3hpn0u"
[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."] [node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."]
stream = ExtResource("2_oeg0c") stream = ExtResource("2_oeg0c")

View file

@ -0,0 +1,51 @@
[gd_scene load_steps=2 format=3 uid="uid://dys7qyy4b3gjt"]
[sub_resource type="GDScript" id="GDScript_vfuxb"]
script/source = "extends Control
signal request_start
signal request_settings
func _on_btn_start_pressed() -> void:
request_start.emit()
func _on_btn_settings_pressed() -> void:
request_settings.emit()
func _on_btn_exit_pressed() -> void:
get_tree().quit()
"
[node name="InitialMenu" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = SubResource("GDScript_vfuxb")
[node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
alignment = 1
[node name="BtnStart" type="Button" parent="VBoxContainer"]
layout_mode = 2
text = "Start the game!"
[node name="BtnSettings" type="Button" parent="VBoxContainer"]
layout_mode = 2
text = "Check out the settings"
[node name="BtnExit" type="Button" parent="VBoxContainer"]
layout_mode = 2
text = "Exit the game"
[connection signal="pressed" from="VBoxContainer/BtnStart" to="." method="_on_btn_start_pressed"]
[connection signal="pressed" from="VBoxContainer/BtnSettings" to="." method="_on_btn_settings_pressed"]
[connection signal="pressed" from="VBoxContainer/BtnExit" to="." method="_on_btn_exit_pressed"]

View file

@ -0,0 +1,152 @@
[gd_scene load_steps=2 format=3 uid="uid://d3b12iqla7uh6"]
[sub_resource type="GDScript" id="GDScript_rmgh7"]
script/source = "extends Control
signal request_play_level
@onready var carousel := $VBoxContainer/Selection/Carousel
@onready var label_time := $VBoxContainer/Presentation/MarginContainer/VBoxContainer/BestTime
const levels = [
\"res://levels/base/level.tscn\",
\"res://levels/forest/level.tscn\",
\"res://levels/night/level.tscn\",
]
var loaded_level: Level
var loaded_level_scene: PackedScene
var loaded_level_path: String
func _enter_tree() -> void:
if len(loaded_level_path):
prepare_level(loaded_level_path)
func _ready() -> void:
var placeholders := carousel.get_children()
for placeholder in placeholders:
placeholder.queue_free()
for i in len(levels):
var btn := Button.new()
btn.text = \"Level \" + str(i + 1)
btn.connect(\"pressed\", func(): prepare_level(levels[i]))
carousel.add_child(btn)
func prepare_level(level_scene_path: String):
if is_instance_valid(loaded_level):
loaded_level.queue_free()
ResourceLoader.load_threaded_request(level_scene_path)
loaded_level_scene = ResourceLoader.load_threaded_get(level_scene_path)
loaded_level = loaded_level_scene.instantiate()
loaded_level_path = level_scene_path
$VBoxContainer/Presentation/Thumbnail.texture = loaded_level.thumbnail
$VBoxContainer/Presentation/MarginContainer/VBoxContainer/LevelName.text = \"The \" + loaded_level.id.capitalize()
$VBoxContainer/Presentation.show()
$VBoxContainer/MarginContainer/PlayButton.show()
display_file_data(SaveFiles.read(SaveFiles.selected_file))
func display_file_data(data: Variant) -> void:
label_time.text = \"Best time: \"
var property_name := loaded_level.id + \"_best_time\"
if data.has(property_name) and data[property_name] is float:
var seconds: float = data[property_name]
var minutes: int = floor(seconds / 60)
label_time.text += (\"%0*d\" % [2, minutes]) + \":\" + (\"%0*.3f\" % [6, seconds - (minutes * 60)])
else:
label_time.text += \"00:00.000\"
func _on_play_button_pressed() -> void:
if is_instance_valid(loaded_level):
request_play_level.emit(loaded_level, loaded_level_scene)
func seconds_to_readable(seconds: float) -> String:
var minutes: int = floor(seconds / 60)
return (\"%0*d\" % [2, minutes]) + \":\" + (\"%0*.3f\" % [6, seconds - (minutes * 60)])
## This prevents a memory leak that is possible when this menu is destroyed
## and the loaded_level becomes unavailable to the rest of the game
## For example in the main menu, go to this menu, select a level,
## press \"return\" and go to this menu again, boom, memory leak prevented by this
func _notification(what: int) -> void:
match what:
NOTIFICATION_PREDELETE:
if is_instance_valid(loaded_level) && !loaded_level.is_inside_tree():
loaded_level.queue_free()
"
[node name="LevelSelectionMenu" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = SubResource("GDScript_rmgh7")
[node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="Selection" type="ScrollContainer" parent="VBoxContainer"]
custom_minimum_size = Vector2(0, 50)
layout_mode = 2
[node name="Carousel" type="HBoxContainer" parent="VBoxContainer/Selection"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_constants/separation = 10
alignment = 1
[node name="Placeholder1" type="Button" parent="VBoxContainer/Selection/Carousel"]
layout_mode = 2
theme_override_constants/icon_max_width = 150
text = "Placeholder"
[node name="Placeholder2" type="Button" parent="VBoxContainer/Selection/Carousel"]
layout_mode = 2
text = "Placeholder"
[node name="Placeholder3" type="Button" parent="VBoxContainer/Selection/Carousel"]
layout_mode = 2
text = "Placeholder"
[node name="Presentation" type="HBoxContainer" parent="VBoxContainer"]
visible = false
layout_mode = 2
[node name="Thumbnail" type="TextureRect" parent="VBoxContainer/Presentation"]
custom_minimum_size = Vector2(150, 150)
layout_mode = 2
expand_mode = 1
stretch_mode = 4
[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/Presentation"]
layout_mode = 2
theme_override_constants/margin_left = 5
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/Presentation/MarginContainer"]
layout_mode = 2
alignment = 1
[node name="LevelName" type="Label" parent="VBoxContainer/Presentation/MarginContainer/VBoxContainer"]
layout_mode = 2
text = "Placeholder"
[node name="BestTime" type="Label" parent="VBoxContainer/Presentation/MarginContainer/VBoxContainer"]
layout_mode = 2
text = "Best time: 00:00.000"
[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer"]
layout_mode = 2
theme_override_constants/margin_top = 15
[node name="PlayButton" type="Button" parent="VBoxContainer/MarginContainer"]
visible = false
layout_mode = 2
text = "Play!"
[connection signal="pressed" from="VBoxContainer/MarginContainer/PlayButton" to="." method="_on_play_button_pressed"]

296
menus/main/main_menu.tscn Normal file
View file

@ -0,0 +1,296 @@
[gd_scene load_steps=16 format=3 uid="uid://ikeidrgprk8k"]
[ext_resource type="PackedScene" uid="uid://wlhsarkeqe8r" path="res://menus/main/panel.tscn" id="1_5vmsf"]
[ext_resource type="PackedScene" uid="uid://cnnvwotv33u1b" path="res://elements/player.tscn" id="2_2rexg"]
[sub_resource type="GDScript" id="GDScript_bt14i"]
script/source = "extends Node3D
signal request_play_level
func _enter_tree() -> void:
$Camera3D/AnimationPlayer.play_backwards(\"camera_pan\")
PhysicsServer3D.area_set_param(
get_viewport().find_world_3d().space,
PhysicsServer3D.AREA_PARAM_GRAVITY_VECTOR,
Vector3.DOWN
)
# Display on Panel 1
const res_initial_menu = preload(\"res://menus/main/initial_menu.tscn\")
func _ready() -> void:
$Menus/Panel2.connect(\"request_return\", func(): rotate_cube_to(0))
$Menus/Panel3.connect(\"request_return\", func(): rotate_cube_to(90))
$Menus/Panel4.connect(\"request_return\", func(): rotate_cube_to(180))
var initial_menu := res_initial_menu.instantiate()
initial_menu.connect(\"request_start\", start)
initial_menu.connect(\"request_settings\", settings)
$Menus/Panel1.change_menu(initial_menu, false)
# Display on Panel 2
const res_settings_menu = preload(\"res://menus/main/settings_menu.tscn\")
func settings() -> void:
var settings_menu := res_settings_menu.instantiate()
$Menus/Panel2.change_menu(settings_menu)
rotate_cube_to(90)
const res_save_file_manager = preload(\"res://menus/main/save_file_manager.tscn\")
func start() -> void:
var save_file_manager := res_save_file_manager.instantiate()
save_file_manager.connect(\"request_start\", level_selection)
$Menus/Panel2.change_menu(save_file_manager)
rotate_cube_to(90)
# Display on Panel 3
const res_level_selection_menu = preload(\"res://menus/main/level_selection_menu.tscn\")
func level_selection() -> void:
var level_selection_menu := res_level_selection_menu.instantiate()
level_selection_menu.connect(\"request_play_level\", func(level: Level, scene: PackedScene):
$Camera3D/AnimationPlayer.play(\"camera_pan\")
await get_tree().create_timer(1.5).timeout
request_play_level.emit(level, scene)
)
$Menus/Panel3.change_menu(level_selection_menu)
rotate_cube_to(180)
# cube
func rotate_cube_to(degrees: int) -> void:
if $Menus/AnimationPlayer.is_playing():
return
var cube_animation: Animation = $Menus/AnimationPlayer.get_animation(\"rotate\")
cube_animation.track_set_key_value(0, 0, $Menus.rotation_degrees)
cube_animation.track_set_key_value(0, 1, Vector3(0, -degrees, 0))
$Menus/AnimationPlayer.play(\"rotate\")
if $AnimationPlayer.is_playing():
await get_tree().create_timer($AnimationPlayer.current_animation_length).timeout
var sky_animation: Animation = $AnimationPlayer.get_animation(\"sky_brightness\")
sky_animation.track_set_key_value(0, 0, $WorldEnvironment.environment.sky.sky_material.energy_multiplier)
sky_animation.track_set_key_value(0, 1, max(90, degrees * 2) / 90)
$AnimationPlayer.play(\"sky_brightness\")
"
[sub_resource type="Animation" id="Animation_0jxef"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:rotation_degrees")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 0, 0)]
}
[sub_resource type="Animation" id="Animation_bt14i"]
resource_name = "rotate"
length = 0.3
step = 0.3
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:rotation_degrees")
tracks/0/interp = 2
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.3),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector3(0, 0, 0), Vector3(0, 0, 0)]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_3bwb0"]
_data = {
&"RESET": SubResource("Animation_0jxef"),
&"rotate": SubResource("Animation_bt14i")
}
[sub_resource type="Animation" id="Animation_2rexg"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("WorldEnvironment:environment:sky:sky_material:energy_multiplier")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [1.0]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Camera3D:fov")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [40.0]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("Camera3D:position")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 0, 2.5)]
}
[sub_resource type="Animation" id="Animation_jinmx"]
resource_name = "camera_pan"
length = 1.5
step = 0.1
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Camera3D:fov")
tracks/0/interp = 2
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 1.5),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [40.0, 75.0]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Camera3D:position")
tracks/1/interp = 2
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 1.5),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector3(0, 0, 2.5), Vector3(0, 0, 15)]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_jinmx"]
_data = {
&"RESET": SubResource("Animation_2rexg"),
&"camera_pan": SubResource("Animation_jinmx")
}
[sub_resource type="PhysicalSkyMaterial" id="PhysicalSkyMaterial_bt14i"]
ground_color = Color(1, 0.484315, 0.700558, 1)
[sub_resource type="Sky" id="Sky_0jxef"]
sky_material = SubResource("PhysicalSkyMaterial_bt14i")
[sub_resource type="Environment" id="Environment_qfa5o"]
background_mode = 2
background_color = Color(0.804743, 0.804743, 0.804743, 1)
sky = SubResource("Sky_0jxef")
ambient_light_source = 3
ambient_light_color = Color(0.986752, 0.986752, 0.986752, 1)
reflected_light_source = 2
[sub_resource type="Animation" id="Animation_j2kye"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("../../WorldEnvironment:environment:sky:sky_material:energy_multiplier")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [1.0]
}
[sub_resource type="Animation" id="Animation_gma2u"]
resource_name = "sky_brightness"
length = 0.3
step = 0.1
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("../../WorldEnvironment:environment:sky:sky_material:energy_multiplier")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.3),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [1.0, 1.0]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_wruj6"]
_data = {
&"RESET": SubResource("Animation_j2kye"),
&"sky_brightness": SubResource("Animation_gma2u")
}
[node name="MainMenu" type="Node3D"]
process_mode = 3
script = SubResource("GDScript_bt14i")
[node name="Menus" type="CSGBox3D" parent="."]
use_collision = true
[node name="Panel1" parent="Menus" instance=ExtResource("1_5vmsf")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.501)
[node name="Panel2" parent="Menus" instance=ExtResource("1_5vmsf")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 0.501, 0, 0)
[node name="Panel3" parent="Menus" instance=ExtResource("1_5vmsf")]
transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, 0, -0.501)
[node name="Panel4" parent="Menus" instance=ExtResource("1_5vmsf")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -0.501, 0, 0)
[node name="AnimationPlayer" type="AnimationPlayer" parent="Menus"]
libraries = {
&"": SubResource("AnimationLibrary_3bwb0")
}
[node name="Camera3D" type="Camera3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 2.5)
current = true
fov = 40.0
[node name="AnimationPlayer" type="AnimationPlayer" parent="Camera3D"]
root_node = NodePath("../..")
libraries = {
&"": SubResource("AnimationLibrary_jinmx")
}
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_qfa5o")
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(0.819152, -0.412596, 0.39844, 0, 0.694658, 0.71934, -0.573576, -0.589249, 0.569031, 0, 0, 0)
[node name="Player" parent="." instance=ExtResource("2_2rexg")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4, 0)
[node name="Camera" parent="Player" index="0"]
visible = false
current = false
[node name="GPUParticles3D" parent="Player/Sphere" index="2"]
visible = false
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
root_node = NodePath("../Camera3D/AnimationPlayer")
libraries = {
&"": SubResource("AnimationLibrary_wruj6")
}
[editable path="Player"]

115
menus/main/panel.tscn Normal file
View file

@ -0,0 +1,115 @@
[gd_scene load_steps=7 format=3 uid="uid://wlhsarkeqe8r"]
[ext_resource type="PackedScene" uid="uid://tasbgr10p84c" path="res://menus/menu.tscn" id="1_3roig"]
[sub_resource type="GDScript" id="GDScript_gfsnp"]
script/source = "# this whole code is from \"GUI in 3D\"
# which is something I downloaded a long time ago so no link
extends Node3D
var is_mouse_inside := false
var last_event_pos2D := Vector2()
var last_event_time := -1.0
@onready var node_viewport: SubViewport = $SubViewport
@onready var node_quad: MeshInstance3D = $MeshInstance3D
@onready var node_area: Area3D = $MeshInstance3D/Area3D
func _ready() -> void:
node_area.mouse_entered.connect(_mouse_entered_area)
node_area.mouse_exited.connect(_mouse_exited_area)
node_area.input_event.connect(_mouse_input_event)
func _mouse_entered_area() -> void:
is_mouse_inside = true
func _mouse_exited_area() -> void:
is_mouse_inside = false
func _unhandled_input(event: InputEvent) -> void:
for mouse_event in [InputEventMouseButton, InputEventMouseMotion, InputEventScreenDrag, InputEventScreenTouch]:
if is_instance_of(event, mouse_event):
return
node_viewport.push_input(event)
func _mouse_input_event(_camera: Camera3D, event: InputEvent, event_position: Vector3, _normal: Vector3, _shape_idx: int) -> void:
var quad_mesh_size: Vector2 = node_quad.mesh.size
var now := Time.get_ticks_msec() / 1000.0
var event_pos3D := event_position
event_pos3D = node_quad.global_transform.affine_inverse() * event_pos3D
var event_pos2D := Vector2()
if is_mouse_inside:
event_pos2D = Vector2(event_pos3D.x, -event_pos3D.y)
event_pos2D.x = event_pos2D.x / quad_mesh_size.x
event_pos2D.y = event_pos2D.y / quad_mesh_size.y
event_pos2D.x += 0.5
event_pos2D.y += 0.5
event_pos2D.x *= node_viewport.size.x
event_pos2D.y *= node_viewport.size.y
elif last_event_pos2D != null:
event_pos2D = last_event_pos2D
event.position = event_pos2D
if event is InputEventMouse:
event.global_position = event_pos2D
if event is InputEventMouseMotion or event is InputEventScreenDrag:
if last_event_pos2D == null:
event.relative = Vector2(0, 0)
else:
event.relative = event_pos2D - last_event_pos2D
event.velocity = event.relative / (now - last_event_time)
last_event_pos2D = event_pos2D
last_event_time = now
node_viewport.push_input(event)
# original code
signal request_return
func change_menu(new_menu: Control, return_button: bool = true):
$SubViewport/Menu.add(new_menu, return_button)
$SubViewport/Menu.connect(\"disabled\", func(): request_return.emit())
"
[sub_resource type="QuadMesh" id="QuadMesh_gfsnp"]
[sub_resource type="ViewportTexture" id="ViewportTexture_gfsnp"]
viewport_path = NodePath("SubViewport")
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_a5lkq"]
resource_local_to_scene = true
transparency = 1
albedo_texture = SubResource("ViewportTexture_gfsnp")
[sub_resource type="BoxShape3D" id="BoxShape3D_gfsnp"]
size = Vector3(1, 1, 0.01)
[node name="Panel" type="Node3D"]
process_mode = 3
script = SubResource("GDScript_gfsnp")
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
mesh = SubResource("QuadMesh_gfsnp")
surface_material_override/0 = SubResource("StandardMaterial3D_a5lkq")
[node name="Area3D" type="Area3D" parent="MeshInstance3D"]
collision_layer = 2
input_capture_on_drag = true
[node name="CollisionShape3D" type="CollisionShape3D" parent="MeshInstance3D/Area3D"]
shape = SubResource("BoxShape3D_gfsnp")
[node name="SubViewport" type="SubViewport" parent="."]
gui_embed_subwindows = true
render_target_update_mode = 4
[node name="Menu" parent="SubViewport" instance=ExtResource("1_3roig")]

View file

@ -0,0 +1,125 @@
[gd_scene load_steps=2 format=3 uid="uid://w5te3qujco7d"]
[sub_resource type="GDScript" id="GDScript_a5kgg"]
script/source = "extends Control
signal request_start
@onready var label_name = $VBoxContainer/MarginContainer/VBoxContainer/Description/Name
func _ready() -> void:
$VBoxContainer/MarginContainer.hide()
## Get the newest \"played_for\" when the main menu appears again
func _enter_tree() -> void:
if len(SaveFiles.selected_file):
display_file_data(SaveFiles.selected_file)
func _on_save_1_pressed() -> void:
label_name.text = $VBoxContainer/Save1.text
display_file_data(SaveFiles.names[0])
func _on_save_2_pressed() -> void:
label_name.text = $VBoxContainer/Save2.text
display_file_data(SaveFiles.names[1])
func _on_save_3_pressed() -> void:
label_name.text = $VBoxContainer/Save3.text
display_file_data(SaveFiles.names[2])
func display_file_data(file_name: String) -> void:
$VBoxContainer/MarginContainer.show()
var label_time := $VBoxContainer/MarginContainer/VBoxContainer/Description/Time
var data = SaveFiles.read(file_name)
$VBoxContainer/MarginContainer.show()
label_time.text = \" | \"
if data.has(\"played_for\") and data.played_for is float:
var seconds: float = data.played_for
var minutes: int = floor(seconds / 60)
label_time.text += (\"%0*d\" % [2, minutes]) + \":\" + (\"%0*.3f\" % [6, seconds - (minutes * 60)])
else:
label_time.text += \"00:00.000\"
func _on_start_pressed() -> void:
request_start.emit()
func _on_delete_pressed() -> void:
SaveFiles.empty(SaveFiles.selected_file)
display_file_data(SaveFiles.selected_file)
"
[node name="SaveFileManager" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = SubResource("GDScript_a5kgg")
[node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 14
anchor_top = 0.5
anchor_right = 1.0
anchor_bottom = 0.5
offset_top = -50.5
offset_bottom = 50.5
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
alignment = 1
[node name="Save1" type="Button" parent="VBoxContainer"]
layout_mode = 2
text = "Save file #1"
[node name="Save2" type="Button" parent="VBoxContainer"]
layout_mode = 2
text = "Save file #2"
[node name="Save3" type="Button" parent="VBoxContainer"]
layout_mode = 2
text = "Save file #3"
[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer"]
layout_mode = 2
theme_override_constants/margin_left = 30
theme_override_constants/margin_top = 30
theme_override_constants/margin_right = 30
theme_override_constants/margin_bottom = 30
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/MarginContainer"]
layout_mode = 2
[node name="Description" type="HBoxContainer" parent="VBoxContainer/MarginContainer/VBoxContainer"]
layout_mode = 2
alignment = 1
[node name="Name" type="Label" parent="VBoxContainer/MarginContainer/VBoxContainer/Description"]
layout_mode = 2
text = "Save File"
horizontal_alignment = 1
[node name="Time" type="Label" parent="VBoxContainer/MarginContainer/VBoxContainer/Description"]
layout_mode = 2
[node name="Buttons" type="HBoxContainer" parent="VBoxContainer/MarginContainer/VBoxContainer"]
layout_mode = 2
theme_override_constants/separation = 10
alignment = 1
[node name="Start" type="Button" parent="VBoxContainer/MarginContainer/VBoxContainer/Buttons"]
layout_mode = 2
size_flags_horizontal = 3
text = "Start"
[node name="Delete" type="Button" parent="VBoxContainer/MarginContainer/VBoxContainer/Buttons"]
layout_mode = 2
text = "Delete"
[connection signal="pressed" from="VBoxContainer/Save1" to="." method="_on_save_1_pressed"]
[connection signal="pressed" from="VBoxContainer/Save2" to="." method="_on_save_2_pressed"]
[connection signal="pressed" from="VBoxContainer/Save3" to="." method="_on_save_3_pressed"]
[connection signal="pressed" from="VBoxContainer/MarginContainer/VBoxContainer/Buttons/Start" to="." method="_on_start_pressed"]
[connection signal="pressed" from="VBoxContainer/MarginContainer/VBoxContainer/Buttons/Delete" to="." method="_on_delete_pressed"]

View file

@ -0,0 +1,96 @@
[gd_scene load_steps=2 format=3 uid="uid://opwiiusu80nu"]
[sub_resource type="GDScript" id="GDScript_wbybg"]
script/source = "extends Control
func _ready() -> void:
$VBoxContainer/Fullscreen/CheckButton.button_pressed = Settings.fullscreen
$VBoxContainer/SoundGravity/CheckButton.button_pressed = Settings.sound_on_gravity_change
$VBoxContainer/VolumeMusic/HSlider.value = Settings.volume_music
$VBoxContainer/VolumeSounds/HSlider.value = Settings.volume_sounds
func _on_fullscreen_check_button_toggled(toggled_on: bool) -> void:
Settings.fullscreen = toggled_on
func _on_soundgravity_check_button_toggled(toggled_on: bool) -> void:
Settings.sound_on_gravity_change = toggled_on
func _on_volumemusic_h_slider_value_changed(value: float) -> void:
Settings.volume_music = int(value)
func _on_volumesounds_h_slider_value_changed(value: float) -> void:
Settings.volume_sounds = int(value)
"
[node name="SettingsMenu" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = SubResource("GDScript_wbybg")
[node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
alignment = 1
[node name="Fullscreen" type="HBoxContainer" parent="VBoxContainer"]
layout_mode = 2
alignment = 1
[node name="Label" type="Label" parent="VBoxContainer/Fullscreen"]
layout_mode = 2
text = "Fullscreen"
[node name="CheckButton" type="CheckButton" parent="VBoxContainer/Fullscreen"]
layout_mode = 2
[node name="SoundGravity" type="HBoxContainer" parent="VBoxContainer"]
layout_mode = 2
alignment = 1
[node name="Label" type="Label" parent="VBoxContainer/SoundGravity"]
layout_mode = 2
text = "Play sound on gravity change"
[node name="CheckButton" type="CheckButton" parent="VBoxContainer/SoundGravity"]
layout_mode = 2
[node name="VolumeMusic" type="HBoxContainer" parent="VBoxContainer"]
layout_mode = 2
alignment = 1
[node name="Label" type="Label" parent="VBoxContainer/VolumeMusic"]
layout_mode = 2
text = "Music volume"
[node name="HSlider" type="HSlider" parent="VBoxContainer/VolumeMusic"]
custom_minimum_size = Vector2(200, 28)
layout_mode = 2
min_value = -15.0
max_value = 15.0
[node name="VolumeSounds" type="HBoxContainer" parent="VBoxContainer"]
layout_mode = 2
alignment = 1
[node name="Label" type="Label" parent="VBoxContainer/VolumeSounds"]
layout_mode = 2
text = "Sound volume"
[node name="HSlider" type="HSlider" parent="VBoxContainer/VolumeSounds"]
custom_minimum_size = Vector2(200, 28)
layout_mode = 2
min_value = -15.0
max_value = 15.0
[connection signal="toggled" from="VBoxContainer/Fullscreen/CheckButton" to="." method="_on_fullscreen_check_button_toggled"]
[connection signal="toggled" from="VBoxContainer/SoundGravity/CheckButton" to="." method="_on_soundgravity_check_button_toggled"]
[connection signal="value_changed" from="VBoxContainer/VolumeMusic/HSlider" to="." method="_on_volumemusic_h_slider_value_changed"]
[connection signal="value_changed" from="VBoxContainer/VolumeSounds/HSlider" to="." method="_on_volumesounds_h_slider_value_changed"]

139
menus/menu.tscn Normal file
View file

@ -0,0 +1,139 @@
[gd_scene load_steps=8 format=3 uid="uid://tasbgr10p84c"]
[ext_resource type="AudioStream" uid="uid://bnbf1nfaxuagi" path="res://sounds/select.ogg" id="1_y8e4h"]
[ext_resource type="AudioStream" uid="uid://bq3tw55s0ud55" path="res://sounds/confirm.ogg" id="2_hl3ms"]
[sub_resource type="GDScript" id="GDScript_18a3y"]
script/source = "extends MarginContainer
signal disabled
func add(node: Control, return_button: bool):
var add_to := $VSplitContainer/MarginContainer/ColorRect
var children := add_to.get_children(true)
for child in children:
child.queue_free()
var regex := RegEx.new()
regex.compile(\"([A-Z])\")
var menu_name := regex.sub(node.name, \" $1\", true, 1)
$VSplitContainer/Label.text = menu_name
add_to.add_child(node)
$VSplitContainer/AnimationPlayer.play(\"split_offset\")
if return_button:
var button = Button.new()
button.text = \"Return\"
button.anchor_top = 1.0
button.anchor_bottom = 1.0
button.grow_vertical = Control.GROW_DIRECTION_BEGIN
button.connect(\"pressed\", disable)
node.add_child(button)
link_to_sounds(node)
func link_to_sounds(node: Control):
var children := node.find_children(\"*\", \"\", true, false)
var buttons := children.filter(func(child): return is_instance_of(child, Button))
for button in buttons as Array[Button]:
button.mouse_entered.connect(func(): $Select.play())
button.pressed.connect(func(): $Confirm.play())
var sliders := children.filter(func(child): return is_instance_of(child, HSlider))
for slider in sliders as Array[HSlider]:
slider.mouse_entered.connect(func(): $Select.play())
slider.drag_ended.connect(func(_value): $Confirm.play())
func disable():
$VSplitContainer/AnimationPlayer.play_backwards(\"split_offset\")
disabled.emit()
"
[sub_resource type="Animation" id="Animation_y8e4h"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:split_offset")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [500]
}
[sub_resource type="Animation" id="Animation_85u52"]
resource_name = "split_offset"
length = 0.5
step = 0.5
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:split_offset")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.5),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [500, 0]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_hl3ms"]
_data = {
&"RESET": SubResource("Animation_y8e4h"),
&"split_offset": SubResource("Animation_85u52")
}
[sub_resource type="LabelSettings" id="LabelSettings_2d4ws"]
font_size = 48
[node name="Menu" type="MarginContainer"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_constants/margin_left = 20
theme_override_constants/margin_top = 20
theme_override_constants/margin_right = 20
theme_override_constants/margin_bottom = 20
script = SubResource("GDScript_18a3y")
[node name="VSplitContainer" type="VSplitContainer" parent="."]
layout_mode = 2
split_offset = 500
dragger_visibility = 1
[node name="AnimationPlayer" type="AnimationPlayer" parent="VSplitContainer"]
libraries = {
&"": SubResource("AnimationLibrary_hl3ms")
}
[node name="Label" type="Label" parent="VSplitContainer"]
custom_minimum_size = Vector2(1, 1)
layout_mode = 2
text = "MENU NAME"
label_settings = SubResource("LabelSettings_2d4ws")
horizontal_alignment = 1
autowrap_mode = 3
uppercase = true
[node name="MarginContainer" type="MarginContainer" parent="VSplitContainer"]
layout_mode = 2
theme_override_constants/margin_top = 20
[node name="ColorRect" type="ColorRect" parent="VSplitContainer/MarginContainer"]
layout_mode = 2
color = Color(0, 0, 0, 1)
[node name="Select" type="AudioStreamPlayer" parent="."]
stream = ExtResource("1_y8e4h")
bus = &"Sounds"
[node name="Confirm" type="AudioStreamPlayer" parent="."]
stream = ExtResource("2_hl3ms")
bus = &"Sounds"

78
menus/pause_menu.tscn Normal file
View file

@ -0,0 +1,78 @@
[gd_scene load_steps=2 format=3 uid="uid://dkxtwpcy4moyo"]
[sub_resource type="GDScript" id="GDScript_d8v8v"]
script/source = "extends Control
signal request_pause
signal request_fullscreen
signal request_restart
func _ready() -> void:
var os_name = OS.get_name()
if os_name == \"Web\": ## you can't quit the game on web (you're stuck here forever :))
$VBoxContainer/Btn_Quit.hide()
func _input(_event: InputEvent) -> void:
if Input.is_action_just_pressed(\"pause_game\"):
request_pause.emit(!self.visible)
func _on_btn_resume_pressed() -> void:
request_pause.emit(false)
func _on_btn_fullscreen_pressed() -> void:
request_fullscreen.emit()
func _on_btn_restart_pressed() -> void:
request_restart.emit()
func _on_btn_quit_pressed() -> void:
get_tree().quit()
"
[node name="PauseMenu" type="Control"]
z_index = 2
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 1
script = SubResource("GDScript_d8v8v")
[node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 14
anchor_top = 0.5
anchor_right = 1.0
anchor_bottom = 0.5
offset_top = -50.5
offset_bottom = 50.5
grow_horizontal = 2
grow_vertical = 2
theme_override_constants/separation = 10
[node name="Btn_Resume" type="Button" parent="VBoxContainer"]
layout_mode = 2
size_flags_vertical = 6
text = "RESUME game"
[node name="Btn_Fullscreen" type="Button" parent="VBoxContainer"]
layout_mode = 2
size_flags_vertical = 6
text = "Toggle FULLSCREEN"
[node name="Btn_Restart" type="Button" parent="VBoxContainer"]
layout_mode = 2
size_flags_vertical = 6
text = "RESTART the level"
[node name="Btn_Quit" type="Button" parent="VBoxContainer"]
layout_mode = 2
size_flags_vertical = 6
text = "QUIT game"
[connection signal="pressed" from="VBoxContainer/Btn_Resume" to="." method="_on_btn_resume_pressed"]
[connection signal="pressed" from="VBoxContainer/Btn_Fullscreen" to="." method="_on_btn_fullscreen_pressed"]
[connection signal="pressed" from="VBoxContainer/Btn_Restart" to="." method="_on_btn_restart_pressed"]
[connection signal="pressed" from="VBoxContainer/Btn_Quit" to="." method="_on_btn_quit_pressed"]

View file

@ -11,19 +11,80 @@ config_version=5
[application] [application]
config/name="DreamBall" config/name="DreamBall"
config/description="I'm Taevas, and this is \"DreamBall\", my entry for the 21st edition of \"Alakajam!\", a gamejam that lasts for 48 hours and starts on 2025-02-21 19:00UTC config/description="Manipulate the gravity to make a ball go through every ring!
https://alakajam.com/21st-alakajam https://kitsunes.dev/Taevas/DreamBall"
https://kitsunes.dev/Taevas/AlakajamEntry" config/version="20250503.0"
config/version="20250223.2"
run/main_scene="res://index.tscn" run/main_scene="res://index.tscn"
config/features=PackedStringArray("4.3", "GL Compatibility") config/features=PackedStringArray("4.4", "GL Compatibility")
boot_splash/show_image=false boot_splash/show_image=false
config/icon="res://icon.png" config/icon="res://icon.png"
config/windows_native_icon="res://icon.ico" config/windows_native_icon="res://icon.ico"
[audio] [autoload]
buses/default_bus_layout="" Settings="*res://settings.gd"
SaveFiles="*res://save_files.gd"
[input]
gravity_up={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194320,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":122,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":11,"pressure":0.0,"pressed":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":-1.0,"script":null)
]
}
gravity_left={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194319,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":113,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":13,"pressure":0.0,"pressed":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":-1.0,"script":null)
]
}
gravity_right={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194321,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":14,"pressure":0.0,"pressed":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":1.0,"script":null)
]
}
gravity_down={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194322,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":12,"pressure":0.0,"pressed":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":1.0,"script":null)
]
}
gravity_strong={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194325,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":1,"pressure":0.0,"pressed":false,"script":null)
]
}
pause_game={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194305,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":6,"pressure":0.0,"pressed":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":4,"pressure":0.0,"pressed":false,"script":null)
]
}
restart_level={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":82,"key_label":0,"unicode":114,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":2,"pressure":0.0,"pressed":false,"script":null)
]
}
display_map={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194326,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":9,"pressure":0.0,"pressed":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":10,"pressure":0.0,"pressed":false,"script":null)
]
}
[physics] [physics]
@ -32,6 +93,7 @@ common/physics_ticks_per_second=120
common/max_physics_steps_per_frame=20 common/max_physics_steps_per_frame=20
3d/physics_engine="GodotPhysics3D" 3d/physics_engine="GodotPhysics3D"
3d/default_gravity=1.0 3d/default_gravity=1.0
3d/default_gravity_vector=Vector3(0, -0.5, 0)
3d/solver/solver_iterations=40 3d/solver/solver_iterations=40
3d/solver/default_contact_bias=1.0 3d/solver/default_contact_bias=1.0
common/physics_interpolation=true common/physics_interpolation=true

49
save_files.gd Normal file
View file

@ -0,0 +1,49 @@
extends Node
const names := [
"user://save_file_1.save",
"user://save_file_2.save",
"user://save_file_3.save",
]
var selected_file: String
func _ready() -> void:
for save_file_name in names:
ensure_existence(save_file_name)
func ensure_existence(save_file_name: String) -> void:
if save_file_name in names and not FileAccess.file_exists(save_file_name):
print("Save file ", save_file_name, " not found, creating it")
empty(save_file_name)
func empty(save_file_name: String) -> void:
print("Writing an empty object on ", save_file_name)
write(JSON.stringify({}), save_file_name)
func read(save_file_name: String) -> Variant:
print("Reading from save file ", save_file_name)
ensure_existence(save_file_name)
selected_file = save_file_name
var save_file := FileAccess.open(save_file_name, FileAccess.READ)
var json := JSON.new()
var json_string := save_file.get_line()
if json.parse(json_string) != OK:
print("(SAVES) JSON Parse Error: ", json.get_error_message(), " in ", json_string, " at line ", json.get_error_line())
return {}
return json.data
func write(json_string: String, save_file_name: String) -> void:
var save_file := FileAccess.open(save_file_name, FileAccess.WRITE)
save_file.store_line(json_string)
save_file.store_line("FOR YOUR SAFETY, ALWAYS CHECK IF THE DATA OF THE FILES YOU DOWNLOAD LOOKS OKAY")
func change_property(property: String, value, save_file_name: String) -> void:
print("Changing property '", property, "' on save file ", save_file_name)
ensure_existence(save_file_name)
var data = read(save_file_name)
data[property] = value
write(JSON.stringify(data), save_file_name)

1
save_files.gd.uid Normal file
View file

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

78
settings.gd Normal file
View file

@ -0,0 +1,78 @@
extends Node
const settings_file_name := "user://settings.save"
var fullscreen := false : set = _set_fullscreen, get = _get_fullscreen
func _get_fullscreen() -> bool:
return fullscreen
func _set_fullscreen(new_fullscreen: bool) -> void:
fullscreen = new_fullscreen
var new_state := DisplayServer.WindowMode.WINDOW_MODE_FULLSCREEN if new_fullscreen else DisplayServer.WindowMode.WINDOW_MODE_WINDOWED
DisplayServer.window_set_mode(new_state)
save_settings()
var sound_on_gravity_change := true : set = _set_sound_on_gravity_change, get = _get_sound_on_gravity_change
func _get_sound_on_gravity_change() -> bool:
return sound_on_gravity_change
func _set_sound_on_gravity_change(new_sound_on_gravity_change: bool) -> void:
sound_on_gravity_change = new_sound_on_gravity_change
save_settings()
var volume_music := 0.0 : set = _set_volume_music, get = _get_volume_music
func _get_volume_music() -> float:
return volume_music
func _set_volume_music(new_volume_music: float) -> void:
volume_music = new_volume_music
for i in AudioServer.bus_count:
var bus_name := AudioServer.get_bus_name(i)
if bus_name != "Master" and bus_name != "Sounds":
AudioServer.set_bus_volume_db(i, volume_music)
AudioServer.set_bus_mute(i, volume_music <= -15.0)
save_settings()
var volume_sounds := 0.0 : set = _set_volume_sounds, get = _get_volume_sounds
func _get_volume_sounds() -> float:
return volume_sounds
func _set_volume_sounds(new_volume_sounds: float) -> void:
var bus_index := AudioServer.get_bus_index("Sounds")
if bus_index == -1:
print("The Sounds audio bus is missing, can't set new volume!")
return
volume_sounds = new_volume_sounds
AudioServer.set_bus_mute(bus_index, volume_sounds <= -15.0)
AudioServer.set_bus_volume_db(bus_index, volume_sounds)
save_settings()
func _ready() -> void:
if not FileAccess.file_exists(settings_file_name):
print("The settings file has not been found, not reading from it")
return
var settings_file := FileAccess.open(settings_file_name, FileAccess.READ)
var json := JSON.new()
var json_string := settings_file.get_line()
if json.parse(json_string) != OK:
print("(SETTINGS) JSON Parse Error: ", json.get_error_message(), " in ", json_string, " at line ", json.get_error_line())
return
if json.data.has("fullscreen") and typeof(json.data["fullscreen"]) == TYPE_BOOL:
fullscreen = json.data["fullscreen"]
if json.data.has("sound_on_gravity_change") and typeof(json.data["sound_on_gravity_change"]) == TYPE_BOOL:
sound_on_gravity_change = json.data["sound_on_gravity_change"]
if json.data.has("volume_music") and typeof(json.data["volume_music"]) == TYPE_FLOAT:
volume_music = json.data["volume_music"]
if json.data.has("volume_sounds") and typeof(json.data["volume_sounds"]) == TYPE_FLOAT:
volume_sounds = json.data["volume_sounds"]
func save_settings() -> void:
var settings_file := FileAccess.open(settings_file_name, FileAccess.WRITE)
var json_string := JSON.stringify({
"fullscreen": fullscreen,
"sound_on_gravity_change": sound_on_gravity_change,
"volume_music": volume_music,
"volume_sounds": volume_sounds,
})
settings_file.store_line(json_string)
settings_file.store_line("FOR YOUR SAFETY, ALWAYS CHECK IF THE DATA OF THE FILES YOU DOWNLOAD LOOKS OKAY")

1
settings.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://6or7tnhtbqe6

BIN
sounds/confirm.ogg Normal file

Binary file not shown.

19
sounds/confirm.ogg.import Normal file
View file

@ -0,0 +1,19 @@
[remap]
importer="oggvorbisstr"
type="AudioStreamOggVorbis"
uid="uid://bq3tw55s0ud55"
path="res://.godot/imported/confirm.ogg-611700f2069cfd206385315fc10e9491.oggvorbisstr"
[deps]
source_file="res://sounds/confirm.ogg"
dest_files=["res://.godot/imported/confirm.ogg-611700f2069cfd206385315fc10e9491.oggvorbisstr"]
[params]
loop=false
loop_offset=0
bpm=0
beat_count=0
bar_beats=4

BIN
sounds/select.ogg Normal file

Binary file not shown.

19
sounds/select.ogg.import Normal file
View file

@ -0,0 +1,19 @@
[remap]
importer="oggvorbisstr"
type="AudioStreamOggVorbis"
uid="uid://bnbf1nfaxuagi"
path="res://.godot/imported/select.ogg-c7e346119419231e86eb892abcba5520.oggvorbisstr"
[deps]
source_file="res://sounds/select.ogg"
dest_files=["res://.godot/imported/select.ogg-c7e346119419231e86eb892abcba5520.oggvorbisstr"]
[params]
loop=false
loop_offset=0
bpm=0
beat_count=0
bar_beats=4

Binary file not shown.

Binary file not shown.