Code Monkey home page Code Monkey logo

nature2d's Introduction



version
devforum model documentation

About

Nature2D is a 2D physics library designed for and on Roblox. Ever wanted to create 2D games but step back because Roblox doesn't have a built-in 2D physics engine? Use Nature2D to create versatile and smooth simulations and mechanics for your 2D games with minimum effort. Nature2D primarily uses methods of Verlet Integration and Convex Hull collisions.

RigidBodies and constraints can potentially be made with almost all UI elements, from Frames to TextBoxes. Create almost anything you can imagine. From bouncy boxes to destructible structures, even character movement in no time. Here's a wrecking ball connected to an invisible constraint knocking a few boxes off of the blue platform.

Showcase

Find all my interactive demos here - https://www.roblox.com/games/9646145835/Physics-Demos-2D

Created something cool with Nature2D? Open an issue or a pull request if you wish to showcase it here!

Rotating Objects

Wrecking Ball

Constraints

Smooth Collisions

Double Pendulum

Inclined Plane

Slingshot

Box Stack

Getting Started

Using the CLI - You can clone the repository on your local device and start experimenting.

$ git clone https://github.com/jaipack17/Nature2D.git

Roblox Model - Nature2D is available on the Roblox asset store for free. You can get the model through the following link.

https://www.roblox.com/library/7625799164/Nature2D

Using .rbxm File - Head over to the Releases page on github, choose a version and download the [email protected] file from its assets. Now right click in Roblox Studio's explorer, click Insert From File and select the file.

Using wally - Use wally, a package manager for roblox to install Nature2D in your external code editor. This requires wally to be installed on your device. Then, add Nature2D to the dependencies listed in your wally.toml file.

[dependencies]
Nature2D = "jaipack17/[email protected]"

After that, Run wally install in the cli. Nature2D should be installed in your root directory. If you encounter any errors or problems installing Nature2D using wally, open an issue!

Require the library and start coding.

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

local World = Instance.new("ScreenGui")
World.IgnoreGuiInset = true
World.Parent = game.Players.LocalPlayer.PlayerGui

local engine = Nature2D.init(World)

-- code

To get familiar with the library, you can go through the documentation. Documentation is available at https://jaipack17.github.io/Nature2D/.

Contribution

If you encounter bugs or would like to support this project by improving the code, adding new features or fixing bugs - Feel free to open issues and pull requests. Also read the contribution guide.

nature2d's People

Contributors

jaipack17 avatar lucasmzreal avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nature2d's Issues

N-gon Custom Rigid Body Construction Plugin

Description

Create a new plugin which makes it easier to create n-gons or in other words n-sided polygonal structures for custom rigid bodies. It is a very tedious task to create custom rigid bodies with more than 4 sides since (i) it is hard to determine which points you should join to create support constraints. (ii) Additionally, there exist plugins for making only quadrilaterals and triangular custom rigid bodies.

Example:

-- A pentagonal custom rigid body.
-- Plugins.ConstructRigidBodyStructure(a, b, c, ..., n)

local Pentagon = Engine:Create("RigidBody", {
    Structure = Plugins.ConstructRigidBodyStructure(
        Vector2.new(10, 10), Vector2.new(20, 20), Vector2.new(15, 30),
        Vector2.new(5, 30), Vector2.new(0, 20)
    ),
    Collidable = true,
    Anchored = false
})

A way this can be accomplished is to form support constraints of the rigid body using the Deulaunay Triangulation algorithm

Importance

This would be quite an important feature since it'll make it easier to create a vast variety of custom rigid bodies provided the positions of its vertices in clock-wise or anti-clock-wise arrangement.

Refactor Creation methods to a single :Create() method

Due to frequent updates and me particularly dumping new methods to the API, its quite cluttered which makes it harder to work with. Newcomers will be impacted due to this, making it confusing/harder for them to get the hang of it. I aim to clean and refactor the API with a couple of changes which may improve developer experiences, thus I wish to collect inputs from your side to help evaluate.

Refactor Creation methods to a single :Create() method.

Something which causes clutter are the methods that do almost the same task as others. The potential addition of new objects such as Joints may make object creation perplexing. I wish to refactor the following methods of the Engine to the latter.

Engine:CreateRigidBody()
Engine:CreatePoint()
Engine:CreateConstraint()

-- to

Engine:Create()

How Engine:Create() would work is that it would take in 2 parameters, firstly the type of the object we are trying to create - RigidBody, Point or Constraint and the 2nd parameter for specifying their properties. An example would be:

