Ben Traje
← Back to unity

How to Create a Real-Time Physics Attractor and Custom Gravity in Unity C#

26 Aug 26 (2mo ago)

Building physics-driven interactions where objects follow a moving target in real-time is a common mechanic in games, useful for item collection, orbital mechanics, magnetic forces, or interactive particle spheres.

Implementing this effectively requires syncing with Unity's physics step, preventing aggressive orbiting, and adjusting gravity per object when the default $-9.81\text{ m/s}^2$ downward pull is too heavy.

1. Implementing the Target Attractor Script

When manipulating physics objects (Rigidbody), always apply forces inside FixedUpdate rather than Update to avoid jitter and unpredictable behavior across varying frame rates.

The Full Attractor Script

using UnityEngine;

public class AttractorCon : MonoBehaviour
{
    [Header("Targets")]
    public GameObject[] emojiBalls;

    [Header("Attraction Settings")]
    public float attractionStrength = 5f; // Strength of the pull
    public float damping = 0.5f;           // Dampens velocity to prevent endless orbiting

    [Header("Custom Gravity")]
    public bool useCustomGravity = true;
    public float customGravityY = -2f;     // Custom gravity acceleration (e.g., -2 instead of -9.81)

    void FixedUpdate()
    {
        Vector3 targetPosition = transform.position;

        foreach (GameObject ball in emojiBalls)
        {
            if (ball != null && ball.TryGetComponent<Rigidbody>(out Rigidbody rb))
            {
                // Apply custom gravity per object if enabled
                if (useCustomGravity)
                {
                    rb.useGravity = false;
                    Vector3 customGravity = new Vector3(0f, customGravityY, 0f);
                    rb.AddForce(customGravity, ForceMode.Acceleration);
                }

                // 1. Calculate direction vector from object to attractor
                Vector3 direction = targetPosition - ball.transform.position;
                float distance = direction.magnitude;

                // 2. Scale force by distance for an elastic spring effect
                Vector3 attractionForce = direction.normalized * distance * attractionStrength;

                // 3. Apply force with velocity damping to stabilize motion
                rb.AddForce(attractionForce - (rb.velocity * damping));
            }
        }
    }
}

2. Core Mechanics Breakdown

  • Distance-Based Acceleration: Multiplying the normalized direction by distance * attractionStrength creates a spring-like force that pulls distant objects faster while easing them in as they approach.
  • Velocity Damping: Subtracting rb.velocity * damping counteracts continuous angular velocity, preventing objects from infinitely orbiting around the attractor origin.
  • TryGetComponent Safety: Eliminates runtime null reference exceptions if an array element lacks a Rigidbody component.

3. How to Set Custom Gravity in Unity

Unity's built-in useGravity toggle only switches between $0\text{ m/s}^2$ and the global physics gravity (default $-9.81\text{ m/s}^2$). When you need a specific low-gravity value like $-2\text{ m/s}^2$:

Option A: Global Scene Gravity

  1. Open Edit > Project Settings.
  2. Navigate to Physics in the left sidebar.
  3. Under Gravity, update the Y field from -9.81 to -2.

Use this when all physics entities across the entire scene require the same floaty behavior.

Option B: Per-Object Scripted Force

  1. Uncheck Use Gravity on the target object's Rigidbody.
  2. Apply rb.AddForce(new Vector3(0f, -2f, 0f), ForceMode.Acceleration) within FixedUpdate.

Use this when only selected objects should fall slowly while standard environment objects retain full earth gravity.