Compare commits

...

6 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
22 changed files with 870 additions and 452 deletions

View file

@ -4,31 +4,38 @@
script/source = "class_name Player script/source = "class_name Player
extends Node3D 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: func _physics_process(_delta: float) -> void:
ball_position = $Sphere.position
$SpotLightMain.position = $Sphere.position + Vector3(0, 5, 0) $SpotLightMain.position = $Sphere.position + Vector3(0, 5, 0)
$SpotLightTop.position = $Sphere.position $SpotLightTop.position = $Sphere.position
$SpotLightLeft.position = $Sphere.position $SpotLightLeft.position = $Sphere.position
$SpotLightRight.position = $Sphere.position $SpotLightRight.position = $Sphere.position
$SpotLightBottom.position = $Sphere.position $SpotLightBottom.position = $Sphere.position
## Keep the ball at the center of the camera, at a distance # Keep the ball at the center of the camera, at a distance
$Camera.position = $Sphere.position + Vector3(0, 0, 15) $Camera.position = $Sphere.position + Vector3(0, 0, 15)
## Angle of the camera, so the player can see where the ball is going # Angle of the camera, so the player can see where the ball is going
velocity = $Sphere.linear_velocity velocity = abs($Sphere.linear_velocity.x) + abs($Sphere.linear_velocity.y)
var desired_x = max(min(velocity.y, 35), -35) var desired_x = max(min($Sphere.linear_velocity.y, 35), -35)
var desired_y = max(min(-velocity.x, 50), -50) var desired_y = max(min(-$Sphere.linear_velocity.x, 50), -50)
var difference_x = $Camera.rotation_degrees.x - desired_x var difference_x = $Camera.rotation_degrees.x - desired_x
var difference_y = $Camera.rotation_degrees.y - desired_y var difference_y = $Camera.rotation_degrees.y - desired_y
$Camera.rotation_degrees.x -= max(min(difference_x / 2, 3), -3) $Camera.rotation_degrees.x -= max(min(difference_x / 2, 3), -3)
$Camera.rotation_degrees.y -= max(min(difference_y / 2, 3), -3) $Camera.rotation_degrees.y -= max(min(difference_y / 2, 3), -3)
## FOV of the camera, so it unzooms more at higher velocities # FOV of the camera, so it unzooms more at higher velocities
const default_fov = 75 const default_fov = 75
var total_velocity = abs(velocity.x) + abs(velocity.y) $Camera.fov = default_fov + (velocity / 12)
$Camera.fov = default_fov + (total_velocity / 12)
" "
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_vumbr"] [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) albedo_color = Color(0.212217, 0.468618, 0, 1)
[node name="Tree" type="Node3D"] [node name="Tree" type="Node3D"]
physics_interpolation_mode = 2
script = SubResource("GDScript_tbkod") script = SubResource("GDScript_tbkod")
[node name="Dirt" type="CSGBox3D" parent="."] [node name="Dirt" type="CSGBox3D" parent="."]

View file

