Compare commits

..

12 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
39 changed files with 1631 additions and 664 deletions

View file

@ -4,31 +4,38 @@
script/source = "class_name Player
extends Node3D
var velocity: Vector3 = Vector3(0, 0, 0)
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)
$SpotLightTop.position = $Sphere.position
$SpotLightLeft.position = $Sphere.position
$SpotLightRight.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)
## Angle of the camera, so the player can see where the ball is going
velocity = $Sphere.linear_velocity
var desired_x = max(min(velocity.y, 35), -35)
var desired_y = max(min(-velocity.x, 50), -50)
# Angle of the camera, so the player can see where the ball is going
velocity = abs($Sphere.linear_velocity.x) + abs($Sphere.linear_velocity.y)
var desired_x = max(min($Sphere.linear_velocity.y, 35), -35)
var desired_y = max(min(-$Sphere.linear_velocity.x, 50), -50)
var difference_x = $Camera.rotation_degrees.x - desired_x
var difference_y = $Camera.rotation_degrees.y - desired_y
$Camera.rotation_degrees.x -= max(min(difference_x / 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
var total_velocity = abs(velocity.x) + abs(velocity.y)
$Camera.fov = default_fov + (total_velocity / 12)
$Camera.fov = default_fov + (velocity / 12)
"
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_vumbr"]

View file

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

View file

@ -9,9 +9,11 @@ custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter="exports/*"
export_path="exports/AlakajamEntry.x86_64"
export_path="exports/DreamBall.x86_64"
patches=PackedStringArray()
encryption_include_filters=""
encryption_exclude_filters=""
seed=0
encrypt_pck=false
encrypt_directory=false
script_export_mode=2
@ -49,9 +51,11 @@ custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter="exports/*"
export_path="exports/AlakajamEntry.exe"
export_path="exports/DreamBall.exe"
patches=PackedStringArray()
encryption_include_filters=""
encryption_exclude_filters=""
seed=0
encrypt_pck=false
encrypt_directory=false
script_export_mode=2
@ -114,9 +118,11 @@ custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter="exports/*"
export_path="exports/web/AlakajamEntry.html"
export_path="exports/web/DreamBall.html"
patches=PackedStringArray()
encryption_include_filters=""
encryption_exclude_filters=""
seed=0
encrypt_pck=false
encrypt_directory=false
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,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="AudioStream" uid="uid://dmdbharecy448" path="res://sounds/gravity.ogg" id="2_5uwlw"]
@ -6,62 +6,35 @@
[sub_resource type="GDScript" id="GDScript_3yq1l"]
script/source = "extends Control
var player_ready = false
const normal = 7
const stronger = normal * 3
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
@onready var direction_node: TextureRect = $Direction
@onready var animation: AnimationPlayer = $Direction/AnimationPlayer
@onready var audio: AudioStreamPlayer = $Direction/AudioStreamPlayer
func _ready() -> void:
# 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:
if ev is InputEventKey and ev.is_pressed():
var k = ev.keycode
if k == KEY_UP or k == KEY_RIGHT or k == KEY_LEFT or k == KEY_DOWN:
var direction = Vector3()
if k == KEY_UP:
direction = Vector3.UP
self.rotation_degrees = -90
$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
self.rotation_degrees = 0
$AudioStreamPlayer.pitch_scale = 0.98
elif k == KEY_DOWN:
direction = Vector3.DOWN
self.rotation_degrees = 90
$AudioStreamPlayer.pitch_scale = 0.95
if get_parent().player_ready == false or direction != PhysicsServer3D.area_get_param(
get_viewport().find_world_3d().space,
PhysicsServer3D.AREA_PARAM_GRAVITY_VECTOR
):
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():
$AnimationPlayer.stop()
$AnimationPlayer.play(\"grow_fadeout\")
if Settings.sound_on_gravity_change:
$AudioStreamPlayer.play()
func react_to_gravity_change(direction: Vector3) -> void:
if direction == Vector3.UP:
direction_node.rotation_degrees = -90
audio.pitch_scale = 1.05
elif direction == Vector3.LEFT:
direction_node.rotation_degrees = -180
audio.pitch_scale = 1.02
elif direction == Vector3.RIGHT:
direction = Vector3.RIGHT
direction_node.rotation_degrees = 0
audio.pitch_scale = 0.98
elif direction == Vector3.DOWN:
direction_node.rotation_degrees = 90
audio.pitch_scale = 0.95
if animation.is_playing():
animation.stop()
animation.play(\"grow_fadeout\")
if Settings.sound_on_gravity_change:
audio.play()
"
[sub_resource type="Animation" id="Animation_6rwl4"]
@ -133,6 +106,7 @@ anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
script = SubResource("GDScript_3yq1l")
[node name="Direction" type="TextureRect" parent="."]
@ -151,8 +125,8 @@ grow_horizontal = 2
grow_vertical = 2
scale = Vector2(0.3, 0.3)
pivot_offset = Vector2(400, 400)
mouse_filter = 2
texture = ExtResource("1_4mbho")
script = SubResource("GDScript_my602")
[node name="AnimationPlayer" type="AnimationPlayer" parent="Direction"]
libraries = {

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,109 +1,125 @@
[gd_scene load_steps=4 format=3 uid="uid://ccgnnif026wb4"]
[gd_scene load_steps=8 format=3 uid="uid://ccgnnif026wb4"]
[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"]
script/source = "extends Node
var playing: bool = false
var seconds_spent: float = 0.00
var changing_level: bool = false
var playing := false
var changing_level := false
var current_level_int: int = 0
var levels = [
preload(\"res://levels/base/level.tscn\"),
preload(\"res://levels/forest/level.tscn\"),
preload(\"res://levels/night/level.tscn\"),
]
var area_resource = preload(\"res://menus/main/area.tscn\")
var main_menu: Node
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:
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
if OS.has_feature(\"editor\"):
$DevInfos.text = \"dev \"
$DevInfos.text += \"build \" + ProjectSettings.get_setting(\"application/config/version\") + \" (\" + os_name + \")\"
launch_area()
$DevInfos.text += \"build \" + ProjectSettings.get_setting(\"application/config/version\") + \" (\" + OS.get_name() + \")\"
## Hide UI stuff that shouldn't be visible until later in the game
pause_menu.hide()
## Connect to necessary signals
pause_menu.connect(\"request_pause\", pause_game)
pause_menu.connect(\"request_fullscreen\", fullscreen_game)
pause_menu.connect(\"request_restart\", restart_level)
set_main_menu()
func launch_area():
func set_main_menu() -> void:
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
var area := area_resource.instantiate()
area.connect(\"request_start\", start_game)
$Levels.add_child(area)
$GUI.hide()
## If no main menu exists yet, create one
if !is_instance_valid(main_menu):
main_menu = res_main_menu.instantiate()
main_menu.connect(\"request_play_level\", start_level)
add_child(main_menu)
## Get all the levels that are currently being played!
## In theory, there should ever be only zero or one,
## but it turns out it's more simple to handle things by using Arrays.
func get_current_levels() -> Array[Level]:
var children := $Levels.get_children(true)
var current_levels: Array[Level] = []
for child in children:
if is_instance_of(child, Level):
current_levels.push_back(child)
return current_levels
func start_level(level_scene: PackedScene) -> void:
$VictoryScreen.hide()
var level = level_scene.instantiate()
$Levels.add_child(level)
level.connect(\"completed\", stop_level)
playing = true
PhysicsServer3D.area_set_param(
get_viewport().find_world_3d().space,
PhysicsServer3D.AREA_PARAM_GRAVITY_VECTOR,
Vector3.DOWN
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 stop_level() -> void:
PhysicsServer3D.area_set_param(get_viewport().find_world_3d().space, PhysicsServer3D.AREA_PARAM_GRAVITY, 1)
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
var current_levels = get_current_levels()
for level in current_levels:
level.music.fadeOut(2)
await get_tree().create_timer(2).timeout
level.queue_free()
SaveFiles.change_property(\"played_for\", gui_timer.seconds_spent_total, SaveFiles.selected_file)
var save_file_data = SaveFiles.read(SaveFiles.selected_file)
var property_name := current_level.id + \"_best_time\"
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:
SaveFiles.change_property(property_name, gui_timer.seconds_spent_level_attempt, SaveFiles.selected_file)
if len(levels) > current_level_int + 1:
current_level_int += 1
start_level(levels[current_level_int])
else:
win_game()
func win_game() -> void:
$VictoryScreen.show()
current_level.music.fadeOut(2)
await get_tree().create_timer(2).timeout
launch_area()
$VictoryScreen.hide()
current_level.queue_free()
set_main_menu()
func restart_level() -> void:
if changing_level == false:
var current_levels = get_current_levels()
if len(current_levels):
pause_game()
changing_level = true
for level in current_levels:
level.queue_free()
start_level(levels[current_level_int])
gui_timer.enabled = false
if !current_level or changing_level:
return
if current_level_scene is not PackedScene:
print(\"Tried to restart the level despite not having the level scene\")
return
SaveFiles.change_property(\"played_for\", gui_timer.seconds_spent_total, SaveFiles.selected_file)
start_level(current_level_scene.instantiate(), current_level_scene)
func pause_game() -> void:
if $Levels.process_mode == PROCESS_MODE_INHERIT:
$Levels.process_mode = Node.PROCESS_MODE_DISABLED
func pause_game(to_pause: bool) -> void:
if !is_instance_valid(current_level) or changing_level:
return
if to_pause:
SaveFiles.change_property(\"played_for\", gui_timer.seconds_spent_total, SaveFiles.selected_file)
current_level.process_mode = Node.PROCESS_MODE_DISABLED
playing = false
$PauseMenu.show()
pause_menu.show()
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
else:
$Levels.process_mode = Node.PROCESS_MODE_INHERIT
current_level.process_mode = Node.PROCESS_MODE_INHERIT
playing = true
$PauseMenu.hide()
pause_menu.hide()
Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)
func fullscreen_game() -> void:
@ -113,179 +129,85 @@ func fullscreen_game() -> void:
else:
DisplayServer.window_set_mode(DisplayServer.WindowMode.WINDOW_MODE_WINDOWED)
func start_game() -> void:
seconds_spent = 0.0
current_level_int = 0
var current_levels = $Levels.get_children(true)
for level in current_levels:
level.queue_free()
$Informations.show()
Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)
start_level(levels[0])
func _process(_delta: float) -> void:
if is_instance_valid(current_level):
gui_speed.ball_velocity = current_level.velocity
if Input.is_action_pressed(\"display_map\"):
gui_map.display_rings(current_level.player, current_level.rings)
func update_timer(delta: float) -> void:
if playing:
seconds_spent += delta
var minutes = floor(seconds_spent / 60)
$Informations/MarginContainer/Timer.text = (\"%0*d\" % [2, minutes]) + \":\" + (\"%0*.2f\" % [5, seconds_spent - (minutes * 60)])
func _process(delta: float) -> void:
update_timer(delta)
var current_levels = get_current_levels()
if len(current_levels):
var current_level = current_levels[0]
$Informations/MarginContainer/VBoxContainer/Speed.text = str(int(floor(current_level.velocity))) + \" km/h\"
$Informations/MarginContainer/VBoxContainer/Rings.text = str(current_level.finished_rings_count) + \"/\" + str(len(current_level.rings))
func _unhandled_key_input(event: InputEvent) -> void:
if event.is_pressed() and event is InputEventKey:
var current_levels := get_current_levels()
if len(current_levels) and changing_level == false:
if event.keycode == KEY_ESCAPE:
pause_game()
elif event.keycode == KEY_R:
pause_game()
restart_level()
func _input(_event: InputEvent) -> void:
if Input.is_action_just_released(\"display_map\"):
gui_map.hide()
if Input.is_action_just_pressed(\"display_map\"):
gui_map.show()
if Input.is_action_just_pressed(\"restart_level\"):
restart_level()
func _on_btn_quit_pressed() -> void:
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)
[node name="Game" type="Node"]
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
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
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"]
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"]
[node name="TopLeft" type="MarginContainer" parent="GUI"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
text = "YOU WON!"
label_settings = SubResource("LabelSettings_1bs00")
horizontal_alignment = 1
vertical_alignment = 1
offset_right = 160.0
offset_bottom = 85.0
rotation = 0.0523599
theme_override_constants/margin_left = 15
[node name="Levels" type="Node" parent="."]
[node name="Timer" parent="GUI/TopLeft" instance=ExtResource("1_356j3")]
layout_mode = 2
[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"]
[node name="TopRight" type="MarginContainer" parent="GUI"]
layout_mode = 1
anchors_preset = 15
anchors_preset = 1
anchor_left = 1.0
anchor_right = 1.0
offset_left = -106.0
offset_bottom = 51.0
grow_horizontal = 0
rotation = -0.0523599
theme_override_constants/margin_top = 5
theme_override_constants/margin_right = 15
[node name="Speed" parent="GUI/TopRight" instance=ExtResource("2_2gn6w")]
layout_mode = 2
[node name="BottomRight" type="MarginContainer" parent="GUI"]
layout_mode = 1
anchors_preset = 3
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
color = Color(1, 0.54902, 1, 0.109804)
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="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"]
[node name="Rings" parent="GUI/BottomRight" instance=ExtResource("3_mbj17")]
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"
[node name="DevInfos" type="Label" parent="."]
anchors_preset = 12
@ -297,7 +219,4 @@ grow_horizontal = 2
grow_vertical = 0
horizontal_alignment = 1
[connection signal="pressed" from="PauseMenu/VBoxContainer/Btn_Resume" to="." method="pause_game"]
[connection signal="pressed" from="PauseMenu/VBoxContainer/Btn_Fullscreen2" to="." method="fullscreen_game"]
[connection signal="pressed" from="PauseMenu/VBoxContainer/Btn_Restart" to="." method="restart_level"]
[connection signal="pressed" from="PauseMenu/VBoxContainer/Btn_Quit" to="." method="_on_btn_quit_pressed"]
[node name="PauseMenu" parent="." instance=ExtResource("4_3bfj3")]

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,20 +1,49 @@
[gd_scene load_steps=8 format=3 uid="uid://ovtknjyj83gh"]
[gd_scene load_steps=11 format=3 uid="uid://ovtknjyj83gh"]
[ext_resource type="PackedScene" uid="uid://ygvokp5f78i5" path="res://levels/base/environment.tscn" id="1_n7fd8"]
[ext_resource type="Script" uid="uid://w3fetao1pegm" 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://cpm3laywhlbq5" path="res://elements/ring.tscn" id="3_hel5x"]
[ext_resource type="PackedScene" uid="uid://dw0xl8644x166" path="res://elements/gravity.tscn" id="3_muudg"]
[ext_resource type="PackedScene" uid="uid://c77bli40240nk" path="res://elements/sign.tscn" id="4_atq6y"]
[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"]
script = ExtResource("1_rj40i")
script = SubResource("GDScript_1yugx")
metadata/_custom_type_script = "uid://w3fetao1pegm"
[node name="Gravity" parent="." instance=ExtResource("3_muudg")]
[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")]
@ -133,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")]
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/Sign7"]
[editable path="Signs/Sign2"]

View file

@ -1,32 +0,0 @@
[gd_scene load_steps=7 format=3 uid="uid://dtfybhftwfn00"]
[ext_resource type="Script" uid="uid://w3fetao1pegm" path="res://levels/level.gd" id="1_scm0b"]
[ext_resource type="PackedScene" uid="uid://dw0xl8644x166" path="res://elements/gravity.tscn" id="2_fo4i1"]
[ext_resource type="PackedScene" uid="uid://b6gnffoboc5j5" path="res://levels/night/environment.tscn" id="3_j4ado"]
[ext_resource type="PackedScene" uid="uid://drfy3vhe6skp1" path="res://levels/night/music.tscn" id="4_qr8kk"]
[ext_resource type="PackedScene" uid="uid://cnnvwotv33u1b" path="res://elements/player.tscn" id="5_j5vh3"]
[ext_resource type="PackedScene" uid="uid://cpm3laywhlbq5" path="res://elements/ring.tscn" id="6_st6rs"]
[node name="Demo" type="Node3D"]
script = ExtResource("1_scm0b")
metadata/_custom_type_script = "uid://w3fetao1pegm"
[node name="Gravity" parent="." instance=ExtResource("2_fo4i1")]
[node name="Environment" parent="." instance=ExtResource("3_j4ado")]
[node name="Music" parent="." instance=ExtResource("4_qr8kk")]
[node name="Player" parent="." instance=ExtResource("5_j5vh3")]
[node name="Rings" type="Node3D" parent="."]
[node name="Ring" parent="Rings" instance=ExtResource("6_st6rs")]
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("6_st6rs")]
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("6_st6rs")]
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://6nfv4ewj3jop"]
[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,14 +1,32 @@
[gd_scene load_steps=12 format=3 uid="uid://e1761h6d522a"]
[gd_scene load_steps=10 format=3 uid="uid://e1761h6d522a"]
[ext_resource type="PackedScene" uid="uid://6nfv4ewj3jop" path="res://levels/forest/environment.tscn" id="1_7clrg"]
[ext_resource type="Script" uid="uid://w3fetao1pegm" path="res://levels/level.gd" id="1_fdxcj"]
[ext_resource type="PackedScene" uid="uid://dw0xl8644x166" path="res://elements/gravity.tscn" id="2_gxmta"]
[ext_resource type="PackedScene" uid="uid://cnnvwotv33u1b" path="res://elements/player.tscn" id="2_mjogx"]
[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://da6lkdiskdh8v" path="res://elements/tree.tscn" id="6_1e514"]
[ext_resource type="PackedScene" uid="uid://c77bli40240nk" path="res://elements/sign.tscn" id="6_ifogr"]
[sub_resource type="GDScript" id="GDScript_mqwxc"]
script/source = "extends Level
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)
@ -30,17 +48,15 @@ ambient_light_color = Color(1, 1, 1, 1)
reflected_light_source = 2
[node name="Forest" type="Node3D"]
script = ExtResource("1_fdxcj")
script = SubResource("GDScript_mqwxc")
metadata/_custom_type_script = "uid://w3fetao1pegm"
[node name="Gravity" parent="." instance=ExtResource("2_gxmta")]
[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" parent="." instance=ExtResource("1_7clrg")]
[node name="Environment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_y3whn")
[node name="Music" parent="." instance=ExtResource("3_n1xsx")]
@ -262,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")]
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"]

BIN
levels/forest/thumbnail.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dhyxogc13hnbe"
path="res://.godot/imported/thumbnail.png-6909560b6205778a3cb325a584af7ca5.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://levels/forest/thumbnail.png"
dest_files=["res://.godot/imported/thumbnail.png-6909560b6205778a3cb325a584af7ca5.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

View file

@ -1,20 +1,47 @@
class_name Level
extends Node3D
signal started_playing
signal gravity_change
signal ring_collected
signal completed
var seconds_spent: float = 0.00
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 velocity: float = 0.0
var rings: Array[Ring] = []
var finished_rings_count: int = 0
var velocity: float = 0.0
var has_started_playing: bool = false
func _init() -> void:
assert(len(id) > 0, self.name + " has no id!")
func _ready() -> void:
PhysicsServer3D.area_set_param(
get_viewport().find_world_3d().space,
PhysicsServer3D.AREA_PARAM_GRAVITY_VECTOR,
Vector3(0, 0, 0)
)
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")
@ -32,7 +59,46 @@ func collect_ring():
if finished_rings_count >= len(rings):
completed.emit()
func _process(delta: float) -> void:
seconds_spent += delta
velocity = abs($Player.velocity.x) + abs($Player.velocity.y)
music.adaptInstrumentsToVelocity(velocity, delta)
func _input(_event: InputEvent) -> void:
if Input.is_action_pressed("gravity_strong") or Input.is_action_just_released("gravity_strong"):
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 up := Input.is_action_just_pressed("gravity_up")
var left := Input.is_action_just_pressed("gravity_left")
var right := Input.is_action_just_pressed("gravity_right")
var down := Input.is_action_just_pressed("gravity_down")
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)

View file

@ -40,7 +40,9 @@ 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, delta: float) -> void:
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)

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,22 +1,51 @@
[gd_scene load_steps=10 format=3 uid="uid://drnqmu4lka22d"]
[gd_scene load_steps=13 format=3 uid="uid://drnqmu4lka22d"]
[ext_resource type="Script" uid="uid://w3fetao1pegm" 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://cnnvwotv33u1b" path="res://elements/player.tscn" id="2_bc1ig"]
[ext_resource type="PackedScene" uid="uid://dw0xl8644x166" path="res://elements/gravity.tscn" id="2_lfplq"]
[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://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://da6lkdiskdh8v" path="res://elements/tree.tscn" id="8_kgstj"]
[sub_resource type="GDScript" id="GDScript_akhnt"]
script/source = "extends Level
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 = ExtResource("1_3m1pa")
script = SubResource("GDScript_akhnt")
metadata/_custom_type_script = "uid://w3fetao1pegm"
[node name="Gravity" parent="." instance=ExtResource("2_lfplq")]
[node name="Environment" parent="." instance=ExtResource("2_wintp")]
[node name="Environment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_8o42c")
[node name="Music" parent="." instance=ExtResource("1_npc74")]
@ -175,7 +204,7 @@ transform = Transform3D(-1.31134e-07, -3, 0, 3, -1.31134e-07, 0, 0, 0, 3, -104.2
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.79443, -7.04289, 0, 7.04289, -3.79443, 0, 0, 0, 8, 28.958, -413.185, -93.8242)
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="."]
@ -309,6 +338,8 @@ transform = Transform3D(-0.99693, 0.0731445, -0.0279554, -0.0555776, -0.912445,
[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)
[connection signal="velocity_change" from="Player" to="." method="_on_player_velocity_change"]
[editable path="Signs/Sign"]
[editable path="Signs/Sign4"]
[editable path="Signs/Sign2"]

View file

@ -1,146 +0,0 @@
[gd_scene load_steps=10 format=3 uid="uid://ikeidrgprk8k"]
[ext_resource type="PackedScene" uid="uid://wlhsarkeqe8r" path="res://menus/main/panel.tscn" id="1_qfa5o"]
[ext_resource type="PackedScene" uid="uid://cnnvwotv33u1b" path="res://elements/player.tscn" id="2_0jxef"]
[sub_resource type="GDScript" id="GDScript_bt14i"]
script/source = "extends Node3D
signal request_start
var start_menu = preload(\"res://menus/main/start_menu.tscn\")
var save_file_manager = preload(\"res://menus/main/save_file_manager.tscn\")
var settings_menu = preload(\"res://menus/main/settings_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 sm = start_menu.instantiate()
sm.connect(\"request_start\", start)
sm.connect(\"request_settings\", settings)
$Menus/Panel1.change_menu(sm, false)
func start() -> void:
request_start.emit()
#var svm = save_file_manager.instantiate()
#$Menus/Panel2.change_menu(svm)
#rotate_cube_to(90)
func settings() -> void:
var sm = settings_menu.instantiate()
$Menus/Panel2.change_menu(sm)
rotate_cube_to(90)
func rotate_cube_to(degrees: int) -> void:
if $Menus/AnimationPlayer.is_playing():
return
degrees = -degrees
var animation: Animation = $Menus/AnimationPlayer.get_animation(\"rotate\")
var new_rotation = Vector3(0, degrees, 0)
animation.track_set_key_value(0, 0, $Menus.rotation_degrees)
animation.track_set_key_value(0, 1, new_rotation)
$Menus/AnimationPlayer.play(\"rotate\")
"
[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="PhysicalSkyMaterial" id="PhysicalSkyMaterial_bt14i"]
ground_color = Color(0.794232, 0.673177, 0.531056, 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
[node name="Area" 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_qfa5o")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.501)
[node name="Panel2" parent="Menus" instance=ExtResource("1_qfa5o")]
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_qfa5o")]
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_qfa5o")]
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="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_0jxef")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.87335, 0)
[node name="Camera" parent="Player" index="0"]
visible = false
current = false
[node name="GPUParticles3D" parent="Player/Sphere" index="2"]
visible = false
[editable path="Player"]

View file

@ -16,7 +16,7 @@ func _on_btn_exit_pressed() -> void:
get_tree().quit()
"
[node name="StartMenu" type="Control"]
[node name="InitialMenu" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
@ -27,12 +27,9 @@ script = SubResource("GDScript_vfuxb")
[node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 14
anchor_top = 0.5
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 0.5
offset_top = -50.5
offset_bottom = 50.5
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
alignment = 1

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

View file

@ -1,102 +1,125 @@
[gd_scene load_steps=5 format=3 uid="uid://w5te3qujco7d"]
[gd_scene load_steps=2 format=3 uid="uid://w5te3qujco7d"]
[sub_resource type="GDScript" id="GDScript_a5kgg"]
script/source = "extends MarginContainer
script/source = "extends Control
signal request_start
@onready var label_name = $VBoxContainer/MarginContainer/VBoxContainer/Description/Name
func _ready() -> void:
$HSplitContainer/CenterContainer/Label.hide()
$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_button_pressed() -> void:
$HSplitContainer/CenterContainer/Label.show()
$AnimationPlayer.play(\"add_information\")
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)
"
[sub_resource type="Animation" id="Animation_a5kgg"]
resource_name = "add_information"
length = 0.2
step = 0.2
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("HSplitContainer/CenterContainer:size_flags_stretch_ratio")
tracks/0/interp = 2
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.2),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [0.0, 2.0]
}
[sub_resource type="Animation" id="Animation_xs01b"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("HSplitContainer/CenterContainer:size_flags_stretch_ratio")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [0.0]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_36lt1"]
_data = {
&"RESET": SubResource("Animation_xs01b"),
&"add_information": SubResource("Animation_a5kgg")
}
[node name="SaveFileManager" type="MarginContainer"]
[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
size_flags_horizontal = 4
size_flags_vertical = 4
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_a5kgg")
[node name="HSplitContainer" type="HSplitContainer" parent="."]
layout_mode = 2
[node name="VBoxContainer" type="VBoxContainer" parent="HSplitContainer"]
layout_mode = 2
[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="Button" type="Button" parent="HSplitContainer/VBoxContainer"]
[node name="Save1" type="Button" parent="VBoxContainer"]
layout_mode = 2
text = "Save file"
text = "Save file #1"
[node name="Button2" type="Button" parent="HSplitContainer/VBoxContainer"]
[node name="Save2" type="Button" parent="VBoxContainer"]
layout_mode = 2
text = "Save file"
text = "Save file #2"
[node name="Button3" type="Button" parent="HSplitContainer/VBoxContainer"]
[node name="Save3" type="Button" parent="VBoxContainer"]
layout_mode = 2
text = "Save file"
text = "Save file #3"
[node name="CenterContainer" type="CenterContainer" parent="HSplitContainer"]
[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
size_flags_stretch_ratio = 0.0
text = "Start"
[node name="Label" type="Label" parent="HSplitContainer/CenterContainer"]
show_behind_parent = true
[node name="Delete" type="Button" parent="VBoxContainer/MarginContainer/VBoxContainer/Buttons"]
layout_mode = 2
text = "Information"
text = "Delete"
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
libraries = {
&"": SubResource("AnimationLibrary_36lt1")
}
[connection signal="pressed" from="HSplitContainer/VBoxContainer/Button" to="." method="_on_button_pressed"]
[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

@ -1,4 +1,7 @@
[gd_scene load_steps=6 format=3 uid="uid://tasbgr10p84c"]
[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
@ -26,6 +29,21 @@ func add(node: Control, return_button: bool):
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\")
@ -96,10 +114,12 @@ libraries = {
}
[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"]
@ -109,3 +129,11 @@ 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

@ -13,7 +13,7 @@ config_version=5
config/name="DreamBall"
config/description="Manipulate the gravity to make a ball go through every ring!
https://kitsunes.dev/Taevas/DreamBall"
config/version="20250330.0"
config/version="20250503.0"
run/main_scene="res://index.tscn"
config/features=PackedStringArray("4.4", "GL Compatibility")
boot_splash/show_image=false
@ -23,6 +23,68 @@ config/windows_native_icon="res://icon.ico"
[autoload]
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]
@ -31,6 +93,7 @@ common/physics_ticks_per_second=120
common/max_physics_steps_per_frame=20
3d/physics_engine="GodotPhysics3D"
3d/default_gravity=1.0
3d/default_gravity_vector=Vector3(0, -0.5, 0)
3d/solver/solver_iterations=40
3d/solver/default_contact_bias=1.0
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

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.