local body = Engine:Create("RigidBody", {
    guiObject = frame
    collidable = true,
    anchored = false
})

local point = Engine:Create("Point", {
    position = Vector2.new(500, 0),
    visible = false,
    snap = true
})

local constraint = Engine:Create("Constraint", {
    type = "Spring", 
    point1 = point, 
    point2 = body:GetVertices()[1], 
    visible = true, 
    thickness = 2, 
    restLength = 100
})

While this seems like a good idea for cleaning up the API and making object creation easy to understand, we'd have to make a sacrifice. And, that is intellisense. It makes it harder to give suggestions for the type of the object but more importantly their properties when trying to create them. Thus this is something I wish to discuss upon.

Moreover, do you wish to see the properties be in camelCase or PascalCase?

Is it a good step foward?

Creation of Custom RigidBodies

Support for RigidBodies formed by user-generated point-constraint structures, has been in development for quite some time now. While I am on it, something I have been puzzled about is the way you would create these objects.

RigidBodies take in UI Elements as their base from which the constraints and points and formed behind the hood, which makes your UI element have physical presence on the screen. But for RigidBodies that you create on your own as per your requirements, say for example a triangle, or an irregular quadrilateral, you would have to create your own constraints and points instead of the library doing the job for you.

There are several methods I have though of, in order to make creation of these objects easier. But first it is important to know what the "point-constraint" structure really is.

image

In the above image, the green dots are the arbitrary points we chose for our RigidBody, if we pass in a UI element, the 4 dots are automatically placed at its corners, also keeping in mind its rotation. There are 6 lines connecting the points all together. The lines in black are the edges of the RigidBody and the lines in red are "support constraints" which are meant to hold the RigidBody's structure in place and it prevent it from collapsing into nothingness. It is worth noting that support constraints are not used in collision detection. All constraints are rods.

You will have to create those points, edges and support constraints on your own! And to make this process easier, I wish to create API that is feasible and easy to understand. Here are some rough ideas I have thought of, and I would need you to help me with the evaluation of the same. If you have better and cleaner methods you would want to be used, please consider sharing that with me.

Creating Points and Constraints from scratch

You would have to create your own points and constraints from scratch using Create() and then pass in those, as properties of the RigidBody. At first glance, this method is very tedious.

-- an example of a triangle

local function makeTriangle(a: Vector2, b: Vector2, c: Vector2)
      local PointA = Engine:Create("Point", { Position = a })
      local PointB = Engine:Create("Point", { Position = b })
      local PointC = Engine:Create("Point", { Position = c })
      
      local C1 = Engine:Create("Constraint", { Type = "Rod", Point1 = PointA, Point2 = PointB, Visible = true })
      local C2 = Engine:Create("Constraint", { Type = "Rod", Point1 = PointB, Point2 = PointC, Visible = true })
      local C3 = Engine:Create("Constraint", { Type = "Rod", Point1 = PointA, Point2 = PointC, Visible = true })
      
      return Engine:Create("RigidBody", {
            Custom = true,
            Collidable = true,
            Anchored = false,
            Points = { PointA, PointB, PointC },
            Constraints = { C1, C2, C3 }
      })
end
 
local triangle = makeTriangle(Vector2.new(10, 10), Vector2.new(5, 10), Vector2.new(15, 10))

Providing just the Positions of vertices

This method would use delaunay triangulation to form the structure behind the scenes. It will handle both support constraints and edges of the RigidBody. A downside of this is, it lacks initial customization and may result into incorrect structures being formed.

local quad = Engine:Create("RigidBody", {
     Custom = true,
     Collidable = true,
     Anchored = true,
     Points = { Vector2.new(0, 0), Vector2.new(10, 0), Vector2.new(10, 10), Vector2.new(0, 10) }
})

Providing the positions for points of each constraint

We provide a table of dictionaries containing required information for the edges and support constraints of a RigidBody.

local struct = {
    { Point1 = Vector2.new(0, 0), Point2 = Vector2.new(0, 10) },
    { Point1 = Vector2.new(0, 10), Point2 = Vector2.new(10, 10) },
    { Point1 = Vector2.new(10, 10), Point2 = Vector2.new(10, 0) },
    { Point1 = Vector2.new(10, 0), Point2 = Vector2.new(0, 0) },
    { Point1 = Vector2.new(0, 0), Point2 = Vector2.new(10, 10), Support = true },
    { Point1 = Vector2.new(10, 0), Point2 = Vector2.new(0, 10), Support = true }
}

local quad = Engine:Create("RigidBody", {
     Custom = true,
     Collidable = true,
     Anchored = true,
     Structure = struct
})

