Gravity Simulator

I’ve been trying to make something that can simulate gravity, but I’m having two problems:

  1. I know nothing about physics. I can make people move towards a certain point, but I don’t know how to realistically simulate the physics involved.

  2. How do I allow a person to walk at an angle or upside down?

  1. If by simulating gravity you mean disabling default Source gravity and then making your own Lua controlled gravity, that can be done easily with a think hook and some velocity changing. Of course there is some kind of PhysicsSimulate funciton out there but I dont know anything about it, so I couldnt help you there .

  2. Source engine doesnt allow full rotation, but you could try enabling a CalcView once the player hits the top of his screen, then whenever the mouse is moving up you can just hijack the angles of the CalcView to simulate going up. Of course CalcView just simulates the view, and doesnt actually make you turn, plus if you tried shooting, you’d just be shooting straight up/down instead of shooting at where the CalcView is. So that probably wouldnt be a good solution unless you’re using it for singleplayer and no shooting involved. If you want to do multiplayer and have guns, I guess instead of hijacking the view, you could do SetAngles() and just add an angle to pl:GetAngles().

Quite a pain in the ass just to get the fucker to rotate, doesnt it seem :confused:

**[Player.SetAllowFullRotation

http://wiki.garrysmod.com/favicon.ico](http://wiki.garrysmod.com/?title=Player.SetAllowFullRotation)**

Lets you adjust the angles of the player freely.

I used a parent in my swep. It works nice, but the camera is fucked up.

Ok, so full rotation will help make it look like they’re actually doing things, but how do I make a player actually walk sideways rather than just look sideways?

Err, fixed a few problems, but here’s my resultant mathematical problem: I want to have a prop use a “baseline” velocity, so it should always go at least a certain speed towards the center of gravity, but if I just say SetVelocity( GetVelocity + Direction ) then it will just keep increasing its speed. What’s the way I’m looking for here, or does that even make sense?

you seem to know much more on this subject then I do. Can you help me with my SWep?
http://www.facepunch.com/showthread.php?t=900710

Only moves the player’s world model, does nothing to the view.

[editline]04:05AM[/editline]

So you want it to always be moving toward the center of gravity? Uh…

You’d want to do:
[lua]
pl:SetVelocity(VECTOR_GRAVITYCENTER * (FLOAT_SPEED - pl:GetVelocity())
[/lua]

Sets the velocity towards the vector position, then cancels out the player’s current velocity so hes always going at a steady rate. Had to do this in my freerunning script :downs:

So what would FLOAT_SPEED be? You seem to be subtracting a vector from a float, which doesn’t make much sense.

FLOAT_SPEED is whatever baseline speed you want the player or entity to be moving at. And about the subtracting Vector from a Float thing, thats my bad, lemme re-write:

[lua]
pl:SetVelocity((VECTOR_GRAVITYCENTER - pl:GetVelocity()) * FLOAT_SPEED)
[/lua]

There, I think that should work… I think… :science:

OK. Starting from the top. Here’s what I have:

[lua]GRAV = {}
GRAV.Centers = { { point = Vector(100,100,1000), strength = 1}, { point = Vector(500,100,700), strength = 1}, { point = Vector( 200, 300, 1200) , strength = 1 } }
GRAV.Speed = 0.3
GRAV.Radius = 2500

if SERVER then

function GRAV:Initialize()
	
	for _,v in pairs( ents.GetAll() ) do
		local phys = v:GetPhysicsObject()
		if IsValid( phys ) then
			phys:Wake()
			v:SetGravity( 0.00000001 )
		end
	end
	
	hook.Add("Think","GRAVDoGravity",function()
		for _,v in pairs( ents.GetAll() ) do
			local phys,dir = v:GetPhysicsObject()
			if not v:IsPlayer() and IsValid( phys ) then
				local valid_points = {}
				local dist
				for _,grav in pairs(self.Centers) do
					if v:GetPos():Distance( grav.point ) <= self.Radius * grav.strength then table.insert(valid_points,grav) end
				end
				local vel = Vector(0,0,0)
				for _,grav in pairs( valid_points ) do
					dist = v:GetPos():Distance( grav.point ) 
					vel = vel + ( grav.point - v:GetPos() - phys:GetVelocity()  ) * self.Speed * math.Clamp( ( self.Radius * grav.strength - dist )  / ( self.Radius * grav.strength ) + 0.2, 0, 1 ) * grav.strength
					debugoverlay.Cross( grav.point, 15, 0.05, color_white, true )
					//debugoverlay.Sphere( grav.point, self.Radius * grav.strength, 0.03, color_white, false )
				end
					
				phys:SetVelocity( vel )
			end
		end
	end)
	
end
	
GRAV:Initialize()

end[/lua]

When I had two points with a strength of 2 and 3 respectively, it worked fine. The ball would go closer to one point than the other.

However, with three points if I add too much to the strength or set GRAV.Speed to 0.5 like it used to be the ball begins to spazz out. What’s the cause of this and how would I fix it? (I’m not really familiar with this kind of stuff…)

For players, I would use the move hook. That way you don’t need to do any hacky SetVelocity addition.

I’ll probably use the Move hook for players, yeah, but that wouldn’t solve the problems about props. I don’t understand what’s making them spazz out.

Maybe you’re adding velocity rather than renewing it?

I haven’t read through the thread so I may be late/wrong, but wouldn’t it be better to apply a force rather than set the velocity, this way you could work out the force to apply using proper physics equations like:


Force = GMm/r^2

Ah, I had entirely forgotten about apply force. I have little background in physics - what are the variables in that equation?

G is the gravitational constant, which is 6.67300 × 10^-11
M and m are the masses of the bodies
r is the distance between them

[editline]07:46PM[/editline]

You may need to adjust the gravitational constant considerably to get the desired effect, because the masses that you will be using are much smaller than the ones that this equation is used for.

[editline]07:54PM[/editline]

Don’t do this when you get the distance squared:

[lua]local r2 = ent2:GetPos():Distance(ent1:GetPos()) ^2[/lua]

that is essentially square rooting and rooting again. Do this instead:

[lua]local r2 = (ent2:GetPos() - ent1:GetPos()):LengthSqr()[/lua]

Ok, thanks. I got it working pretty well for a single point (it actually orbits the point).

So here’s what I have so far:

[lua]hook.Add(“Think”,“GRAVDoGravity”,function()
for _,v in pairs( ents.GetAll() ) do
local phys = v:GetPhysicsObject()
if not v:IsPlayer() and IsValid( phys ) then
local valid_points = {}
local dist
for _,grav in pairs(self.Centers) do
if v:GetPos():Distance( grav.point ) <= self.Radius * grav.mass / 10000 then table.insert(valid_points,grav) end
end
local force,vel = 0,Vector(0,0,0)
for _,grav in pairs( valid_points ) do
dist = v:GetPos():Distance( grav.point )
vel = vel + ( grav.point - v:GetPos() )
force = force + 6.67300 * 10e-3 * grav.mass * phys:GetMass() / ( math.pow(dist,2) )
debugoverlay.Cross( grav.point, 15, 0.05, color_white, true )
end

		if valid_points[1] then
			phys:ApplyForceCenter( vel * force )
		end
	end
end

end)
[/lua]

So from here: would that correctly calculate the approximate force given two centers of gravity with different masses?

And, I have a default radius for gravity as 2500 ( times the mass / 10000 ). Do y’all think I should make that bigger/smaller?


v:SetGravity( 0.00000001 )

Not as good as:


 v:EnableGravity(false)

You should also use a force. I’m not sure on the math, so I won’t try to mislead you. I’ll probably have to do this myself at some point, so I’ll be back when I get around to it, if you haven’t already resolved your problem.

It’s worth noting that using PhysicsSimulate is actually very easy. I’m already doing gravity simulation for another project. You can apply forces inside it at will, and it gives you the physics object and the deltatime. Just return zero vectors with SIM_LOCAL_FORCE if you don’t want to do anything with the forces it gives and you want to apply your own. I use the apply force functions for my gravity, and return angular torques (I prefer torques over AddAngleVelocity). PhysicsSimulate also seems to run at a different speed than, say, think.

For the gravity, I just decided to do physenv.SetGravity( vector_origin ). Also, isn’t PhysicsSimulate a custom entity hook? I need this to work for all entities on a map.

I don’t think you should have a limit to the distance that gravity effects other entities, the equation is divided by distance squared, meaning that the gravity should drop off pretty rapidly as the distance increases.