From a6ad2026751fcfd38a5dbb11a6c41160e1e62172 Mon Sep 17 00:00:00 2001 From: RandomCyberCoder <109709571+RandomCyberCoder@users.noreply.github.com> Date: Thu, 19 Oct 2023 18:18:30 -0700 Subject: [PATCH] Emmanuel_Delgado PongRL Week 1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code Exploration Pong/_Pong.cs This seems to be the master class that contains all the constants. It also seems that the GameCache class will hold the data for one frame of the game. The GameHelpers class seems to be for updating the ball and players position _Pong.cs :GameConstants, hold important constants _Pong.cs :GameCache, hold data of a frame of the game or values to be used during the game _Pong.cs: RIGHT_PADDLE_X_POSITION, the right paddle’s fixed x position _Pong.cs: LEFT_PADDLE_X_POSITION, the left paddle’s fixed x position _Pong.cs: RIGHT_PADDLE_CONTROLS, right paddle controls _Pong.cs: LEFT_PADDLE_CONTROLS, left paddle controls pong/GamePlayer/_Pong-GamePlayer.cs Defines the partial classes that will be essential for the data of the player, how the player will be controlled, and a playercontroller class which I'm unsure of. _Pong-GamePlayer.cs: PlayerData, class to hold player data _Pong-GamePlayer.cs: PlayerControls, how the player will be controlled _Pong-GamePlayer.cs: Player, class that holds all player information Pong/Ball/_Pong-Ball.cs Holds classes for how we define a one opponent scoring a goal on the other opponent. The header file also seems to have the class for the how the ball’s collision will be handled _Pong-Ball.cs: PongBall, how when the ball hits a paddle _Pong-Ball.cs: BallGoal, hold data for when one opponent scores a goal Pong/GameManager.cs Holds the game logic and has a function to start the game. This file also seems to store information of each frame for the player and the ball. Also displays the score of the game GameManager.cs: Start(), sets the values for the speed of ball and player. Also initializes the player objects and ball object GameManager.cs: Update(), updates the player and ball every frame of the game GameManager.cs: GameCache.{variables}, sets the values for the speeds, and max angles the ball can have Pong/GamePlayer/Player.cs Contains the player class which will initialize the player with its data, the controls for that player, and its scoreboard. Also, it has functions to update the player, set the player’s opponent, and the dimensions of the player Player.cs: playerData, hold data of the player Player.cs: scoreboard, holds the score of the player Player.cs: opponent, opponent of the player Player.cs: Player(), constructor of the player Player.cs: Opponent(), set the player’s opponent Player.cs: Update(), function that will be used to update the player’s information each frame Player.cs: ScorePoint(), determines if the player scored the point, seems like this will be use for the RL agent later on Pong/Ball/PongBall.cs The class controls how the ball will behave depending on if a player scored a goal or if the ball hit a player’s opponent PongBall.cs: attacker, last player that touched the ball, helps us determine who scores a goal PongBall.cs: OnScore, what should happen if a goal is scored PongBall.cs: OnRebound, what should happen if the player hits the ball back PongBall.cs: PongBall(), holds the logic for what should happen if goal is made of player hits ball back PongBall.cs: SetAttacker(), sets the player who last touched the ball PongBall.cs: DestroyBall(), destroys the ball when the player scores a goal to allow it to be reset Testing Modified the BALL_Y-MAX_DERIVIATIVE in the _Pong.cs header file. Increasing the value seemed to have a slight change in the velocity of the ball. I also noticed that increasing the value to high seemed to have the effect of the ball suddenly not moving. Modified playerSpeeedVP in GameManager.cs. This seemed to affect how fast I could move the paddles. However, the speed the paddles moved didn’t seem to differ much when I changed the values. I set it to zero and the paddles still moved so I’m not to sure what this controls Modified the function PlayerControls in _pong-GamePlayer.cs to reverse the controls of the player. I found that the KeyCode type stores the button that the player will use to control the paddles. Documentation _Pong-GamePlayer.cs _Pong.cs _Pong-Ball.cs Player.cs GameManager.cs PongBall.cs --- GameManager.cs | 111 +++++++++++++++++++++++ Player.cs | 143 ++++++++++++++++++++++++++++++ PongBall.cs | 211 ++++++++++++++++++++++++++++++++++++++++++++ _Pong-Ball.cs | 57 ++++++++++++ _Pong-GamePlayer.cs | 32 +++++++ _Pong.cs | 92 +++++++++++++++++++ 6 files changed, 646 insertions(+) create mode 100644 GameManager.cs create mode 100644 Player.cs create mode 100644 PongBall.cs create mode 100644 _Pong-Ball.cs create mode 100644 _Pong-GamePlayer.cs create mode 100644 _Pong.cs diff --git a/GameManager.cs b/GameManager.cs new file mode 100644 index 0000000..b351c50 --- /dev/null +++ b/GameManager.cs @@ -0,0 +1,111 @@ +//namespace Pong; +using Pong; + +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +using Pong.GamePlayer; +using Pong.Ball; + +using TMPro; +using System; + +namespace Pong { + public partial class GameManager : MonoBehaviour + { + private Player player1, player2; + private PongBall ball; + + // CONTEXT: public => reference in the Unity Editor + public string player1Name = PlayerData.NO_NAME, player2Name = PlayerData.NO_NAME; + public float playerSpeedVP = 1.0f; // per second; travel 100% vertical screen size in one second + public float ballSpeedVP = .45f; // per second; travel 45% horizontal screen size in one second + public float ballServeMaxAngle = (3f / 7f) * Mathf.PI; + public float ballBounceMaxAngle = (3f / 7f) * Mathf.PI; + public uint scoreToWin = GameConstants.DEFAULT_WIN_SCORE; + public GameObject playerPrefab; // will be a sprite prefab + public GameObject ballPrefab; // will be a sprite prefab + public GameObject backgroundSprite; // reference a GameObject in the Scene + public TMP_Text player1scoreText, player2scoreText; // reference in Scene + + /// + /// for debugging purposes? + /// + void Awake() + { + // Hello World message + Debug.Log("Hello World!"); + + //Debug.Log(GameConstants.RIGHT_PADDLE_START_POSITION); + //Debug.Log(GameConstants.LEFT_PADDLE_START_POSITION); + } + + /// + /// starts the game and stores important data in GameCache.{attribute}. Initialize the player and give the player data. + /// Initialize the ball object and serve it so gameplay can begin + /// + void Start() + { + // Cache Desired Global Variables + GameCache.BG_TRANSFORM = backgroundSprite.transform; + GameCache.PLAYER_SPEED_VP = playerSpeedVP; + GameCache.BALL_SPEED_VP = ballSpeedVP; + GameCache.BALL_SERVE_MAX_ANGLE = ballServeMaxAngle; + GameCache.BALL_BOUNCE_MAX_ANGLE = ballBounceMaxAngle; + GameCache.WIN_SCORE = scoreToWin; + //TODO: use import audio library + //Audio.Cache.SFX = Audio.SfxPack.FromRegisteredMappings(); + + // Initialize Players/Pong Paddles + player1 = Player.CreateNew(player1Name, playerPrefab, GameConstants.RIGHT_PADDLE_START_POSITION, GameConstants.RIGHT_PADDLE_CONTROLS, player1scoreText); + player2 = Player.CreateNew(player2Name, playerPrefab, GameConstants.LEFT_PADDLE_START_POSITION, GameConstants.LEFT_PADDLE_CONTROLS, player2scoreText); + + // Make them enemies!!! >:) + player1.Opponent = player2; + player2.Opponent = player1; + + //* Create ball, then make it go at a random direction (left or right) + ball = PongBall.FromPrefab(ballPrefab); + ball.Initialize(server: RandomPlayer()); + ball.Serve(); + } + + // Update is called once per frame + /// + /// update the player information and the all information every frame. + /// update players first so you don't have instances where the ball seemed like it was in one place but then the ball was + /// updated before the player so the player missed it. This can help solve this issue + /// + void Update() + { + // Player Updates + player1.Update(); + player2.Update(); + + // PongBall Update + ball.Update(); // didn't call this before the player updates for a better user experience + } + + /// + /// display the score board + /// + /// + /// return as string that contains both players score so it can be displayed + /// + public string GetCurrentScore() { + return player1.GetScoreboard().GetScore() + "-" + player2.GetScoreboard().GetScore(); + } + + // pick a random Player. Either player1 or player2 + public Player RandomPlayer() { + bool isPlayer1 = UnityEngine.Random.Range(0, 2) == 0; // random boolean + + if (isPlayer1) { + return player1; + } else { + return player2; + } + } + } +} \ No newline at end of file diff --git a/Player.cs b/Player.cs new file mode 100644 index 0000000..579d8c9 --- /dev/null +++ b/Player.cs @@ -0,0 +1,143 @@ +//namespace Pong.GamePlayer; +using Pong.GamePlayer; + +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +using System; +using UnityUtils; + +using Pong; +using Pong.GamePlayer.Force; +using Pong.Physics; +using Pong.UI; + +using TMPro; + +using static Pong.GameHelpers; + +namespace Pong.GamePlayer { + /** + ** PlayerController controller + ** PlayerData playerData + */ + public partial class Player { + // For RL and save/loading + private PlayerData playerData; + + // Tangible GameObjects + public readonly ControlledGameObject playerSprite; + private readonly Scoreboard scoreboard; + + // For physics + private readonly ForceMap forceMap; + + private Player opponent; + + // load from data + /// + /// Intialize a player with their data, how to control the player, and give the paddles a boundary box so + /// the ball can bounce off it + /// + /// + /// + /// + /// + public Player(PlayerData playerData, GameObject sprite, PlayerControls controls, Scoreboard scoreboard) { + this.playerData = playerData; + this.scoreboard = scoreboard; + + // add + initialize controller + PlayerController controller = sprite.AddComponent(); + controller.InitializeControls(controls); + + // collision detection + RectangularBodyFrame bodyFrame = sprite.AddComponent(); + + // collision forces + forceMap = new ForceMap(sprite.transform); + + // wrap it up + playerSprite = new ControlledGameObject(sprite, controller); + } + + public static Player CreateNew(string name, GameObject prefab, Vector2 viewportPos, PlayerControls controls, TMP_Text scoreText) { + // create paddle + GameObject paddle = GameObject.Instantiate(prefab, ToLocal(viewportPos), Quaternion.identity); + + // default value + string playerName = name; + + // decide name if not named + if (playerName.Equals(PlayerData.NO_NAME)) { // empty => no name => current date time name + playerName = DateTime.Now.ToString("MM/dd/yyyy H:mm"); + } + + // initialize and set name + PlayerData playerData = ScriptableObject.CreateInstance(); + playerData.Initialize(playerName); + + return new Player(playerData, paddle, controls, new Scoreboard(scoreText)); + } + + //TODO: + //public static Player LoadExisting(string ) + + public PlayerData GetPlayerData() { return playerData; } + public Scoreboard GetScoreboard() { return scoreboard; } + public ForceMap GetForceMap() { return forceMap; } + + public Player Opponent { + get { return opponent; } + set { opponent = value; } + } + + /// + /// update the information of the player's padldle. For example update the velocity and acceleration when the player + /// wants to switch the direction of the paddle of the player no long is moving the paddle + /// + public void Update() { + forceMap.PaddleVelocity = ToLocal(playerSprite.controller.GetViewportMotionTracker().velocity).y; + forceMap.PaddleAcceleration = ToLocal(new Vector2(0f, playerSprite.controller.GetViewportMotionTracker().Y_Acceleration)).y; + + //TODO: playerData.feed(...); + } + + /// + /// update the player's score when they socre a goal + /// + public void ScorePoint() { + // Game: score point + scoreboard.ScorePoint(); + + // onScore + //TODO ... + //? update RL agent? + } + + public Rebounder AsRebounder() { + return new Rebounder(forceMap, playerSprite.gameObj.GetComponent()); + } + + /// + /// set the paddles dimensions base off percentages of the viewport + /// + /// + /// + public void SetLocalPaddleDimensionsFromVP(float vpXThickness, float vpYLength) { + Vector3 bgScale = GameCache.BG_TRANSFORM.localScale; + + playerSprite.transform.localScale = new Vector3( + vpXThickness * bgScale.x, + vpYLength * bgScale.y, + playerSprite.transform.localScale.z + ); + } + + // @param Vector2 vpDimensions - viewport dimensions Vector2f[thickness, length] + public void SetLocalPaddleDimensionsFromVP(Vector2 vpDimensions) { + SetLocalPaddleDimensionsFromVP(vpDimensions.x, vpDimensions.y); + } + } +} \ No newline at end of file diff --git a/PongBall.cs b/PongBall.cs new file mode 100644 index 0000000..7ed03b8 --- /dev/null +++ b/PongBall.cs @@ -0,0 +1,211 @@ +//namespace Pong.Ball; +using Pong.Ball; + +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +using UnityUtils; + +using Pong; +using Pong.GamePlayer; +using Pong.Physics; +using static Pong.GameHelpers; +using static Pong.GameCache; + +namespace Pong.Ball { + //* After scoring, it goes: DestroyBall() -> [tiny delay] -> Reset() -> [small delay] -> Serve() + public partial class PongBall { + public readonly ControlledGameObject ballSprite; // it won't actually be destroyed; it will just vanish and look like it was destroyed + private readonly Stack<(float, bool)> serveAngles = new Stack<(float, bool)>(); // float is in radians, and the int is the attackerDesire + + // Player on the offensive + private Player attacker; // "lastTouchedBy"; the initial trajectory will also set this as the player opposite to where it is traveling + private bool attackerDesire; + + // Listeners + private readonly Action OnScore; + private readonly Action OnRebound; + + /// + /// constructor for the ball object and give the ball object the logic if how the ball will react when a player + /// scores a goal or how the ball should change its velocity vector when it rebounds the paddle or boundary of the viewport + /// + /// + public PongBall(GameObject sprite) { + OnScore = () => { + //* Attacker Scored Goal + + DestroyBall(); + + attacker.ScorePoint(); + + //TODO: [tiny delay] + Reset(); + //TODO: [small delay] + Serve(); + }; + + OnRebound = () => { + //* Ball was Rebounded by the defender + ballSprite.controller.ResetBallState(); + SwapAttacker(); + }; + + // add + initialize controller + PongBallController controller = sprite.AddComponent(); + controller.Initialize(OnScore, OnRebound); + + // collision detection + RectangularBodyFrame bodyFrame = sprite.AddComponent(); + + // wrap it up + ballSprite = new ControlledGameObject(sprite, controller); + } + + public static PongBall FromPrefab(GameObject prefab) { + GameObject sprite = GameManager.Instantiate(prefab, GetStartLocalPosition(), Quaternion.identity); + + PongBall pongBall = new PongBall(sprite); + pongBall.SetLocalScaleFromVPY(GameConstants.BALL_SCALE_Y); + + return pongBall; + } + + /// + /// initialize the ball and let a player serve the ball so it heads toward opponnet + /// + /// + public void Initialize(Player server) { + // First, reset the ball (just in case) + Reset(); + + // Handle which server this is + bool serverIsToRight = server.playerSprite.transform.localPosition.x > GetStartLocalPosition().x; + + // initialize desire + attackerDesire = serverIsToRight; // serverIsToRight => serverIsToRight = BallGoal.LEFT = true + + // either 0 or 1, depending on whether it is even or odd respectively + // if first server (even, index 0) is to the left, the remaining odd servers will be to the right and therefore have the ball traveling left on serve + // if first server is to the right, all the rest of the even servers on the right will have the ball traveling left on serve. the remaining odd servers will be to the left, and the ball + uint playerFactor = (uint)(serverIsToRight ? 0 : 1); + + // initialize serveAngles + uint maxRounds = (WIN_SCORE) + (WIN_SCORE - 1); + for (uint i = 0; i < maxRounds; ++i) { + float angle = UnityEngine.Random.Range(-BALL_SERVE_MAX_ANGLE, BALL_SERVE_MAX_ANGLE); // base; works for if server is on left + bool desire; + + // (i % 2 == 0) => first server is to the right => the right server is on even rounds to serve left + // (i % 2 == 1) => first server is to the left => the right server is on odd rounds to serve left + if (i % 2 == playerFactor) { // if odd/even, add PI so that it goes on the left side + //* Player on the Right's turn to Serve + angle += Mathf.PI; + desire = BallGoal.LEFT; + } else { + //* Player on the Left's turn to Serve + desire = BallGoal.RIGHT; + } + + //Debug.Log(angle); + serveAngles.Push((angle, desire)); + + //TODO: debug + /*if (i == 10) { + break; + }*/ + } + + // the Player serving is the one on the offensive + SetAttacker(server); + } + + // serve the ball + public void Serve() { + (float angle, bool serverDesire) = serveAngles.Pop(); + float speed = BALL_SPEED_VP; // in terms of viewport x percentage + + bool otherPlayerServingInstead = attackerDesire != serverDesire; + if (otherPlayerServingInstead) { + SwapAttacker(); + } + + Vector2 direction = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)); // unit vector + Vector2 viewportVelocity = speed * direction; + + ballSprite.controller.ViewportVelocity = viewportVelocity; // set velocity + ballSprite.controller.BeginTrajectory(); // start the timer for y'(t) + } + + public void Update() { + //TODO: feed to players? + } + + + /// + /// destroys the ball when a player scores so it doesn't go off the screen + /// + public void DestroyBall() { + ballSprite.gameObj.SetActive(false); + ballSprite.controller.HaltTrajectory(); // stop the ball from going off the screen + } + + /// + /// reset the position of the ball + /// + public void Reset() { + // set position to start position + ballSprite.transform.localPosition = GetStartLocalPosition(); + + // activate + ballSprite.gameObj.SetActive(true); + } + + /// + /// set the attacker for who hit the ball last so goals are scored properly? + /// + /// + private void SetAttacker(Player atkr) { + attacker = atkr; + + // Now that the attacker has been set, the ball will be headed towards the "rebounder", or in other words, the other player + ballSprite.controller.Rebounder = attacker.Opponent.AsRebounder(); + } + + /// + /// update the ball to swap the attacker + /// + private void SwapAttacker() { + SetAttacker(attacker.Opponent); + attackerDesire = !attackerDesire; + } + + /// + /// set the dimmensions of the ball? + /// + /// + public void SetLocalScaleFromVPY(float viewportY) { + Vector3 bgScale = BG_TRANSFORM.localScale; + + ballSprite.transform.localScale = new Vector3( + viewportY * bgScale.y, // square + viewportY * bgScale.y, // square + ballSprite.transform.localScale.z + ); + + //Debug.Log("LocalScale: " + sprite.transform.localScale); + } + + /// + /// sets the starting position for the ball, center of screen + /// + /// + /// returns the starting position of the ball + /// + public static Vector3 GetStartLocalPosition() { + return ToLocal(GameConstants.BALL_START_POSITION); + } + } +} \ No newline at end of file diff --git a/_Pong-Ball.cs b/_Pong-Ball.cs new file mode 100644 index 0000000..9fcab83 --- /dev/null +++ b/_Pong-Ball.cs @@ -0,0 +1,57 @@ +// * NAMESPACE HEADER FILE + +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +using Pong; + +namespace Pong.Ball { + /* + * Player lastTouchedBy + * Destroys the ball and increments points + */ + + /// + /// partial class to be later fully defined. Controls how the ball will behave when a player scores a goal + /// or the ball rebounds off a paddle. May also include how to update the balls postion + /// + public partial class PongBall {} + + /* + * Handle collisions -> adjust trajectory + speedX = GameCache.BALL_SPEED_VP + velocityY = ForceAdjustment => Equation (due to possible derivatives) + */ + + /// + /// define the parital class to be later defined for how the ball will behave + /// + public partial class PongBallController : MonoBehaviour {} + + /*public static class BallStatus { + private const int GOAL = 1; + + public const int GOAL_LEFT = -GOAL; + public const int NO_GOAL = 0; + public const int GOAL_RIGHT = GOAL; + public const int REBOUNDED = 2; + + public static int INVERT(int ballStatus) { + return ballStatus * -1; + } + + public static bool IsGoal(int ballStatus) { + return Mathf.Abs(ballStatus) == GOAL; + } + }*/ + /// + /// store who socred the last goal + /// + public static class BallGoal { + public const bool LEFT = true; + public const bool RIGHT = false; + + // Note: we don't even need an INVERT() function because the ! operator already does that with bools! + } +} \ No newline at end of file diff --git a/_Pong-GamePlayer.cs b/_Pong-GamePlayer.cs new file mode 100644 index 0000000..4703fcc --- /dev/null +++ b/_Pong-GamePlayer.cs @@ -0,0 +1,32 @@ +// * NAMESPACE HEADER FILE + +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Pong.GamePlayer { + /// + /// future class to be defined of how player information/actoins will be stored + /// + public partial class Player {} + /// + /// playerData class derived from ScriptableObjet to be later deifined + /// + public partial class PlayerData : ScriptableObject {} + //public partial class AIPlayerData : PlayerData {} + /// + /// partial class on how the player will be controlled + /// + public partial class PlayerController : MonoBehaviour {} + + /// + /// class stores keys players will use to control their paddle + /// + public class PlayerControls { + public readonly KeyCode Up, Down; + public PlayerControls(KeyCode up, KeyCode down) { + Up = up; + Down = down; + } + } +} \ No newline at end of file diff --git a/_Pong.cs b/_Pong.cs new file mode 100644 index 0000000..8b7bf17 --- /dev/null +++ b/_Pong.cs @@ -0,0 +1,92 @@ +// * NAMESPACE HEADER FILE + +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +using Pong.GamePlayer; + +namespace Pong { + /// + /// defines global game constants that will be used for the player, ball, and win conditions + /// + public static class GameConstants { + // must be >= 1 because velocity is required + public const uint BALL_Y_MAX_DERIVATIVE = 3; // velocity + (acceleration, acceleration') + + public const uint MAX_SCORE = 999; // any more than that and the UI kinda clips + public const uint DEFAULT_WIN_SCORE = 11; // 11 points is a win in the original Pong game! + + // used for abnormal shots + public const float PADDLE_MASS = 1.00f; + + // viewport y + public const float BALL_SCALE_Y = 0.05f; + + // constants for if origin of a viewport is in the middle of the screen + public const float CENTER_ORIGIN_X = 0.5f; + public const float CENTER_ORIGIN_Y = 0.5f; + + // viewport x [CENTER ORIGIN] + public const float RIGHT_PADDLE_X_POSITION = 0.95f - CENTER_ORIGIN_X; // 95% of the horizontal portion of the screen + public const float LEFT_PADDLE_X_POSITION = -RIGHT_PADDLE_X_POSITION; //= (1.0f - (RIGHT_PADDLE_X_POSITION + CENTER_ORIGIN_X)) - CENTER_ORIGIN_X; + + // viewport vector [CENTER ORIGIN]: position + public static readonly Vector2 BALL_START_POSITION = new Vector2((0.5f - CENTER_ORIGIN_X), (0.5f - CENTER_ORIGIN_Y)); // start in the middle of the screen + public static readonly Vector2 RIGHT_PADDLE_START_POSITION = new Vector2(RIGHT_PADDLE_X_POSITION, (0.5f - CENTER_ORIGIN_Y)); // midpoint on y-axis + public static readonly Vector2 LEFT_PADDLE_START_POSITION = new Vector2(LEFT_PADDLE_X_POSITION, (0.5f - CENTER_ORIGIN_Y)); // midpoint on y-axis + + // controls for each human player + public static readonly PlayerControls RIGHT_PADDLE_CONTROLS = new PlayerControls(KeyCode.UpArrow, KeyCode.DownArrow); + public static readonly PlayerControls LEFT_PADDLE_CONTROLS = new PlayerControls(KeyCode.W, KeyCode.S); + + public static readonly char[] WINDOWS_BANNED_CHARS = {'\\', '/', ':', '*', '?', '\"', '<', '>', '|'}; + } + /// + /// stores the values of the game that other functions will call when initialzing the player and ball + /// + public static class GameCache { + // cached at the beginning of GameManager + public static Transform BG_TRANSFORM; + + // these are context passed into GameManager and set by it + public static float PLAYER_SPEED_VP; // in terms of viewport percentage Y + public static float BALL_SPEED_VP; // in terms of viewport percentage X + public static float BALL_SERVE_MAX_ANGLE; // in radians + public static float BALL_BOUNCE_MAX_ANGLE; // in radians + public static uint WIN_SCORE; + + // A single hotkey (likely M) will mute the sounds + public static bool MUTE_SOUNDS = false; // when turned on, audio won't be played + } + /// + /// vectors used to update the player's and ball's position? + /// + public static class GameHelpers { + public static Vector2 ToVector2(Vector3 vector) { + return new Vector2(vector.x, vector.y); + } + + public static Vector3 ToLocal(Vector2 viewportVec) { + Vector3 bgScale2f = ToVector2(GameCache.BG_TRANSFORM.localScale); + + Vector2 localVec2f = viewportVec * bgScale2f; + Vector3 localVec = new Vector3(localVec2f.x, localVec2f.y, 0f); + + return localVec; + } + + public static Vector2 ToViewport(Vector3 localVec) { + Vector2 localVec2f = ToVector2(localVec); + Vector2 bgScale2f = ToVector2(GameCache.BG_TRANSFORM.localScale); + + Vector2 viewportVec = localVec2f / bgScale2f; + + return viewportVec; + } + } + + public partial class GameManager : MonoBehaviour {} + + //public partial class GameContext {} +} \ No newline at end of file