Force Effects

Force Effects let you place gravity wells, repulsors, tractor beams, wind zones and similar fields in a scene and have any Rigidbody feel them, with no per-object code. A field decides where and how strongly an effect applies, an effect asset decides what it does, and a receiver on the body decides which bodies listen. Everything here has a 2D twin with the suffix 2D that works with Rigidbody2D.

How it fits together #

  • Force Effect Field (ForceEffectField) acts from a point. It affects bodies around it, strongest at the source and fading with distance.
  • Force Effect Direction (ForceEffectDirection) acts along its forward (Z) axis, such as a steady wind, a current or a conveyor. In 2D it acts along its right (X) axis.
  • Force Effect assets (AttractEffect, RepulseEffect, TractorEffect, GravityEffect, SuspendEffect, WindEffect) are ScriptableObjects that you create from the Assets, Create, Physics menu and list on a field. See Effect Types for what each one does.
  • Force Effect Receiver (ForceEffectReceiver) goes on every Rigidbody that should be affected.

Setting up a field #

  1. Create an effect asset, for example Assets, Create, Physics, Effects, Gravity, and set its options.
  2. Add a ForceEffectField to an empty GameObject and drop the effect asset into its forceEffects list. Set strength, radius and, if you want, the falloff curve.
  3. Add a trigger collider to the same object, sized to the area you want the field to cover. Unless the field is global, the trigger collider decides which bodies it affects.
  4. Add a ForceEffectReceiver to each Rigidbody that should feel it, and tick useLinear, useAngular or both. Both default to off, so a receiver does nothing until you choose.
  5. Make sure the effect itself has the matching switch on (EffectLinear or EffectTorque). An effect only applies the parts you enable, so both the receiver and the effect must agree.

Force Effect Field #

SettingDefaultWhat it does
IsGlobaloffWhen on, the field acts on every receiver in the scene regardless of distance, and the falloff curve is not applied.
strength1The strength passed to the effects, before falloff. What it means depends on the effect (an acceleration, a speed, a rate). The receiver’s sensitivity multiplies it.
radius10The distance over which the strength follows the curve.
curvefull strength at the source falling to 0The strength multiplier by distance. x is 0 at the source and 1 at radius, y is the multiplier.
forceEffectsemptyThe effects applied to a body in range. Each is applied in turn.

A field draws its radius as a yellow wire sphere in the scene view when selected.

Falloff and which bodies are affected #

The two questions are separate and it is worth keeping them apart.

  • Which bodies are affected is decided by the field’s trigger collider. A receiver is affected while its body is inside the trigger. A non-global field with no trigger collider affects nothing, so either make it global or give it a trigger.
  • How strongly is decided by the curve, measured by distance from the source as a fraction of radius. Beyond the radius there is no cutoff: the strength stays at the end of the curve. With the default curve that end value is zero, so the effect fades out. If you want a constant effect across the whole trigger, use a constant curve.

A gravity well with a very large trigger collider therefore needs a radius that matches the trigger, or a constant curve, or the effect will fade to nothing well inside the volume.

Force Effect Direction #

A directional field pushes along its forward axis instead of from a point. Wind blows along that axis, Attract and Tractor pull along it, and Repulse pushes against it. Its settings match the point field, except reach replaces radius: it is how far either side of the object’s plane the strength follows the curve, measured along the field’s own forward axis. Selected, it draws a yellow arrow along its direction.

The common recipe for global wind is a ForceEffectDirection with IsGlobal on and a WindEffect in its list, so every receiver in the scene feels it with no collider.

Force Effect Receiver #

SettingDefaultWhat it does
useLinearoffApply the linear (pushing) part of the effects.
useAngularoffApply the angular (turning) part of the effects.
sensitivity1How susceptible this body is. A multiplier on every effect’s strength. Zero makes the body immune.
EffectorsemptyThe fields whose trigger this receiver is currently inside. Kept up to date as the body enters and leaves, and you can read it from code.
IgnoreListemptyFields this receiver does not feel, both global and local.

The receiver applies its fields every FixedUpdate. A field destroyed while a body is inside it is cleaned up automatically. The receiver requires a Rigidbody (a Rigidbody2D for the 2D version) and finds fields through trigger events, so the field’s trigger collider and the receiver’s body must be able to generate trigger messages in the usual Unity way.

From code #

  • Heathen.UnityPhysics.API.ForceEffects.GlobalEffects is the list of global sources. The 2D version is API.ForceEffects2D.
  • Set IsGlobal at runtime and the field registers or unregisters itself.
  • Call AddForce(Rigidbody subject, float sensitivity, bool useAngular, bool useLinear) on any ForceEffectSource to apply it to a body yourself.

Writing your own effect #

Derive from ForceEffect (or ForceEffect2D), implement LinearEffect and AngularEffect, and create instances from the Assets menu. You receive a ForceSource describing where the force comes from, the final strength after falloff and sensitivity, and the body.

using Heathen.UnityPhysics;
using UnityEngine;

[CreateAssetMenu(menuName = "Physics/Effects/Lift")]
public class LiftEffect : ForceEffect
{
    public float multiplier = 1f;

    public override void LinearEffect(in ForceSource source, float strength, Rigidbody subject)
    {
        subject.AddForce(Vector3.up * strength * multiplier, ForceMode.Acceleration);
    }

    public override void AngularEffect(in ForceSource source, float strength, Rigidbody subject)
    { }
}

ForceSource #

ForceSource is the readonly struct every effect receives. Create one with ForceSource.Point(position) or ForceSource.Directional(position, direction). Its fields are position, direction (a unit vector, zero for a point source) and directional. It gives you the vectors effects need for a subject position:

MemberReturns
Toward(subjectPosition)The unit vector an attracting effect pulls along: toward the source for a point, along the direction for a directional source, zero at the point itself.
Away(subjectPosition)The opposite of Toward.
Blow(subjectPosition)The unit vector wind blows along: away from a point source, along the direction for a directional source.
TargetPoint(subjectPosition)The point a subject is drawn toward, used to slow it on arrival: the position of a point source, or a point one unit ahead of the subject for a directional source.

Samples #

Import the Example Scenes sample from the Package Manager. The Force Effects folder contains Force Effect Fields, Spherical Gravity and Multi-body Gravity scenes that show each kind of field working. See the Overview for the sample import path.

System Log #

Force Effects log through System Log under the UnityPhysics.ForceEffects category, gated by Heathen.LogGates.UnityPhysics.ForceEffects. Configure it in Project Settings, Subsystems, System Log.

Rate This Article!