Let me know about what you think about these creation methods. Which one should I consider? Any other options?

Applying upwards force, makes the rigidbody go downwards

Description

When applying an upwards force to a rigidbody, instead going up, it goes down.

Reproduction Steps

  1. Create a rigidbody
  2. Use :ApplyForce() with a random amount of Y force, preferably 50
  3. Put the :ApplyForce() into UserInputService.InputBegan function or any function that get's called multiple times.
  4. That's all

Expected Behavior

When applying upwards force the rigidbody should go upwards

Actual Behavior

The rigidbody goes downwards, instead of going up

Media

bug.mp4

Encounters

Always happening no matter what

self is nil in Engine:Start() method

"Engine:83: attempt to index nil with 'canvas' " is the error.
This happens when i call the method Start() in Engine class.

Also if I try to call to call method CreateCanvas in Engine class it will drops
"Engine:354: canvas is not a valid member of Players.Player.PlayerGui.Main.Canvas" - meaning that the self is the frame in this case.

Point/Rod not colliding with RigidBody.

Description

I have a complex shape I constructed using rods and points. It works fine, holds itself properly and collides properly with the screen's boundaries. Although, it won't collide with other RigidBodies.

Reproduction Steps

Create multiple frames and trace them using rods. Try making a part collide with it.

Expected Behavior

I expect the block to hit my structure and make it move.

Actual Behavior

The block can't sense it's existence.

Media

Video:
https://user-images.githubusercontent.com/68619882/142733996-9cf3fc55-fdd9-456e-9989-00f41b6a6afa.mp4

Place file:
https://mega.nz/file/WdVXQQxZ#H7y496g_JqAbnUvUq44niYUz-R4L8_U19VylXh4BJdE

Encounters

I first encountered this when playing around with points and . Pretty much about an hour ago.

Lastly

I can confirm that I haven't touched anything regarding CollisionFiltering. It also gives me an empty array when I request the FilteredRigidBodies.

Move a rigidbody without freezing it in the air

Description

What do you need help with/what is your query? Describe in 30-40 words or more!

Lately I started working again on the camera, but I have this problem that I can't move without making the unanchored rigidbody(s) freeze in the air.

Is there any other option to move a rigidbody without making it freeze in the air?
I know :ApplyForce() exists but I need precision

So far I have

What have you tried so far? (Optional)

I have tried using :SetPosition() but it just made the rigidbody freeze. (In RenderStepped)

Lastly

Anything else you would like to share?

2022-08-09.14-24-21.mp4

Engine still maintained?

I have a question about the engine. I wanted to make a 2d game on Roblox and found this engine. But the last release was last year on March in 2022. So i want to know if it's still maintained or should I use another engine?

Get name of obj that touched the rigidbody using .Touched

Description

What do you need help with/what is your query? Describe in 30-40 words or more!

When using .Touched, I am unable to get the name of the obj that has touched the rigidbody

example:
sprite.Touched:Connect(function(id)
objTouched = engine:GetBodyById(id)
print(tostring( objTouched.Name )) -- Returns nil, I've tried many other ways but it returns a table value or just the id
end)

So far I have

What have you tried so far? (Optional)

Searched online, searched nature2d forum

Lastly

Anything else you would like to share?

If this is an easy fix I'll feel stupid

Lots of rigidbodies lagging the game

Hello sir,

first of all I want to say how impressive this is and would like to thank you for it!
but second, I am making a plinko game I added 52 obstacles and then the user spawns in balls, I added all of them as a Rigidbody,
but when I spawn in even 2 balls it gets extremely laggy and my roblox studio almost crashes, I saw that you already created something like that but it doesn't lag that bad, how did you do it if I may ask?

Kind regards!

RigidBody:SetSize() changes only the size of the GuiObject

RigidBody:SetSize() only changes the size of the GuiObject and not the size of the actual point-constraint structure of the rigid body.

Reproduction Steps

  • Create a RigidBody with a GuiObject. Make sure it isn't a custom rigid body.
  • Call RigidBody:SetSize() with the size parameters.

Expected Behavior

The size of the rigid body's GuiObject changes as well as the point-constraint structure.

Actual Behavior

Only the size of the rigid body's GuiObject changes. Its structure remains the same.

FPS Unlocker causes physics issues

As the title says, FPS unlocker seems to mess with certain physics features such as friction, gravity and possibly other physics-based things as well. At 60 fps, friction behaves expectedly but setting the fps cap to none causes issues in which friction seems to be instantaneous and also causes gravity to be stronger.

