diff --git a/Scenes/MainMenu.tscn b/Scenes/MainMenu.tscn
new file mode 100644
index 0000000..14306d5
--- /dev/null
+++ b/Scenes/MainMenu.tscn
@@ -0,0 +1,29 @@
+[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"]
diff --git a/Scenes/Pong.tscn b/Scenes/Pong.tscn
index d16e54c..a0b47d6 100644
--- a/Scenes/Pong.tscn
+++ b/Scenes/Pong.tscn
@@ -1,7 +1,8 @@
-[gd_scene load_steps=6 format=3 uid="uid://wn48xnd0lstq"]
+[gd_scene load_steps=7 format=3 uid="uid://wn48xnd0lstq"]
[ext_resource type="PackedScene" path="res://Scenes/Paddle.tscn" id="1_5rs0o"]
[ext_resource type="Script" path="res://Scripts/Managers/SceneManager.cs" id="1_m8437"]
+[ext_resource type="PackedScene" uid="uid://co2rv0nci8sbm" path="res://Scenes/Score.tscn" id="2_f3jwj"]
[ext_resource type="PackedScene" uid="uid://67qguep14iko" path="res://Scenes/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/Enemy.tscn" id="4_uwvof"]
@@ -9,6 +10,8 @@
[node name="Pong" type="Node2D"]
script = ExtResource("1_m8437")
+[node name="Score" parent="." instance=ExtResource("2_f3jwj")]
+
[node name="Paddle" parent="." instance=ExtResource("1_5rs0o")]
position = Vector2(-350, 0)
_moveSpeed = 50.0
diff --git a/Scenes/Score.tscn b/Scenes/Score.tscn
new file mode 100644
index 0000000..ae48c00
--- /dev/null
+++ b/Scenes/Score.tscn
@@ -0,0 +1,30 @@
+[gd_scene load_steps=3 format=3 uid="uid://co2rv0nci8sbm"]
+
+[ext_resource type="Script" path="res://Scripts/Managers/ScoreManager.gd" id="1_bdtqr"]
+
+[sub_resource type="LabelSettings" id="LabelSettings_piogj"]
+font_size = 64
+
+[node name="Score" type="HFlowContainer"]
+z_index = 1
+offset_left = -378.0
+offset_top = -272.0
+offset_right = 378.0
+offset_bottom = 268.0
+script = ExtResource("1_bdtqr")
+
+[node name="Player1" type="Label" parent="."]
+layout_mode = 2
+size_flags_horizontal = 3
+text = "0
+"
+label_settings = SubResource("LabelSettings_piogj")
+vertical_alignment = 1
+
+[node name="Player2" type="Label" parent="."]
+layout_mode = 2
+size_flags_horizontal = 3
+text = "0"
+label_settings = SubResource("LabelSettings_piogj")
+horizontal_alignment = 2
+vertical_alignment = 1
diff --git a/Scenes/Walls.tscn b/Scenes/Walls.tscn
index 23defd9..a4a2866 100644
--- a/Scenes/Walls.tscn
+++ b/Scenes/Walls.tscn
@@ -3,28 +3,30 @@
[ext_resource type="Script" path="res://Scripts/Managers/WallManager.cs" id="1_mxer2"]
[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_f7jy5"]
-size = Vector2(30, 600)
+size = Vector2(30, 1)
[sub_resource type="RectangleShape2D" id="RectangleShape2D_1mqst"]
-size = Vector2(30, 600)
+size = Vector2(30, 1)
[sub_resource type="RectangleShape2D" id="RectangleShape2D_sip7s"]
-size = Vector2(30, 600)
+size = Vector2(30, 1)
[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_868ov"]
-size = Vector2(756, 30)
+size = Vector2(1, 30)
[sub_resource type="RectangleShape2D" id="RectangleShape2D_rw4mt"]
-size = Vector2(756, 30)
+size = Vector2(1, 30)
[sub_resource type="RectangleShape2D" id="RectangleShape2D_dydpt"]
-size = Vector2(756, 30)
+size = Vector2(1, 30)
[node name="Walls" type="Node2D"]
[node name="Left" type="Area2D" parent="."]
position = Vector2(-393, -2)
+scale = Vector2(1, 600)
script = ExtResource("1_mxer2")
+PlayerNumber = 1
[node name="Left" type="Sprite2D" parent="Left"]
position = Vector2(2.08165e-12, 2.08165e-12)
@@ -36,6 +38,7 @@ shape = SubResource("RectangleShape2D_1mqst")
[node name="Right" type="Area2D" parent="."]
position = Vector2(393, -2)
+scale = Vector2(1, 600)
script = ExtResource("1_mxer2")
[node name="Right" type="Sprite2D" parent="Right"]
@@ -48,6 +51,7 @@ shape = SubResource("RectangleShape2D_sip7s")
[node name="Top" type="StaticBody2D" parent="."]
position = Vector2(2.08165e-12, -287)
+scale = Vector2(756, 1)
collision_layer = 2
collision_mask = 2
@@ -61,6 +65,7 @@ shape = SubResource("RectangleShape2D_rw4mt")
[node name="Bottom" type="StaticBody2D" parent="."]
position = Vector2(2.08165e-12, 283)
+scale = Vector2(756, 1)
collision_layer = 2
collision_mask = 2
@@ -71,3 +76,6 @@ texture = SubResource("PlaceholderTexture2D_868ov")
[node name="CollisionShape2D" type="CollisionShape2D" parent="Bottom"]
position = Vector2(-2.08165e-12, 0)
shape = SubResource("RectangleShape2D_dydpt")
+
+[connection signal="body_entered" from="Left" to="Left" method="OnBodyEntered"]
+[connection signal="body_entered" from="Right" to="Right" method="OnBodyEntered"]
diff --git a/Scripts/Data/PlayerNumber.cs b/Scripts/Data/PlayerNumber.cs
new file mode 100644
index 0000000..a3a9031
--- /dev/null
+++ b/Scripts/Data/PlayerNumber.cs
@@ -0,0 +1,7 @@
+namespace Pong.Scripts.Data;
+
+public enum PlayerNumber
+{
+ PlayerOne,
+ PlayerTwo
+}
diff --git a/Scripts/Managers/MainMenuManager.cs b/Scripts/Managers/MainMenuManager.cs
new file mode 100644
index 0000000..684302a
--- /dev/null
+++ b/Scripts/Managers/MainMenuManager.cs
@@ -0,0 +1,28 @@
+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();
+ }
+
+ ///
+ /// code that executes when the start button is pressed. this loads the Pong scene to the root
+ /// of the scene tree.
+ ///
+ private void OnButtonPressed()
+ {
+ GetTree().Root.SizeChanged -= AdaptUiToScreenResolution;
+ GetTree().ChangeSceneToFile("res://Scenes/Pong.tscn");
+ }
+
+ private void AdaptUiToScreenResolution()
+ {
+ Size = DisplayServer.WindowGetSize();
+ }
+}
diff --git a/Scripts/Managers/ScoreManager.gd b/Scripts/Managers/ScoreManager.gd
new file mode 100644
index 0000000..ec5730c
--- /dev/null
+++ b/Scripts/Managers/ScoreManager.gd
@@ -0,0 +1,34 @@
+extends HFlowContainer
+
+var PlayerOneScore: int
+var PlayerTwoScore: int
+
+var PlayerOneLabel: Label
+var PlayerTwoLabel: Label
+
+enum {PlayerOne, PlayerTwo}
+
+# Called when the node enters the scene tree for the first time.
+func _ready():
+ PlayerOneLabel = get_node("Player1")
+ PlayerTwoLabel = get_node("Player2")
+
+# Called every frame. 'delta' is the elapsed time since the previous frame.
+func _process(_delta):
+ pass
+
+## when the ball collides with the wall, this method is called by the WallManager
+func score(player_number: int):
+ if player_number == PlayerOne:
+ PlayerOneScore += 1
+ update_label(player_number)
+ elif player_number == PlayerTwo:
+ PlayerTwoScore += 1
+ update_label(player_number)
+
+## this method takes care of updating labels
+func update_label(player_number: int):
+ if player_number == PlayerOne:
+ PlayerOneLabel.text = str(PlayerOneScore)
+ elif player_number == PlayerTwo:
+ PlayerTwoLabel.text = str(PlayerTwoScore)
diff --git a/Scripts/Managers/WallManager.cs b/Scripts/Managers/WallManager.cs
index e843964..751c474 100644
--- a/Scripts/Managers/WallManager.cs
+++ b/Scripts/Managers/WallManager.cs
@@ -1,17 +1,29 @@
using Godot;
+using Pong.Scripts.Data;
namespace Pong.Scripts.Managers;
public partial class WallManager : Area2D
{
+ [Export] internal PlayerNumber PlayerNumber;
+
+ private GodotObject _scoreManager;
+ private StringName _score = "score";
+
public override void _Ready()
{
- BodyEntered += OnBodyEntered;
+ _scoreManager = GetNode("/root/Pong/Score");
}
+ ///
+ /// code that runs when a ball collides the wall.
+ ///
+ /// the body of the collider.
private void OnBodyEntered(Node2D body)
{
if (body is not Nodes.Ball ball) return;
+ _scoreManager.Call(_score, (long)PlayerNumber);
+
ResetBall(ball);
}
diff --git a/project.godot b/project.godot
index 2b8af3d..0003d3d 100644
--- a/project.godot
+++ b/project.godot
@@ -11,7 +11,7 @@ config_version=5
[application]
config/name="Pong"
-run/main_scene="res://Scenes/Pong.tscn"
+run/main_scene="res://Scenes/MainMenu.tscn"
config/features=PackedStringArray("4.0", "C#", "Double Precision", "Mobile")
config/icon="res://icon.svg"