Using platfomer to control player movement
To control the player the movement, the scripting API has a builtin Platformer controls which provides a WASD type of navigation. WASD
is named after the keys W
, A
, S
, D
, it's a popular scheme for controlling character movement in 3D game
Key | Action |
---|---|
W or ArrowUp | Moves the character forwards |
A or ArrowLeft | Moves the character to the left |
S or ArrowRight | Moves the character to the right |
D or ArrowDown | Moves the character backwards |
Space | Perform a jump on the character |
Shift + Direction Key | Speeds up character movement in that direction |
Creating Platformer controls
Here's an example on how to create the controls
import { Camera, Player, Controls } from "@oo/scripting";
export default class GameManager {
controls = null;
// ...
onReady() {
this.controls = this.controls = Controls.get({
type: "platformer",
object: Player.avatar,
target: Camera,
})
}
}
The example uses ControlsFactory.get()
method to instantiate the controls. Let's look at the options passed to the method:
type
: we used"platformer"
to create the WASD type navigation controlsobject
: the character moved by the controls. We set it to the main player avatartarget
: is used to determine the forward direction of the movement. We want the player to move in the direction where the camera is looking.
When specifying "platformer"
as type, the factory returns an instance of PlatformerControlsWrapper
.
Customizing Platformer's parameters
We can also provide additional parameters to control some aspects of the controls like character speed, jump height ...
import { Camera, Player, Controls } from "@oo/scripting";
export default class GameManager {
//...
this.controls = Controls.get({
type: "platformer",
object: Player.avatar,
target: Camera,
params: {
run : {
maxSpeed : 15, // Default is 10
boost: 2, // Default is 1.5
},
jump: {
height: 10, // Default is 3
},
autoAnimate: false // Default is true
}
})
}
We pass the parameters in the params
field. The shape of the params depend on the type of controls we create. For Platfomer controls, the possible params are:
run.maxSpeed
: this is the walking speed of the charcaterrun.boost
: how much to accelrate the charcater whenShift
is pressedjump.height
: max height the character will reach whenSpace
is pressedautoAnimate
: tells wether the controls should set the appropriate animation on the charcater depending on its current state (running, jumping, idle ...). This only applies when the attached object is anAvatarComponent
Below is a table of animations applied to the character, depending on its state
State | Animation name | Notes |
---|---|---|
Not moving | "idle" | |
Walking | "walk" | |
Running | "run" | |
Jumping | "jump" | |
Flying | "fly" | the flying state happens if the character stays on the air for a long duration |
You can customize the animation behavior in 2 ways
-
If you want to change how the standard animations (
"idle"
,"walk"
, ...) look all toghether in the game. You can upload custom animations using the VRM animation component on the studio. See Customizing avatar animations for more info. -
If you want to control the logic of picking which animation to choose, set
autoAnimate
tofalse
. You can then use the assign the desired animation to the attached object manually (e.g.Player.avatar.animation = "..."
).
Activating / Deactivating
At some moment in the game you may want to deactivate the controls (e.g when the game is paused). You can use the controls active
property to activate or deactivate the controls, for example:
controls.active = false
Note that deactivating the controls will stop the attached characted movement at the moment of invocation. So if the character is in the middle of jump, for example, the character will stop in mid air (Stopping the character movement refer only to changes in position or rotations of the character, the last assigned animation will keep playing).
If you want the controls to keep processing past actions (like keep falling from the current jump), but prevent further user input from affecting its state, you should write instead
controls.controller.active = false
This will keep the controls responsive to the game update events, but ignore future user inputs.
The Platformer controller
is the object responsible of translating user input (keyboard, joystick) into meaninful actions for the controls (forward, left ...). It does so by listening to the relevent user events (keyDown, keyUp ...) then toggling the appropriate field on the actions
property of the controller.
This separation gives you a greater control over the platformer's behavior, and make it possible to implement some custom character control without having to write a new custom controls from scratch.
For example, suppose you're making a Statues like game (opens in a new tab). Where the only action possible is moving forward. Furthermore the user doesn't have to keep pressing the ArrowUp
key to keep moving. When the players are allowed to move, the user can just press the key once and the character should keep moving until the next key press.
Let's see how to implement this behavior using the platformer
import { Camera, Player, Controls, } from "@oo/scripting";
export default class GameManager {
controls = null;
// ...
onReady() {
this.controls = Controls.get({
type: "platformer",
object: Player.avatar,
target: Camera,
})
this.controls.controller.active = false
Emitter.on(Events.KEY_DOWN, this.onKeyDown)
}
onKeyDown = (e) => {
if (e.repeat || e.key !== "ArrowUp") return
this.controls.actions.forward = !this.controls.actions.forward
}
onStop() {
Emitter.off(Events.KEY_DOWN, this.onKeyDown)
}
}
In the above example:
- We disabled the platformer's controller to deactivate the default input binding
- Then we attached our own event listener that will set the
actions.forward
property directly as appropriate
🚧 Applying kinematic forces
TBD