Reproduction Steps

The FPS Unlocker being used is created by axstin.
Using :ApplyForce() with the fps cap set to none.

Code utilized below:

local Nature2D = require(script:WaitForChild("Nature2D"))

local Viewport = workspace.CurrentCamera.ViewportSize
local Canvas = script.Parent:FindFirstChild("Canvas")

local Engine = Nature2D.init(script.Parent)
Engine:CreateCanvas(Vector2.new(), Viewport, Canvas)

local Floor = Engine:Create("RigidBody", {
	Object = Canvas.Ground,
	Collidable = true,
	Anchored = true
})

local Object = Engine:Create("RigidBody", {
	Object = Canvas.Object,
	Collidable = true,
	Anchored = false
})


Object:CanRotate(false)
Engine:Start()

local UserInputService = game:GetService("UserInputService")
UserInputService.InputBegan:Connect(function(Input)
	if Input.KeyCode == Enum.KeyCode.E then
		Object:ApplyForce(Vector2.new(50, 0), 1)
	end
	
	if Input.KeyCode == Enum.KeyCode.F then
		Object:ApplyForce(Vector2.new(0, -50), 1)
	end
end)

Expected Behavior

For friction and gravity to behave similar to how they behave at 60 fps.

Actual Behavior

Friction seemed to be instantaneous instead of being smooth, and gravity seems to be normal.

Media

Behavior with 60 fps cap:

60fpscap

Behavior with no fps cap:

NoCap

Lastly

I'm not sure what else this may possibly affect, but I just wanted to notify incase it also shows other issues that fps unlocker may cause. Sorry if this isn't very informative, it's my first bug report.

how do I get the MouseConstraint to work?

Description

I want to be able to move my object with the mouse but I cant figure out where the script goes and how it works.

So far I have

Ive tried placing it in all different spots in the script but none of them worked

Lastly

no

2D multiplayer sync?

I have a game idea stuck in my head that depends on 2D multiplayer physics.

But how do you think one would implement this with less bandwidth close to how Roblox does live physics step-by-step? Surely it would be more than just remote-events.

GuiObject flying out of the screen

I have been encountering an issue for a while which is where the gui just goes through the ScreenGui and never to be seen again.

It usually occurs when its too far into the screen’s edges. It’s also ocurring with a spring when set the 2nd point too far.

I probably suck at explaining, I have a video demonstrating here.

Screen.Recording.2021-11-17.at.6.48.05.mp4

CanRotate property for rigidbodies

Description

I would like to request a feature, where you can disable the rotation of rigidbodies.

Alternatives

I have tried to edit the :Render method to do not rotate the frame. It worked, sometimes, however I noticed that the points and the cconstraints still rotated. Resulting in the frame hovering over the ground.

Importance

I feel like this feature isn't that important, however would make everything much more easier with creating player characters.

GuiObject can't decide which way it should be rotated

I'm using Nature2D along with a drag module to be able to drag the GuiObject across the screen. When dragging, I noticed that the ImageLabel kept rotating upwards and downwards and couldn't decide even if my mouse was kept still while holding.

I attached the place file where this issue occurs below in a mega. It also appears that smaller sizes of GuiObjects are not effected by this bug.
https://mega.nz/file/ORcTXI6T#N3Jh9cpRK976d2nQsBfzw4O4jnoJaaBx7WX6-rGujU4

Error Code with mouse constraints

Description

I am trying to get Mouse Constraints working but I keep getting the error code "ReplicatedStorage.Nature2D.Plugins.MouseConstraint:48: attempt to index nil with 'snap'" I couldn't find any fix on DevForums so I came here, I have the code from the website and tried some others listed on dev forums and they all had the same error message. Do I need any extra variables or is it a simple new code line? Please help :)

So far I have

I have looked on devforums and the website, no youtube videos about it that i can find about the error code or mouse constraints in general.

Lastly

N/A

Collisions break if body goes outside the viewport

Noticed that collisions suddenly stop working and bodies start going through each other if they are outside of the viewport.

Reproduction Steps

  1. Create a "Ground" body, which is Collidable and Anchored and is positioned in the center of the screen and has a size of UDim2.new(3, 0, 0, 50)
  2. Create another body, which is Collidable and has KeepInCanvas set to false and is positioned at UDim2.new(0.99, 0, 0, 0)
  3. Start the simulation
  4. Notice that the body we created in the second step just phased through the Ground body

Expected Behavior

Rigidbodies should always have collisions no matter if they are visible on the screen or not

Actual Behavior

