Nature2D - 2D Physics Engine for UI Elements

ApplyForce will make the RigidBody accelerate, so if you want limit forces applied you could use the following method:

local maxForce = 0.5
body.forces =, -maxForce, maxForce), body.forces.Y)

You can increase the Friction and AirFriction, fidget with the gravity and set the collision multiplier to something like 0.1! You can do that by Engine:SetPhysicalProperty()

v0.5.1 Support for different Masses of RigidBodies

You can now set any mass value you like for different RigidBodies to see changes in Collision Response and how forces are applied to each RigidBody. This paves the way for more accurate physical simulations with guis!

  • Added the ability to set a mass value other than 1 for different RigidBodies
  • Added new methods to RigidBodies
    • RigidBody:SetMass(mass: number)
  • Updated Point:ApplyForce() and RigidBody:ApplyForce(). Divides the force by the RigidBody’s mass to calculate acceleration.
  • Updated Collision detection and response to have effects according to the masses of each RigidBody. Now calculates accurate ratios for the force applied to each body after collision.
  • Cleaned some code, replaced bad practices with good ones, used Vector2:Dot() which is slightly faster than calculating the dot product of two vectors from scratch.

A little demonstration of the same. You can see the smaller box is having a hard time pushing the larger box because one has a mass of 100 and the smaller one has a mass of 1. A force of -0.35, 0 is being applied for 5 seconds on the smaller box.

v0.5.2 - Introducing Nature2D Plugins!

  • Added new methods to Points
    • Point:SetMaxForce(maxForce: number)
  • Added new methods to RigidBodies
    • RigidBody:SetMaxForce(maxForce: number)
  • Added Plugins
    • Quad
    • Triangle
    • MouseConstraint

So what are these “Plugins” all about? Don’t get confused, these plugins are not Roblox Studio plugins. These plugins are essentially utility modules that many people may find useful! I decided to create some of them for practices which are prominent, like creating custom RigidBody structures and being able to drag and move RigidBodies here and there using the mouse button.

There are 3 Plugins available as of now

  • Quad - To create a 4 sided custom RigidBody structure given 4 points.
  • Triangle - To create a triangular custom RigidBody structure given 3 points.
  • MouseConstraint - A tool for dragging and moving RigidBodies using the mouse cursor.

In order to use plugins, you may require them in your script like this:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Plugins = require(ReplicatedStorage.Nature2D.Plugins) 

Example of the Triangle Plugin:

    Plugins.Triangle(a: Vector2, b: Vector2, c: Vector2)

local TriangleBody = Engine:Create("RigidBody", {
    Mass = 5,
    Structure = Plugins.Triangle(, 10),, 20),, 20)),
    Collidable = true,
    Anchored = false

Example of the Quad Plugin:

    Plugins.Quad(a: Vector2, b: Vector2, c: Vector2, d: Vector2)

local QuadBody = Engine:Create("RigidBody", {
    Mass = 5,
    Structure = Plugins.Quad(, 0),, 20),, 20),, 0)),
    Collidable = true,
    Anchored = false

Example of MouseConstraint:

    Plugins.MouseConstraint(engine: Engine, range: number)

Plugins.MouseConstraint(Engine, 10) -- RigidBodies that are closest to the mouse and under a radius of 10 pixels can be dragged around by holding and moving the mouse.


If you wish to see more plugins be added, do share some feedback with me. If you wish to have your plugins be added to Nature2D, open a pull request at the Github Repository!

Updated Roblox Asset & Github

Updated Documentation

Updated Wally Package - 0.5.1 → 0.5.2

Documentation up to the latest version will be updated soo !


Was messing around with this, and accidentaly created a killing-low-end-pcs machine lol. other than fps, this is pretty cool!

Ah well, having so many RigidBodies spawned is going to make any PC lag. There can be a lot of optimizations in the code though. I’ll look into that and hopefully make this library faster than it is right now, sometime in the future.

Thanks! Glad you liked it.


This is pretty cool and interesting! Only one thing: this link is not working

Thanks for letting me know! Fixed it!


Hey, I noticed that anchored RigidBodies with anchor points other than (0, 0) don’t mix well with the engine (but unanchored ones work fine).


