[Release] Custom character controller

Wow, thanks a ton! I was doing it all wrong and adding textbox detectors etc but this does the job very well! :smiley:

I was just wondering if it’s possible to remove the lerp from zooming and moving the camera but keeping the smoothening on walking up walls etc? I tried messing around for around half an hour and got nowhere, I ended up removing smoothing altogether and not keeping it on walking walls and making the camera go crazy

There are two tweens that pertain to zooming and moving the camera respectively:

Zoom

In the UISTable of CameraScript, there is an extra variable I use to differentiate between the actual value I use for zoom and the value formed from tweening this value, known as zoomTween.
If you want to remove tweening from this, the simplest fix is just using zoom in the camera.CFrame/point definition instead of zoomTween

Camera Movement

Just before the definition of point in the RunService:BindToRenderStep event binding, I steeply lerp angle between its initial angle and intended angle so transitions between slopes smooth over without appearing disruptive.
I believe it’s definition looks like this:

local camFocus = (lastPart.CFrame - lastPart.Position) * 
    (fakeLastPart.CFrame - fakeLastPart.Position):Inverse()
--...
angle = angle:Lerp(
    camFocus * 
    CFrame.Angles(0,x,0) * CFrame.Angles(y,0,0),
    0.5
) --0.5 could be larger or smth

The solution would be to lerp the CFrame that comes from the camFocus definition most likely, and ignore the one made by angle if you wanted. Something like this:

camFocus = camFocus:Lerp(
    (lastPart.CFrame - lastPart.Position) * 
    (lastFakePart.CFrame - lastFakePart.Position):Inverse(),
    0.5
)
--...
angle = camFocus * 
    CFrame.Angles(0,x,0) * CFrame.Angles(y,0,0)

Since the camFocus does not interfere with the position of the camera and only the orientation, this should not look glitchy at all. However, I have not looked at my codebase in a long time and I may be wrong in how RunService:BindToRenderStep is utilized or how the variables are defined, but lerping (lP.CFrame - lP.Position) * (fLP.CFrame - fLP.Position):Inverse() is how you can smooth over slope transitions without tweening camera movement.

1 Like

Wondering if there’s a way other than invisible wedges to make it easier to go from floor directly to a straight wall

They were suppose to on an old trello roadmap. They never did implement it.

1 Like

The controller has a setNormal method for custom changes in gravity, you could use this in combination with .Touched events and getNormal checks to create a custom gravity system.
E.g: say you have a floor + wall combo that you want to script to change normals.
You could probably have a setup like this, except each part covers the entire wall/floor:
image
Part1 would set the character’s normal to the floor on touch, and Part2 would set the character’s normal to the wall on touch, all with a debounce of maybe 0.5 seconds.
A script like this would suffice:

-- add the character/controller to the table 
-- every time you make a new controller
local Interfaces = {
 -- [Character] = {Controller = controller, Debounce = false}
}

local GravParts = {
 -- [hitbox] = normal
    [Part1] = Vector3.new(0,1,0),
    [Part2] = Vector3.new(1,0,0)
}

for hitbox, normal in pairs(GravParts)
    hitbox.Touched:Connect(function(hit)
        local i = Interfaces[hit.Parent]
        if i and not i.Debounce and i.Controller:getNormal() ~= normal then
            i.Debounce = true
            i.Controller:setNormal(normal)
            wait(0.5)
            i.Debounce = false
        end
    end)
end
3 Likes


I uploaded the place files to Roblox as Uncopylocked Games for ease of accessibility and play testing

Hope you don’t mind.

5 Likes

I might as well post my version of the place on here as well:


I’m not sure if it will always be public, but it is here for now. Also keep in mind that I have not created mobile controls for this yet. For right now, only keyboard and mouse is supported.

4 Likes

I figured out how to get the camera movement specifically to tween instead of the entire angle, if you were stuck on that. I just made an extra xOffset value since the offset and part:fakePart relationship is basically coupled together.

This also bugged out the ControlScript, so I also made an extra camXSum variable under CameraScript to fix it.

Here are the individual scripts if you want to replace it, I also updated gravity swords up there to show this:

CameraScript.rbxm (3.6 KB)
ControlScript.lua (1.9 KB)

2 Likes

I also just integrated the custom ControlScript with Roblox’s default one. Literally added three lines and changed one line. Surprisingly easy.

ControlScript.rbxm (47.5 KB)

I also published the change to gravity swords up there.

This is apparently only partial so far…

Update: The CameraScript is huge, I got the Classic camera integrated, but the Follow camera is causing trouble…
All this is in a separate game, so it has not been updated yet.

Update to the update: I just integrated CameraScript’s Classic camera and Follow camera modules, which are the two camera types provided to the player on default:

CameraScript.rbxm (80.2 KB)

If you need support for additional camera types, you can reply to this post, and I will try my best to integrate those scripts as well. I just updated gravity swords up there to show it.

I will begin work for the modification of the entire up-to-date module, which already looks much cleaner!

1 Like

:shushing_face: Don’t give them my secret!

In all seriousness I am very excited about this especially with it being open source. Thank you and good work!


also I did miss how old this is, sorry if that is against etiquette

3 Likes

I have now integrated the entire PlayerModule, published on gravity swords:

PlayerModule.rbxm (125.6 KB)

This includes modifications to CameraModule.RootCamera, CameraModule.ClassicCamera, and ControlModule.BaseCharacterController. The ClickToMoveController doesn’t work because it requires a unique pathfinder, something I don’t think I have high confidence in creating because of its lack of correlation with the geometry of contorted unions and meshes.
I probably added about 100 lines in total, and it took me longer than it should’ve because of implementation details. Now that this is done though, this can be used as a component instead of its own standalone product, allowing for usage with other controllers, such as EgoMoose’s platformer controller, given the proper implementation.

I will need to unreverse X inputs when I get home
Done!

5 Likes

A cool idea would be nice like, when ur upside down your camera would rotate or move back to a normal fixed position so it just looks like nothing happened hhh.

Could you elaborate on what you mean by this? Are you suggesting some kind of cinematic camera? I could probably implement it into the CameraType.Watch Enum. The CameraType.Watch Enum is actually easier to implement in…

2 Likes

ok so basically, when you’re upside down on a part your camera should instead rotate like it was when you were normally on a surface part or something. hh

So like, you want an option to return the camera’s orientation to what it would be if it wasn’t accounting for gravity?

yeah, something like that basically.

1 Like

Sorry, just to be clear, you have seen @goldenstein64’s gravity swords place?

1 Like

Yeah, we have. Off topic, is there any way to make this character controller work when using swords, for example, have it support lunging and velocity changes?

1 Like

This will probably merit for a new method in the controller for accessing the physCharacter, honestly. Then you could apply physical BodyMovers and Constraint objects directly instead of via proxy to the real character. It’s easy to make, I could probably reproduce the code in this post real quick:

function controller:getPhysCharacter()
	return self.physCharacter
end

In an outside module, if you don’t want to use that method, the controller has physCharacter as a property, so you could probably access it from main in StarterCharacterScripts as:

controller.physCharacter
2 Likes