the paddle can now scale to the resolution
i added a GameArea class which makes it easier to operate on in coordinates bounds with the GameCoordinate struct wrapper which does calculations for me. the GameArea class also has a normalization system which is how the ScalingManager can teleport items in bounds to relatively the same place when resized. it took quite a while to get the paddle to teleport. looks like im supposed to modify the position inside IntegrateForces instead of PhysicsProcess which is my mistake.
This commit is contained in:
parent
e1b0fa338f
commit
604d79e654
14 changed files with 178 additions and 96 deletions
|
@ -1,4 +1,4 @@
|
||||||
[gd_scene load_steps=5 format=3]
|
[gd_scene load_steps=5 format=3 uid="uid://ijf4pw1wmb4t"]
|
||||||
|
|
||||||
[ext_resource type="PhysicsMaterial" uid="uid://e05n66x8ug77" path="res://Resources/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/Objects/Paddle.cs" id="1_uv7s3"]
|
[ext_resource type="Script" path="res://Scripts/Objects/Paddle.cs" id="1_uv7s3"]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[gd_scene load_steps=8 format=3 uid="uid://bh3p1hnvsviu6"]
|
[gd_scene load_steps=8 format=3 uid="uid://bh3p1hnvsviu6"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" path="res://Scenes/Objects/Paddle.tscn" id="1_5rs0o"]
|
[ext_resource type="PackedScene" uid="uid://ijf4pw1wmb4t" path="res://Scenes/Objects/Paddle.tscn" id="1_5rs0o"]
|
||||||
[ext_resource type="Script" path="res://Scripts/Managers/PongSceneManager.cs" id="1_ee533"]
|
[ext_resource type="Script" path="res://Scripts/Managers/PongSceneManager.cs" id="1_ee533"]
|
||||||
[ext_resource type="Script" path="res://Scripts/Managers/ScalingManager.cs" id="2_dc5sv"]
|
[ext_resource type="Script" path="res://Scripts/Managers/ScalingManager.cs" id="2_dc5sv"]
|
||||||
[ext_resource type="PackedScene" uid="uid://clsmrwvyrt7av" path="res://Scenes/UI/Score.tscn" id="2_f3jwj"]
|
[ext_resource type="PackedScene" uid="uid://clsmrwvyrt7av" path="res://Scenes/UI/Score.tscn" id="2_f3jwj"]
|
||||||
|
|
|
@ -5,11 +5,16 @@ public static class Constants
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// a constant representing 1 Meter in pixels.
|
/// a constant representing 1 Meter in pixels.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal const double Meter = 10;
|
public const double Meter = 10;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// the pixel size of either the vertical or the horizontal size of the walls.
|
||||||
|
/// </summary>
|
||||||
|
public const long WallSize = 30;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// the extents (half of the size) of the pixel size of either the width for the vertical walls,
|
/// the extents (half of the size) of the pixel size of either the width for the vertical walls,
|
||||||
/// or the height for the horizontal walls.
|
/// or the height for the horizontal walls.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal const long WallSizeExtents = 15;
|
public const long WallSizeExtents = WallSize / 2;
|
||||||
}
|
}
|
||||||
|
|
37
Scripts/Data/GameArea.cs
Normal file
37
Scripts/Data/GameArea.cs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
namespace Pong.Scripts.Data;
|
||||||
|
|
||||||
|
public record GameArea
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// the X coordinate of the GameArea wrapped in a struct that makes operating on it easier. this is divided
|
||||||
|
/// by 2 in the constructor to represent both sides of the screen by either negative or positive of the number.
|
||||||
|
/// </summary>
|
||||||
|
public GameCoordinate X { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// the Y coordinate of the GameArea wrapped in a struct that makes operating on it easier. this is divided
|
||||||
|
/// by 2 in the constructor to represent both sides of the screen by either negative or positive of the number.
|
||||||
|
/// </summary>
|
||||||
|
public GameCoordinate Y { get; }
|
||||||
|
|
||||||
|
public Vector2 NormalizePosition(Vector2 globalPosition)
|
||||||
|
{
|
||||||
|
var normalizedX = Mathf.InverseLerp(-X.ByWallSizeExtents, X.ByWallSizeExtents, globalPosition.X);
|
||||||
|
var normalizedY = Mathf.InverseLerp(-Y.ByWallSizeExtents, Y.ByWallSizeExtents, globalPosition.Y);
|
||||||
|
return new Vector2(normalizedX, normalizedY);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Vector2 GlobalizePosition(Vector2 normalizedPosition)
|
||||||
|
{
|
||||||
|
var globalizedX = Mathf.Lerp(-X.ByWallSizeExtents, X.ByWallSizeExtents, normalizedPosition.X);
|
||||||
|
var globalizedY = Mathf.Lerp(-Y.ByWallSizeExtents, Y.ByWallSizeExtents, normalizedPosition.Y);
|
||||||
|
return new Vector2(globalizedX, globalizedY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameArea(Vector2 area)
|
||||||
|
{
|
||||||
|
X = new GameCoordinate(area.X / 2);
|
||||||
|
Y = new GameCoordinate(area.Y / 2);
|
||||||
|
}
|
||||||
|
}
|
25
Scripts/Data/GameCoordinate.cs
Normal file
25
Scripts/Data/GameCoordinate.cs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
namespace Pong.Scripts.Data;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// simple wrapper structure to a double that makes it easy to get commonly used calculations of the number.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Coordinate">the coordinate you want to wrap.</param>
|
||||||
|
public readonly record struct GameCoordinate(double Coordinate)
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// the original coordinate. you don't really need to use this as the struct has an implicit operator, but
|
||||||
|
/// its here if you need it.
|
||||||
|
/// </summary>
|
||||||
|
public readonly double Coordinate = Coordinate;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// get the coordinate but calculated by the extents of the wall size.
|
||||||
|
/// </summary>
|
||||||
|
public double ByWallSizeExtents => Coordinate - Constants.WallSizeExtents;
|
||||||
|
/// <summary>
|
||||||
|
/// get the coordinate but calculated by the wall size.
|
||||||
|
/// </summary>
|
||||||
|
public double ByWallSize => Coordinate - Constants.WallSize;
|
||||||
|
|
||||||
|
public static implicit operator double(GameCoordinate coord) => coord.Coordinate;
|
||||||
|
}
|
|
@ -1,6 +1,3 @@
|
||||||
using System;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Pong.Scripts.Data;
|
namespace Pong.Scripts.Data;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
using Godot;
|
|
||||||
|
|
||||||
namespace Pong.Scripts.Managers;
|
namespace Pong.Scripts.Managers;
|
||||||
|
|
||||||
public partial class PongSceneManager : Node2D
|
public partial class PongSceneManager : Node2D
|
||||||
|
|
|
@ -1,96 +1,102 @@
|
||||||
|
using System;
|
||||||
|
using Pong.Scripts.Data;
|
||||||
|
|
||||||
namespace Pong.Scripts.Managers;
|
namespace Pong.Scripts.Managers;
|
||||||
|
|
||||||
public partial class ScalingManager : Node
|
public partial class ScalingManager : Node
|
||||||
{
|
{
|
||||||
private HFlowContainer _score;
|
private HFlowContainer _score;
|
||||||
private RigidBody2D _paddle;
|
private RigidBody2D _paddle;
|
||||||
private CharacterBody2D _ball;
|
private CharacterBody2D _ball;
|
||||||
|
|
||||||
private Area2D _leftWall;
|
private Area2D _leftWall;
|
||||||
private Area2D _rightWall;
|
private Area2D _rightWall;
|
||||||
private StaticBody2D _topWall;
|
private StaticBody2D _topWall;
|
||||||
private StaticBody2D _bottomWall;
|
private StaticBody2D _bottomWall;
|
||||||
|
|
||||||
private RigidBody2D _enemy;
|
private RigidBody2D _enemy;
|
||||||
|
|
||||||
private Vector2I _gameResolution;
|
private Vector2I _gameResolution;
|
||||||
private Vector2 _edgePosition;
|
private GameArea _gameArea;
|
||||||
|
|
||||||
public override void _EnterTree()
|
public event EventHandler<Vector2> NewPaddlePosition;
|
||||||
{
|
|
||||||
GetNodes();
|
|
||||||
GetTree().Root.SizeChanged += AdaptToGameResolution;
|
|
||||||
AdaptToGameResolution();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void _ExitTree()
|
public override void _EnterTree()
|
||||||
{
|
{
|
||||||
GetTree().Root.SizeChanged -= AdaptToGameResolution;
|
GetNodes();
|
||||||
}
|
GetTree().Root.SizeChanged += AdaptToGameResolution;
|
||||||
|
AdaptToGameResolution();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
public override void _ExitTree()
|
||||||
/// a method that gets all the nodes that the scaling manager will manage the position and scale of.
|
{
|
||||||
/// </summary>
|
GetTree().Root.SizeChanged -= AdaptToGameResolution;
|
||||||
private void GetNodes()
|
}
|
||||||
{
|
|
||||||
_score = GetNode<HFlowContainer>("../Score");
|
|
||||||
_paddle = GetNode<RigidBody2D>("../Paddle");
|
|
||||||
_ball = GetNode<CharacterBody2D>("../Ball");
|
|
||||||
|
|
||||||
_leftWall = GetNode<Area2D>("../Walls/Left");
|
/// <summary>
|
||||||
_rightWall = GetNode<Area2D>("../Walls/Right");
|
/// a method that gets all the nodes that the scaling manager will manage the position and scale of.
|
||||||
_topWall = GetNode<StaticBody2D>("../Walls/Top");
|
/// </summary>
|
||||||
_bottomWall = GetNode<StaticBody2D>("../Walls/Bottom");
|
private void GetNodes()
|
||||||
|
{
|
||||||
|
_score = GetNode<HFlowContainer>("../Score");
|
||||||
|
_paddle = GetNode<RigidBody2D>("../Paddle");
|
||||||
|
_ball = GetNode<CharacterBody2D>("../Ball");
|
||||||
|
|
||||||
_enemy = GetNode<RigidBody2D>("../Enemy");
|
_leftWall = GetNode<Area2D>("../Walls/Left");
|
||||||
}
|
_rightWall = GetNode<Area2D>("../Walls/Right");
|
||||||
|
_topWall = GetNode<StaticBody2D>("../Walls/Top");
|
||||||
|
_bottomWall = GetNode<StaticBody2D>("../Walls/Bottom");
|
||||||
|
|
||||||
/// <summary>
|
_enemy = GetNode<RigidBody2D>("../Enemy");
|
||||||
/// adapt to the current resolution of the game.
|
}
|
||||||
/// </summary>
|
|
||||||
private void AdaptToGameResolution()
|
|
||||||
{
|
|
||||||
_gameResolution = DisplayServer.WindowGetSize();
|
|
||||||
_edgePosition = CalculateEdgePosition(_gameResolution);
|
|
||||||
|
|
||||||
SetWallPosition();
|
/// <summary>
|
||||||
SetScorePosition();
|
/// adapt to the current resolution of the game.
|
||||||
}
|
/// </summary>
|
||||||
|
private void AdaptToGameResolution()
|
||||||
|
{
|
||||||
|
var normalizedPaddlePosition =
|
||||||
|
_gameArea?.NormalizePosition(_paddle.Position) ?? new Vector2(0, 0.5);
|
||||||
|
_gameResolution = DisplayServer.WindowGetSize();
|
||||||
|
_gameArea = new GameArea(_gameResolution);
|
||||||
|
|
||||||
/// <summary>
|
SetWallPosition();
|
||||||
/// calculate the edges of the screen according to 0, 0 being in the center of the screen.
|
SetScorePosition();
|
||||||
/// </summary>
|
SetPaddlePosition(normalizedPaddlePosition);
|
||||||
private static Vector2 CalculateEdgePosition(Vector2 resolution)
|
}
|
||||||
{
|
|
||||||
return new Vector2(resolution.X / 2, resolution.Y / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// set the position and scale of the walls according to the edge position.
|
/// set the position and scale of the walls according to the edge position.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void SetWallPosition()
|
private void SetWallPosition()
|
||||||
{
|
{
|
||||||
var xSize = _edgePosition.X - Constants.WallSizeExtents;
|
var xSize = _gameArea.X.ByWallSizeExtents;
|
||||||
var ySize = _edgePosition.Y - Constants.WallSizeExtents;
|
var ySize = _gameArea.Y.ByWallSizeExtents;
|
||||||
|
|
||||||
_leftWall.Position = new Vector2(-xSize, 0);
|
_leftWall.Position = new Vector2(-xSize, 0);
|
||||||
_rightWall.Position = new Vector2(xSize, 0);
|
_rightWall.Position = new Vector2(xSize, 0);
|
||||||
_topWall.Position = new Vector2(0, -ySize);
|
_topWall.Position = new Vector2(0, -ySize);
|
||||||
_bottomWall.Position = new Vector2(0, ySize);
|
_bottomWall.Position = new Vector2(0, ySize);
|
||||||
|
|
||||||
_leftWall.Scale = _leftWall.Scale with { Y = _gameResolution.Y };
|
_leftWall.Scale = _leftWall.Scale with { Y = _gameResolution.Y };
|
||||||
_rightWall.Scale = _rightWall.Scale with { Y = _gameResolution.Y };
|
_rightWall.Scale = _rightWall.Scale with { Y = _gameResolution.Y };
|
||||||
_topWall.Scale = _topWall.Scale with { X = _gameResolution.X - 60 };
|
_topWall.Scale = _topWall.Scale with { X = _gameResolution.X - 60 };
|
||||||
_bottomWall.Scale = _bottomWall.Scale with { X = _gameResolution.X - 60 };
|
_bottomWall.Scale = _bottomWall.Scale with { X = _gameResolution.X - 60 };
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// set the position of the score ui. this has to be calculated with 0, 0 being the top left of the screen as
|
/// set the position of the score ui. this has to be calculated with 0, 0 being the top left of the screen as
|
||||||
/// the UI's point starts from there instead of the point being in the middle of the screen.
|
/// the UIs point starts from there instead of the point being in the middle of the screen.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void SetScorePosition()
|
private void SetScorePosition()
|
||||||
{
|
{
|
||||||
_score.Position = new Vector2(-_edgePosition.X + 30, -_edgePosition.Y + 30);
|
_score.Position = new Vector2(-_gameArea.X.ByWallSize, -_gameArea.Y.ByWallSize);
|
||||||
_score.Size = new Vector2(_gameResolution.X - 60, _gameResolution.Y - 60);
|
_score.Size = new Vector2(_gameResolution.X - 60, _gameResolution.Y - 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetPaddlePosition(Vector2 normalizedPosition)
|
||||||
|
{
|
||||||
|
var newPaddlePos = _gameArea.GlobalizePosition(normalizedPosition with { X = 0 }) + new Vector2(24, 0);
|
||||||
|
NewPaddlePosition?.Invoke(this, newPaddlePos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Godot;
|
|
||||||
using Pong.Scripts.Data;
|
using Pong.Scripts.Data;
|
||||||
|
|
||||||
namespace Pong.Scripts.Managers;
|
namespace Pong.Scripts.Managers;
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
using Godot;
|
|
||||||
|
|
||||||
namespace Pong.Scripts.Managers.UI;
|
namespace Pong.Scripts.Managers.UI;
|
||||||
|
|
||||||
public partial class BaseMenu : VBoxContainer
|
public partial class BaseMenu : VBoxContainer
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
using Godot;
|
|
||||||
|
|
||||||
namespace Pong.Scripts.Managers.UI.Menus;
|
namespace Pong.Scripts.Managers.UI.Menus;
|
||||||
|
|
||||||
public partial class MainMenu : BaseMenu
|
public partial class MainMenu : BaseMenu
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
using Godot;
|
|
||||||
|
|
||||||
namespace Pong.Scripts.Managers.UI.Menus;
|
namespace Pong.Scripts.Managers.UI.Menus;
|
||||||
|
|
||||||
public partial class Settings : BaseMenu
|
public partial class Settings : BaseMenu
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using Godot;
|
|
||||||
using Pong.Scripts.Data;
|
using Pong.Scripts.Data;
|
||||||
using Pong.Scripts.Objects;
|
using Pong.Scripts.Objects;
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
using Pong.Scripts.Managers;
|
||||||
|
|
||||||
namespace Pong.Scripts.Objects;
|
namespace Pong.Scripts.Objects;
|
||||||
|
|
||||||
public partial class Paddle : RigidBody2D
|
public partial class Paddle : RigidBody2D
|
||||||
|
@ -7,20 +9,40 @@ public partial class Paddle : RigidBody2D
|
||||||
private double _verticalInput;
|
private double _verticalInput;
|
||||||
private readonly StringName _paddleUp = "paddle_up";
|
private readonly StringName _paddleUp = "paddle_up";
|
||||||
private readonly StringName _paddleDown = "paddle_down";
|
private readonly StringName _paddleDown = "paddle_down";
|
||||||
|
private ScalingManager _scalingManager;
|
||||||
|
|
||||||
|
private bool _canMove = true;
|
||||||
|
private Vector2 _originalPosition;
|
||||||
|
|
||||||
|
private Vector2? _newPosition;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// property that multiples the moveSpeed by the <see cref="Constants.Meter">Meter</see> constant.
|
/// property that multiples the moveSpeed by the <see cref="Constants.Meter">Meter</see> constant.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private double MoveSpeed => _moveSpeed * Constants.Meter;
|
private double MoveSpeed => _moveSpeed * Constants.Meter;
|
||||||
|
|
||||||
|
public override void _EnterTree()
|
||||||
|
{
|
||||||
|
SetNotifyTransform(true);
|
||||||
|
SetNotifyLocalTransform(true);
|
||||||
|
_scalingManager = GetNode<ScalingManager>("../ScalingManager");
|
||||||
|
_scalingManager.NewPaddlePosition += (_, vector2) => _newPosition = vector2;
|
||||||
|
}
|
||||||
|
|
||||||
public override void _Process(double delta)
|
public override void _Process(double delta)
|
||||||
{
|
{
|
||||||
_verticalInput = GetVerticalInput();
|
_verticalInput = GetVerticalInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _PhysicsProcess(double delta)
|
public override void _IntegrateForces(PhysicsDirectBodyState2D state)
|
||||||
{
|
{
|
||||||
LinearVelocity = Vector2.Up * MoveSpeed * _verticalInput;
|
if (_newPosition.HasValue)
|
||||||
|
{
|
||||||
|
state.Transform = new Transform2D(0, _newPosition.Value);
|
||||||
|
_newPosition = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.LinearVelocity = Vector2.Up * MoveSpeed * _verticalInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
Loading…
Reference in a new issue