Brandons-MassiveLoop-CSharp-Scripts / DodgeballScript.cs
DodgeballScript.cs
Raw
using ML.SDK;
using UnityEngine;

public class DodgeballScript : MonoBehaviour
{
    [SerializeField] private MLGrab grabComponent;
    [SerializeField] private Rigidbody ballRigidbody;
    private MLPlayer currentUser;

    // Size limits for size change (relative change)
    [SerializeField] private float minSize = 0.5f; // Minimum scale factor
    [SerializeField] private float maxSize = 2.0f; // Maximum scale factor

    // Absolute size limits for local scale
    [SerializeField] private float absoluteMinSize = 0.3f;
    [SerializeField] private float absoluteMaxSize = 3.0f;

    [SerializeField] private float throwForceMultiplier = 10.0f; // Multiplier for throw force
    [SerializeField] private float maxThrowForce = 100.0f; // Cap for throw force magnitude

    [SerializeField] private Material BlueTeamMaterial; // Change to this material whenever a blue player is holding the ball
    [SerializeField] private Material RedTeamMaterial; // Change to this material whenever a blue player is holding the ball
    [SerializeField] private Material ResetMaterial; // Change to this material whenever The game gets reset
    [SerializeField] private GameObject HitEffect;

    [SerializeField] private GameObject DodgeBallGameManagerObjectReference;

    //  [SerializeField] private TrailRenderer LineRenderer; //Change this color to whichever team is holding it.


    private Vector3 initialScale;
    private float initialDistance;
    private bool isSizeChangeEnabled = false;
    private bool isHeld = false;

    [SerializeField] private GameObject objectToChange;
    private Rigidbody objectRigidbody;
    private Vector3 lastPosition;

    const string EVENT_ID_Throw = "ThrowEvent";
    private EventToken tokenThrow;
    public MLPlayer player;

    const string EVENT_HIT = "HitEvent";
    private EventToken tokenHit;

    const string EVENT_CHANGE_COLOR = "ChangeColor";
    private EventToken tokenChange;

    private DodgeBallGameManager DodgeBallGameManagerSCRIPTReference;

    private bool isThrown = false; // Flag to indicate if the object is thrown
    private Vector3 throwForce = Vector3.zero; // Store the calculated throw force

    private void Start()
    {
        // Setup event listeners
        grabComponent.OnPrimaryGrabBegin.AddListener(OnPrimaryGrabBegin);
        grabComponent.OnPrimaryGrabEnd.AddListener(OnPrimaryGrabEnd);
        grabComponent.OnSecondaryGrabBegin.AddListener(OnSecondaryGrabBegin);
        grabComponent.OnSecondaryGrabEnd.AddListener(OnSecondaryGrabEnd);
        grabComponent.OnPrimaryTriggerDown.AddListener(OnPrimaryTriggerDown);

        tokenThrow = this.AddEventHandler(EVENT_ID_Throw, OnThrowEvent);
        tokenHit = this.AddEventHandler(EVENT_HIT, OnHitEvent);
        tokenChange = this.AddEventHandler(EVENT_CHANGE_COLOR, OnChangeColor);

        // Ensure Rigidbody is attached
        objectRigidbody = objectToChange.GetComponent<Rigidbody>();
        if (objectRigidbody == null)
        {
            Debug.LogError("No Rigidbody component found on the object!");
        }

        DodgeBallGameManagerSCRIPTReference = (DodgeBallGameManager)DodgeBallGameManagerObjectReference.GetComponent(typeof(DodgeBallGameManager));


    }

    private void Update()
    {
        /*
        // Handle ball reset during game state changes
        if (DodgeBallGameManagerSCRIPTReference.isGameActive == false)
        {
            DodgeBallGameManagerSCRIPTReference.OnResetBallPosition();
            grabComponent.ForceRelease();
            ballRigidbody.isKinematic = true;
        }
        else if (DodgeBallGameManagerSCRIPTReference.isGameActive == true)
        {
            ballRigidbody.isKinematic = false;
        }
        */
    }

    private void OnChangeColor(object[] args)
    {
        if (this == null || gameObject == null || gameObject.name == null || args[0] == null)
        {
            return;
        }

        if ((string)args[1] == "Blue")
        {
            MeshRenderer meshRenderReference = (MeshRenderer)this.gameObject.GetComponent(typeof(MeshRenderer));
            meshRenderReference.material = BlueTeamMaterial;

        }
        else if ((string)args[1] == "Red")
        {
            MeshRenderer meshRenderReference = (MeshRenderer)this.gameObject.GetComponent(typeof(MeshRenderer));
            meshRenderReference.material = RedTeamMaterial;
        }

    }

