Awesome work, I have one question though. How did you do the force gravity change and are you using wallstick of gravity controller.
Thanks, I’m using gravity controller.
What exactly do you mean by the force of gravity?
At first I thought you were using wall stick because when the play falls off they immediately fall back to normal gravity. I want to know how you managed that because it doesn’t work with normal gravity controller from the copied game.
What do you mean by “repeat them?” can you give a more detailed explanation?
That’s part of the controller, just change the drop distance at which gravity is restored. It’s this part here:
RUNSERVICE.Heartbeat:Connect(function(dt)
local height = Controller:GetFallHeight()
if height < -50 then
Controller:ResetGravity(Vector3.new(0, 1, 0))
end
end)
I used heartbeat to create a table that contains the position and orientation of each part of the player while I am crossing the obstacle, this table is saved in DataStore. When the obstacle first appears in the game the server downloads it and stores it in a cache for use it every time the obstacle reappears. When the player talks to the dummy the server sends the table to the client and I use heartbeat again to read it and give the dummy a fluid movement, basically it’s a replay.
I made my own code to do this, but there is a module that does all this, it didn’t work for me, but the idea definitely came from there
Very much interested also. My spider morphs need to be able to climb walls again. Thanks
Where can I find the latest version that has the ability to be enable and disabled, that I can apply these changes to, to get it working?
Thanks
EgoMoose hasn’t accepted the pull request yet. If you want the code, my proposed quick fix is here:
My main branch also gets rid of the need to use the CameraInjector and setfenv, which is probably a better fix in the long run.
I’ve been working on a refactor that I think will be less likely to break going forward, that create a separate UpVectorCamera module that doesn’t require the CameraModule injector and wraps the BaseCamera instead. I used that as an excuse to update the code some, add in --!strict luau Script Analysis, and just make sure everything has kept up with the last couple camera controller api changes.
I’ve been wanting to publish that and it got away from me a little. Script Analysis opened a can of worms. Hopefully I can share the refactor/rework version soon and see what EgoMoose thinks of it
Sorry to ask this, as I feel everyone gets the whole 'GitHub, branches, submissions, pulls, etc… But I just don’t really understand all of that.
So, dumb question… if I have the Gravity Controller from here…
where do I get the code that needs to be changed to get it to work?
I see you posted two links, but isn’t that for the ‘Wall Stick’ controller, which uses a de-rotated copy of the world?
I was needing the one where gravity is changed.
Thanks.
OK, I’ll show you exactly what you need to change, but I’ll start with how to find the change.
The code change for Gravity Controller and Wallstick is basically the same:
- I added a workaround so we can obtain the local player’s CameraModule using lua trickery, then inject code to adjust the camera angle for our desired UpVector
- I fixed a missing parameter caused by Roblox changing TransparencyController:Update() to need dt that has been making camera control weird for a while now
If you look at the EgoMoose project:
Click on Pull Requests
Click on my pull request
Click on Files changed:
you see exactly what code you need to change:
If you just want to copy/paste overwrite the files instead of editing them, you can get a direct link to the modified CameraInjector lua code
And PlayerScriptsLoader
I am having an issue with the gravity controller, where, when active, I can’t step up on small parts (parts small enough that you can’t walk on their ‘walls’, and in normal walking you would be able to step up on them)
Anyone have any issues like this and know of a fix?
I haven’t forgotten about this. I promise I’ll take a look soon! I was traveling for RDC so I’ve been very busy as of late.
Can you set up a demo place that has the issue? I would take a look
If you have any feedback on the fix, I’d be happy to make some adjustments.
I’m curious if you have feedback about what it should do or where it should go in the future.
The pull request I sent does the minimum - fixes CameraInjector in all 3 repos. Should just work.
Gratuitous Pull Request Summary
(setfenv’s a setmetatable() in CameraModule .new and causes require(PlayerModule.CameraModule) to return the properly instantiated CameraModule singleton)
with that patch
- anyone using the old pattern should be able to continue overriding or calling methods of CameraModule
- it no longer needs FakeUserSettings and doesn’t rely on FFlag settings that can change and break things in the future.
- for Wallstick and Gravity Controller repos, also minor fix to camera glitch from missing dt parameter
I don’t think I tested it on mobile yet, but I did test on console.
That said, I won’t be relying on CameraInjector or overriding CameraModule in my own projects.
I’m warming up to the idea that Roblox yanking CameraModule out of our hands wasn’t such a bad move. Trying to replace CameraModule.Update has proven painful. I’ve been working up to posting on the CameraInjector thread about it. (their suggestion of forking is just as bad. anything near an FFlag is a landmine)
The follow up commit to my repo does not override CameraModule.Update. I tested an improved custom camera method I think will be safer and more reliable going forward by wrapping BaseCamera methods.
BaseCameraExtender method details
I have a BaseCameraExtender puts a proxy .Update() on any camera controller that extends BaseCamera.
- CameraModule.Update() calls activeCameraController.Update
( this will always be the injected BaseCamera Update method) - The injected method calls the official roblox corecript CameraController.Update, so futre changes to the implementation are unlikely to be a problem
- the (newCameraCFrame, newCameraFocus) returned from the active camera controller Update() are then adjusted for the current UpVector before being returned to the caller (CameraModule.Update())
What I would actually suggest is refactoring the custom camera overrides into a separate module. I created an UpVectorCamera module that can be used by both wallstick and gravity controllers that uses the BaseCameraExtender method.
UpVectorCamera and BaseCameraExtender module
I would like to release these as a standalone module, and credit you @EgoMoose for the base implementation, unless you have any other ideas.
As I moved the Egomoose camera override methods into UpVectorCamera, I compared them with diffs of the last few versions of roblox player scripts to make sure they were using properties and functions that are still valid.
The BaseCameraExtender lets you put any number of proxy method overrides on camera controller classes. Whenever a camera controller is enabled, the extender makes sure the overrides are on that controller.
The proxy method can modify the arguments, pass them to the camera controller method, then alter the results before returning them.
It doesn’t actually use CameraInjector or FakeUserSettings at this time, so I should probably them out. It’s better I don’t have to use them, but I’m just worried they might be needed in the future.
Since I’m not using them for now, there is no setfenv() happening, so the luau vm doesn’t have to disable optimizations due to 'dirty" environment.
UpVectorCamera exposes methods needed by wallstick or gravity controllers
function UpVectorCamera:GetUpVector(oldUpVector:Vector3)
return oldUpVector
end
function UpVectorCamera.SetUpVector(newUpVector:Vector3)
upVector = newUpVector
end
function UpVectorCamera:SetSpinPart(part)
spinPart = part
end
function UpVectorCamera:SetTransitionRate(rate)
transitionRate = rate
end
function UpVectorCamera:GetTransitionRate()
return transitionRate
end
function UpVectorCamera:IsCamRelative() : boolean
if activeCameraController then
return activeCameraController.inFirstPerson or activeCameraController.inMouseLockedMode
--return activeCameraController:GetIsMouseLocked() or activeCameraController:IsInFirstPerson()
end
return false
end
Internally, it passes camera controller proxy methods to BaseCameraExtender
local CameraExtensions = BaseCameraExtender:GetExtensionFunctions()
-- mgmTodo: Hook MouseLockController.new
local MouseLockController:types.MouseLockController = nil
function CameraExtensions:Update(dt:number, ...)
local cameraControllerMeta:BaseCamera = getmetatable(self) -- this is the underlying camera controller __index and metatable
local newCameraCFrame, newCameraFocus
= cameraControllerMeta.Update(self, dt, ...) -- get cframe and focus from underlying camera controller update
--return self:UpdateWithUpVector(dt, newCameraCFrame, newCameraFocus)
newCameraFocus = CFrame.new(newCameraFocus.p) -- vehicle camera fix
calculateUpCFrame(dt)
calculateSpinCFrame()
local lockOffset = Vector3.new(0, 0, 0)
if MouseLockController and MouseLockController:GetIsMouseLocked() then
lockOffset = MouseLockController:GetMouseLockOffset()
end
local offset = newCameraFocus:ToObjectSpace(newCameraCFrame)
local camRotation = upCFrame * twistCFrame * offset
newCameraFocus = newCameraFocus - newCameraCFrame:VectorToWorldSpace(lockOffset) + camRotation:VectorToWorldSpace(lockOffset)
newCameraCFrame = newCameraFocus * camRotation
self.lastCameraTransform = newCameraCFrame
self.lastCameraFocus = newCameraFocus
return newCameraCFrame, newCameraFocus, ...
end
function CameraExtensions:CalculateNewLookCFrameFromArg(suppliedLookVector: Vector3?, rotateInput:Vector2, ...)
local currLookVector = suppliedLookVector or self:GetCameraLookVector()
currLookVector = upCFrame:VectorToObjectSpace(currLookVector, ...)
-- get underlying camera controller __index and metatable
local cameraControllerMeta:BaseCamera = getmetatable(self)
return cameraControllerMeta.CalculateNewLookCFrameFromArg(self, currLookVector, rotateInput, ...)
end
lol I just remembered I forgot to test mouse lock. Clearly that’s not yet working
Those camera controller proxy functions pass varargs through for a bit of future proofing that will probably work unless Roblox completely changes the parameters.
There are still places in the UpVectorCamera that depend more on the CameraModule child script implementation than I’d prefer:
local CameraUtils:CameraUtils = require(CameraModuleScript:WaitForChild("CameraUtils"))
-- todo: see if this is still needed
function CameraExtensions:UpdateMouseBehavior()
-- get underlying camera controller __index and metatable
local cameraControllerMeta:BaseCamera = getmetatable(self)
cameraControllerMeta.UpdateMouseBehavior(self)
CameraUtils.setRotationTypeOverride(Enum.RotationType.MovementRelative)
--[[
if UserGameSettings.RotationType == Enum.RotationType.CameraRelative then
UserGameSettings.RotationType = Enum.RotationType.MovementRelative
end
]]
end
Roblox moved that RotationType logic into CameraUtils.setRotationTypeOverride, but I don’t trust that function is going to 100% stay there, and it would be better to have a fallback if they remove/rename it.
Some places there isn’t a clear way to use a proxy method, and so basically the original code is still there
local Poppercam = require(CameraModuleScript:WaitForChild("Poppercam"))
local ZoomController = require(CameraModuleScript:WaitForChild("ZoomController"))
function Poppercam:Update(renderDt, desiredCameraCFrame, desiredCameraFocus, cameraController)
local rotatedFocus = desiredCameraFocus * (desiredCameraCFrame - desiredCameraCFrame.p)
local extrapolation = self.focusExtrapolator:Step(renderDt, rotatedFocus)
local zoom = ZoomController.Update(renderDt, rotatedFocus, extrapolation)
return rotatedFocus*CFrame.new(0, 0, zoom), desiredCameraFocus
end
I wanted to post about it last week, after I spiked a basic wallstick refactor, but I got lost in the weeds in a deeper refactor due to fights with luau, script analysis, and the difference between BasePart.Velocity and BasePart.AssemblyLinearVelocity causing drift on spinning parts.
That is now working and looks like this:
The UpVectorCamera refactor is nearly done, I just need to test in VR and with mouselock.
I will probably follow up with that in a day or two, with a common UpVectorCamera for wallstick and gravity controller, and submit another pull request to those repos if you’re interested in removing the CameraController dependency.
Tomorrow I will set up a demo place with the code I have, and also if anyone has any advice on how to make the thing a bit … lighter… I guess?
In my game I have my own sound code, and my own animation code, so I really don’t need all the animation and sound stuff associated with the module, just a simple way to determine if I am ‘walking’ or ‘idle’ or ‘jumping’ when the module is active. I have tried 3x to remove the animation code and sound code but each time, I really mess it up, it seems to be rather integrated.
Hello all. I am trying to make a gravity runner game with the new camera controller. But what I want is to automatically move the player like in a runner game. I also need the player to jump and move side to side as well. If you can please help because it will be heavily appreciated. Thanks!
Gravity Controller Roblox Working.rbxl (96.2 KB)
Here is the place file with ‘what I think’ is the most updated / patched gravity controller.
When you spawn in, if you step off of the spawn pad, you can not step back up onto the spawn pad.
I can confirm that you included all the fixes from my patch in that file and didn’t introduce any breaking changes.
Also, yes, when I try to step back onto the spawn pad, I hit it like a wall and do not step up on it.
In some ways, the gravity controller is more simple than the wallstick controller. The wallstick controller forces you to change any code that isn’t aware of the replication of the character between the copied physics world and the visible world.
Assuming that would continue causing more unexpected issues and be harder to maintain in the long run, that’s why I switched from the Wallstick controller to the Gravity Controller a couple years ago.
The Wallstick controller gets around hard-coded behavior in the roblox client
(like detecting there is a ladder or step in front of the player and changing to a climbing state, based on an assumed down vector of (0,-1,0) )
by making a copy of the world around the character rotated to the correct custom UpVector cframe relative to the player, so when you bump into a ladder, roblox reacts normally.
I had to eventually go back and switch the project back to the Wallstick controller because it works the way I need it to more often than the simpler gravity controller.
Do you know how long the small step up issue has been a problem? I got used to ignoring those movement interaction glitches with it, so I’m not sure if that worked better at some point.
Any reason you don’t switch to Wallstick?
There are people who can answer this question better than me, but I’ll take a crack at it.
I can tell you that if I were going to do that, I would probably use the Egomoose wallstick controller and rebind and override the standard character movement controls, so players aren’t finessing the controls (assuming you’re doing the standard runner thing where the player presses a direction but the character doesn’t start moving that way until it reaches the next grid point or lane or whatever)
Then I’d use Humanoid.WalkToPart on the WallStick.Physics.Humanoid
I don’t think you can use Humanoid.MoveTo or set the Humanoid.WalkToPoint or WalkToPart to move up a wall normally. The wallstick controller duplicates the objects in the workspace to a proxy world, rotated so the Wallstick.Physics copy of the player character can move around normally.
You can place a part for the character to walk to in the normal workspace world, but you’ll have to find it’s copy in the physics world and tell the physics world humanoid to go to that one.