8 /// The controller for the basketball-game logic.
10 public class GameController : MonoBehaviour
12 private State state = State.JumpBall; // A basketball game always starts with a jump ball.
13 internal Animator BallAnimation;
18 private float startTime;
19 [SerializeField] private float timeLimit;
22 /// The single ball for the game.
24 [SerializeField] public Ball ball;
27 [SerializeField] public Hoop PlayerHoop;
28 [SerializeField] public Hoop EnemyHoop;
31 [SerializeField] public AudioSource dribbleSound;
34 [SerializeField] private Text playerScoreText;
35 [SerializeField] private Text enemyScoreText;
36 [SerializeField] private Text timerText;
40 player = new Player { isEnemy = false, controller = this };
41 enemy = new Player { isEnemy = true, controller = this };
42 ball.controller = this;
43 PlayerHoop.controller = this;
44 EnemyHoop.controller = this;
45 BallAnimation = ball.GetComponentInChildren<Animator>();
50 startTime = Time.time;
58 private void UpdateUI()
60 playerScoreText.text = $"{player.score}";
61 enemyScoreText.text = $"{enemy.score}";
63 var remaining = TimeSpan.FromSeconds(timeLimit - (Time.time - startTime));
64 timerText.text = $"{remaining.Minutes:00}:{remaining.Seconds:00}";
70 /// Whether this player is the AI-enemy.
72 internal bool isEnemy;
75 /// A back-reference to the containing GameController.
77 internal GameController controller;
81 private Vector2 lastShotPosition;
82 public void Score(Vector2 Rim)
84 if (Vector2.Distance(lastShotPosition, Rim) >= 10)
94 private State dribble => isEnemy ? State.EnemyDribble : State.PlayerDribble;
95 private State shoot => isEnemy ? State.EnemyShoot : State.PlayerShoot;
97 private Hoop hoop => isEnemy ? controller.EnemyHoop : controller.PlayerHoop;
99 public bool HasBall => controller.state == dribble;
102 /// When dribbling, move the ball with the player.
104 /// <param name="handPosition">The position of the hand dribbling the ball.</param>
105 public void Move(Vector2 handPosition)
107 if (controller.state == (isEnemy ? State.EnemyDribble : State.PlayerDribble)) // Make sure they're dribbling.
108 controller.ball.transform.position = handPosition; // TODO: Make this perform a dribbling motion, otherwise it looks like they're travelling.
112 /// Grab the ball if possible given the current game state.
114 /// <param name="handPosition">The position of the hand to attempt grabbing from.</param>
115 /// <returns>Whether or not the ball was able to be picked up.</returns>
116 public bool GrabBall(Vector2 handPosition)
118 // Don't allow the ball to be picked up if someone shot it. Also don't try picking it up if we're already holding it.
119 if (controller.state == shoot || controller.state == dribble) return false;
121 // Make sure its within their grab area.
122 if (Vector2.Distance(controller.ball.transform.position, handPosition) >= 1f) return false;
124 controller.state = dribble;
125 controller.BallAnimation.enabled = false;
126 controller.dribbleSound.Play();
129 controller.ball.Rigidbody.bodyType = RigidbodyType2D.Kinematic;
135 /// Shoot the ball if possible.
137 /// <param name="playerTransform"></param>
138 /// <param name="time"></param>
139 /// <returns>Whether or not the ball was shot</returns>
140 public bool Shoot(Transform playerTransform, float time)
142 if (controller.state != dribble) return false; // We must be dribbling the ball to shoot it.
143 controller.BallAnimation.enabled = true;
144 controller.dribbleSound.Stop();
145 controller.state = shoot;
146 controller.ball.Rigidbody.bodyType = RigidbodyType2D.Dynamic;
147 controller.ball.Shoot(hoop, time);
148 lastShotPosition = playerTransform.position;
153 internal void BallDropped()
155 BallAnimation.enabled = true;
157 ball.Rigidbody.bodyType = RigidbodyType2D.Dynamic;
172 internal static class GameControllerStateExtensions
174 internal static bool IsShot(this GameController.State state)
176 return state == GameController.State.EnemyShoot || state == GameController.State.PlayerShoot;
179 internal static bool IsDribble(this GameController.State state)
181 return state == GameController.State.EnemyDribble || state == GameController.State.PlayerDribble;