]> git.cameronkatri.com Git - gmtk-gamejam.git/blob - Assets/Scripts/Controllers/GameController.cs
Add game clock
[gmtk-gamejam.git] / Assets / Scripts / Controllers / GameController.cs
1 using System;
2 using UnityEngine;
3 using UnityEngine.UI;
4
5 namespace Controllers
6 {
7 /// <summary>
8 /// The controller for the basketball-game logic.
9 /// </summary>
10 public class GameController : MonoBehaviour
11 {
12 private State state = State.JumpBall; // A basketball game always starts with a jump ball.
13 internal Animator BallAnimation;
14
15 public Player player;
16 public Player enemy;
17
18 private float startTime;
19 [SerializeField] private float timeLimit;
20
21 /// <summary>
22 /// The single ball for the game.
23 /// </summary>
24 [SerializeField] public Ball ball;
25
26 [Header("Hoops")]
27 [SerializeField] public Hoop PlayerHoop;
28 [SerializeField] public Hoop EnemyHoop;
29
30 [Header("SFX")]
31 [SerializeField] public AudioSource dribbleSound;
32
33 [Header("UI")]
34 [SerializeField] private Text playerScoreText;
35 [SerializeField] private Text enemyScoreText;
36 [SerializeField] private Text timerText;
37
38 private void Awake()
39 {
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>();
46 }
47
48 private void Start()
49 {
50 startTime = Time.time;
51 }
52
53 private void Update()
54 {
55 UpdateUI();
56 }
57
58 private void UpdateUI()
59 {
60 playerScoreText.text = $"{player.score}";
61 enemyScoreText.text = $"{enemy.score}";
62
63 var remaining = TimeSpan.FromSeconds(timeLimit - (Time.time - startTime));
64 timerText.text = string.Format("{0:00}:{1:00}", remaining.Minutes, remaining.Seconds);
65 }
66
67 public struct Player
68 {
69 /// <summary>
70 /// Whether this player is the AI-enemy.
71 /// </summary>
72 internal bool isEnemy;
73
74 /// <summary>
75 /// A back-reference to the containing GameController.
76 /// </summary>
77 internal GameController controller;
78
79 internal int score;
80
81 private Vector2 lastShotPosition;
82 public void Score(Vector2 Rim)
83 {
84 if (Vector2.Distance(lastShotPosition, Rim) >= 10)
85 {
86 score += 3;
87 }
88 else
89 {
90 score += 2;
91 }
92 }
93
94 private State dribble => isEnemy ? State.EnemyDribble : State.PlayerDribble;
95 private State shoot => isEnemy ? State.EnemyShoot : State.PlayerShoot;
96
97 private Hoop hoop => isEnemy ? controller.EnemyHoop : controller.PlayerHoop;
98
99 public bool HasBall => controller.state == dribble;
100
101 /// <summary>
102 /// When dribbling, move the ball with the player.
103 /// </summary>
104 /// <param name="handPosition">The position of the hand dribbling the ball.</param>
105 public void Move(Vector2 handPosition)
106 {
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.
109 }
110
111 /// <summary>
112 /// Grab the ball if possible given the current game state.
113 /// </summary>
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)
117 {
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;
120
121 // Make sure its within their grab area.
122 if (Vector2.Distance(controller.ball.transform.position, handPosition) >= 1f) return false;
123
124 controller.state = dribble;
125 controller.BallAnimation.enabled = false;
126 controller.dribbleSound.Play();
127 Move(handPosition);
128
129 controller.ball.Rigidbody.bodyType = RigidbodyType2D.Kinematic;
130
131 return true;
132 }
133
134 /// <summary>
135 /// Shoot the ball if possible.
136 /// </summary>
137 /// <param name="playerTransform"></param>
138 /// <returns>Whether or not the ball was shot</returns>
139 public bool Shoot(Transform playerTransform)
140 {
141 if (controller.state != dribble) return false; // We must be dribbling the ball to shoot it.
142 controller.BallAnimation.enabled = true;
143 controller.dribbleSound.Stop();
144 controller.state = shoot;
145 controller.ball.Rigidbody.bodyType = RigidbodyType2D.Dynamic;
146 controller.ball.Shoot(hoop.transform.position);
147 lastShotPosition = playerTransform.position;
148 return true;
149 }
150 }
151
152 internal void BallDropped()
153 {
154 BallAnimation.enabled = true;
155 dribbleSound.Stop();
156 ball.Rigidbody.bodyType = RigidbodyType2D.Dynamic;
157 state = State.Idle;
158 }
159
160 internal enum State
161 {
162 Idle,
163 JumpBall,
164 PlayerDribble,
165 PlayerShoot,
166 EnemyDribble,
167 EnemyShoot,
168 }
169 }
170
171 internal static class GameControllerStateExtensions
172 {
173 internal static bool IsShot(this GameController.State state)
174 {
175 return state == GameController.State.EnemyShoot || state == GameController.State.PlayerShoot;
176 }
177
178 internal static bool IsDribble(this GameController.State state)
179 {
180 return state == GameController.State.EnemyDribble || state == GameController.State.PlayerDribble;
181 }
182 }
183 }