Recent update to PlayerModule ControlModule - Unexpected behavior

The default PlayerModule was recently updated with a new feature in the ControlModule. Specifically, this functionality is behind the fast flag FFlagUserFixMovementCameraStraightDown.

Previously, ControlModule.moveFunction was called each frame with the raw movement input along with a cameraRelative boolean indicating whether to transform according to the angle of the Camera. I believe the default moveFunction would then be responsible for accounting for the camera transformation. However, the transformation is now applied before calling moveFunction.

It is very useful to write custom functions for special movement cases and overwrite ControlModule.moveFunction from an external script, in order to receive raw directional input regardless of the user’s control scheme; whether it be keyboard, gamepad, or one of the multiple forms of touch movement input. Please reorganize the code so that the input transformation takes place in the default ControlModule.moveFunction so that we may again be able to easily get raw movement input.

1 Like

What special movement cases are you doing that this change interferes with? Why is it important for you to get camera relative rather than absolute movement vectors?

1 Like

Some of the use cases:

  1. A player equips a hoverboard and it uses the left/right inputs to steer and the forward/backward inputs to move; i.e. custom vehicles without using VehicleSeat.
  2. A player enters a puzzle in the game that is constrained to a grid. The camera moves to a fixed location and I am interested in which adjacent tile to move the character onto when they interact with any of the existing movement inputs mentioned above (keyboard, gamepad, touch) without caring about what orientation the grid is in within 3D space.

E.g. if the player presses the “D” key, I want to be able to receive (1, 0, 0) regardless of the Camera’s orientation.

The exact use cases mentioned above are already implemented and used to work, this update simply broke them because now my custom moveFunction only receives the world-space vectors rather than the raw ones.

1 Like

I think the best way to handle custom movement cases like that would be to temporarily bind over the input used by the PlayerScripts using ContextActionService. The problem with the current method you were using is that it heavily relies on the internal structure and implementation of the playerscripts so there is a high chance of it changing unexpectantly in the future. In this case even if this function was considered a public API that can be overridden, it would still be bad practice to override it in a way that expects the input to be constrained (cameraRelative = true) rather than handling all possible inputs.

ContextActionService is not a solution. The goal is to intercept all movement input types without the player ever feeling like anything has changed. Touch controls are among the most complex with a wide variety of user settings available, with new inputs (e.g. DynamicThumbstick) being added and updated over time. Re-implementing all cases would not be sane.

Overwriting the moveFunction was an incredibly elegant solution. In a single line of code, you could preserve all input functionality and cases, while intercepting the input values. The fact that moveFunction was a publicly accessible member of the ControlModule (as opposed to a local variable), to me, meant that being able to override it was at one point intended behavior.

Forking PlayerModule is also not a good solution.

I could be wrong, but to me it seems that it would be simple (and more efficient) to move the fix for the “camera straight down” edge case into the underlying C code for the Player.Move method to preserve the previous, expected functionality.

2 Likes

Hi, I would tend to agree with you, however the situation is not quite as bad as you think.
I have a system that I originally made for upgrading old Gear (the old Gear just takes keyboard input)
to allow any Gear directional features to work with any type of input–At first I thought as you did, that
the touch controls would be a nightmare, but it turns out that it’s not too bad, as the controller move vector
is still available without having to resort to overriding moveFunction().
After the updates to the PlayerScripts new structure a number of months back, it’s been much easier
to not have to fork them.
You can use PlayerModule:GetControls():GetMoveVector()
on the RenderStep (In my case, I then “D-pad-ify” the vector.)
(Jumping is hairier–Hint: w/ Enum.RenderPriority.First.Value to get Controller.isJumping)

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.