Ball controller gravity

Hello everyone, I am new to Unity and scripting in C#, so this might not be the most efficient piece of code you have ever seen, but my problem is: When I am not moving the ball (Using the arrow keys) the ball is in a sort of suspended gravity. As soon as I move the ball again, gravity goes back to normal. I’ve tried playing with the mass and adding force, but this probably won’t work because I’m using velocity instead of AddForce.

Any help would be appreciated :slight_smile:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class PlayerController : MonoBehaviour
{
    [Range(0.1f, 50f)]
    public float speed;
    private float moveHorizontal;
    private float moveVertical;
   

    [Range(1, 1.001f)] public float slowDownBase;

    private Rigidbody Playerrb;
    private float slowDown;

    void Start()
    {
        Playerrb = GetComponent<Rigidbody>();

        slowDown = slowDownBase;
    }

    void FixedUpdate()
    {
        moveHorizontal = Input.GetAxis("Horizontal");
        moveVertical = Input.GetAxis("Vertical");

        Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);

        Playerrb.AddForce(movement * speed);

        if (!Input.GetKey("left") && !Input.GetKey("up") && !Input.GetKey("down") && !Input.GetKey("right")){

           
            Playerrb.velocity = new Vector3(Playerrb.velocity.x, 0, Playerrb.velocity.z) / slowDown;
            slowDown += 0.00012f;

           

           
        }
       
    }
}

You’re explicitly setting the y velocity of the ball to 0 when you don’t push a button, so not really sure what you expect to happen with that.

Yeah I know in the code that is shown in this thread it’s set to 0, but I’ve tried playing with it for a while and the velocity isn’t actually 0 at all, it stays the same no matter the number (It slowly falls down to the ground) so I’m not sure what to do here.

What are you trying to do? How do you want the ball to behave? What’s the point of it all?

I am trying to quickly stop the ball when there is no player input, but the speed at which it slows down should be adjustable. I’ve been trying to do it with mass, but haven’t figured out a way to properly do it so that the ball still feels natural to control.

I know this might seem silly, and easy to achieve, but keep in mind that I am still trying to learn, and that tutorials on the internet are either not suitable for my case or just not what I am looking for.

You set the y velocity to zero. Gravity accumulates for one frame, setting the y velocity to 9.12 * fixed delta time, the ball moves down a fraction of a fraction of a unit. You set the y velocity to zero…

If you want to slowly adjust the ball’s velocity without input, simply up the drag and angular drag values on the rigidbody and get rid of your velocity override OR do what you’re doing now and set the y value to the current velocity’s y value so gravity continues to accumulate.

But wouldn’t that mean that the ball also moves slower when there is an imput?

This is not an adequate description. Saying you want to stop the ball implies that you sometimes want the ball to move. How do you want the ball to move? Why is it moving? What sort of motion does it need to show?

I’m trying to determine whether you should even be using the physics engine for this, and in either case, how you should be controlling this ball. I can’t do that if you won’t tell me what you’re trying to accomplish. (For that matter, if you can’t clearly describe what you’re trying to achieve, you probably won’t be able to achieve it yourself either.)

Well, think of it as an upgraded version of roll-a-ball (The ball does not actually have to roll, if that helps), where you move the ball through input, and can complete a level. I have however added a few features.

In the classic roll-a-ball tutorial on unity/youtube, the ball feels very unnatural, and it takes far too long for the ball to stop moving. That’s why I wanted to make a way of slowing down the ball faster, so it feels more natural to control it.

Since the ball won’t be having detailed skins and just a plain color, it just basically needs to move in the desired direction the input gives it, and after which it slows down. It just needs to be able to move, to collect items, go to the next level, etc.

So what’s this “gravity” you mentioned in the first post? If the objective is really what you said (“it just basically needs to move in the desired direction the input gives it, and after which it slows down”), then I don’t see how gravity has anything to do with it.

