using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Unity.Netcode; using Unity.VisualScripting; using UnityEngine; using UnityEngine.Assertions; using Object = UnityEngine.Object; using Random = UnityEngine.Random; namespace Game { public class GameManager : NetworkBehaviour { public static GameManager Singleton { get; private set; } private void OnEnable() { Singleton = this; // Move this to settings Application.targetFrameRate = 144; QualitySettings.vSyncCount = 0; } public Object ballPrefab; public Object playerPrefab; public Object modificationPrefab; public ModificationProperties[] modifications; public List Balls { get; } = new(); public Player Player1 { get; private set; } public Player Player2 { get; private set; } private void Awake() { Settings.Type = Type.Hybrid; Settings.AIDifficulty = Difficulty.Hard; var p1Obj = Instantiate(playerPrefab); var p2Obj = Instantiate(playerPrefab); Player p1, p2; switch (Settings.Type) { case Type.AI: p1 = p1Obj.AddComponent(); p2 = p2Obj.AddComponent(); ((AIPlayer) p1).Difficulty = Settings.AIDifficulty; ((AIPlayer) p2).Difficulty = Settings.AIDifficulty; break; case Type.RealOnline: p1 = p1Obj.AddComponent(); p2 = p2Obj.AddComponent(); ((RealPlayer) p1).isThisClient = true; break; case Type.Hybrid: p1 = p1Obj.AddComponent(); p2 = p2Obj.AddComponent(); ((RealPlayer) p1).isThisClient = true; ((AIPlayer) p2).Difficulty = Settings.AIDifficulty; break; default: throw new ArgumentOutOfRangeException(); } p1.Side = Side.Bottom; p2.Side = Side.Top; Player1 = p1; Player2 = p2; SpawnBall(Player1, true); } private IEnumerator Start() { while (Application.isPlaying) { yield return new WaitForSeconds(1); SpawnModification(); } } private void SpawnModification() { Vector2 pos = new Vector2(Random.Range(Dimensions.Singleton.left, Dimensions.Singleton.right), Random.Range(-2, 2)); ModificationProperties properties = modifications[Random.Range(0, modifications.Length)]; var mod = Instantiate(modificationPrefab, pos, Quaternion.identity).GetComponent(); mod.Properties = properties; } public void SpawnBall(Player towards, bool isPermanent) { const float startSpeed = 15; Vector2 position = new Vector2(0, -towards.transform.position.y * 0.5f); var ball = Instantiate(ballPrefab, position, Quaternion.identity).GetComponent(); ball.Rb.velocity = RandomDirectionTowards(towards) * startSpeed; ball.IsPermanent = isPermanent; ball.Radius = 0.5f; Balls.Add(ball); } private static Vector2 RandomDirectionTowards(Player player) { const float maxAngle = 45; float radians = Random.Range(-maxAngle, maxAngle) * Mathf.PI / 180; float x = Mathf.Sin(radians); float y = Mathf.Cos(radians) * player.Side switch { Side.Top => 1, Side.Bottom => -1, _ => throw new ArgumentOutOfRangeException() }; return new Vector2(x, y); } public void RemoveBall(Ball ball) { Balls.Remove(ball); Destroy(ball.gameObject); } } }