    private void FixedUpdate()
    {
        // Handle size change during secondary grab
        if (isSizeChangeEnabled && grabComponent.PrimaryHand && grabComponent.SecondaryHand)
        {
            AdjustSizeBasedOnGrab();
        }

        // Apply throw force if the object has been thrown
        if (isThrown)
        {
            // Immediately reset the flag to prevent multiple applications
            isThrown = false;

            // Calculate the release direction based on the hand's orientation
            Vector3 releaseDirection = transform.forward;

            // Scale the release force
            throwForce = releaseDirection * throwForceMultiplier;

            // Clamp the force to a maximum value
            if (throwForce.magnitude > maxThrowForce)
            {
                throwForce = throwForce.normalized * maxThrowForce;
            }

            // Apply the impulse force to the Rigidbody
            objectRigidbody.isKinematic = false; // Ensure the Rigidbody is dynamic
            objectRigidbody.AddForce(throwForce, ForceMode.Impulse);

            // Debug information for validation
            Debug.Log($"Object thrown with impulse force: {throwForce}");

            // Reset throwForce to avoid unintended force in the next frame
            throwForce = Vector3.zero;
        }
    }



    private void OnPrimaryTriggerDown()
    {
        grabComponent.ForceRelease();
        // this.InvokeNetwork(EVENT_ID_Throw, EventTarget.Master, null);
    }
    private void OnPrimaryGrabBegin()
    {
        if (grabComponent.CurrentUser != null)
        {
            //    player = grabComponent.CurrentUser;
            isHeld = true;
            currentUser = grabComponent.CurrentUser;
            lastPosition = grabComponent.PrimaryHand.transform.position;

            if (grabComponent.GrabMechanic == SDKGrabMechanicsBehaviorV2.Custom)
            {
                objectToChange.transform.parent = grabComponent.PrimaryHand.transform;
            }

            if ((string)currentUser.GetProperty("team") == "Blue")
            {
                MeshRenderer meshRenderReference = (MeshRenderer)this.gameObject.GetComponent(typeof(MeshRenderer));
                meshRenderReference.material = BlueTeamMaterial;
                this.InvokeNetwork(EVENT_CHANGE_COLOR, EventTarget.All, null,  this.gameObject.GetInstanceID(), "Blue");
           //     LineRenderer.startColor = Color.blue;

            }else if ((string) currentUser.GetProperty("team") == "Red")
            {
                MeshRenderer meshRenderReference = (MeshRenderer)this.gameObject.GetComponent(typeof(MeshRenderer));
                meshRenderReference.material = RedTeamMaterial;
                this.InvokeNetwork(EVENT_CHANGE_COLOR, EventTarget.All, null, this.gameObject.GetInstanceID(), "Red");
                //    LineRenderer.startColor = Color.red;

            }
        }
    }

    private void OnPrimaryGrabEnd()
    {
        // Unparent the object if using custom grab mechanics
        if (grabComponent.GrabMechanic == SDKGrabMechanicsBehaviorV2.Custom)
        {
            transform.parent = null;
        }

        if (isHeld && objectRigidbody != null)
        {
            /*
            // Calculate the release direction based on the hand's orientation
            Vector3 releaseDirection = grabComponent.PrimaryHand.transform.forward;

            // Scale the release force
            throwForce = releaseDirection * throwForceMultiplier;

            // Clamp the force to a maximum value
            if (throwForce.magnitude > maxThrowForce)
            {
                throwForce = throwForce.normalized * maxThrowForce;
            }

            */
            // Trigger physics update in FixedUpdate
            isThrown = true;

            // Optionally invoke a network event
            this.InvokeNetwork(EVENT_ID_Throw, EventTarget.All, null, this.gameObject.GetInstanceID());
        }

        isHeld = false; // Reset the held flag
    }

    private void OnSecondaryGrabBegin()
    {
        if (grabComponent.PrimaryHand && grabComponent.SecondaryHand)
        {
            isSizeChangeEnabled = true;
            initialDistance = Vector3.Distance(
                grabComponent.PrimaryHand.transform.position,
                grabComponent.SecondaryHand.transform.position
            );
            initialScale = objectToChange.transform.localScale;
        }
    }

    private void OnSecondaryGrabEnd()
    {
        isSizeChangeEnabled = false;
    }

    private void AdjustSizeBasedOnGrab()
    {
        // Calculate current distance between hands
        float currentDistance = Vector3.Distance(
            grabComponent.PrimaryHand.transform.position,
            grabComponent.SecondaryHand.transform.position
        );

        // Calculate scale factor and new scale
        float scaleFactor = Mathf.Clamp(currentDistance / initialDistance, minSize, maxSize);
        Vector3 newScale = initialScale * scaleFactor;

        // Clamp to absolute scale limits
        newScale.x = Mathf.Clamp(newScale.x, absoluteMinSize, absoluteMaxSize);
        newScale.y = Mathf.Clamp(newScale.y, absoluteMinSize, absoluteMaxSize);
        newScale.z = Mathf.Clamp(newScale.z, absoluteMinSize, absoluteMaxSize);

        objectToChange.transform.localScale = newScale;
    }

