Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions GameManager.cs
Original file line number Diff line number Diff line change
@@ -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

/// <summary>
/// for debugging purposes?
/// </summary>
void Awake()
{
// Hello World message
Debug.Log("Hello World!");

//Debug.Log(GameConstants.RIGHT_PADDLE_START_POSITION);
//Debug.Log(GameConstants.LEFT_PADDLE_START_POSITION);
}

/// <summary>
/// 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
/// </summary>
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
/// <summary>
/// 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
/// </summary>
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
}

/// <summary>
/// display the score board
/// </summary>
/// <returns>
/// return as string that contains both players score so it can be displayed
/// </returns>
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;
}
}
}
}
143 changes: 143 additions & 0 deletions Player.cs
Original file line number Diff line number Diff line change
@@ -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<PlayerController> playerSprite;
private readonly Scoreboard scoreboard;

// For physics
private readonly ForceMap forceMap;

private Player opponent;

// load from data
/// <summary>
/// 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
/// </summary>
/// <param name="playerData"></param>
/// <param name="sprite"></param>
/// <param name="controls"></param>
/// <param name="scoreboard"></param>
public Player(PlayerData playerData, GameObject sprite, PlayerControls controls, Scoreboard scoreboard) {
this.playerData = playerData;
this.scoreboard = scoreboard;

// add + initialize controller
PlayerController controller = sprite.AddComponent<PlayerController>();
controller.InitializeControls(controls);

// collision detection
RectangularBodyFrame bodyFrame = sprite.AddComponent<RectangularBodyFrame>();

// collision forces
forceMap = new ForceMap(sprite.transform);

// wrap it up
playerSprite = new ControlledGameObject<PlayerController>(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>();
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; }
}

/// <summary>
/// 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
/// </summary>
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(...);
}

/// <summary>
/// update the player's score when they socre a goal
/// </summary>
public void ScorePoint() {
// Game: score point
scoreboard.ScorePoint();

// onScore
//TODO ...
//? update RL agent?
}

public Rebounder AsRebounder() {
return new Rebounder(forceMap, playerSprite.gameObj.GetComponent<RectangularBodyFrame>());
}

/// <summary>
/// set the paddles dimensions base off percentages of the viewport
/// </summary>
/// <param name="vpXThickness"></param>
/// <param name="vpYLength"></param>
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);
}
}
}
Loading