Noob - is this a sensible way to do magnetic balls?

Hi all,
I’ve just started using Unity (this week) and have been through a few tutorials and run through the forums and answers areas.

I’m attempting to create a script which simulates magnetic balls, so they get attracted to the player. I’ve considered using spring joints between the player ball and the other balls but couldn’t get one working in the way I wanted. I also tried setting up multiple colliders on the player ball one for collisions and one for “sphere of magnetcs” but that came with lots of problems too.

I’ve settled for tagging the “other” balls which can be attracted by the player ball and calculating a distance and applying a simple force.

Does this seem sensible? Is there a better way?
Here’s the code

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

public class PlayerController : MonoBehaviour {
    public float speed;
    public float maxDistanceAttract;
    public float attractForce;
    public Color magneticColor;

    private Color originalColor;
    private Rigidbody rb;
    private bool isMagnetic = false;
    private float maxDistanceAttractSqr;
    private GameObject[] attractees;
    private float moveHorizontal;
    private float moveVertical;

    void Start()
    {
        //this object's Rigid Body
        rb = GetComponent<Rigidbody>();
        originalColor = rb.GetComponent<Renderer>().material.color;
        //get the objects we're trying to track
        attractees = GameObject.FindGameObjectsWithTag("Attractee");
        //store the sqr value for comparisons (so we're not calculating every loop
        maxDistanceAttractSqr = maxDistanceAttract * maxDistanceAttract;
    }

    //the control tests in Update
    void Update()
    {
        if (Input.GetKeyUp(KeyCode.Space))
        {
            isMagnetic = !isMagnetic; //toggle magnetic value

            if (isMagnetic) {
                rb.GetComponent<Renderer>().material.color = magneticColor;
            } else {
                rb.GetComponent<Renderer>().material.color = originalColor;
            }
        }

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

    }

    //all the physics calcs in Fixed Update
    void FixedUpdate()
    {
        //this objects movement

        if(moveHorizontal != 0 || moveVertical != 0)
        {
            Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
            rb.AddForce(movement*speed);
        }

        if (isMagnetic)
        {
            //the other objects attraction forces - something a bit like magnetism
            foreach (GameObject attractee in attractees)
            {
                Vector3 heading = rb.transform.position - attractee.transform.position;
                //use sqrMagnitude in the test as its not an expensive test
                //limit force applying to not happen if the bodies are really close
                if (heading.sqrMagnitude < maxDistanceAttractSqr && heading.sqrMagnitude > 1.8f)
                {
// now get the real distance
                    var distance = heading.magnitude; 
// calc the direction vector
                    var direction = heading / distance; 
//force is inverse by distance
                    var force = attractForce / distance;
                    attractee.GetComponent<Rigidbody> ().AddForce (direction * force);

                }
            }
        }
    }
}

You can see it in action here, space switches magnetism on and move the player ball with arrow keys:

Thanks to anyone in advance

1 Like

Sure! Best of all… it works! Run forward with it for now, I say.

I know it isn’t a cheap asset, but whenever I need to do anything like this I just use Circular Gravity Force off the asset store.