Making a hover board

Yeah, that is how I got my calculation for the time. From the equation 0 studs/sec = a * t + v we get t = -v/a.

Looking at it I think I may have used -g in some places and g in others… I think this did lead me to an untruthful equation. I’ll fix it and repost.

As for ∆h, it seems to match the definition I gave it here:

Btw I meant to say uA not ∆h

I feel like that’s wrong because you are assuming max acceleration(?) as uA but in reality it should be the current acceleration, which also happens to be what you are solving for?

Look at my code it has spring mechanics already

I did
Damping the velocity seems more like a hack to me because I think you can’t dampen in real life?
Also why do you use self so much xd? Is it cuz u dont want to think of a variable name or what

I just use it because it is highlighted differently so I can clearly see references to the object itself and the damping and whatever is straight from roblox calcs and it is using a force not a spring/shock setup

Okay, I got a solid solution. I’ll write it more verbose this time:

given
velocity studs/sec = acceleration studs/sec2 * t sec + init_velocity studs/sec
then when the desired velocity is zero:
0 studs/sec = acceleration studs/sec2 * t sec + init_velocity studs/sec
solving for the time to reach this desired velocity given any acceleration and initial velocity:
t sec = -(init_velocity studs/sec) / (acceleration studs/sec2) = -init_velocity / acceleration sec

And given
distance studs = 1/2 * acceleration studs/sec2 * (time sec)^2 + velocity studs/sec * time sec
We can find the required acceleration to travel a desired distance while arriving at our desired velocity at the same time by substituting time as solved above:
distance studs = 1/2 * acceleration studs/sec2 * (-init_velocity / acceleration sec)^2 + init_velocity studs/sec * -init_velocity / acceleration sec
Giving shorter aliases to clean this up, we get:

d = a/2 * (-v / a)^2 + v * (-v / a)
-> d = a * v^2 / (2 * a^2) - v^2 / a
-> d = v^2 / (2 * a) - v^2 / a
-> d / v^2 = 1 / (2 * a) - 1 / a
-> d / v^2 = 1 / (2 * a) - 1 / a
-> d / v^2 = -1 / (2 * a)
-> -2 * d / v^2 = 1 / a
-> a = -v^2 / (2 * d)

which expands back out to:

acceleration studs/sec2 = -(init_velocity studs/sec) ^ 2 / (2 * distance studs)
-> acceleration studs/sec2 = -(init_velocity ^ 2 studs2/sec2) / (2 * distance studs)
-> acceleration studs/sec2 = -init_velocity ^ 2 / (2 * distance) studs/sec2

And there we have it. Given any initial velocity and distance to cover, we can find the acceleration required to simultaneously cover the distance and cancel out our velocity at the same time. Applying these general concepts to this application is fairly straight forward, so I’ll leave it to you.

Edit: here is an article I found on it. The equations match.

5 Likes

you have your own damper to decay the force too so you are damping the bodythrust on top of the bodythrust.D property: local f = -stiffness*len-damping*self.Velocity:Dot(self.CFrame.rightVector)

also you use self as variable names for roblox instances (the “Hover” part), can you elaborate on why? (i think its kinda clean so I might wanna start doing it ;P)

And Body Thrusts do not have any damping. The script is also designed to make it so that the hoverpad does not push down toward the ground and instead falls (only applying levitational forces) and it also is a lot more stable than roblox springs. You also need to make multiple hoverpads and not hovergroups to keep the same config (welding together or etc should be fine). Theyre designed so that you could slap invisible ones on a car object (given the config is appropriate) and it would float.

2 Likes

Okay, I will try implementing this and let you know how it goes
My confusion with this method before was that I felt like it was relying on acceleration to find acceleration in that from the velocity equation you are finding T based on acceleration then you are using the T (which is based on acceleration) to find acceleration
I thought that this meant it was an iterative solution but I realize now that I was completely wrong because (this is the reason I think I was wrong, if I’m mistaken please correct me) you’re using the variables at the same time step to solve for the two unknowns, T and a - albeit you don’t care about T but you have the right amount of degrees of freedom with two equations and two unknowns

