aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Assets/Scripts/Controllers/GameController.cs
blob: c326c4ef78540c9fb233826fe60e1ae22448e5fc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
using System;
using UnityEngine;

namespace Controllers
{
  /// <summary>
  /// The controller for the basketball-game logic.
  /// </summary>
  public class GameController : MonoBehaviour
  {
    private State state = State.JumpBall; // A basketball game always starts with a jump ball.

    public Player player;
    public Player enemy;
    
    /// <summary>
    /// The single ball for the game.
    /// </summary>
    [SerializeField] public Ball ball;

    private void Awake()
    {
      player = new Player { isEnemy = false, controller = this };
      enemy = new Player { isEnemy = true, controller = this };
      ball.controller = this;
    }
    
    public struct Player
    {
      /// <summary>
      /// Whether this player is the AI-enemy.
      /// </summary>
      internal bool isEnemy;
      
      /// <summary>
      /// A back-reference to the containing GameController.
      /// </summary>
      internal GameController controller;
      
      private State dribble => isEnemy ? State.EnemyDribble : State.PlayerDribble;
      private State shoot => isEnemy ? State.EnemyShoot : State.PlayerShoot;

      /// <summary>
      /// When dribbling, move the ball with the player.
      /// </summary>
      /// <param name="handPosition">The position of the hand dribbling the ball.</param>
      public void Move(Vector2 handPosition)
      {
        if (controller.state == (isEnemy ? State.EnemyDribble : State.PlayerDribble)) // Make sure they're dribbling.
          controller.ball.transform.position = handPosition; // TODO: Make this perform a dribbling motion, otherwise it looks like they're travelling.
      }

      /// <summary>
      /// Grab the ball if possible given the current game state.
      /// </summary>
      /// <param name="handPosition">The position of the hand to attempt grabbing from.</param>
      /// <returns>Whether or not the ball was able to be picked up.</returns>
      public bool GrabBall(Vector2 handPosition)
      { 
        // 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.
        if (controller.state.IsShot() || controller.state == dribble) return false;
        
        // Make sure its within their grab area.
        if (Vector2.Distance(controller.ball.transform.position, handPosition) > 0.75f) return false;
        
        controller.state = dribble;
        Move(handPosition);
        return true;
      }

      /// <summary>
      /// Shoot the ball if possible.
      /// </summary>
      /// <param name="playerTransform"></param>
      /// <returns>Whether or not the ball was shot</returns>
      public bool Shoot(Transform playerTransform)
      {
        if (controller.state != dribble) return false; // We must be dribbling the ball to shoot it.
        controller.state = shoot;
        controller.ball.Shoot(playerTransform);
        return true;
      }
    }

    internal void BallDropped()
    {
      state = State.Idle;
    }

    internal enum State
    {
      Idle,
      JumpBall,
      PlayerDribble,
      PlayerShoot,
      EnemyDribble,
      EnemyShoot,
    }
  }

  internal static class GameControllerStateExtensions
  {
    internal static bool IsShot(this GameController.State state)
    {
      return state == GameController.State.EnemyShoot || state == GameController.State.PlayerShoot;
    }
    
    internal static bool IsDribble(this GameController.State state)
    {
      return state == GameController.State.EnemyDribble || state == GameController.State.PlayerDribble;
    }
  }
}