How can I toggle the gravity controller so seats will work
Using the new GitHub version; how can I add to the IgnoreList // Whitelist?
I.E. The gravity only kicks in on Parts called: “FloorPart” ?
Thanks so much ! I was wondering if anyone had any idea how to get this to work with only focusing on the humanoidrootpart so I could use it with custom morphs? I was messing around with it for a bit, but I’m not entirely sure what parts of it I could adjust to get the script to work with anything that isn’t R15 or R6.
This controller has been a huge help in my space game, but is there anyway to bring the physics simulation server-side? I want to be able to have physics parts stick to moving objects, and it would also help the server control the player character a bit more to help prevent exploits.
How can I disable either of the modules and then enable them again?
Yes I think so. How did you do it?
I would actually like to know how this was done too.
- Edit the game in studio, Gravity Controller - Roblox
- Find the
LocalScript
inStarterCharacterScripts
- Uncomment the code starting from line 124:
If you press K
, it will toggle the gravity controller between “normal” and “wall stick” mode.
Explanation:
The line that enables the “wall stick” mode:
Controller = GravityController.new(game.Players.LocalPlayer)
The line that disables it:
Controller:Destroy()
There is a problem regarding shift lock. When I turn with shift lock the character is a little delayed is there any way to fix this?
It’s b/c I have to emulate shift lock w/ a body mover. You can try going in the code and tuning the body mover, but it’ll probably always feel slightly off from standard shift lock.
Oh okay thanks but which script is it in? Because if that’s so is there anyway to disable it?
EgoMoose, do you see any reason why I might run into trouble replacing the gravity controller BodyGyro with an AlignOrientationConstraint?
I did mostly get what I needed from the Wallstick controller, but I wanted to see if using the gravity controller would be a better fit. I haven’t figured out yet exactly what I loose by not having the re-oriented cloned phantom physics world.
In my game, workspace.Gravity is 0 and there is custom gravity logic that places a VectorForce on any non-anchored non-massless assembly to push it where it belongs. I tied a custom UpVector callback to GravityController, and it’s working pretty good.
I also have things like grappling hooks and jetpacks which use other physics constraints to do their thing. I have run into certain bugs when the HRP with the BodyGyro is mechanically attached to another assembly by some constraint, where server and client disagree on the HRP position and the only thing that fixes them is to remove the BodyGyro.
I’m planning on hacking an AlignOrientationConstraint in it’s place, which is what I’m using on other objects that need to right themselves in the custom gravity.
Aside from the fact that it’s just more intuitive to use as a BodyGyro, is there any other shortcoming to the constraint system that led you to chose the gyro? Is there anything I’m going to be missing by using the constraint instead?
I’ll let you know how it works out, but I’d love any warnings if I’m about to do something that just won’t work.
I can’t think of any reason off the top of my head that the orientation constraint wouldn’t work. I probably chose to use a gyro b/c it’s faster to instance as opposed to creating 2 attachments + the constraint.
I’m having a bit of an issue with the Wallstick controller. Everything is vanilla, and I’m even using the unmodified “Boots” module from the test place. I’d like to add a modification to the system that allows for a constant acceleration to everyone’s HumanoidRootParts, and I can’t quite get it working right because in Wallstick generalStep() you always set the velocity back to 0 before adding on the Physics.HRP.Velocity. I don’t quite understand how I would add this acceleration to Physics.HRP.Velocity since the desired acceleration is a world coordinate, and it seems like Physics.HRP.Velocity very much isn’t… How would I go about accomplishing this? Got any tips?
Swapping to the align constraint in the gravity controller from the gyro was pretty straightforward and solved some of my problems.
I had already solved some of them by switching to instantiating the parts on the server for replication purposes, but the gyro just didn’t want to play along.
In my previous vehicle gyros, I parented the attachment1 to workspace.Terrain, modifying the attachment.WorldAxis. Working on a hunch it will replicate and synchronize better, for the gravity controller gyro replacement, I created a align target part on the server and give ownership to the player.
I actually like this better because it also provides a visualization of what the alignment is trying to do. I’ll try to post some video later so I can ask the follow up question.
I just left the attachment in the proxy Part instance at zero rotation and orient the part cframe as the gyro cframe would have been.
Code, if you’re curious what I did.
Swap out gyro for align using proxy part ended up being a clean change:
local vForce = Instance.new("VectorForce")
vForce.Force = Vector3.new(0, 0, 0)
vForce.ApplyAtCenterOfMass = true
vForce.RelativeTo = Enum.ActuatorRelativeTo.World
vForce.Attachment0 = attach
vForce.Parent = hrp
local gyro = nil --[[Instance.new("BodyGyro")
gyro.P = 25000
gyro.MaxTorque = Vector3.new(100000, 100000, 100000)
gyro.CFrame = hrp.CFrame
gyro.Parent = hrp]]
sphere.Parent = model
floor.Parent = model
floor2.Parent = model
model.Name = colliderName
model.Parent = character
local alignBlock = Instance.new("Part")
alignBlock.Name = player.Name .. "_OrientationTarget"
alignBlock.CanCollide = false
alignBlock.Massless = true
alignBlock.Transparency = 0.5
local face = Instance.new("SurfaceSelection", alignBlock)
face.Adornee = alignBlock
face.TargetSurface = Enum.NormalId.Front
local attAlignTarget = Instance.new("Attachment", alignBlock)
attAlignTarget.Name = player.Name .. "_OrientationAttachment"
local align = Instance.new("AlignOrientation")
align.Name = player.Name .. "_AlignOrientation"
align.Attachment0 = attach
align.Attachment1 = attAlignTarget
align.PrimaryAxisOnly = false
align.MaxTorque = 100000
align.Responsiveness = 60
alignBlock.Parent = character
align.Parent = hrp
alignBlock:SetNetworkOwner(player)
--alignBlock.Anchored = true
So the cframe that was driving the gyro can go to the proxy part instead:
function ColliderClass:Update(force, cframe)
self.VForce.Force = force
if self.Gyro then
self.Gyro.CFrame = cframe
end
if self.AlignBlock then
self.AlignBlock.CFrame = cframe
end
end
I suspect that animating the proxy part cframe every heartbeat is not going to always look the best to the server and other clients. I think long term I’m either going to tween updates based on a delta epsilon. Or use another align constraint to gently control the orientation of the proxy part if that replicates better.
It actually is starting to look to me like I’m heading toward needing a custom client prediction layer so player movement is smoother and more consistent from the perspective of the server and other clients.
For now, I just added HRP position to the manual orientation cframe animation your stock gravity controller does:
local function onGravityStep(self, dt)
-- no changes until the end:
local charRotation = CFrame.new(self.HRP.Position) * newCharRotation * newCharCF
self.StateTracker:Update(self._gravityUp, self._collider:IsGrounded(false), isInputMoving)
self._collider:Update(walkForce + gForce, charRotation)
end
Anyway, it works mostly.
Thanks for all the amazing work you’ve done with character controllers.
When I get videos up to show what is not quite working, I’ll have to ask for some advice.
Gratuitous details
To minimize changes to your GravityController, I created a factory module to allow the collider to be created on server or client. I’ll try to push it up to my github fork later.
GravityController keeps a reference to it:
local Collider = require(script:WaitForChild("Collider"))
local StateTracker = require(script:WaitForChild("StateTracker"))
local ColliderPartFactory = require(script:WaitForChild("ColliderPartFactory"))
and lower down
-- mgm ServerInstanceCreate Refactor
GravityControllerClass.ColliderPartFactory = ColliderPartFactory
Collider has:
--[[ mgm ServerInstanceCreate Refactor : ]]
function ColliderClass.CreateColliderModel(gravCollider, gravController)
local player = gravController.Player
local model, sphere, vForce, floor, floor2, gyro, alignBlock, format
= table.unpack(gravController.ColliderPartFactory.GetOrCreateColliderModel(player))
In the gravity control tool:
local GravityControllerClass = require(ReplicatedStorage:WaitForChild("GravityController"))
local gravityController = nil
GravityControllerClass.ColliderPartFactory.GetOrCreateColliderModel = function(player)
ArkClient.SendServerMessage("CreatePlayerGravityCollider", Players.LocalPlayer)
--GravityControllerClass.ColliderPartFactory.CreateColliderModelParts(player)
return GravityControllerClass.ColliderPartFactory.GetModelFromServer(player)
end
To override the behavior to send a message to the server and wait.
The actual model creation function can be called on client or server, but server works for my purposes.
ColliderPartFactory:
function ColliderPartFactory.CreateColliderModelParts(player)
local humanoid, hrp, character = WaitForPlayerHumanoidAndRootPart(player)
local hipHeight = getHipHeight(humanoid)
local attach = getAttachement(humanoid, hrp)
local colliderName = "Collider"
if character:FindFirstChild(colliderName)~=nil then
return ColliderPartFactory.WaitForColliderModelParts(character, colliderName, hrp)
end
local model = Instance.new("Model")
local sphere = Instance.new("Part")
sphere.Name = "Sphere"
sphere.Massless = true
sphere.Size = Vector3.new(2, 2, 2)
sphere.Shape = Enum.PartType.Ball
sphere.Transparency = 1
sphere.CustomPhysicalProperties = CUSTOM_PHYSICAL
local floor = Instance.new("Part")
floor.Name = "FloorDectector"
floor.CanCollide = false
floor.Massless = true
floor.Size = Vector3.new(2, 1, 1)
floor.Transparency = 1
local floor2 = Instance.new("Part")
floor2.Name = "JumpDectector"
floor2.CanCollide = false
floor2.Massless = true
floor2.Size = Vector3.new(2, 0.2, 1)
floor2.Transparency = 1
local weld = Instance.new("Weld")
weld.C0 = CFrame.new(0, -hipHeight, 0.1)
weld.Part0 = hrp
weld.Part1 = sphere
weld.Parent = sphere
local weld = Instance.new("Weld")
weld.C0 = CFrame.new(0, -hipHeight - 1.5, 0)
weld.Part0 = hrp
weld.Part1 = floor
weld.Parent = floor
local weld = Instance.new("Weld")
weld.C0 = CFrame.new(0, -hipHeight - 1.1, 0)
weld.Part0 = hrp
weld.Part1 = floor2
weld.Parent = floor2
local vForce = Instance.new("VectorForce")
vForce.Force = Vector3.new(0, 0, 0)
vForce.ApplyAtCenterOfMass = true
vForce.RelativeTo = Enum.ActuatorRelativeTo.World
vForce.Attachment0 = attach
vForce.Parent = hrp
local gyro = nil --[[Instance.new("BodyGyro")
gyro.P = 25000
gyro.MaxTorque = Vector3.new(100000, 100000, 100000)
gyro.CFrame = hrp.CFrame
gyro.Parent = hrp]]
sphere.Parent = model
floor.Parent = model
floor2.Parent = model
model.Name = colliderName
model.Parent = character
local alignBlock = Instance.new("Part")
alignBlock.Name = player.Name .. "_OrientationTarget"
alignBlock.CanCollide = false
alignBlock.Massless = true
alignBlock.Transparency = 0.5
local face = Instance.new("SurfaceSelection", alignBlock)
face.Adornee = alignBlock
face.TargetSurface = Enum.NormalId.Front
local attAlignTarget = Instance.new("Attachment", alignBlock)
attAlignTarget.Name = player.Name .. "_OrientationAttachment"
local align = Instance.new("AlignOrientation")
align.Name = player.Name .. "_AlignOrientation"
align.Attachment0 = attach
align.Attachment1 = attAlignTarget
align.PrimaryAxisOnly = false
align.MaxTorque = 100000
align.Responsiveness = 60
alignBlock.Parent = character
align.Parent = hrp
alignBlock:SetNetworkOwner(player)
--alignBlock.Anchored = true
return {
model,
sphere,
vForce,
floor,
floor2,
gyro,
alignBlock,
"model,sphere,vForce,floor,floor2,gryo,alignBlock",
}
end
Nevermind, I fixed the issue.
For some reason anytime I changed the physics HRP velocity directly, it would only change on the Y axis. This was really annoying, but I found I could get around it by putting bodyvelocities and bodyforces in the physics HRP itself. I could disable these within the :Set function so they didn’t interfere with the wallstick physics.
The HRP, or the physics world HRP?
I didn’t get good results on the standard chatter model HRP.
The physics world one works with all sorts of body movers just fine, you just need to make sure you disable them anytime you want the wallstick behavior to work properly.
Using constraints, I did not have to disable them. My gravity is 100% artificial, so the physics world HRP would just float in space if the VectorForce was disabled.
I just had to translate the vector to physics world space.