OrbitLib: Space Flight Dynamics for Roblox Lua

forthebadge forthebadge forthebadge

OrbitLib implements an optimized two-body orbital mechanics library for simulating celestial mechanics and space flight dynamics. All in Roblox.

With OrbitLib, the stars are now within reach!

Features

ezgif-1-f49f751c075f

  • Orbital Properties, including Keplerian Orbital Elements

  • Orbital Derivation from Position and Velocity

  • Orbital Prediction over Time

  • Utilities for Rendering

  • And Much More!

Latest Release

Grab the Latest Release on Github!

Documentation

Check out our thorough API Documentation!

Web Demo

Check it out for yourself!

This demo was made using Typescript & Three.js frameworked in Svelte, but all the non-rendering orbital mechanics code shares a 1:1 feature parity with the Roblox Lua library.

Github

If you want to support this project or think its cool, please consider leaving a star on our GitHub!

As Seen in These Devblogs!

This package is the underlying library for my now-abandoned project that you might have seen here:

50 Likes

When I clicked all of the links, “#### it or ship it”

I’ll modify the For the Badge links just to ensure this isn’t problematic.

1 Like

Wow, that’s cool! Reminds me of Kerbal Space Program lol

3 Likes

I like how this has the gravitational pull on planets, therefore speeding the rotation up, when they get close to the star. Great work!

2 Likes

This is insane! Thanks a ton! I love it

2 Likes

Hello @daftcube!

This is very incredible. Just a few notes in the code.

  • When you put the code from the API Documentation it errors and says requested module experienced error while loading. This is for in the module when CelestialBody or Orbit is requiring PhysicsConstraints or LuaMath2D it is put as a different I’m guessing previous name.

  • Next in Orbit on line 245 there is another error attempt to perform arithmetic(mul) on nil and number. This has been happening a lot to me lately because Roblox seems to be changing the math side of things a lot these days.

That’s as far as I got so far with this epic module.

Not trying to make anyone feel bad whatsoever but just wanted to try and help making this epic module even better! :smiley:

1 Like

For the first issue: it looks like you installed the library incorrectly, can I have a full stack trace of your issue?

For the second issue: Again, it looks like you aren’t providing enough arguments somewhere so their default value is nil, can I have the full stack trace and source you tried to run?

1 Like

For the first issue I guess I installed a more outdated version of the package and it was easily fixable anyway.

For the second issue I just used the code on the API Documentation in the Rendering Orbital Motion.
Code here:

-- Import OrbitLib
local CelestialBody = require(game.ReplicatedStorage.OrbitLib.CelestialBody)
local Orbit = require(game.ReplicatedStorage.OrbitLib.Orbit)

-- Convert from Roblox coordinates to OrbitLib coordinates.
function RobloxToOrbitLib(x: number, y: number, z: number)
    return x, -z, y
end

-- Convert from OrbitLib coordinates to Roblox Coordinates.
function OrbitLibToRoblox(i: number, j: number, k: number)
    return i, k, -j
end

-- Conversion Factors
local oneStudEqualsKilometers = 1000
local oneKilometerEqualsStuds = 1/oneStudEqualsKilometers


-- Time Values
local timeAcceleration = 10000 -- How many times normal speed
local currentTime = 0

-- Prediction constants
local TOLERANCE = 0.0008 -- A constant used for calculating precision of prediction
                         -- See Orbital Prediction for documentation.

-- Parent body and orbit
local earth = CelestialBody.new("Earth", 5.972e24, 6378.1)
local orbit = Orbit.fromKeplerianElements(
    earth, 0.3, 22000, 1, 0, 0, 0, 0
)

-- Makes a part to show the spacecraft's position.
function CreateSpacecraftPart()

    -- Create part to match
    local part = Instance.new("Part")
    part.Anchored = true
    part.Color = Color3.new(1,0,0)
    part.Name = "Spacecraft"
    part.Size = Vector3.new(1, 1, 1)
    part.Shape = Enum.PartType.Ball
    part.TopSurface = Enum.SurfaceType.Smooth
    part.BottomSurface = Enum.SurfaceType.Smooth
    part.Position = Vector3.new(0,0,0)
    part.Parent = game.Workspace

    return part

