make a settings menu and general refactoring
i added more to the main menu, as it has a settings menu now, that stores its files with json. i also changed the font to atkinson hyperlegible and made a BaseMenu class that takes care of the screen scaling for menus. i also refactored the project folder structure to make it more organized.
This commit is contained in:
parent
f84479e03a
commit
425bf2ad27
29 changed files with 440 additions and 98 deletions
BIN
Fonts/AtkinsonHyperlegible-Regular.ttf
Normal file
BIN
Fonts/AtkinsonHyperlegible-Regular.ttf
Normal file
Binary file not shown.
38
Fonts/AtkinsonHyperlegible-Regular.ttf.import
Normal file
38
Fonts/AtkinsonHyperlegible-Regular.ttf.import
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="font_data_dynamic"
|
||||||
|
type="FontFile"
|
||||||
|
uid="uid://dq8ojwul8884x"
|
||||||
|
path="res://.godot/imported/AtkinsonHyperlegible-Regular.ttf-8428368664fa87474099ab40902da12f.fontdata"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://Fonts/AtkinsonHyperlegible-Regular.ttf"
|
||||||
|
dest_files=["res://.godot/imported/AtkinsonHyperlegible-Regular.ttf-8428368664fa87474099ab40902da12f.fontdata"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
Rendering=null
|
||||||
|
antialiasing=1
|
||||||
|
generate_mipmaps=false
|
||||||
|
multichannel_signed_distance_field=true
|
||||||
|
msdf_pixel_range=8
|
||||||
|
msdf_size=48
|
||||||
|
allow_system_fallback=true
|
||||||
|
force_autohinter=false
|
||||||
|
hinting=1
|
||||||
|
subpixel_positioning=1
|
||||||
|
oversampling=0.0
|
||||||
|
Fallbacks=null
|
||||||
|
fallbacks=[]
|
||||||
|
Compress=null
|
||||||
|
compress=true
|
||||||
|
preload=[{
|
||||||
|
"chars": [],
|
||||||
|
"glyphs": [],
|
||||||
|
"name": "New Configuration",
|
||||||
|
"size": Vector2i(16, 0)
|
||||||
|
}]
|
||||||
|
language_support={}
|
||||||
|
script_support={}
|
||||||
|
opentype_features={}
|
11
Resources/MenuTheme.tres
Normal file
11
Resources/MenuTheme.tres
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[gd_resource type="Theme" load_steps=2 format=3 uid="uid://bk0vu443pyq1g"]
|
||||||
|
|
||||||
|
[ext_resource type="FontFile" uid="uid://dq8ojwul8884x" path="res://Fonts/AtkinsonHyperlegible-Regular.ttf" id="1_aadm8"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
Button/font_sizes/font_size = 32
|
||||||
|
Button/fonts/font = ExtResource("1_aadm8")
|
||||||
|
Label/font_sizes/font_size = 32
|
||||||
|
Label/fonts/font = ExtResource("1_aadm8")
|
||||||
|
LineEdit/font_sizes/font_size = 32
|
||||||
|
LineEdit/fonts/font = ExtResource("1_aadm8")
|
7
Resources/ScoreLabelSettings.tres
Normal file
7
Resources/ScoreLabelSettings.tres
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
[gd_resource type="LabelSettings" load_steps=2 format=3 uid="uid://dkyqusswobqb3"]
|
||||||
|
|
||||||
|
[ext_resource type="FontFile" uid="uid://dq8ojwul8884x" path="res://Fonts/AtkinsonHyperlegible-Regular.ttf" id="1_hcuvo"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
font = ExtResource("1_hcuvo")
|
||||||
|
font_size = 64
|
|
@ -1,29 +0,0 @@
|
||||||
[gd_scene load_steps=3 format=3 uid="uid://0vkrkvlevwkj"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://Scripts/Managers/MainMenuManager.cs" id="1_tuygx"]
|
|
||||||
|
|
||||||
[sub_resource type="LabelSettings" id="LabelSettings_vv6u3"]
|
|
||||||
font_size = 64
|
|
||||||
|
|
||||||
[node name="MainMenu" type="VBoxContainer"]
|
|
||||||
offset_right = 800.0
|
|
||||||
offset_bottom = 600.0
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
size_flags_vertical = 3
|
|
||||||
script = ExtResource("1_tuygx")
|
|
||||||
|
|
||||||
[node name="Label" type="Label" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Pong
|
|
||||||
"
|
|
||||||
label_settings = SubResource("LabelSettings_vv6u3")
|
|
||||||
horizontal_alignment = 1
|
|
||||||
vertical_alignment = 1
|
|
||||||
|
|
||||||
[node name="Button" type="Button" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 32
|
|
||||||
text = "Play
|
|
||||||
"
|
|
||||||
|
|
||||||
[connection signal="pressed" from="Button" to="." method="OnButtonPressed"]
|
|
|
@ -1,6 +1,6 @@
|
||||||
[gd_scene load_steps=4 format=3 uid="uid://67qguep14iko"]
|
[gd_scene load_steps=4 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://Scripts/Nodes/Ball.cs" id="1_474si"]
|
[ext_resource type="Script" path="res://Scripts/Objects/Ball.cs" id="1_474si"]
|
||||||
|
|
||||||
[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_yq7ub"]
|
[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_yq7ub"]
|
||||||
size = Vector2(50, 50)
|
size = Vector2(50, 50)
|
|
@ -1,7 +1,7 @@
|
||||||
[gd_scene load_steps=5 format=3]
|
[gd_scene load_steps=5 format=3]
|
||||||
|
|
||||||
[ext_resource type="PhysicsMaterial" uid="uid://e05n66x8ug77" path="res://BouncyMaterial.tres" id="1_e3kk5"]
|
[ext_resource type="PhysicsMaterial" uid="uid://e05n66x8ug77" path="res://Resources/BouncyMaterial.tres" id="1_e3kk5"]
|
||||||
[ext_resource type="Script" path="res://Scripts/Nodes/Enemy.cs" id="1_fbrtv"]
|
[ext_resource type="Script" path="res://Scripts/Objects/Enemy.cs" id="1_fbrtv"]
|
||||||
|
|
||||||
[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_iw3nx"]
|
[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_iw3nx"]
|
||||||
size = Vector2(50, 75)
|
size = Vector2(50, 75)
|
|
@ -1,7 +1,7 @@
|
||||||
[gd_scene load_steps=5 format=3]
|
[gd_scene load_steps=5 format=3]
|
||||||
|
|
||||||
[ext_resource type="PhysicsMaterial" uid="uid://e05n66x8ug77" path="res://BouncyMaterial.tres" id="1_76uik"]
|
[ext_resource type="PhysicsMaterial" uid="uid://e05n66x8ug77" path="res://Resources/BouncyMaterial.tres" id="1_76uik"]
|
||||||
[ext_resource type="Script" path="res://Scripts/Nodes/Paddle.cs" id="1_uv7s3"]
|
[ext_resource type="Script" path="res://Scripts/Objects/Paddle.cs" id="1_uv7s3"]
|
||||||
|
|
||||||
[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_iw3nx"]
|
[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_iw3nx"]
|
||||||
size = Vector2(50, 75)
|
size = Vector2(50, 75)
|
|
@ -1,6 +1,6 @@
|
||||||
[gd_scene load_steps=8 format=3 uid="uid://dsvv7vqonylr1"]
|
[gd_scene load_steps=8 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://Scripts/Managers/WallManager.cs" id="1_mxer2"]
|
[ext_resource type="Script" path="res://Scripts/Managers/Walls.cs" id="1_mxer2"]
|
||||||
|
|
||||||
[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_f7jy5"]
|
[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_f7jy5"]
|
||||||
size = Vector2(30, 1)
|
size = Vector2(30, 1)
|
|
@ -1,14 +1,14 @@
|
||||||
[gd_scene load_steps=7 format=3 uid="uid://wn48xnd0lstq"]
|
[gd_scene load_steps=7 format=3 uid="uid://bh3p1hnvsviu6"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" path="res://Scenes/Paddle.tscn" id="1_5rs0o"]
|
[ext_resource type="PackedScene" path="res://Scenes/Objects/Paddle.tscn" id="1_5rs0o"]
|
||||||
[ext_resource type="Script" path="res://Scripts/Managers/SceneManager.cs" id="1_m8437"]
|
[ext_resource type="Script" path="res://Scripts/Managers/PongSceneManager.cs" id="1_ee533"]
|
||||||
[ext_resource type="PackedScene" uid="uid://co2rv0nci8sbm" path="res://Scenes/Score.tscn" id="2_f3jwj"]
|
[ext_resource type="PackedScene" uid="uid://clsmrwvyrt7av" path="res://Scenes/UI/Score.tscn" id="2_f3jwj"]
|
||||||
[ext_resource type="PackedScene" uid="uid://67qguep14iko" path="res://Scenes/Ball.tscn" id="2_u2ksv"]
|
[ext_resource type="PackedScene" path="res://Scenes/Objects/Ball.tscn" id="2_u2ksv"]
|
||||||
[ext_resource type="PackedScene" uid="uid://dsvv7vqonylr1" path="res://Scenes/Walls.tscn" id="3_jfis7"]
|
[ext_resource type="PackedScene" path="res://Scenes/Objects/Walls.tscn" id="3_jfis7"]
|
||||||
[ext_resource type="PackedScene" path="res://Scenes/Enemy.tscn" id="4_uwvof"]
|
[ext_resource type="PackedScene" path="res://Scenes/Objects/Enemy.tscn" id="4_uwvof"]
|
||||||
|
|
||||||
[node name="Pong" type="Node2D"]
|
[node name="Pong" type="Node2D"]
|
||||||
script = ExtResource("1_m8437")
|
script = ExtResource("1_ee533")
|
||||||
|
|
||||||
[node name="Score" parent="." instance=ExtResource("2_f3jwj")]
|
[node name="Score" parent="." instance=ExtResource("2_f3jwj")]
|
||||||
|
|
||||||
|
|
32
Scenes/UI/Menus/MainMenu.tscn
Normal file
32
Scenes/UI/Menus/MainMenu.tscn
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
[gd_scene load_steps=4 format=3 uid="uid://buvptlse06qej"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://Scripts/Managers/UI/Menus/MainMenu.cs" id="1_essvw"]
|
||||||
|
[ext_resource type="Theme" uid="uid://bk0vu443pyq1g" path="res://Resources/MenuTheme.tres" id="1_qt6h4"]
|
||||||
|
[ext_resource type="LabelSettings" uid="uid://dkyqusswobqb3" path="res://Resources/ScoreLabelSettings.tres" id="2_mtqkf"]
|
||||||
|
|
||||||
|
[node name="MainMenu" type="VBoxContainer"]
|
||||||
|
offset_right = 800.0
|
||||||
|
offset_bottom = 600.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
theme = ExtResource("1_qt6h4")
|
||||||
|
script = ExtResource("1_essvw")
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="."]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Pong"
|
||||||
|
label_settings = ExtResource("2_mtqkf")
|
||||||
|
horizontal_alignment = 1
|
||||||
|
vertical_alignment = 1
|
||||||
|
|
||||||
|
[node name="PlayButton" type="Button" parent="."]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Play
|
||||||
|
"
|
||||||
|
|
||||||
|
[node name="SettingsButton" type="Button" parent="."]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Settings"
|
||||||
|
|
||||||
|
[connection signal="pressed" from="PlayButton" to="." method="OnPlayButtonPressed"]
|
||||||
|
[connection signal="pressed" from="SettingsButton" to="." method="OnSettingsButtonPressed"]
|
63
Scenes/UI/Menus/Settings.tscn
Normal file
63
Scenes/UI/Menus/Settings.tscn
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
[gd_scene load_steps=5 format=3 uid="uid://ic7535p11pds"]
|
||||||
|
|
||||||
|
[ext_resource type="Theme" uid="uid://bk0vu443pyq1g" path="res://Resources/MenuTheme.tres" id="1_p8g8v"]
|
||||||
|
[ext_resource type="Script" path="res://Scripts/Managers/UI/Menus/Settings.cs" id="2_vlocu"]
|
||||||
|
[ext_resource type="LabelSettings" uid="uid://dkyqusswobqb3" path="res://Resources/ScoreLabelSettings.tres" id="2_wkoeb"]
|
||||||
|
[ext_resource type="FontFile" uid="uid://dq8ojwul8884x" path="res://Fonts/AtkinsonHyperlegible-Regular.ttf" id="3_ngmnl"]
|
||||||
|
|
||||||
|
[node name="Settings" type="VBoxContainer"]
|
||||||
|
offset_right = 800.0
|
||||||
|
offset_bottom = 600.0
|
||||||
|
theme = ExtResource("1_p8g8v")
|
||||||
|
script = ExtResource("2_vlocu")
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="."]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Settings
|
||||||
|
"
|
||||||
|
label_settings = ExtResource("2_wkoeb")
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="ScrollContainer" type="ScrollContainer" parent="."]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="InternalMainContainer" type="VBoxContainer" parent="ScrollContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="ScaleContainer" type="VBoxContainer" parent="ScrollContainer/InternalMainContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 4
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="ScrollContainer/InternalMainContainer/ScaleContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 4
|
||||||
|
text = "Scale
|
||||||
|
"
|
||||||
|
|
||||||
|
[node name="Scale" type="SpinBox" parent="ScrollContainer/InternalMainContainer/ScaleContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
min_value = 1.0
|
||||||
|
max_value = 2.0
|
||||||
|
step = 0.01
|
||||||
|
value = 1.0
|
||||||
|
alignment = 1
|
||||||
|
|
||||||
|
[node name="SaveButton" type="Button" parent="."]
|
||||||
|
layout_mode = 2
|
||||||
|
disabled = true
|
||||||
|
text = "Save
|
||||||
|
"
|
||||||
|
|
||||||
|
[node name="BackButton" type="Button" parent="."]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 8
|
||||||
|
theme_override_fonts/font = ExtResource("3_ngmnl")
|
||||||
|
theme_override_font_sizes/font_size = 32
|
||||||
|
text = "Back
|
||||||
|
"
|
||||||
|
|
||||||
|
[connection signal="pressed" from="SaveButton" to="." method="OnSaveButtonPressed"]
|
||||||
|
[connection signal="pressed" from="BackButton" to="." method="OnBackButtonPressed"]
|
|
@ -1,9 +1,7 @@
|
||||||
[gd_scene load_steps=3 format=3 uid="uid://co2rv0nci8sbm"]
|
[gd_scene load_steps=3 format=3 uid="uid://clsmrwvyrt7av"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://Scripts/Managers/ScoreManager.gd" id="1_bdtqr"]
|
[ext_resource type="Script" path="res://Scripts/Managers/UI/Score.gd" id="1_ytifn"]
|
||||||
|
[ext_resource type="LabelSettings" uid="uid://dkyqusswobqb3" path="res://Resources/ScoreLabelSettings.tres" id="2_mh7dc"]
|
||||||
[sub_resource type="LabelSettings" id="LabelSettings_piogj"]
|
|
||||||
font_size = 64
|
|
||||||
|
|
||||||
[node name="Score" type="HFlowContainer"]
|
[node name="Score" type="HFlowContainer"]
|
||||||
z_index = 1
|
z_index = 1
|
||||||
|
@ -11,20 +9,20 @@ offset_left = -378.0
|
||||||
offset_top = -272.0
|
offset_top = -272.0
|
||||||
offset_right = 378.0
|
offset_right = 378.0
|
||||||
offset_bottom = 268.0
|
offset_bottom = 268.0
|
||||||
script = ExtResource("1_bdtqr")
|
script = ExtResource("1_ytifn")
|
||||||
|
|
||||||
[node name="Player1" type="Label" parent="."]
|
[node name="Player1" type="Label" parent="."]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
text = "0
|
text = "0
|
||||||
"
|
"
|
||||||
label_settings = SubResource("LabelSettings_piogj")
|
label_settings = ExtResource("2_mh7dc")
|
||||||
vertical_alignment = 1
|
vertical_alignment = 1
|
||||||
|
|
||||||
[node name="Player2" type="Label" parent="."]
|
[node name="Player2" type="Label" parent="."]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
text = "0"
|
text = "0"
|
||||||
label_settings = SubResource("LabelSettings_piogj")
|
label_settings = ExtResource("2_mh7dc")
|
||||||
horizontal_alignment = 2
|
horizontal_alignment = 2
|
||||||
vertical_alignment = 1
|
vertical_alignment = 1
|
20
Scripts/Data/Settings.cs
Normal file
20
Scripts/Data/Settings.cs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Pong.Scripts.Data;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// a structure containing the data of the settings.
|
||||||
|
/// </summary>
|
||||||
|
public struct Settings
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// the scale of the game. this can be from 1.0 to 2.0
|
||||||
|
/// </summary>
|
||||||
|
public double Scale;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// the default values of settings.
|
||||||
|
/// </summary>
|
||||||
|
public static Settings Default => new() { Scale = 1.0 };
|
||||||
|
}
|
|
@ -1,28 +0,0 @@
|
||||||
using Godot;
|
|
||||||
|
|
||||||
namespace Pong.Scripts.Managers;
|
|
||||||
|
|
||||||
public partial class MainMenuManager : VBoxContainer
|
|
||||||
{
|
|
||||||
// Called when the node enters the scene tree for the first time.
|
|
||||||
public override void _Ready()
|
|
||||||
{
|
|
||||||
GetTree().Root.SizeChanged += AdaptUiToScreenResolution;
|
|
||||||
AdaptUiToScreenResolution();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// code that executes when the start button is pressed. this loads the Pong scene to the root
|
|
||||||
/// of the scene tree.
|
|
||||||
/// </summary>
|
|
||||||
private void OnButtonPressed()
|
|
||||||
{
|
|
||||||
GetTree().Root.SizeChanged -= AdaptUiToScreenResolution;
|
|
||||||
GetTree().ChangeSceneToFile("res://Scenes/Pong.tscn");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AdaptUiToScreenResolution()
|
|
||||||
{
|
|
||||||
Size = DisplayServer.WindowGetSize();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,7 +2,7 @@ using Godot;
|
||||||
|
|
||||||
namespace Pong.Scripts.Managers;
|
namespace Pong.Scripts.Managers;
|
||||||
|
|
||||||
public partial class SceneManager : Node2D
|
public partial class PongSceneManager : Node2D
|
||||||
{
|
{
|
||||||
public override void _Process(double delta)
|
public override void _Process(double delta)
|
||||||
{
|
{
|
78
Scripts/Managers/SettingsManager.cs
Normal file
78
Scripts/Managers/SettingsManager.cs
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
using System;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Godot;
|
||||||
|
using Pong.Scripts.Data;
|
||||||
|
|
||||||
|
namespace Pong.Scripts.Managers;
|
||||||
|
|
||||||
|
public partial class SettingsManager : Node
|
||||||
|
{
|
||||||
|
private const string SettingsPath = "user://settings.json";
|
||||||
|
public Settings SettingsData = Settings.Default;
|
||||||
|
private static readonly JsonSerializerOptions SerializerOptions = new() { IncludeFields = true };
|
||||||
|
public event Action SettingsChanged;
|
||||||
|
|
||||||
|
public override async void _EnterTree()
|
||||||
|
{
|
||||||
|
await LoadSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// load the settings data from the filesystem.
|
||||||
|
/// </summary>
|
||||||
|
private async Task LoadSettings()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!FileAccess.FileExists(SettingsPath))
|
||||||
|
{
|
||||||
|
await SaveSettings(Settings.Default);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using var file = await OpenSettingsFile(FileAccess.ModeFlags.Read);
|
||||||
|
|
||||||
|
SettingsData =
|
||||||
|
await Task.Run(() => JsonSerializer.Deserialize<Settings>(file.GetAsText(), SerializerOptions));
|
||||||
|
SettingsChanged?.Invoke();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
PrintFileError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// open the settings file from the filesystem.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns> a godot FileAccess object.</returns>
|
||||||
|
private static async Task<FileAccess> OpenSettingsFile(FileAccess.ModeFlags flag)
|
||||||
|
{
|
||||||
|
return await Task.Run(() => FileAccess.Open(SettingsPath, flag));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal async Task<bool> SaveSettings(Settings settings)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var file = await OpenSettingsFile(FileAccess.ModeFlags.WriteRead);
|
||||||
|
var json = await Task.Run(() => JsonSerializer.Serialize(settings, SerializerOptions));
|
||||||
|
await Task.Run(() => file.StoreBuffer(json.ToUtf8Buffer()));
|
||||||
|
SettingsData = settings;
|
||||||
|
SettingsChanged?.Invoke();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
PrintFileError(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PrintFileError(Exception e)
|
||||||
|
{
|
||||||
|
GD.PrintErr($"a {e.GetType()} has occured while trying to load the settings file: {e}.");
|
||||||
|
GD.PrintErr("default settings will be used.");
|
||||||
|
}
|
||||||
|
}
|
43
Scripts/Managers/UI/BaseMenu.cs
Normal file
43
Scripts/Managers/UI/BaseMenu.cs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace Pong.Scripts.Managers.UI;
|
||||||
|
|
||||||
|
public partial class BaseMenu : VBoxContainer
|
||||||
|
{
|
||||||
|
private SettingsManager _settingsManager;
|
||||||
|
|
||||||
|
public override void _EnterTree()
|
||||||
|
{
|
||||||
|
_settingsManager = GetNode<SettingsManager>("/root/SettingsManager");
|
||||||
|
_settingsManager.SettingsChanged += AdaptUiToGameResolution;
|
||||||
|
GetTree().Root.SizeChanged += AdaptUiToGameResolution;
|
||||||
|
AdaptUiToGameResolution();
|
||||||
|
|
||||||
|
EnterTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void _ExitTree()
|
||||||
|
{
|
||||||
|
GetTree().Root.SizeChanged -= AdaptUiToGameResolution;
|
||||||
|
_settingsManager.SettingsChanged -= AdaptUiToGameResolution;
|
||||||
|
ExitTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void EnterTree()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void ExitTree()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// change the size of the UI container to the current resolution of the game.
|
||||||
|
/// </summary>
|
||||||
|
protected void AdaptUiToGameResolution()
|
||||||
|
{
|
||||||
|
var scale = _settingsManager.SettingsData.Scale;
|
||||||
|
Size = (Vector2)DisplayServer.WindowGetSize() / scale;
|
||||||
|
Scale = new Vector2(scale, scale);
|
||||||
|
}
|
||||||
|
}
|
20
Scripts/Managers/UI/Menus/MainMenu.cs
Normal file
20
Scripts/Managers/UI/Menus/MainMenu.cs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace Pong.Scripts.Managers.UI.Menus;
|
||||||
|
|
||||||
|
public partial class MainMenu : BaseMenu
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// code that executes when the start button is pressed. this loads the Pong scene to the root
|
||||||
|
/// of the scene tree.
|
||||||
|
/// </summary>
|
||||||
|
private void OnPlayButtonPressed()
|
||||||
|
{
|
||||||
|
GetTree().ChangeSceneToFile("res://Scenes/Pong.tscn");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSettingsButtonPressed()
|
||||||
|
{
|
||||||
|
GetTree().ChangeSceneToFile("res://Scenes/UI/Menus/Settings.tscn");
|
||||||
|
}
|
||||||
|
}
|
52
Scripts/Managers/UI/Menus/Settings.cs
Normal file
52
Scripts/Managers/UI/Menus/Settings.cs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace Pong.Scripts.Managers.UI.Menus;
|
||||||
|
|
||||||
|
public partial class Settings : BaseMenu
|
||||||
|
{
|
||||||
|
private SettingsManager _settings;
|
||||||
|
private SpinBox _scale;
|
||||||
|
private Button _saveButton;
|
||||||
|
|
||||||
|
private bool _scaleModified;
|
||||||
|
|
||||||
|
protected override void EnterTree()
|
||||||
|
{
|
||||||
|
GetNodes();
|
||||||
|
|
||||||
|
_scale.Value = _settings.SettingsData.Scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnBackButtonPressed()
|
||||||
|
{
|
||||||
|
GetTree().ChangeSceneToFile("res://Scenes/UI/Menus/MainMenu.tscn");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GetNodes()
|
||||||
|
{
|
||||||
|
_settings = GetNode<SettingsManager>("/root/SettingsManager");
|
||||||
|
_scale = GetNode<SpinBox>("ScrollContainer/InternalMainContainer/ScaleContainer/Scale");
|
||||||
|
_saveButton = GetNode<Button>("SaveButton");
|
||||||
|
|
||||||
|
_scale.ValueChanged += ScaleChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ScaleChanged(double value)
|
||||||
|
{
|
||||||
|
_scaleModified = !value.Equals(_settings.SettingsData.Scale);
|
||||||
|
CheckIfModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CheckIfModified()
|
||||||
|
{
|
||||||
|
var isModified = _scaleModified;
|
||||||
|
_saveButton.Disabled = !isModified;
|
||||||
|
return isModified;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void OnSaveButtonPressed()
|
||||||
|
{
|
||||||
|
if (!await _settings.SaveSettings(_settings.SettingsData with { Scale = _scale.Value })) return;
|
||||||
|
_saveButton.Disabled = true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,10 @@
|
||||||
using Godot;
|
using Godot;
|
||||||
using Pong.Scripts.Data;
|
using Pong.Scripts.Data;
|
||||||
|
using Pong.Scripts.Objects;
|
||||||
|
|
||||||
namespace Pong.Scripts.Managers;
|
namespace Pong.Scripts.Managers;
|
||||||
|
|
||||||
public partial class WallManager : Area2D
|
public partial class Walls : Area2D
|
||||||
{
|
{
|
||||||
[Export] internal PlayerNumber PlayerNumber;
|
[Export] internal PlayerNumber PlayerNumber;
|
||||||
|
|
||||||
|
@ -21,7 +22,7 @@ public partial class WallManager : Area2D
|
||||||
/// <param name="body">the body of the collider.</param>
|
/// <param name="body">the body of the collider.</param>
|
||||||
private void OnBodyEntered(Node2D body)
|
private void OnBodyEntered(Node2D body)
|
||||||
{
|
{
|
||||||
if (body is not Nodes.Ball ball) return;
|
if (body is not Ball ball) return;
|
||||||
_scoreManager.Call(_score, (long)PlayerNumber);
|
_scoreManager.Call(_score, (long)PlayerNumber);
|
||||||
|
|
||||||
ResetBall(ball);
|
ResetBall(ball);
|
||||||
|
@ -30,8 +31,8 @@ public partial class WallManager : Area2D
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// reset the ball to the starting position and flick it again.
|
/// reset the ball to the starting position and flick it again.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ball">a <see cref="Nodes.Ball"/> object that you want to reset.</param>
|
/// <param name="ball">a <see cref="Ball"/> object that you want to reset.</param>
|
||||||
private async void ResetBall(Nodes.Ball ball)
|
private async void ResetBall(Ball ball)
|
||||||
{
|
{
|
||||||
ball.Velocity = Vector2.Zero;
|
ball.Velocity = Vector2.Zero;
|
||||||
ball.Position = Vector2.Zero;
|
ball.Position = Vector2.Zero;
|
|
@ -1,6 +1,6 @@
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
namespace Pong.Scripts.Nodes;
|
namespace Pong.Scripts.Objects;
|
||||||
|
|
||||||
public partial class Ball : CharacterBody2D
|
public partial class Ball : CharacterBody2D
|
||||||
{
|
{
|
||||||
|
@ -26,7 +26,8 @@ public partial class Ball : CharacterBody2D
|
||||||
using var rng = new RandomNumberGenerator();
|
using var rng = new RandomNumberGenerator();
|
||||||
rng.Randomize();
|
rng.Randomize();
|
||||||
// set the velocity currently to the left of the screen with a random y angle.
|
// set the velocity currently to the left of the screen with a random y angle.
|
||||||
var randomAngle = new Vector2(0, rng.RandfRange(-_maxRandomAngle, _maxRandomAngle) * BallSpeed);
|
var randomAngle = new Vector2 { Y = rng.RandfRange(-_maxRandomAngle, _maxRandomAngle) * BallSpeed };
|
||||||
|
|
||||||
Velocity = GetRandomStartingDirection() * BallSpeed + randomAngle;
|
Velocity = GetRandomStartingDirection() * BallSpeed + randomAngle;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||||
using Godot;
|
using Godot;
|
||||||
using Godot.Collections;
|
using Godot.Collections;
|
||||||
|
|
||||||
namespace Pong.Scripts.Nodes;
|
namespace Pong.Scripts.Objects;
|
||||||
|
|
||||||
public partial class Enemy : RigidBody2D
|
public partial class Enemy : RigidBody2D
|
||||||
{
|
{
|
||||||
|
@ -33,7 +33,7 @@ public partial class Enemy : RigidBody2D
|
||||||
if (!_drawDebugShapes) return;
|
if (!_drawDebugShapes) return;
|
||||||
DrawRect(_scanArea, Colors.Aqua);
|
DrawRect(_scanArea, Colors.Aqua);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Scan(double delta)
|
private void Scan(double delta)
|
||||||
{
|
{
|
||||||
using var spaceState = GetWorld2D().DirectSpaceState;
|
using var spaceState = GetWorld2D().DirectSpaceState;
|
||||||
|
@ -51,7 +51,7 @@ public partial class Enemy : RigidBody2D
|
||||||
LinearVelocity = Vector2.Zero;
|
LinearVelocity = Vector2.Zero;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TrackBall(delta, result);
|
TrackBall(delta, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,12 +65,12 @@ public partial class Enemy : RigidBody2D
|
||||||
private void TrackBall(double delta, IReadOnlyList<Dictionary> result)
|
private void TrackBall(double delta, IReadOnlyList<Dictionary> result)
|
||||||
{
|
{
|
||||||
// checks if the collider is a ball, if not, return.
|
// checks if the collider is a ball, if not, return.
|
||||||
if (result[0]["collider"].As<Nodes.Ball>() is not { } ball) return;
|
if (result[0]["collider"].As<Objects.Ball>() is not { } ball) return;
|
||||||
|
|
||||||
// gets the sign of the distance between the ball and the paddle on the y axis
|
// gets the sign of the distance between the ball and the paddle on the y axis
|
||||||
var normalisedDistance = new Vector2(0, Mathf.Sign(ball.Position.Y - Position.Y));
|
var normalisedDistance = new Vector2 { Y = Mathf.Sign(ball.Position.Y - Position.Y) };
|
||||||
var linearVelocity = normalisedDistance * _moveSpeed * Constants.Meter;
|
var linearVelocity = normalisedDistance * _moveSpeed * Constants.Meter;
|
||||||
|
|
||||||
// lerp the velocity to smooth out jerky movement.
|
// lerp the velocity to smooth out jerky movement.
|
||||||
LinearVelocity = LinearVelocity.Lerp(linearVelocity, delta);
|
LinearVelocity = LinearVelocity.Lerp(linearVelocity, delta);
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ public partial class Enemy : RigidBody2D
|
||||||
{
|
{
|
||||||
if (_collisionShape.Shape is not RectangleShape2D shape)
|
if (_collisionShape.Shape is not RectangleShape2D shape)
|
||||||
throw new InvalidOperationException("the collision shape needs to be a rectangle shape");
|
throw new InvalidOperationException("the collision shape needs to be a rectangle shape");
|
||||||
|
|
||||||
// grow the area the enemy can see by around half of the screen area.
|
// grow the area the enemy can see by around half of the screen area.
|
||||||
_scanArea = shape.GetRect().GrowSide(Side.Left, 400).GrowIndividual(0, 190, 0, 190);
|
_scanArea = shape.GetRect().GrowSide(Side.Left, 400).GrowIndividual(0, 190, 0, 190);
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
namespace Pong.Scripts.Nodes;
|
namespace Pong.Scripts.Objects;
|
||||||
|
|
||||||
public partial class Paddle : RigidBody2D
|
public partial class Paddle : RigidBody2D
|
||||||
{
|
{
|
20
addons/BaseMenu/BaseMenu.cs
Normal file
20
addons/BaseMenu/BaseMenu.cs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#if TOOLS
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace Pong.addons.BaseMenu;
|
||||||
|
|
||||||
|
[Tool]
|
||||||
|
public partial class BaseMenu : EditorPlugin
|
||||||
|
{
|
||||||
|
public override void _EnterTree()
|
||||||
|
{
|
||||||
|
var baseMenuScript = GD.Load<Script>("res://Scripts/Managers/UI/BaseMenu.cs");
|
||||||
|
AddCustomType("BaseMenu", "VBoxContainer", baseMenuScript, GetEditorIcon("VBoxContainer"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Texture2D GetEditorIcon(string iconName)
|
||||||
|
{
|
||||||
|
return GetEditorInterface().GetBaseControl().GetThemeIcon(iconName, "EditorIcons");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
7
addons/BaseMenu/plugin.cfg
Normal file
7
addons/BaseMenu/plugin.cfg
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
[plugin]
|
||||||
|
|
||||||
|
name="BaseMenu"
|
||||||
|
description=""
|
||||||
|
author="Fries"
|
||||||
|
version=""
|
||||||
|
script="BaseMenu.cs"
|
|
@ -11,10 +11,14 @@ config_version=5
|
||||||
[application]
|
[application]
|
||||||
|
|
||||||
config/name="Pong"
|
config/name="Pong"
|
||||||
run/main_scene="res://Scenes/MainMenu.tscn"
|
run/main_scene="res://Scenes/UI/Menus/MainMenu.tscn"
|
||||||
config/features=PackedStringArray("4.0", "C#", "Double Precision", "Mobile")
|
config/features=PackedStringArray("4.0", "C#", "Double Precision", "Mobile")
|
||||||
config/icon="res://icon.svg"
|
config/icon="res://icon.svg"
|
||||||
|
|
||||||
|
[autoload]
|
||||||
|
|
||||||
|
SettingsManager="*res://Scripts/Managers/SettingsManager.cs"
|
||||||
|
|
||||||
[display]
|
[display]
|
||||||
|
|
||||||
window/size/viewport_width=800
|
window/size/viewport_width=800
|
||||||
|
@ -29,6 +33,10 @@ project/assembly_name="Pong"
|
||||||
version_control/plugin_name="GitPlugin"
|
version_control/plugin_name="GitPlugin"
|
||||||
version_control/autoload_on_startup=true
|
version_control/autoload_on_startup=true
|
||||||
|
|
||||||
|
[editor_plugins]
|
||||||
|
|
||||||
|
enabled=PackedStringArray("res://addons/BaseMenu/plugin.cfg")
|
||||||
|
|
||||||
[input]
|
[input]
|
||||||
|
|
||||||
paddle_up={
|
paddle_up={
|
||||||
|
|
Loading…
Reference in a new issue