A Better Player Controller

Started by
2 comments, last by AestheticHatter 2 years, 9 months ago

Hello, you wonderful people I'm new here??. I wanted to ask for assistance, right now I am creating a Billy Hatcher/Katamari Damacy clone in unity. I've made strides in development and was able to create a script whenever the player collides with a sphere, to able to roll the sphere. While there are some hiccups, I'm asking if there is any way to make this system better?

Script implementation:

public class AttachToGum : MonoBehaviour
{
    //For Attaching with Gumball
    private GameObject[] gumBalls;
    private Transform playerTransform;
    private Transform player;
    float distacne = Mathf.Infinity;
    public float attachRequireDistance = 4f;
    public GameObject gum;
    public GameObject GumControl;
    GumballMovement mov;


    Rigidbody hitRB;
    Rigidbody forGum;
    public Vector3 offset = new Vector3(0, 1, 0);
    public LayerMask pickupMask;
    bool isAttached = false;

    // Start is called before the first frame update
    void Start()
    {
        gumBalls = GameObject.FindGameObjectsWithTag("GumBall");
        player = GameObject.FindWithTag("Player").transform;
        player.gameObject.layer = LayerMask.NameToLayer("BallDetatch");
        mov = FindObjectOfType<GumballMovement>();
        
    }

    // Update is called once per frame
    void Update()
    {
        TouchingGum();
    }


    private void TouchingGum()
    {
        
        foreach (GameObject gumball in gumBalls)
        {
            RaycastHit hit = new RaycastHit();
            distacne = Vector3.Distance(gumball.transform.position, player.transform.position);
            CharacterController DetectCollisions = gumball.GetComponent<CharacterController>();
            //Debug.Log(gumball);
            if (distacne < attachRequireDistance)
            {
                if (Input.GetButtonDown("Attach"))
                {
                    isAttached = true;
                }
            }
            else
            {
                isAttached = false;
            }

            if (isAttached)
            {
                //DetectCollisions.enabled = true;
                hitRB = gumball.gameObject.GetComponent<Rigidbody>();
                Vector3 heldOffset = (transform.right * offset.x) + (transform.forward * offset.z) + (transform.up * offset.y);
                hitRB.isKinematic = true;
                //gumball.GetComponent<SphereCollider>().enabled = false;
                //player.GetComponent<CharacterController>().center = new Vector3(offset.x, offset.y, offset.z);
                //player.GetComponent<CharacterController>().radius = 3.0f;
                //hit.collider.gameObject.transform.position = GumControl.transform.position;
                //hit.collider.gameObject.transform.position = player.transform.position + heldOffset;
                //player.transform.position = gumball.transform.position + heldOffset;
                hitRB.MovePosition(GumControl.transform.position);
                hitRB.MoveRotation(GumControl.transform.rotation);
                //Vector3 gumVector = GumControl.transform.position - gumball.transform.position;
                //forGum.AddForce(gumVector * 1);

            }
            else if (!isAttached && !hitRB == null)
            {
                hitRB.isKinematic = false;
            }
        }

    }

}

Implementation reference:

(from 2:08-2:22): https://www.youtube.com/watch?v=ncQmmeLz8xI


None

Advertisement

There are some issues of doubtful gravity:

  • Unused objects (e.g. hit, DetectCollisions )
  • Bad names (e.g. distacne, TouchingGum)
  • No broadphase collision detection (but wait until you have a performance problem before dealing with it)
  • Possibility of tunneling because you check collisions between the positions at one specific time per frame rather than continuously (but it might be very unlikely or impossible if objects move slowly enough)

Where do you actually move objects? In commented code?

Omae Wa Mou Shindeiru

@lorenzogatti Hey sorry for the long wait. I sort of figured out a way to improve my code and it's to have the player pick up the sphere to mimic it rolling the sphere. The problem I'm having is whenever the player jumps are is near the ledge the ball keeps moving around. Is there any way I can remedy this, it's been bothering me a lot

For trying to hold the sphere:


public class AttachBall2 : MonoBehaviour
{
   [Header("InteractableInfo")]
   public float sphereCastRadius = 0.5f;
   public int interactableLayerIndex;
   private Vector3 raycastPos;
   public GameObject lookObject;
   private PhysicsObject physicsObject;

   [Header("Pickup")]
   [SerializeField] private Transform pickupParent;
   public GameObject currentlyPickedUpObject;
   private Rigidbody pickupRB;
   ActivatePowerUp toActivate;