It appears from what you’ve said and what the code does, that you want to control the movement of a ball in the XZ plane (maintaining constant Y). The ball doesn’t actually rotate, and movement control is absolute, i.e., a horizontal positive input should always move the ball in the +X direction, and a vertical positive input should always move it in the +Z direction. You want the ball to smoothly but quickly accelerate to some maximum speed in the direction of the inputs, and quickly (but smoothly) come to a stop when the inputs are zero.

Is that it?

If this is indeed your objective, then yeah, you shouldn’t be using the physics engine for this… you certainly could do it that way, but you’ll waste a lot of time tweaking and adjusting and wrangling with the physics engine trying to get the behavior you want, and you may never achieve the sort of tight, video-gamey control you’re after. I’ll whip up a quick example of how to do it the old fashioned (and IMHO, better) way.

OK, so something like this ought to do it.

using UnityEngine;


public class XZControl : MonoBehaviour {

    [Tooltip("Full movement speed, in units/sec")]
    public float topSpeed = 3;
   
    [Tooltip("Acceleration speed, in units/sec/sec")]
    public float acceleration = 10;
   
    // Current velocity
    public Vector3 velocity;
   
    void Update() {
        // Get the input, and compute target velocity
        Vector3 input = new Vector3(Input.GetAxis("Horizontal"), 0.0f, Input.GetAxis("Vertical"));
        if (input.magnitude > 1) input.Normalize();
        Vector3 targetV = input * topSpeed;
       
        // Accelerate our current velocity towards the target velocity
        velocity = Vector3.MoveTowards(velocity, targetV, acceleration * Time.deltaTime);
       
        // Finally, update our position from the velocity
        transform.position += velocity * Time.deltaTime;
    }

}

That’s off the top of my head and probably contains some small errors, but should be approximately right. (And remove the Rigidbody from your GameObject, or else set isKinematic, so the physics engine doesn’t fight you.)

That pretty much is exactly what I need, other than the fact that it does need to be able to collide with objects, bounce off them for example and being able to interact with them, and be influenced by gravity.

1 Like

Well I still don’t understand (because you haven’t explained) what gravity has to do with it.

You also didn’t say anything about bouncing off objects! If you really want it to do that, in a realistic-looking way, then you probably will have to wrestle with the physics engine after all. Now you’re no longer talking about controlling the ball; you’re talking about sharing control of the ball with the physics engine, since when you bump into something, it sounds like you want the ball to move for a while in ways that have little to do with the inputs.

This has been a good exercise in the value of having a clear spec. :slight_smile:

I am sorry for not being 100% specific, but I do appreciate the help!

What i need, is a roll-a-ball script, in which the player can move around with the ball, bounce it against objects, collect objects, jump, roll down the terrain, fall from a ramp, etc.
The ball needs to realistically slow down after not recieving an input (A bit like rolling a ball on a rubber surface in real life), and needs to have the ability to be easily adjusted within the engine or through other scripts.

And currently, the only real problem I have is not being able to realistically slow down the ball.

OK, now I think it’s finally clear what you’re trying to do. And in that case, you were right to use physics in the first place. You could of course do it all yourself, but by the time you’ve accounted for acceleration up/down slopes and bouncing off of things, it will have gotten at least as hairy as wrestling with the physics engine.

Which brings you back to your original problem, and it’s going to take a lot of tweaking to get a behavior you like. First, turn up drag considerably, so that when you stop applying force to a ball rolling on a flat part, it comes to a stop fairly quickly. Then increase the force you’re applying to move to compensate for all that drag.

If that alone isn’t enough, then you may have to look into active braking when the inputs are at zero. Do that by either adjusting the drag on the fly during the run, or by applying a force opposite the ball’s current velocity. I guess you might also be able to do it by reducing the velocity towards zero (use Vector3.MoveTowards, as I did in my example, to move the current velocity towards Vector3.zero a little bit each physics frame).

Good luck!

Thanks for the help! Let me see if i can solve it :wink: