How do i make my ball like a magnet?

So i´m currently making a ball rolling game which is like a platformer.
But after i´ve added some rotated/tilted floor objects the ball bumps when going down the floor rather than stick to it the whole way.

So how would i make my object glue to the floor objects but still be able to move on it?
I dont necessarily ask for a complete script, but i know there must be a keyword to this! :slight_smile:

This is what my maps look like:
In this map it bumps a lot when going down the hill so it cant jump properly because it needs to interract with the ground to do so.
Screenshot - da7b5c3240356fadedcf88eb29d72f72 - Gyazo

The same with these tilted objects
Screenshot - 79b18e35d6e0d12dc749cf57f3f31866 - Gyazo

This is my movement script:

#pragma strict

var jumpHeight = 0.02;
static var jumpCount = 0;
var canJump = true;

var Slow = false;

function FixedUpdate ()
{
        GetComponent.<Rigidbody>().AddForce (Vector3.down * 35);
       
        if (Input.GetKey (KeyCode.W) && jumpCount == 0)
        {
            GetComponent.<Rigidbody>().AddForce (Vector3.forward * 100);
        }
        if (Input.GetKey (KeyCode.S))
        {
            GetComponent.<Rigidbody>().AddForce (Vector3.back * 100);
        }
        if (Input.GetKey (KeyCode.A))
        {
            GetComponent.<Rigidbody>().AddForce (Vector3.left * 100);
        }
        if (Input.GetKey (KeyCode.D))
        {
            GetComponent.<Rigidbody>().AddForce (Vector3.right * 100);
        }
        if (Input.GetKey (KeyCode.Space) && jumpCount == 0)
        {
            GetComponent.<Rigidbody>().AddForce(Vector3.up * jumpHeight, ForceMode.Impulse); jumpCount = 1;
        }   
        {
            GetComponent.<Rigidbody>().velocity = Vector3.ClampMagnitude(GetComponent.<Rigidbody>().velocity, maxVel);
        }        
}

var maxVel : float = 16.0;


function OnCollisionEnter (hit : Collision)
{
  if(hit.gameObject.tag == "Floor")
  {
  jumpCount = 0;
  }
}

function OnCollisionExit (hit : Collision)
{
  if(hit.gameObject.tag == "Floor")
  {
  jumpCount = 1;
  }
}

Note All floor objects are tagged with “Floor”
Note Gravity is set to 0 and the player is instead held down to earth by:
javascript** ** GetComponent.<Rigidbody>().AddForce (Vector3.down * 35);** **

Have you tried doing something as simple as adding a PhysicsMateral/2DPhysicsMaterial to it and setting the bounce to minimal? That way you could easily have different materials and scenario’s with different friction and bounce.

I havent worked on the game for 5 months, just came back to it today. But i am pretty sure i have tried this, but anyway i will try it and get back to you within a few minutes :slight_smile:

Okay so it helps a lot, but it only decreased the height of the jumps rather than removing it totally :slight_smile:

Have you set bounciness to 0, and the combine to minimum, and done the same on the other object’s material as well? Unless you’ve set a default PhysicsMaterial in the editor settings, the other material will have a default bounce as well.

Yes i´ve done that.
Look at the 2 following picture

https://gyazo.com/9abfb0bdf52f9ecc22ee4de63589bdbc
https://gyazo.com/852d71c695ac6dccd150caa64f10133e

Should the player have it too?

You could get the height of the ball by raycasting to the floor, then snap the ball position such that the height is zero.

Oh yeah definitely, assign it to both of them. Primarily the player, as well as the floor. PhysicsMaterials work in their relationship with each other. Not just by themselves. An object without a PhysicsMaterial (your player right now), will actually use the default PhysicsMaterial set in the player settings, which I think has a bounce of 0.3 or something.

You could perhaps do that in LateUpdate(), to avoid the constant downward force overriding from AddForce getting in the way…

Now that you say it i´ve actually tried this once but ended up quitting it because i couldn´t figure out of i could stop the raycast from rotating with the ball.

I´ve now tried having the PhysicMaterial on both and it definately helps, but the bounch still exists…
The problem is that my players movement script requires the player to be 100% in touch with the ground to be able to jump. Thereby, if the player is just a mini mini mini pixel over a floor object because of a bump then the player cant jump in time.

private void LateUpdate()
        {
            float snappingRange = 1f;
            RaycastHit hit;
            Ray ray = new Ray(transform.position, Vector3.down); // << Vector3.Down is the world's down. Instead of transform.down
            if (Physics.Raycast(ray, out hit, snappingRange))
            {
                if (hit.collider.tag == "Floor")
                {
                    transform.Translate(new Vector3(0, hit.distance, 0), Space.World);
                }
            }
        }

The only thing you may need to do is make sure that you’re not hitting your own player. So add a Debug.Log(hit.collider.gameObject.name) in there to check. If it is hitting, just add a layerMask to the RayCast.

I´ve translated it to my language (JS) and it looks like the following:

function LateUpdate()
{
    var snappingRange : float = 1f;
    var hit : RaycastHit;
    var ray = new Ray(transform.position, Vector3.down); // << Vector3.Down is the world's down. Instead of transform.down
    if (Physics.Raycast(ray, hit, snappingRange))
    {
        if (hit.collider.tag == "Floor")
        {
            transform.Translate(new Vector3(0, hit.distance, 0), Space.World);
        }
    }
    Debug.Log(hit.collider);
}

In the debug it says that it hits an object called “null” so i guess it has something to do with the player.
How do i add a layermask to the raycast called “Floor”?

Aaah that means you’re not hitting anything at all. Sadly

function LateUpdate()
{
    var snappingRange : float = 1f;
    var hit : RaycastHit;
    var ray = new Ray(transform.position, Vector3.down); // << Vector3.Down is the world's down. Instead of transform.down
    if (Physics.Raycast(ray, hit, snappingRange))
    {
        Debug.Log(hit.collider);
        if (hit.collider.tag == "Floor")
        {
            transform.Translate(new Vector3(0, hit.distance, 0), Space.World);
        }
    }
    else
    {
        Debug.Log("hit nothing");
    }
}

Because you’re calling the Debug.Log outside of the physics if statement, it’s not necessarily saying it ‘hit’. Physics.Raycast returns a bool saying whether it hit something or not, so you only know that it’s made a hit when a Debug.Log get’s called the if statement, like above. What you’ll want to do is see the actual direction the ray is firing. To do that you’ll use Debug.DrawRay()

So you’d use it like this:

[code=CSharp]function LateUpdate()
{
    var snappingRange : float = 1f;
    var hit : RaycastHit;
    var ray = new Ray(transform.position, Vector3.down); // << Vector3.Down is the world's down. Instead of transform.down
    Debug.DrawRay(transform.position, Vector3.down * 500, Color.Red, 500);
    if (Physics.Raycast(ray, hit, snappingRange))
    {
        Debug.Log(hit.collider);
        if (hit.collider.tag == "Floor")
        {
            transform.Translate(new Vector3(0, hit.distance, 0), Space.World);
        }
    }
    else
    {
        Debug.Log("hit nothing");
    }
}

What this does it shows you the direction the ray is firing in the game, but you need to look for the line in the scene view, not game view. Let me know which way it’s facing.

Hey again!

It´s facing downwards as supposed but its outputting “hit nothing” as following:

https://gyazo.com/c1a75675a7882b8e46e7832112109fb4

Right now the player keeps bouncing up and down and the ray seems to stay where the player started :slight_smile:

Well in that case, knowing it’s firing in the right direction, there’s only two possible issues:

  • You’re not making the ray trace far enough (so up the snappingRange, like so:)
function LateUpdate()
        {
            var snappingRange : float = 500f;
            var hit : RaycastHit;
            var ray = new Ray(transform.position, Vector3.down); // << Vector3.Down is the world's down. Instead of transform.down
            Debug.DrawRay(transform.position, Vector3.down * 500, Color.Red, 500);
            if (Physics.Raycast(ray, hit, snappingRange))
            {
                Debug.Log(hit.collider);
                if (hit.collider.tag == "Floor")
                {
                    transform.Translate(new Vector3(0, hit.distance, 0), Space.World);
                }
            }
            else
            {
                Debug.Log("hit nothing");
            }
        }
  • The floor has no collision. Though I’m guessing it must for the ball to be bouncing off of it. Make sure it’s on the ‘default’ layer, to be sure (found in the top right of the inspector when clicking on it)

Yeah i forgot i had the floors on the “floor” layer instead of default - anyway it does still not work.
It looks like it now knows that it hits the floor, but the player keeps bounching up and down like a bouncy ball of Redbull… haha :smile:

Here is a video of what it looks like:
https://vimeo.com/157432919