end

-- Part for spacecraft
local spacecraftPart = CreateSpacecraftPart()


-- Positions the spacecraft based on the current time.
function PositionPartBasedOnPrediction(orbit: table, part: BasePart, currentTime: number)

    -- Get the predicted true anomaly
    local trueAnomaly = orbit:UniversalPrediction(currentTime, TOLERANCE)

    print(trueAnomaly)

    -- Get ECI position from true anomaly
    local currentPosXEci, currentPosYEci, currentPosZEci =
        orbit:GetPositionVelocityECI(trueAnomaly)

    -- Convert ECI position from OrbitLib reference vectors
    -- to Roblox reference vectors
    currentPosXEci, currentPosYEci, currentPosZEci =
        OrbitLibToRoblox(currentPosXEci, currentPosYEci, currentPosZEci)

    -- Convert from kilometers to Roblox studs from
    -- our arbitrary conversion factor
    currentPosXEci = currentPosXEci * oneKilometerEqualsStuds
    currentPosYEci = currentPosYEci * oneKilometerEqualsStuds
    currentPosZEci = currentPosZEci * oneKilometerEqualsStuds

    -- Position part
    part.Position = Vector3.new(currentPosXEci, currentPosYEci, currentPosZEci)

end


-- A handler for the Heartbeat event. The argument step contains the time since the last frame.
function OnHeartbeat(step: number)

    currentTime += step * timeAcceleration

    PositionPartBasedOnPrediction(orbit, spacecraftPart, currentTime)

end
game:GetService("RunService").Heartbeat:Connect(OnHeartbeat)

Here’s a low quality screenshot of my output currently.

1 Like

hey,i got some errors,could you show the output more clearly,i wanna see if the error is same as mine

1 Like

Here it is. Glad I’m not the only one.

1 Like

i dont know why that happens,its not my same error,you should ask the creator for help
i did your code,it works fine

1 Like

That’s odd. I’ll see if I can find a newer version.

1 Like

For the first issue here, you definitely installed the library incorrectly. Please check the module names, there is no module called PhysicsConstraints nor LuaMath2D. There is a PhysicsConstants and a DoubleMath2D module, did you make a typo?

For the second issue, it is important to note that the Renderer article’s concepts build on top of one another. It doesn’t look like you have the conversion functions included in your source:

-- Convert from Roblox coordinates to OrbitLib coordinates.
function RobloxToOrbitLib(x: number, y: number, z: number)
    return x, -z, y
end

-- Convert from OrbitLib coordinates to Roblox Coordinates.
function OrbitLibToRoblox(i: number, j: number, k: number)
    return i, k, -j
end

This is making the elements of the current ECI position nil, which is floating down the fromKeplerianElements constructor.

1 Like

BestOrbits.rbxl (66.3 KB)

in case you want here is my fully installed rbxl

2 Likes

i may have found a bug where putting semi major as negative value doesnt make the spacecraft fly… i want negative values so i can make things orbit the other way etc

Kinda cool to see someone using my library correctly. Looks awesome!

One suggestion: For your rotational controls, you might want to consider representing the slider in degrees and then converting to radians for use with the library. While the library uses radians because radians have much more mathematical meaning than degrees (radians are based on properties of a circle whereas degrees are arbitrary), humans understand degrees more intuitively.

1 Like

Thanks it fixed the weird orbital plane glitch which i was lazy to fix lol
does putting timeacceleration to 1 make it go real time?

A negative semimajor axis will never be supported as that does not have meaning. The semimajor axis ultimately represents a distance on a euclidean plane, and at least in conventional geometry it doesn’t make sense to have a negative distance.

The direction of orbit is not controlled by the semimajor axis; the semimajor axis just defines the shape.

In astrodynamics, we have a term for orbital direction. A counterclockwise orbit is a prograde orbit, and a clockwise orbit is retrograde. The orbital direction is determined from the inclination.

Let i = inclination.

Inclination is usually defined in the range [0, π]

When 0 < i < π/2, the orbit is prograde.
When π/2 < i < π, the orbit is retrograde.

ahh now i get it,yeah it definetely doenst make sense to have -distance