I need to make a model of a stereotypical atom. I built the nucleus, and I tried a few "Body" objects, like BodyForce, BodyPosition, BodyGyro, you get the gist.
I don't think this requires much scripting, if any. I think I just need to play around with the variables. I just need someone to point me in the right direction.
From a force perspective, "oribts" happen because there is a strong inward force happening. In particular,
ma = v^2 / r
where m
is the mass, a
is the acceleration (so ma = F
, force), r
is the radius and v
is the velocity.
If you're in a stable orbit, r
and v
are constant. m
will also be constant.
(Neglect gravity:) If we compare this to, for instance, a BodyPosition, we know that the force applied will be precisely inward, and since the distance isn't changing the force applied will be constant. So we just need to get the right amount of push inwards (in addition to compensating for gravity with a BodyForce upwards)
In practice, that won't work at all, though. The errors will accumulate and it will just sporadically orbit around.
Instead, we should probably manage the orbit directly -- no body objects at all, and just set the CFrame of the orbiting (anchored) object.
We can make a circle using cos(t), 0, sin(t)
:
-- (nucleus is some part) -- (elec is some part) -- (radius in studs the radius of the orbit) while wait() do local t = tick() * (math.pi * 2) * 1.5 -- 1.5 revolutions per second local orbit = Vector3.new( math.cos(t), 0, math.sin(t) ) elec.CFrame = CFrame.new( nucleus.Position + orbit * radius ) end
This will only make a flat orbit, though. If we want orbits at other angles, we should just think in a different way. The above math is equivalent to this:
local orbit = Vector3.new(1, 0, 0) * math.cos(t) + Vector3.new(0, 0, 1) * math.sin(t) elec.CFrame = CFrame.new( nucleus.Position + orbit * radius )
The important property here is that Vector3.new(1, 0, 0)
and Vector3.new(0, 0, 1)
are perpendicular.
In order to get random perpendicular vectors, we could do something crazy like this:
function randomVector() -- returns a random vector in the unit sphere local x repeat x = Vector3.new( math.random()*2-1, math.random()*2-1, math.random()*2-1) until x.magnitude <= 1 return x -- We need it to be in the unit *sphere* so that we don't get -- unfair biases towards the corners. -- It will still "work" if we just went with the Vector3 we make -- inside of the repeat, but it will prefer certain -- orbits to others for no reason. end function randomPerpendicularPair() local a = randomVector() local b = randomVector() return a:Cross(b).unit, b.unit -- a:Cross(b) (the cross product of a and b) is -- in the direction that is perpendicular to both -- a and b -- Thus b and a:Cross(b) are perpendicular. end local u, v = randomPerpendicularPair() while wait() do local t = tick() * (math.pi * 2) * 1.5 local orbit = u * math.cos(t) + v * math.sin(t) elec.CFrame = CFrame.new( nucleus.Position + orbit * radius ) end
You're referring to the Bohr model which is at least useful to use for properties, but of course, like most models taught in school, is completely inaccurate (physically speaking).