    private void OnThrowEvent(object[] args)
    {
        //   Debug.Log($"Throw event triggered. Passed in force amount : {(Vector3)args[0]}");


        isThrown = true;

        // Apply throw force if the object has been thrown
        if (isThrown)
        {
            // Immediately reset the flag to prevent multiple applications
            isThrown = false;

            // Calculate the release direction based on the hand's orientation
            Vector3 releaseDirection = transform.forward;

            // Scale the release force
            throwForce = releaseDirection * throwForceMultiplier;

            // Clamp the force to a maximum value
            if (throwForce.magnitude > maxThrowForce)
            {
                throwForce = throwForce.normalized * maxThrowForce;
            }

            // Apply the impulse force to the Rigidbody
            objectRigidbody.isKinematic = false; // Ensure the Rigidbody is dynamic
            objectRigidbody.AddForce(throwForce, ForceMode.Impulse);

            // Debug information for validation
            Debug.Log($"Object thrown with impulse force: {throwForce}");

            // Reset throwForce to avoid unintended force in the next frame
            throwForce = Vector3.zero;
        }

        /*
        // Calculate the release direction based on the hand's orientation
        Vector3 releaseDirection = this.gameObject.transform.forward;

        // Scale the release force
        Vector3 throwForce = releaseDirection * throwForceMultiplier;

        // Clamp the force to a maximum value
        if (throwForce.magnitude > maxThrowForce)
        {
            throwForce = throwForce.normalized * maxThrowForce;
        }


        if (MassiveLoopClient.IsMasterClient)
        {
        //    this.gameObject.RequestOwnership();
            objectRigidbody.AddForce(throwForce, ForceMode.Impulse);
        }
        */


    }

    private void OnHitEvent(object[] args) {

        int throwingPlayer = (int)args[0];
        int hitPlayer = (int)args[1];

        Object.Instantiate(HitEffect, this.gameObject.transform.position, Quaternion.identity);

        MLPlayer hitplyerMLReference = MassiveLoopRoom.FindPlayerByActorNumber(hitPlayer);

        DodgeBallGameManagerSCRIPTReference.OnPlayerHit(hitplyerMLReference);

       // Debug.Log($"Player : {throwingPlayer} hit player : {hitPlayer} with a dodgeball ");
    
    }


    private void OnGrabBegin()
    {
        currentUser = grabComponent.CurrentUser;
    }

    private void OnGrabEnd()
    {
        currentUser = null; // Reset current user when the ball is released
    }

    private void OnCollisionEnter(Collision collision)
    {
        // Check if the ball collides with a player
        MLPlayer hitPlayer = (MLPlayer)collision.gameObject.GetPlayer();

        if (hitPlayer != null && currentUser != null)
        {
            Debug.Log($"Player found : {hitPlayer.NickName}");
            // Ensure the hit player is not the current user
            if (hitPlayer != currentUser)
            {
                // Check team property
                string currentUserTeam = (string)currentUser.GetProperty("team");
                string hitPlayerTeam = (string)hitPlayer.GetProperty("team");

                if (currentUser != null && hitPlayer != null && hitPlayerTeam != currentUserTeam)
                {
                    Debug.Log("Local hit detected from ball thrower attempting to call network function");
                    this.InvokeNetwork(EVENT_HIT, EventTarget.All, null, currentUser.ActorId, hitPlayer.ActorId);

                    currentUserTeam = "Empty";
                    hitPlayerTeam = "none";
                }


                if (hitPlayerTeam != currentUserTeam)
                {
                   // Debug.Log($"Player from team {hitPlayerTeam} was hit by team {currentUserTeam}!");

                    // Handle game logic for a valid hit
                    OnPlayerHit(hitPlayer);
                    currentUser = null;
                }
                else
                {
                    //Debug.Log("Hit player is on the same team. No action taken.");
                }
            }
        }
    }

    /*private void OnTriggerEnter(Collider collision)
    {
        // Check if the ball collides with a player
        MLPlayer hitPlayer = (MLPlayer)collision.gameObject.GetPlayer();

        if (hitPlayer != null && currentUser != null)
        {
            Debug.Log($"Player found : {hitPlayer.NickName}");
            // Ensure the hit player is not the current user
            if (hitPlayer != currentUser)
            {
                // Check team property
                string currentUserTeam = (string)currentUser.GetProperty("team");
                string hitPlayerTeam = (string)hitPlayer.GetProperty("team");

                if (hitPlayerTeam != currentUserTeam)
                {
                    Debug.Log($"Player from team {hitPlayerTeam} was hit by team {currentUserTeam}!");

                    // Handle game logic for a valid hit
                    OnPlayerHit(hitPlayer);
                    currentUser = null;
                }
                else
                {
                    Debug.Log("Hit player is on the same team. No action taken.");
                }
            }
        }
    }
    */

    private void OnPlayerHit(MLPlayer hitPlayer)
    {
        // Logic for when a player is hit
       // Debug.Log($"Player {hitPlayer.NickName} has been hit!");
        this.InvokeNetwork(EVENT_HIT, EventTarget.All, null, currentUser.ActorId, hitPlayer.ActorId);
        // Example: Disable player temporarily
        //  hitPlayer.gameObject.SetActive(false);

        // Optionally, add more game-specific logic here (e.g., scoring, respawn mechanics)
    }
}