Rigidbodies go through each other

Media

Scene file:

---@module src.init
local Rethink = require(game:GetService("ReplicatedStorage").Rethink)
local Modules = Rethink.GetModules()
local Scene = Modules.Scene
local Symbols = Scene.Symbols

return {
	Name = "nature2D_bug_report.scene",

	Rigidbodies = {
		[Symbols.Type] = "Rigidbody",

		Ground = {
			AnchorPoint = Vector2.new(0.5, 0),
			Position = UDim2.new(0.5, 0, 1, -50),
			Size = UDim2.new(3, 0, 0, 50),
			BackgroundColor3 = Color3.fromRGB(126, 126, 126),

			[Symbols.Rigidbody] = {
				Anchored = true,
				Collidable = true,
			},
		},

		Body = {
			Size = UDim2.fromOffset(100, 100),
			Position = UDim2.new(0.99, 0),

			[Symbols.Rigidbody] = {
				Collidable = true,
				KeepInCanvas = false,
			},
		},
	},
}
nature2D_bug.mp4

:CreateCanvas() creating a canvas in the wrong position?

Description

When using :CreateCanvas(), targeting a frame of a specific size and position, and parenting RigidBodies to that frame, it positions the Canvas offset from the actual targeted size and position. Parenting RigidBodies to anything but this canvas causes errors. Not sure what the solve is.

So far I have

  • Setting TopLeft to Vector2.zero (results in a canvas size of 0?)
  • Parenting RigidBodies to a different frame (causes the 'attempt to index nil with :Dot()' error)
  • Assigning the Frame I'm trying to use as the canvas (doesn't seem to do anything?)

keep velocity after collision

Dear jaipack17 or Git User,

Of the many methods you scripted, the one I like the most is RigidBody:ApplyForce(). However, I've been stumbling upon a problem recently. While trying to calculate the new velocity after collision seems nice in theory it seems the force is reset due to the CollisionResponse defined in the Runner file.

Is there a way to Add up the Forces? or a calculation which would work in my case?

PS: I experimented with a ball colliding and accelerating in an empty box

CanTouch Property for RigidBodies.

Regarding the possible addition of the new CanTouch property for RigidBodies.

At present each RigidBody has a Collidable property which is a boolean. This property determines if collision detection will be processed for the rigidbody and if .Touched, .TouchEnded and .CanvasEdgeTouched events will be fired.

Each frame when collisions are detected and processed, any Rigidbody whos Collidable property is set to false will be ignored. The idea of CanTouch is to detect collisions between the RigidBodies even if Collidable is false. If two RigidBodies collide, and either or both of them have their Collidable property set to false but CanTouch as true, .Touched will be fired but no separating/collision response force will be applied to them. This also relates to .CanvasEdgeTouched. Even if KeepInCanvas is set to false, .CanvasEdgeTouched will still fire but forces to keep the RigidBody inside the canvas won't be applied.

There are a few concerns and questions which emerge with such a change. So before adding this functionality, I'd like to hear from you on these points.

  • Considering how expensive collision detection is, would it be feasible to detect collisions by default between RigidBodies even if their Collidable properties are set to false? Should CanTouch be false for Non-Collidable bodies by default? I wouldn't want to sacrifice performance for a simple feature.

  • Would it be worth adding a property which introduces performance issues, if using methods that are already available to you can be used even if Collidable is set to false? Detecting collisions between two RigidBodies irrespective of their Collidable property, can be done with RigidBody:DetectCollision(otherBody: RigidBody). Hence, your own custom implementation of .Touched can be made for non-collidable rigidbodies. This can help save up on unnecessary collision detection checks.

  • As far as .CanvasEdgeTouched is concerned, even if KeepInCanvas is set to false, you could loop through the vertices of the RigidBody to see if any one of them crosses/touches any edge of the canvas and create a custom implementation of .CanvasEdgeTouched. RigidBody:IsInBounds() can also be utilized. Which once again saves on collision detection checks.

So I'm pretty sceptical about this addition. Though it may be deemed helpful to many because of how convenient and easy collision detection for Non-Collidable RigidBodies will be. Would this property be useful? Let me know if you have any questions, feedback or answers.

ApplyForce wont stop after value is set to false

Description

Hello! I apologize in advance because I'm new to luau and don't know alot. So what I tried to make is a simple platform on which the player can control a frame with the keys A & D. The issue I'm having is that ApplyForce wont stop after it should stop when releasing the key A

So far I have

I've tried using Kodezi and ChatGPT to find a possible error but to no avail

localscript.txt

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.