aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Assets/Scripts/Controllers/AIController.cs
blob: 72460231ddb5cad88242d0544c9962c46de4b277 (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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
using System;
using Controllers.Player;
using UnityEngine;
using Random = UnityEngine.Random;

namespace Controllers
{
  [RequireComponent(typeof(Rigidbody2D))]
  [RequireComponent(typeof(BoxCollider2D))]
  [RequireComponent(typeof(Animator))]
  public class AIController : MonoBehaviour
  {
    [SerializeField] private float speed;

    [SerializeField] private Transform flipper;
    
    [Header("Legs")]
    [SerializeField] private Leg leftLeg;
    [SerializeField] private Leg rightLeg;
    [SerializeField] private float maxLegAngle;
    [SerializeField] private float legSpeed;
    
    [Header("Arsm")]
    [SerializeField] private GameObject leftArm;
    [SerializeField] private GameObject rightArm;

    [Header("References")]
    [SerializeField] private GameController game;
    [SerializeField] private PlayerController player;

    public Rigidbody2D Rigidbody => _rigidbody != null ? _rigidbody : _rigidbody = GetComponent<Rigidbody2D>();
    private Rigidbody2D _rigidbody;

    private bool turn;
    
    public BoxCollider2D BoxCollider => _boxCollider != null ? _boxCollider : _boxCollider = GetComponent<BoxCollider2D>();
    private BoxCollider2D _boxCollider;
    
    public Animator Animator => _animator != null ? _animator : _animator = GetComponent<Animator>();
    private Animator _animator;

    private void Start()
    {
      // Try to grab (steal) the ball every n seconds.
      InvokeRepeating(nameof(GrabBall), 0, 0.5f);
      InvokeRepeating(nameof(ShootBall), 0, 2f);
    }

    private void GrabBall()
    {
      // Grab from the middle, and the bottom.
      if (!game.player.HasBall || Random.Range(0, 100) > 70) // 30% chance of them grabbing the ball from the player.
      {
        game.enemy.GrabBall(transform.position);
        game.enemy.GrabBall(transform.position + new Vector3(0f, BoxCollider.size.y / 2, 0f));
      }
    }

    private void ShootBall()
    {
      if (!game.enemy.HasBall) return;
      var hoopDistance = Mathf.Abs(transform.position.x - game.EnemyHoop.transform.position.x);
      var playerHoopDistance = Mathf.Abs(player.root.transform.position.x - game.EnemyHoop.transform.position.x);
      if (hoopDistance < 10.5f && hoopDistance > 2.5f && (Random.Range(0, 100) > 30 || playerHoopDistance > hoopDistance)) // Take the shot when in range. 70% chance he decides to if the player is standing between him and the basket.
      {
        game.enemy.Shoot(transform, Random.Range(0.5f, 1f));
      }
    }

    private Vector3 lastPosition;
    private static readonly int Running = Animator.StringToHash("Running");
    private void FixedUpdate()
    {
      Animator.SetBool(Running, (lastPosition - transform.position).x > 0.025);
      
      lastPosition = transform.position;
    }

    private void Update()
    {
      if (game.freezeMotion) return;
      
      var movement = transform.position;
      
      if (!game.enemy.HasBall) // Move towards the ball to grab it.
      {
        if (Vector2.Distance(player.root.transform.position, transform.position) < 0.8f) // Repel from the player if they get too close.
        {
          // transform.position += new Vector3(-(player.transform.position - transform.position).normalized.x, 0, 0) * (Time.deltaTime * speed / 2f);
          transform.position = new Vector2(Vector2.MoveTowards(transform.position, player.root.transform.position, -1.5f * speed * Time.deltaTime).x, transform.position.y);
        }
        else
        {
          // transform.position += new Vector3(game.ball.transform.position.x - transform.position.x, 0f, 0f).normalized * (Time.deltaTime * speed);
          var direction = Vector2.MoveTowards(transform.position, game.ball.transform.position, speed * Time.deltaTime);
          transform.position = new Vector2(direction.x, transform.position.y);
        }
      }
      else // Otherwise, move toward the basket, and then once we get within range, take the shot.
      {
        // How far the enemy tries to get from the hoop before shooting.
        // Currently, it will try to shoot a 3pt. shot if down, but a 2pt. shot if up or tied.
        var targetDistance = game.enemy.score < game.player.score ? 10f : 4f;
        transform.position = new Vector2(Vector2.MoveTowards(transform.position, game.EnemyHoop.transform.position + new Vector3(targetDistance, 0, 0), speed * Time.deltaTime).x, transform.position.y);
      }

      movement -= transform.position;

      bool currentTurn = movement.x > 0;
      if (turn && currentTurn)
        flipper.transform.localScale = new Vector3(1f, 1f, 1f);
      else
        flipper.transform.localScale = new Vector3(-1f, 1f, 1f);

      game.enemy.Move(transform.position + new Vector3(0f, BoxCollider.size.y * 3/4, 0f) + (transform.right * (0.5f * (turn && currentTurn ? -1 : 1))));
      turn = currentTurn;
      
      // Point the arms at the ball.
      leftArm.transform.up = -(game.ball.transform.position - leftArm.transform.position);
      rightArm.transform.up = -(game.ball.transform.position - rightArm.transform.position);
    }

    [Serializable]
    private struct Leg
    {
      public GameObject top;
      public GameObject bottom;
    }
  }
}