So ya, thanks :smiley:

this doesn’t really work because you are solving for the time at which you make the velocity 0, and if the velocity is already 0, you wont move at all (even though you may not be at the desired height)

um no im solving for the spring force.
i thought that was extremely obvious considering a bodythrust applies a local force…
and being at the desired height does not matter, just raise the height or the stiffness and it will be more accurate.

This is mostly true… If we apply it like so:

Then gravity will continue to accelerate the board down until the last moment the board can pull out of it with the desired maximum force. Now that is an intelligent board! While it is possible to create an equation to tell us when we need to apply the upward thrust instead of an equation that is checked every frame, if external forces act on the board then the time to apply the upward thrust will change. Checking every frame seems like a less stateful and therefor less bug prone approach to me.

mine checks every frame also to adjust the force and that is how a hoverboard works, it applies force with magnets or something of the sort against the floor. The force increases with more weight so

I’ll try yours if Idiomic’s solution doesn’t work, his seems more interesting though which is why I want to see if it works

@IdiomicLanguage when I get home from school I’ll give a more detailed reply and post how I am applying the equations-sorry for the wait

Heres what I’m doing

local ignore=env.Ink.Black{workspace.Debris}
local cast=env.Spatial.Cast
local v3=Vector3.new
local cf=CFrame.new
local height=5
local maxaccel=1000

local board=script.Part:Clone()
board.Parent=workspace.Debris

local mover=board.VectorForce
local move=board.Move
move.Position=v3(0,0,0)

env.Beat:Connect(function(dt)
	local p=board.Position
	local hit,h,n=cast(p,-move.WorldAxis*1000,ignore)
	local a=math.clamp(-board.Velocity.Y^2/(2*(height-(h-p).Magnitude)),-maxaccel,maxaccel)
	
	mover.Force=v3(board:GetMass()*a,0,0)
end)

I’m running at heartbeat to incorporate the newly applied gravity as part of the velocity

This doesn’t really work though:
https://gyazo.com/c1c6eb65353ddd9bb82300671d4de890.gif

Could you explain what all of these variables are?

I’m envisioning something more like this:

local g = v3(0, -196.2, 0)
local maxAccel = v3(0, 500, 0) - g
local stopping = false

local function getRequiredYAccel(v, h)
  return -v * v / (2 * h)
end

env.Beat:Connect(function()
  local acceleration

  ... -- include code for x and z [de/a]cceleration

  if curHeight > maxHeight then
    if stopping or getRequiredYAccel(board.Velocity.Y, curHeight - maxHeight) > maxAccel.Y then
      stopping = true
      acceleration = acceleration + maxAccel
    end
  else
    stopping = false
    acceleration = -(g + board.Velocity)
  end

  mover.Force=v3(board:GetMass()*a,0,0)
end

thats the delta h you need to travel
height is desired offset from ground (constant),p is the board position,h is the ground position (raycast)

also your code has a lot of typos, like you’re declaring acceleration within heartbeat but then you’re incrementing it in currHeight>maxHeight branch

also do you mean to write this?
mover.Force=v3(board:GetMass()*acceleration,0,0)

If the board is 15 studs high, the ground is 10 studs below that, then depending on if the function you supplied returns the distance to the ground as positive or negative we get (h - p).magnitude = -5 or -25 assuming that h and p will always have the same x and z coordinates. If the desired height is at 10 studs above ground, then height - (h - p).Magnitude = 15 or 35, neither of which is the correct distance from the current height to the maximum height above ground. That may be part of the reason why the code didn’t work.

Defining it inside of heartbeat was not a mistake. The acceleration that needs to be applied to the board should be recalculated every heartbeat. I don’t want to keep around the old variable from the last run to store state which could cause bugs down the road if the code was changed improperly.

Yes. I did make a mistake here. a should have been acceleration.

Have you attempted to make the hoverboard using this method again?

Your code is too buggy, I’ll just use springs :confused:

wow thanks!!!