local Nature2D = require(game:GetService("ReplicatedStorage").Nature2D)
local GuiBase = script:FindFirstAncestorOfClass("ScreenGui")
local MainFrame = GuiBase.Canvas

local Engine = Nature2D.init(GuiBase)

	Object = MainFrame.Floor;
	Collidable = true;
	Anchored = true;

for i,v in pairs(MainFrame.Physics:GetChildren()) do
		Object = v;
		Collidable = true;
		Anchored = false;


Screen Shot 2021-12-20 at 2.41.57 PM
Anchor point of (0, 0):

Anchor point of (0.5, 0.5):
(I readjusted the frame to the middle)

Are there plans to fix this, or is it intended?


Yep, its a bug. Thanks for reporting! I’ll fix this up in the next release :slight_smile:. It was a problem in the code itself.


Thank you!

Also, quick question, is there support for registering collisions on objects with Collidable = false? I have a special case where I want an action to happen if a collider goes through an object without Collision, and I noticed the .Touched event doesn’t fire. Is there some way to register them or disable a check? If there isn’t, that’s fine, it’d just be nice to know.

Collidable is like CanTouch & CanCollide combined together. Hence .Touched and .CanvasEdgeTouched only fire if Collidable is true. This may be a design flaw. It’d make sense to add a CanTouch property to the RigidBodies and treat Collidable as CanCollide. I’ll be sure to look into it for the next release!

Alright, cool! Thanks for the quick responses!

Also, sorry for the barrage of replies, but is there a way to invalidate a RigidBody without removing the GuiObject it affects? For example, say I had a frame which was affected by a RigidBody. Is there a way to stop it from being simulated like one without destroying the frame itself?

Thanks for all your help!

A hacky way of doing this would be to loop through the RigidBodies of the Engine and remove the one you want manually:

local id = "id of the rigidbody you want to remove"

for i, b in ipairs(Engine.bodies) do 
   if b:GetId() == id then 
       table.remove(Engine.bodies, i)

I am not exactly sure if this makes any errors pop up though!

No worries! I am thankful that you’re pointing out and suggesting some actually important features and design flaws that should’ve been kept in mind earlier. Thanks again! And I’ll be sure to add an easier way to do this in the next release. :grin:

v0.5.3 - Improvements to .Touched Event.

  • Improvements to .Touched Event. The event does not fire every frame anymore if two bodies are colliding. It’ll only fire the moment the two bodies collide. Playing collision sounds etc is now possible.
  • RigidBody:Destroy() now takes in an optional argument “keepFrame: boolean|nil”. If passed in as true, the RigidBody’s UIElement will not be destroyed. If passed as false or nil, the RigidBody’s UIElement will be destroyed along with it.
  • Changes to Signal utility. Curtsy of @LucasMZ_RBX
    • Made Connection property .Connected public

Updated Roblox Asset & Github

Updated Documentation

Updated Wally Package - 0.5.2 → 0.5.3

The ability for Anchored RigidBodies to have different anchor points will be added soon. CanTouch property needs to be revised before being added since I wish to maintain less collision detection checks each frame!


Great! This adds a lot of great features. I appreciate your effort and response to feedback!

By the way, since the .Touched event no longer fires every frame, is there a way to detect when a touch ends (like Roblox’s BasePart .TouchEnded event)?

Not currently, will think about adding it. Thank you for the suggestions :slight_smile:


v0.5.4 - TouchEnded Event

  • Added .TouchEnded event to RigidBodies. This event fires the moment two RigidBodies stop colliding with each other.
  • SomeRigidBody.TouchEnded:Connect(function(otherID)
        local OtherRigidBody = Engine:GetBodyById(otherID)
        print("Touch ended")
  • Fixed AnchorPoint bug with anchored RigidBodies. Anchored RigidBodies can now have any AnchorPoint, which does not affect how they are positioned on the screen. cc: @Inconcludable

Updated Roblox Asset & Github

Updated Documentation

Updated Wally Package - 0.5.3 → 0.5.4


A quick demo for this:


1 Like

Thank you so much!! I’ve never seen a resource creator that responds to feedback as much as you do. These events should make my game easier to make, so I appreciate your hard work!

1 Like