Brandons-MassiveLoop-CSharp-Scripts / Paddle2AI.cs
Paddle2AI.cs
Raw
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Paddle2AI : MonoBehaviour
{
    //TODO: change this user type to a blank gameobject, it's invoking an error
    public GameObject paddle;
    public Transform aiTriggerBox;
    public float aiSpeed = 7.0f;
    public float windUpDistance = 1.0f;
    public float swingSpeedMultiplier = 2.5f;
    public float delayBeforeSwing = 0.1f;
    public float stoppingDistance = 0.05f;
    public float returnSpeedMultiplier = 1.0f;
    public float ballSpeedThreshold = 0.1f; // Threshold to consider the ball as stopped
    public float ballCheckInterval = 1.0f; // Interval to check ball speed
    public Transform ballRespawnPoint; // Position to respawn the ball
    public float hitForce = 10f; // Force applied to the ball when hit
    public float hitRange = 0.5f; // Range within which the ball can be hit
    public Transform table; // The table's transform to aim at
    public float tableHeight = 0.75f; // Height of the table for aiming
   // public LayerMask floorLayer; // Layer for the floor to check collisions

   // private GameObject ball;
    private bool isWindingUp = false;
    private bool isSwinging = false;
    private bool isReturning = false;
    private Vector3 windUpPosition;
    private Vector3 targetPosition;
    private Vector3 originalPosition;
    public GameObject ball;


    /* This script holds the AI that moves the paddle to respond to the ball entering its trigger zone.
     *  It could be made to be more accurate, and the serialized numbers can be tweaked to make it a harder
     *  opponent.
     *  
     *  One of the buttons from the game manager would enable this AI player for the normal human player to play against.
     */

    void Start()
    {
        /*
        if (paddle == null)
        {
            paddle = GetComponent<Paddle2>();
        }*/

        if (aiTriggerBox == null)
        {
            Debug.LogError("AI Trigger Box not assigned.");
        }

        if (ballRespawnPoint == null)
        {
            Debug.LogError("Ball Respawn Point not assigned.");
        }

        originalPosition = paddle.transform.position;

        StartCoroutine(CheckBallSpeed());
    }

    void FixedUpdate()
    {
        if (ball != null)
        {
    

            if (IsBallInTriggerBox() && !isSwinging && !isReturning)
            {
                StartCoroutine(WindUpAndSwing());
            }
        }
    }

    private bool IsBallInTriggerBox()
    {
        if (aiTriggerBox != null && ball != null)
        {
            return aiTriggerBox.GetComponent<Collider>().bounds.Contains(ball.transform.position);
        }
        return false;
    }

    private IEnumerator WindUpAndSwing()
    {
        isWindingUp = true;

        // Calculate the wind-up position
        windUpPosition = paddle.transform.position - (paddle.transform.forward * windUpDistance);
        targetPosition = new Vector3(ball.transform.position.x, ball.transform.position.y, ball.transform.position.z);

        // Move the paddle to the wind-up position
        while (Vector3.Distance(paddle.transform.position, windUpPosition) > stoppingDistance)
        {
            paddle.transform.position = Vector3.MoveTowards(paddle.transform.position, windUpPosition, aiSpeed * Time.deltaTime);
            yield return null;
        }

        isWindingUp = false;

        // Add a delay before swinging
        yield return new WaitForSeconds(delayBeforeSwing);

        // Aim the paddle towards the table
        AimTowardsTable();

        isSwinging = true;

        // Move the paddle to hit the ball
        while (Vector3.Distance(paddle.transform.position, targetPosition) > stoppingDistance)
        {
            paddle.transform.position = Vector3.MoveTowards(paddle.transform.position, targetPosition, aiSpeed * swingSpeedMultiplier * Time.deltaTime);

            // Check if the ball is within hit range and hit it
            if (Vector3.Distance(paddle.transform.position, ball.transform.position) <= hitRange)
            {
                HitBall();
                break;
            }

            yield return null;
        }

        isSwinging = false;

        // Move back to original position
        StartCoroutine(ReturnToOriginalPosition());
    }

    private void AimTowardsTable()
    {
        if (table != null)
        {
            Vector3 tablePosition = new Vector3(table.position.x, tableHeight, table.position.z);
            Vector3 directionToTable = (tablePosition - paddle.transform.position).normalized;
            paddle.transform.rotation = Quaternion.LookRotation(directionToTable);
        }
    }

    private IEnumerator ReturnToOriginalPosition()
    {
        isReturning = true;

        // Move the paddle back to its original position
        while (Vector3.Distance(paddle.transform.position, originalPosition) > stoppingDistance)
        {
            paddle.transform.position = Vector3.MoveTowards(paddle.transform.position, originalPosition, aiSpeed * returnSpeedMultiplier * Time.deltaTime);
            yield return null;
        }

        isReturning = false;
    }

    private void HitBall()
    {
        if (ball != null)
        {
            Rigidbody ballRigidbody = ball.GetComponent<Rigidbody>();
            Vector3 hitDirection = (ball.transform.position - paddle.transform.position).normalized;
            ballRigidbody.AddForce(hitDirection * hitForce, ForceMode.Impulse);
            Debug.Log("Ball hit by paddle.");
        }
    }

    private IEnumerator CheckBallSpeed()
    {
        while (true)
        {
            yield return new WaitForSeconds(ballCheckInterval);

            if (ball != null)
            {
                Rigidbody ballRigidbody = ball.GetComponent<Rigidbody>();

                if (ballRigidbody != null && ballRigidbody.velocity.magnitude < ballSpeedThreshold && IsBallInTriggerBox())
                {
                    RespawnBall();
                }
            }
        }
    }

    private void RespawnBall()
    {
        if (ball != null && ballRespawnPoint != null)
        {
            ball.transform.position = ballRespawnPoint.position;
            ball.GetComponent<Rigidbody>().velocity = Vector3.zero; // Reset the ball's velocity
            Debug.Log("Ball respawned at the given position.");
        }
    }

}