@ -1,4 +1,4 @@
[gd_scene load_steps=8 format=3 uid="uid://dw0xl8644x166"] [gd_scene load_steps=7 format=3 uid="uid://dw0xl8644x166"]
[ext_resource type="Texture2D" uid="uid://ctjugvy1v3y6b" path="res://graphics/arrow.svg" id="1_4mbho"] [ext_resource type="Texture2D" uid="uid://ctjugvy1v3y6b" path="res://graphics/arrow.svg" id="1_4mbho"]
[ext_resource type="AudioStream" uid="uid://dmdbharecy448" path="res://sounds/gravity.ogg" id="2_5uwlw"] [ext_resource type="AudioStream" uid="uid://dmdbharecy448" path="res://sounds/gravity.ogg" id="2_5uwlw"]
@ -6,66 +6,35 @@
[sub_resource type="GDScript" id="GDScript_3yq1l"] [sub_resource type="GDScript" id="GDScript_3yq1l"]
script/source = "extends Control script/source = "extends Control
var player_ready = false @onready var direction_node: TextureRect = $Direction
const normal = 7 @onready var animation: AnimationPlayer = $Direction/AnimationPlayer
const stronger = normal * 3 @onready var audio: AudioStreamPlayer = $Direction/AudioStreamPlayer
func _input(_event: InputEvent) -> void:
if player_ready:
var grav = stronger if Input.is_action_pressed(\"gravity_strong\") else normal
PhysicsServer3D.area_set_param(get_viewport().find_world_3d().space, PhysicsServer3D.AREA_PARAM_GRAVITY, grav)
"
[sub_resource type="GDScript" id="GDScript_my602"]
script/source = "extends TextureRect
func _ready() -> void: func _ready() -> void:
# set the indicator to be fully transparent when it first spawns # set the indicator to be fully transparent when it first spawns
self.self_modulate = Color(1, 1, 1, 0) direction_node.self_modulate = Color(1, 1, 1, 0)
func _input(ev: InputEvent) -> void: func react_to_gravity_change(direction: Vector3) -> void:
if ev is InputEventKey and ev.is_pressed(): if direction == Vector3.UP:
var up := Input.is_action_just_pressed(\"gravity_up\") direction_node.rotation_degrees = -90
var left := Input.is_action_just_pressed(\"gravity_left\") audio.pitch_scale = 1.05
var right := Input.is_action_just_pressed(\"gravity_right\") elif direction == Vector3.LEFT:
var down := Input.is_action_just_pressed(\"gravity_down\") direction_node.rotation_degrees = -180
audio.pitch_scale = 1.02
if up or left or right or down: elif direction == Vector3.RIGHT:
var direction = Vector3() direction = Vector3.RIGHT
if up: direction_node.rotation_degrees = 0
direction = Vector3.UP audio.pitch_scale = 0.98
self.rotation_degrees = -90 elif direction == Vector3.DOWN:
$AudioStreamPlayer.pitch_scale = 1.05 direction_node.rotation_degrees = 90
elif left: audio.pitch_scale = 0.95
direction = Vector3.LEFT
self.rotation_degrees = -180 if animation.is_playing():
$AudioStreamPlayer.pitch_scale = 1.02 animation.stop()
elif right: animation.play(\"grow_fadeout\")
direction = Vector3.RIGHT
self.rotation_degrees = 0 if Settings.sound_on_gravity_change:
$AudioStreamPlayer.pitch_scale = 0.98 audio.play()
elif 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()
" "
[sub_resource type="Animation" id="Animation_6rwl4"] [sub_resource type="Animation" id="Animation_6rwl4"]
@ -137,6 +106,7 @@ anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
mouse_filter = 2
script = SubResource("GDScript_3yq1l") script = SubResource("GDScript_3yq1l")
[node name="Direction" type="TextureRect" parent="."] [node name="Direction" type="TextureRect" parent="."]
@ -155,8 +125,8 @@ grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
scale = Vector2(0.3, 0.3) scale = Vector2(0.3, 0.3)
pivot_offset = Vector2(400, 400) pivot_offset = Vector2(400, 400)
mouse_filter = 2
texture = ExtResource("1_4mbho") texture = ExtResource("1_4mbho")
script = SubResource("GDScript_my602")
[node name="AnimationPlayer" type="AnimationPlayer" parent="Direction"] [node name="AnimationPlayer" type="AnimationPlayer" parent="Direction"]
libraries = { libraries = {

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

View file

@ -8,13 +8,9 @@ script/source = "extends VBoxContainer
var enabled := false: var enabled := false:
get: return enabled get: return enabled
set(value): set(value):
if enabled == value:
return
enabled = value enabled = value
if value == true:
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
if value == false: if value == false:
$AnimationPlayer.play(\"scale_linear\") $AnimationPlayer.play(\"scale_linear\")
await get_tree().create_timer($AnimationPlayer.current_animation_length).timeout await get_tree().create_timer($AnimationPlayer.current_animation_length).timeout
@ -31,10 +27,13 @@ var seconds_spent_level_attempt := 0.0:
seconds_spent_level_attempt = value seconds_spent_level_attempt = value
$Level.text = \"Level: \" + seconds_to_readable(seconds_spent_level_attempt) $Level.text = \"Level: \" + seconds_to_readable(seconds_spent_level_attempt)
func _ready(): func _on_visibility_changed() -> void:
var data = SaveFiles.read(SaveFiles.selected_file) if self.visible and len(SaveFiles.selected_file):
if data.has(\"played_for\") and data.played_for is float: var save_file = SaveFiles.read(SaveFiles.selected_file)
seconds_spent_total = data.played_for 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: func seconds_to_readable(seconds: float) -> String:
var minutes: int = floor(seconds / 60) var minutes: int = floor(seconds / 60)
@ -77,23 +76,6 @@ tracks/0/keys = {
"values": [Vector2(1, 1)] "values": [Vector2(1, 1)]
} }
[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="Animation" id="Animation_houb3"] [sub_resource type="Animation" id="Animation_houb3"]
resource_name = "scale_cubic" resource_name = "scale_cubic"
length = 0.25 length = 0.25
@ -111,6 +93,23 @@ tracks/0/keys = {
"values": [Vector2(1, 1), Vector2(1.2, 1.2)] "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"] [sub_resource type="AnimationLibrary" id="AnimationLibrary_jmgpn"]
_data = { _data = {
&"RESET": SubResource("Animation_m1tld"), &"RESET": SubResource("Animation_m1tld"),
@ -120,27 +119,24 @@ _data = {
[node name="Timer" type="VBoxContainer"] [node name="Timer" type="VBoxContainer"]
process_mode = 3 process_mode = 3
anchors_preset = 15 offset_right = 315.0
anchor_right = 1.0 offset_bottom = 85.0
anchor_bottom = 1.0
offset_right = -992.0
offset_bottom = -563.0
grow_horizontal = 2
grow_vertical = 2
theme_override_constants/separation = -5 theme_override_constants/separation = -5
script = SubResource("GDScript_q235s") script = SubResource("GDScript_q235s")
[node name="Total" type="Label" parent="."] [node name="Total" type="Label" parent="."]
layout_mode = 2 layout_mode = 2
text = "Total timer" text = "Total: 0:00.000"
label_settings = SubResource("LabelSettings_m1tld") label_settings = SubResource("LabelSettings_m1tld")
[node name="Level" type="Label" parent="."] [node name="Level" type="Label" parent="."]
layout_mode = 2 layout_mode = 2
text = "Level timer" text = "Level: 0:00.000"
label_settings = SubResource("LabelSettings_2a86r") label_settings = SubResource("LabelSettings_2a86r")
[node name="AnimationPlayer" type="AnimationPlayer" parent="."] [node name="AnimationPlayer" type="AnimationPlayer" parent="."]
libraries = { libraries = {
&"": SubResource("AnimationLibrary_jmgpn") &"": SubResource("AnimationLibrary_jmgpn")
} }
[connection signal="visibility_changed" from="." to="." method="_on_visibility_changed"]

View file

@ -1,24 +1,26 @@
[gd_scene load_steps=7 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://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://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://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"] [ext_resource type="PackedScene" uid="uid://dkxtwpcy4moyo" path="res://menus/pause_menu.tscn" id="4_3bfj3"]
[sub_resource type="GDScript" id="GDScript_8n212"] [sub_resource type="GDScript" id="GDScript_8n212"]
script/source = "extends Node script/source = "extends Node
var playing: bool = false var playing := false
var changing_level: bool = false var changing_level := false
var current_level_int: int = 0 var main_menu: Node
var levels = [ var current_level: Level
preload(\"res://levels/base/level.tscn\"), var current_level_scene: PackedScene
preload(\"res://levels/forest/level.tscn\"),
preload(\"res://levels/night/level.tscn\"),
]
var area_resource = preload(\"res://menus/main/area.tscn\")
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_timer := $GUI/TopLeft/Timer
@onready var gui_speed := $GUI/TopRight/Speed @onready var gui_speed := $GUI/TopRight/Speed
@onready var gui_rings := $GUI/BottomRight/Rings @onready var gui_rings := $GUI/BottomRight/Rings
@ -31,8 +33,6 @@ func _ready() -> void:
$DevInfos.text += \"build \" + ProjectSettings.get_setting(\"application/config/version\") + \" (\" + OS.get_name() + \")\" $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 ## Hide UI stuff that shouldn't be visible until later in the game
$VictoryScreen.hide()
$GUI.hide()
pause_menu.hide() pause_menu.hide()
## Connect to necessary signals ## Connect to necessary signals
@ -40,107 +40,84 @@ func _ready() -> void:
pause_menu.connect(\"request_fullscreen\", fullscreen_game) pause_menu.connect(\"request_fullscreen\", fullscreen_game)
pause_menu.connect(\"request_restart\", restart_level) pause_menu.connect(\"request_restart\", restart_level)
launch_area() set_main_menu()
func launch_area(): func set_main_menu() -> void:
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
var area := area_resource.instantiate() $GUI.hide()
area.connect(\"request_start\", start_game)
$Levels.add_child(area) ## 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! func start_level(level: Level, scene: PackedScene) -> void:
## In theory, there should ever be only zero or one, if is_instance_valid(current_level):
## but it turns out it's more simple to handle things by using Arrays. current_level.queue_free()
func get_current_levels() -> Array[Level]: if is_instance_valid(main_menu) and self.is_ancestor_of(main_menu):
var children := $Levels.get_children(true) self.remove_child(main_menu)
var current_levels: Array[Level] = []
for child in children: current_level = level
if is_instance_of(child, Level): current_level_scene = scene
current_levels.push_back(child) add_child(current_level)
return current_levels
current_level.connect(\"started_playing\", func(): gui_timer.enabled = true)
func start_level(level_scene: PackedScene) -> void: current_level.connect(\"gravity_change\", gui_gravity.react_to_gravity_change)
$VictoryScreen.hide() current_level.connect(\"completed\", finish_current_level)
var level = level_scene.instantiate() current_level.connect(\"ring_collected\", func():
$Levels.add_child(level) gui_rings.remaining_rings = len(current_level.rings) - current_level.finished_rings_count
level.connect(\"completed\", stop_level)
level.connect(\"ring_collected\", func():
gui_rings.remaining_rings = len(level.rings) - level.finished_rings_count
) )
gui_rings.remaining_rings = len(level.rings) - 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 playing = true
PhysicsServer3D.area_set_param(
get_viewport().find_world_3d().space,
PhysicsServer3D.AREA_PARAM_GRAVITY_VECTOR,
Vector3.DOWN
)
changing_level = false changing_level = false
gui_timer.seconds_spent_level_attempt = 0.0 gui_timer.seconds_spent_level_attempt = 0.0
gui_timer.enabled = true
func stop_level() -> void: func finish_current_level() -> void:
gui_timer.enabled = false gui_timer.enabled = false
PhysicsServer3D.area_set_param(get_viewport().find_world_3d().space, PhysicsServer3D.AREA_PARAM_GRAVITY, 1) PhysicsServer3D.area_set_param(get_viewport().find_world_3d().space, PhysicsServer3D.AREA_PARAM_GRAVITY, 0.5)
playing = false playing = false
changing_level = true changing_level = true
SaveFiles.change_property(\"played_for\", gui_timer.seconds_spent_total, SaveFiles.selected_file) SaveFiles.change_property(\"played_for\", gui_timer.seconds_spent_total, SaveFiles.selected_file)
var save_file_data = SaveFiles.read(SaveFiles.selected_file) var save_file_data = SaveFiles.read(SaveFiles.selected_file)
var property_name := \"best_time_for_level_\" + str(current_level_int) 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: 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) SaveFiles.change_property(property_name, gui_timer.seconds_spent_level_attempt, SaveFiles.selected_file)
var current_levels = get_current_levels() current_level.music.fadeOut(2)
for level in current_levels:
level.music.fadeOut(2)
await get_tree().create_timer(2).timeout
level.queue_free()
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()
await get_tree().create_timer(2).timeout await get_tree().create_timer(2).timeout
launch_area() current_level.queue_free()
$VictoryScreen.hide()
set_main_menu()
func restart_level() -> void: func restart_level() -> void:
var current_levels := get_current_levels() gui_timer.enabled = false
if len(current_levels) && !changing_level: if !current_level or changing_level:
pause_game(false) return
changing_level = true if current_level_scene is not PackedScene:
print(\"Tried to restart the level despite not having the level scene\")
for level in current_levels: return
level.queue_free() SaveFiles.change_property(\"played_for\", gui_timer.seconds_spent_total, SaveFiles.selected_file)
start_level(levels[current_level_int]) start_level(current_level_scene.instantiate(), current_level_scene)
func start_game() -> void:
current_level_int = 0
var current_levels = $Levels.get_children(true)
for level in current_levels:
level.queue_free()
$GUI.show()
Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)
start_level(levels[current_level_int])
func pause_game(to_pause: bool) -> void: func pause_game(to_pause: bool) -> void:
if !len(get_current_levels()) or changing_level: if !is_instance_valid(current_level) or changing_level:
return return
SaveFiles.change_property(\"played_for\", gui_timer.seconds_spent_total, SaveFiles.selected_file)
if to_pause: if to_pause:
$Levels.process_mode = Node.PROCESS_MODE_DISABLED SaveFiles.change_property(\"played_for\", gui_timer.seconds_spent_total, SaveFiles.selected_file)
current_level.process_mode = Node.PROCESS_MODE_DISABLED
playing = false playing = false
pause_menu.show() pause_menu.show()
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
else: else:
$Levels.process_mode = Node.PROCESS_MODE_INHERIT current_level.process_mode = Node.PROCESS_MODE_INHERIT
playing = true playing = true
pause_menu.hide() pause_menu.hide()
Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN) Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)
@ -153,12 +130,16 @@ func fullscreen_game() -> void:
DisplayServer.window_set_mode(DisplayServer.WindowMode.WINDOW_MODE_WINDOWED) DisplayServer.window_set_mode(DisplayServer.WindowMode.WINDOW_MODE_WINDOWED)
func _process(_delta: float) -> void: func _process(_delta: float) -> void:
var current_levels = get_current_levels() if is_instance_valid(current_level):
if len(current_levels):
var current_level = current_levels[0]
gui_speed.ball_velocity = current_level.velocity 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 _input(_event: InputEvent) -> void: 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\"): if Input.is_action_just_pressed(\"restart_level\"):
restart_level() restart_level()
@ -166,11 +147,6 @@ func _on_btn_quit_pressed() -> void:
get_tree().quit() get_tree().quit()
" "
[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"] [node name="Game" type="Node"]
script = SubResource("GDScript_8n212") script = SubResource("GDScript_8n212")
@ -181,7 +157,14 @@ anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
mouse_filter = 1 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 = 1
[node name="TopLeft" type="MarginContainer" parent="GUI"] [node name="TopLeft" type="MarginContainer" parent="GUI"]
layout_mode = 1 layout_mode = 1
@ -226,30 +209,6 @@ theme_override_constants/margin_bottom = 15
[node name="Rings" parent="GUI/BottomRight" instance=ExtResource("3_mbj17")] [node name="Rings" parent="GUI/BottomRight" instance=ExtResource("3_mbj17")]
layout_mode = 2 layout_mode = 2
[node name="VictoryScreen" type="Control" parent="."]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="Label" type="Label" parent="VictoryScreen"]
layout_mode = 1
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
[node name="Levels" type="Node" parent="."]
[node name="PauseMenu" parent="." instance=ExtResource("4_3bfj3")]
[node name="DevInfos" type="Label" parent="."] [node name="DevInfos" type="Label" parent="."]
anchors_preset = 12 anchors_preset = 12
anchor_top = 1.0 anchor_top = 1.0
@ -259,3 +218,5 @@ offset_top = -23.0
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 0 grow_vertical = 0
horizontal_alignment = 1 horizontal_alignment = 1
[node name="PauseMenu" parent="." instance=ExtResource("4_3bfj3")]

View file

@ -1,12 +1,21 @@
[gd_scene load_steps=12 format=3 uid="uid://ovtknjyj83gh"] [gd_scene load_steps=11 format=3 uid="uid://ovtknjyj83gh"]
[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://cnnvwotv33u1b" path="res://elements/player.tscn" id="2_b00jj"]
[ext_resource type="PackedScene" uid="uid://cpm3laywhlbq5" path="res://elements/ring.tscn" id="3_hel5x"] [ext_resource type="PackedScene" uid="uid://cpm3laywhlbq5" path="res://elements/ring.tscn" id="3_hel5x"]
[ext_resource type="PackedScene" uid="uid://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://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"] [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="Gradient" id="Gradient_hs6gw"]
[sub_resource type="GradientTexture2D" id="GradientTexture2D_hyysp"] [sub_resource type="GradientTexture2D" id="GradientTexture2D_hyysp"]
@ -30,11 +39,9 @@ ambient_light_color = Color(1, 1, 1, 1)
reflected_light_source = 2 reflected_light_source = 2
[node name="Base" type="Node3D"] [node name="Base" type="Node3D"]
script = ExtResource("1_rj40i") script = SubResource("GDScript_1yugx")
metadata/_custom_type_script = "uid://w3fetao1pegm" metadata/_custom_type_script = "uid://w3fetao1pegm"
[node name="Gravity" parent="." instance=ExtResource("3_muudg")]
[node name="Environment" type="WorldEnvironment" parent="."] [node name="Environment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_y0yoy") environment = SubResource("Environment_y0yoy")
@ -155,6 +162,8 @@ transform = Transform3D(0.0172464, 0.899835, 0, -0.899835, 0.0172464, 0, 0, 0, 0
[node name="Ring13" parent="Rings" instance=ExtResource("3_hel5x")] [node name="Ring13" parent="Rings" instance=ExtResource("3_hel5x")]
transform = Transform3D(0.0114976, 0.59989, 0, -0.59989, 0.0114976, 0, 0, 0, 0.6, -414.274, 8.64172, 0) transform = Transform3D(0.0114976, 0.59989, 0, -0.59989, 0.0114976, 0, 0, 0, 0.6, -414.274, 8.64172, 0)
[connection signal="velocity_change" from="Player" to="." method="_on_player_velocity_change"]
[editable path="Signs/Sign"] [editable path="Signs/Sign"]
[editable path="Signs/Sign7"] [editable path="Signs/Sign7"]
[editable path="Signs/Sign2"] [editable path="Signs/Sign2"]

View file

@ -1,50 +0,0 @@
[gd_scene load_steps=11 format=3 uid="uid://0re2mcnpub4e"]
[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://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"]
[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="Demo" type="Node3D"]
script = ExtResource("1_scm0b")
metadata/_custom_type_script = "uid://w3fetao1pegm"
[node name="Gravity" parent="." instance=ExtResource("2_fo4i1")]
[node name="Environment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_8o42c")
[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,13 +1,32 @@
[gd_scene load_steps=11 format=3 uid="uid://e1761h6d522a"] [gd_scene load_steps=10 format=3 uid="uid://e1761h6d522a"]
[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://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://cakmsiye3hjfe" path="res://levels/forest/music.tscn" id="3_n1xsx"]
[ext_resource type="PackedScene" uid="uid://cpm3laywhlbq5" path="res://elements/ring.tscn" id="4_p8yhq"] [ext_resource type="PackedScene" uid="uid://cpm3laywhlbq5" path="res://elements/ring.tscn" id="4_p8yhq"]
[ext_resource type="PackedScene" uid="uid://da6lkdiskdh8v" path="res://elements/tree.tscn" id="6_1e514"] [ext_resource type="PackedScene" uid="uid://da6lkdiskdh8v" path="res://elements/tree.tscn" id="6_1e514"]
[ext_resource type="PackedScene" uid="uid://c77bli40240nk" path="res://elements/sign.tscn" id="6_ifogr"] [ext_resource type="PackedScene" uid="uid://c77bli40240nk" path="res://elements/sign.tscn" id="6_ifogr"]
[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"] [sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_grcut"]
sky_top_color = Color(0, 0.504542, 0.579919, 1) sky_top_color = Color(0, 0.504542, 0.579919, 1)
sky_horizon_color = Color(9.62615e-08, 0.776269, 0.496436, 1) sky_horizon_color = Color(9.62615e-08, 0.776269, 0.496436, 1)
@ -29,11 +48,9 @@ ambient_light_color = Color(1, 1, 1, 1)
reflected_light_source = 2 reflected_light_source = 2
[node name="Forest" type="Node3D"] [node name="Forest" type="Node3D"]
script = ExtResource("1_fdxcj") script = SubResource("GDScript_mqwxc")
metadata/_custom_type_script = "uid://w3fetao1pegm" metadata/_custom_type_script = "uid://w3fetao1pegm"
[node name="Gravity" parent="." instance=ExtResource("2_gxmta")]
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] [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) 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 shadow_enabled = true
@ -261,4 +278,6 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -218.208, 206.247, 0)
[node name="Ring23" parent="Rings" instance=ExtResource("4_p8yhq")] [node name="Ring23" parent="Rings" instance=ExtResource("4_p8yhq")]
transform = Transform3D(0.939693, 0.34202, 0, -0.34202, 0.939693, 0, 0, 0, 1, -1018.15, -96.9134, 0) transform = Transform3D(0.939693, 0.34202, 0, -0.34202, 0.939693, 0, 0, 0, 1, -1018.15, -96.9134, 0)
[connection signal="velocity_change" from="Player" to="." method="_on_player_velocity_change"]
[editable path="Sign"] [editable path="Sign"]

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 class_name Level
extends Node3D extends Node3D
signal started_playing
signal gravity_change
signal ring_collected signal ring_collected
signal completed 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 music: Music
var velocity: float = 0.0
var rings: Array[Ring] = [] var rings: Array[Ring] = []
var finished_rings_count: int = 0 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: 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() var children = get_children()
for child in children: for child in children:
if is_instance_of(child, Music): if is_instance_of(child, Music):
music = child music = child
if child.name == "Player" and is_instance_of(child, Node3D):
player = child
assert(is_instance_valid(music), self.name + " has no music!") assert(is_instance_valid(music), self.name + " has no music!")
var rings_node = get_node("Rings") var rings_node = get_node("Rings")
@ -32,7 +59,46 @@ func collect_ring():
if finished_rings_count >= len(rings): if finished_rings_count >= len(rings):
completed.emit() completed.emit()
func _process(delta: float) -> void: func _input(_event: InputEvent) -> void:
seconds_spent += delta if Input.is_action_pressed("gravity_strong") or Input.is_action_just_released("gravity_strong"):
velocity = abs($Player.velocity.x) + abs($Player.velocity.y) PhysicsServer3D.area_set_param(
music.adaptInstrumentsToVelocity(velocity, delta) 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_volume_db(bus_index, db + Settings.volume_music)
AudioServer.set_bus_mute(bus_index, Settings.volume_music <= -15.0) 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_needed = floor(velocity / 8)
var instruments_playing = instruments.filter(func(i: AudioStreamPlayer): return i.volume_db > -50) var instruments_playing = instruments.filter(func(i: AudioStreamPlayer): return i.volume_db > -50)

View file

@ -1,14 +1,27 @@
[gd_scene load_steps=14 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://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://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://cpm3laywhlbq5" path="res://elements/ring.tscn" id="4_brcr0"] [ext_resource type="PackedScene" uid="uid://cpm3laywhlbq5" path="res://elements/ring.tscn" id="4_brcr0"]
[ext_resource type="PackedScene" uid="uid://c77bli40240nk" path="res://elements/sign.tscn" id="6_36yav"] [ext_resource type="PackedScene" uid="uid://c77bli40240nk" path="res://elements/sign.tscn" id="6_36yav"]
[ext_resource type="PackedScene" uid="uid://b4jtpua36m6b1" path="res://elements/star.tscn" id="7_ltcl0"] [ext_resource type="PackedScene" uid="uid://b4jtpua36m6b1" path="res://elements/star.tscn" id="7_ltcl0"]
[ext_resource type="PackedScene" uid="uid://da6lkdiskdh8v" path="res://elements/tree.tscn" id="8_kgstj"] [ext_resource type="PackedScene" uid="uid://da6lkdiskdh8v" path="res://elements/tree.tscn" id="8_kgstj"]
[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="Gradient" id="Gradient_x6q8u"]
[sub_resource type="GradientTexture1D" id="GradientTexture1D_lu6nv"] [sub_resource type="GradientTexture1D" id="GradientTexture1D_lu6nv"]
@ -28,11 +41,9 @@ ambient_light_color = Color(1, 1, 1, 1)
reflected_light_source = 2 reflected_light_source = 2
[node name="Night" type="Node3D"] [node name="Night" type="Node3D"]
script = ExtResource("1_3m1pa") script = SubResource("GDScript_akhnt")
metadata/_custom_type_script = "uid://w3fetao1pegm" metadata/_custom_type_script = "uid://w3fetao1pegm"
[node name="Gravity" parent="." instance=ExtResource("2_lfplq")]
[node name="Environment" type="WorldEnvironment" parent="."] [node name="Environment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_8o42c") environment = SubResource("Environment_8o42c")
@ -193,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) 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")] [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="."] [node name="Signs" type="Node3D" parent="."]
@ -327,6 +338,8 @@ transform = Transform3D(-0.99693, 0.0731445, -0.0279554, -0.0555776, -0.912445,
[node name="Star32" parent="Stars" instance=ExtResource("7_ltcl0")] [node name="Star32" parent="Stars" instance=ExtResource("7_ltcl0")]
transform = Transform3D(-0.99693, 0.0731445, -0.0279554, -0.0555776, -0.912445, -0.405407, -0.055161, -0.402609, 0.913709, 0.952739, 0.24193, 7.10684) transform = Transform3D(-0.99693, 0.0731445, -0.0279554, -0.0555776, -0.912445, -0.405407, -0.055161, -0.402609, 0.913709, 0.952739, 0.24193, 7.10684)
[connection signal="velocity_change" from="Player" to="." method="_on_player_velocity_change"]
[editable path="Signs/Sign"] [editable path="Signs/Sign"]
[editable path="Signs/Sign4"] [editable path="Signs/Sign4"]
[editable path="Signs/Sign2"] [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:
var svm = save_file_manager.instantiate()
svm.connect(\"request_start\", func(): request_start.emit())
$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() get_tree().quit()
" "
[node name="StartMenu" type="Control"] [node name="InitialMenu" type="Control"]
layout_mode = 3 layout_mode = 3
anchors_preset = 15 anchors_preset = 15
anchor_right = 1.0 anchor_right = 1.0

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

@ -6,21 +6,31 @@ script/source = "extends Control
signal request_start signal request_start
@onready var label_name = $VBoxContainer/MarginContainer/VBoxContainer/Description/Name @onready var label_name = $VBoxContainer/MarginContainer/VBoxContainer/Description/Name
@onready var label_time = $VBoxContainer/MarginContainer/VBoxContainer/Description/Time
func _ready() -> void:
$VBoxContainer/MarginContainer.hide()
## Get the newest \"played_for\" when the main menu appears again
func _enter_tree() -> void:
if len(SaveFiles.selected_file):
display_file_data(SaveFiles.selected_file)
func _on_save_1_pressed() -> void: func _on_save_1_pressed() -> void:
label_name.text = $VBoxContainer/Save1.text label_name.text = $VBoxContainer/Save1.text
display_file_data(SaveFiles.read(SaveFiles.names[0])) display_file_data(SaveFiles.names[0])
func _on_save_2_pressed() -> void: func _on_save_2_pressed() -> void:
label_name.text = $VBoxContainer/Save2.text label_name.text = $VBoxContainer/Save2.text
display_file_data(SaveFiles.read(SaveFiles.names[1])) display_file_data(SaveFiles.names[1])
func _on_save_3_pressed() -> void: func _on_save_3_pressed() -> void:
label_name.text = $VBoxContainer/Save3.text label_name.text = $VBoxContainer/Save3.text
display_file_data(SaveFiles.read(SaveFiles.names[2])) display_file_data(SaveFiles.names[2])
func display_file_data(data: Variant) -> void: 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() $VBoxContainer/MarginContainer.show()
label_time.text = \" | \" label_time.text = \" | \"
if data.has(\"played_for\") and data.played_for is float: if data.has(\"played_for\") and data.played_for is float:
@ -28,14 +38,14 @@ func display_file_data(data: Variant) -> void:
var minutes: int = floor(seconds / 60) var minutes: int = floor(seconds / 60)
label_time.text += (\"%0*d\" % [2, minutes]) + \":\" + (\"%0*.3f\" % [6, seconds - (minutes * 60)]) label_time.text += (\"%0*d\" % [2, minutes]) + \":\" + (\"%0*.3f\" % [6, seconds - (minutes * 60)])
else: else:
label_time.text += \"00:00\" label_time.text += \"00:00.000\"
func _on_start_pressed() -> void: func _on_start_pressed() -> void:
request_start.emit() request_start.emit()
func _on_delete_pressed() -> void: func _on_delete_pressed() -> void:
SaveFiles.empty(SaveFiles.selected_file) SaveFiles.empty(SaveFiles.selected_file)
display_file_data(SaveFiles.read(SaveFiles.selected_file)) display_file_data(SaveFiles.selected_file)
" "
[node name="SaveFileManager" type="Control"] [node name="SaveFileManager" type="Control"]

View file

@ -114,10 +114,12 @@ libraries = {
} }
[node name="Label" type="Label" parent="VSplitContainer"] [node name="Label" type="Label" parent="VSplitContainer"]
custom_minimum_size = Vector2(1, 1)
layout_mode = 2 layout_mode = 2
text = "MENU NAME" text = "MENU NAME"
label_settings = SubResource("LabelSettings_2d4ws") label_settings = SubResource("LabelSettings_2d4ws")
horizontal_alignment = 1 horizontal_alignment = 1
autowrap_mode = 3
uppercase = true uppercase = true
[node name="MarginContainer" type="MarginContainer" parent="VSplitContainer"] [node name="MarginContainer" type="MarginContainer" parent="VSplitContainer"]

View file

@ -13,7 +13,7 @@ config_version=5
config/name="DreamBall" config/name="DreamBall"
config/description="Manipulate the gravity to make a ball go through every ring! config/description="Manipulate the gravity to make a ball go through every ring!
https://kitsunes.dev/Taevas/DreamBall" https://kitsunes.dev/Taevas/DreamBall"
config/version="20250423.0" config/version="20250503.0"
run/main_scene="res://index.tscn" run/main_scene="res://index.tscn"
config/features=PackedStringArray("4.4", "GL Compatibility") config/features=PackedStringArray("4.4", "GL Compatibility")
boot_splash/show_image=false boot_splash/show_image=false
@ -78,6 +78,13 @@ restart_level={
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":2,"pressure":0.0,"pressed":false,"script":null) , Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":2,"pressure":0.0,"pressed":false,"script":null)
] ]
} }
display_map={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194326,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":9,"pressure":0.0,"pressed":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":10,"pressure":0.0,"pressed":false,"script":null)
]
}
[physics] [physics]
@ -86,6 +93,7 @@ common/physics_ticks_per_second=120
common/max_physics_steps_per_frame=20 common/max_physics_steps_per_frame=20
3d/physics_engine="GodotPhysics3D" 3d/physics_engine="GodotPhysics3D"
3d/default_gravity=1.0 3d/default_gravity=1.0
3d/default_gravity_vector=Vector3(0, -0.5, 0)
3d/solver/solver_iterations=40 3d/solver/solver_iterations=40
3d/solver/default_contact_bias=1.0 3d/solver/default_contact_bias=1.0
common/physics_interpolation=true common/physics_interpolation=true

View file

@ -6,7 +6,7 @@ const names := [
"user://save_file_3.save", "user://save_file_3.save",
] ]
var selected_file := names[0] var selected_file: String
func _ready() -> void: func _ready() -> void:
for save_file_name in names: for save_file_name in names:
@ -22,6 +22,7 @@ func empty(save_file_name: String) -> void:
write(JSON.stringify({}), save_file_name) write(JSON.stringify({}), save_file_name)
func read(save_file_name: String) -> Variant: func read(save_file_name: String) -> Variant:
print("Reading from save file ", save_file_name)
ensure_existence(save_file_name) ensure_existence(save_file_name)
selected_file = save_file_name selected_file = save_file_name
@ -41,6 +42,7 @@ func write(json_string: String, save_file_name: String) -> void:
save_file.store_line("FOR YOUR SAFETY, ALWAYS CHECK IF THE DATA OF THE FILES YOU DOWNLOAD LOOKS OKAY") 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: 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) ensure_existence(save_file_name)
var data = read(save_file_name) var data = read(save_file_name)
data[property] = value data[property] = value