   [Header("ObjectFollow")]
   [SerializeField] private float minSpeed = 0;
   [SerializeField] private float maxSpeed = 300f;
   [SerializeField] private float maxDistance = 10f;
   private float currentSpeed = 0f;
   private float currentDist = 0f;
   [SerializeField] public float followSpeed = 20f;
   PlayerBhysics playerSpeed;

   [Header("Rotation")]
   public float rotationSpeed = 100f;
   Quaternion lookRot;

   [Header("Player Speed")]
   public float playerTopSpeed;
   public float playerAccel;
   public float playerSlopeLimit;


   private void Start()
   {
       toActivate = GetComponent<ActivatePowerUp>();
   }
   //A simple visualization of the point we're following in the scene view
   private void OnDrawGizmos()
   {
       Gizmos.color = Color.yellow;
       Gizmos.DrawSphere(pickupParent.position, 0.5f);
   }

   //Interactable Object detections and distance check
   void Update()
   {
       //Here we check if we're currently looking at an interactable object
       RaycastHit hit;
       if (Physics.SphereCast(transform.position, sphereCastRadius, transform.forward, out hit, maxDistance, 1 << interactableLayerIndex))
       {

           lookObject = hit.collider.transform.root.gameObject;
           //Debug.Log(lookObject);

       }
       else
       {
           lookObject = null;

       }



       //if we press the button of choice
       if (Input.GetButtonDown("Attach"))
       {
           //and we're not holding anything
           if (currentlyPickedUpObject == null)
           {
               //and we are looking an interactable object
               if (lookObject != null)
               {
                   Debug.Log("Picked up");
                   PickUpObject();
                   toActivate.hasGumball = true;
               }

           }
           //if we press the pickup button and have something, we drop it
           else
           {
               BreakConnection();
               toActivate.hasGumball = false;
           }
       }


   }

   ////Velocity movement toward pickup parent and rotation
   private void FixedUpdate()
   {
       if (currentlyPickedUpObject != null)
       {
           currentDist = Vector3.Distance(pickupParent.position, pickupRB.position);
           //Calculate the current speed
           currentSpeed = Mathf.SmoothStep(minSpeed, maxSpeed, currentDist / maxDistance);
           currentSpeed *= Time.fixedDeltaTime;
           Vector3 direction = pickupParent.position - pickupRB.position;
           pickupRB.velocity = direction.normalized * (followSpeed * 100f * Time.deltaTime);
           //Rotation
           lookRot = Quaternion.LookRotation(transform.position - pickupRB.position);
           lookRot = Quaternion.Slerp(transform.rotation, lookRot, rotationSpeed * Time.fixedDeltaTime);
           pickupRB.MoveRotation(lookRot);
       }

   }

   ////Release the object
   public void BreakConnection()
   {
       pickupRB.constraints = RigidbodyConstraints.None;
       currentlyPickedUpObject = null;
       physicsObject.pickedUp = false;
       currentDist = 0;
   }

   public void PickUpObject()
   {
       physicsObject = lookObject.GetComponentInChildren<PhysicsObject>();
       currentlyPickedUpObject = lookObject;
       pickupRB = currentlyPickedUpObject.GetComponent<Rigidbody>();
       pickupRB.constraints = RigidbodyConstraints.FreezeRotation;
       physicsObject.playerInteractions = this;
       StartCoroutine(physicsObject.PickUp());

       //Increase Player Speed
       movSpeed.TopSpeed = playerTopSpeed;
       movSpeed.MoveAccell = playerAccel;
       movSpeed.SlopeSpeedLimit = playerSlopeLimit;


   }


}

The Sphere's Physics Script:

public class PhysicsObject : MonoBehaviour
{
   public float waitOnPickup = 0.2f;
   public float breakForce = 35f;
   [HideInInspector] public bool pickedUp = false;
   [HideInInspector] public AttachBall2 playerInteractions;
   [SerializeField] public int gumTotal = 25;
   public ActivatePowerUp gumCounter;

   private void Start()
   {
       gumCounter = FindObjectOfType<ActivatePowerUp>();
   }
   private void OnCollisionEnter(Collision collision)
   {
       if (pickedUp)
       {
           if (collision.relativeVelocity.magnitude > breakForce)
           {
               playerInteractions.BreakConnection();
           }

           if(collision.gameObject.tag == "GumSplat")
           {
               Destroy(collision.gameObject);
               gumCounter.gumSplatsCollected += 1;
           }

       }
   }

   //this is used to prevent the connection from breaking when you just picked up the object as it sometimes fires a collision with the ground or whatever it is touching
   public IEnumerator PickUp()
   {
       yield return new WaitForSecondsRealtime(waitOnPickup);
       pickedUp = true;

   }
}

None

This topic is closed to new replies.

Advertisement