mirror of
https://github.com/godotengine/godot-docs.git
synced 2026-09-03 18:14:53 +03:00
Add joypad motion sensors tutorial
Co-Authored-By: Malcolm Anderson <malcolminyo@gmail.com> Co-Authored-By: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> Co-Authored-By: Cyril Bissey <53737317+Cykyrios@users.noreply.github.com> Co-Authored-By: Hugo Locurcio <hugo.locurcio@hugo.pro>
This commit is contained in:
@@ -92,3 +92,179 @@ The following example makes the LED blink red three times when the south button
|
||||
blink_tween.tween_interval(0.2)
|
||||
blink_tween.set_loops(3)
|
||||
|
||||
Motion sensors (gyroscope and accelerometer)
|
||||
--------------------------------------------
|
||||
|
||||
With motion controls, games can track the controller's physical rotation and movement.
|
||||
This can be used to let the player turn the in-game camera by moving their controller, or shaking their controller to perform a special action.
|
||||
|
||||
There are several controller brands that have implemented gyroscope and accelerometer sensors
|
||||
into their modern controllers, the biggest two being PlayStation and Nintendo.
|
||||
Note that the Xbox controllers don't have motion sensors inside of them.
|
||||
|
||||
To check if a connected controller has motion sensors, use :ref:`Input.has_joy_motion_sensors()<class_Input_method_has_joy_motion_sensors>`.
|
||||
|
||||
Motion sensors are disabled by default to avoid draining the controller battery when games don't use those features.
|
||||
To enable them, call :ref:`Input.set_joy_motion_sensors_enabled()<class_Input_method_set_joy_motion_sensors_enabled>`.
|
||||
|
||||
Note that the axes of the values that controller's motion sensors report are always relative to the controller's natural orientation.
|
||||
Here's an image of the axes mapping for more clarity:
|
||||
|
||||
.. image:: img/controller_axes.webp
|
||||
|
||||
The controller's gyroscope values show rotation around their respective axes:
|
||||
- the X value of the gyroscope data shows the rotation around the X axis (roll).
|
||||
- the Y value of the gyroscope data shows the rotation around the Y axis (yaw).
|
||||
- the Z value of the gyroscope data shows the rotation around the Z axis (pitch).
|
||||
|
||||
The controller's accelerometer will provide values in the following ways, respectively:
|
||||
- Movement left and right are reported as **+X** and **-X**.
|
||||
- Movement down and up are reported as **+Y** and **-Y**.
|
||||
- Movement away from and towards the user are reported as **+Z** and **-Z**.
|
||||
|
||||
Gyroscope
|
||||
~~~~~~~~~
|
||||
|
||||
A **gyroscope** is a type of sensor that detects the controller's rotation.
|
||||
Here are some notable examples of gyroscope use in games:
|
||||
|
||||
- In *Helldivers 2*, *Horizon Forbidden West*, *Star Wars: Dark Forces Remaster*, and *Fortnite*,
|
||||
tilting the controller causes the camera to rotate accordingly ("gyro aiming").
|
||||
`This video by *Daven On The Moon* <https://www.youtube.com/watch?v=Vlfg9yku2hY>`_ demonstrates and discusses gyro aiming in more detail.
|
||||
- In *Death Stranding*, BB can be soothed by rotating the controller softly.
|
||||
|
||||
The following example rotates an object using a controller's gyroscope sensor.
|
||||
You can also access this example by taking a look at the
|
||||
:ref:`Input.start_joy_motion_sensors_calibration()<class_Input_method_start_joy_motion_sensors_calibration>` documentation.
|
||||
|
||||
.. code-block::
|
||||
|
||||
const GYRO_SENSITIVITY = 10.0
|
||||
|
||||
func _ready():
|
||||
# In this example we only use the first connected joypad (id 0).
|
||||
if 0 not in Input.get_connected_joypads():
|
||||
return
|
||||
|
||||
if not Input.has_joy_motion_sensors(0):
|
||||
return
|
||||
|
||||
# We must enable the motion sensors before using them.
|
||||
Input.set_joy_motion_sensors_enabled(0, true)
|
||||
|
||||
# (Tell the users here that they need to put their joypads on a flat surface and wait for confirmation.)
|
||||
|
||||
# Start the calibration process.
|
||||
calibrate_motion()
|
||||
|
||||
func _process(delta):
|
||||
# Only move the object if the joypad motion sensors are calibrated.
|
||||
if Input.is_joy_motion_sensors_calibrated(0):
|
||||
move_object(delta)
|
||||
|
||||
func calibrate_motion():
|
||||
Input.start_joy_motion_sensors_calibration(0)
|
||||
|
||||
# Wait for some time.
|
||||
await get_tree().create_timer(1.0).timeout
|
||||
|
||||
Input.stop_joy_motion_sensors_calibration(0)
|
||||
# The joypad is now calibrated.
|
||||
|
||||
func move_object(delta):
|
||||
var node: Node3D = ... # Put your object here.
|
||||
|
||||
var gyro := Input.get_joy_gyroscope(0)
|
||||
node.rotation.x -= -gyro.y * GYRO_SENSITIVITY * delta # Use rotation around the Y axis (yaw) here.
|
||||
node.rotation.y += -gyro.x * GYRO_SENSITIVITY * delta # Use rotation around the X axis (pitch) here.
|
||||
|
||||
Note that before using the gyroscope's data, we must first calibrate it by calling :ref:`Input.start_joy_motion_sensors_calibration()<class_Input_method_start_joy_motion_sensors_calibration>`
|
||||
and :ref:`Input.stop_joy_motion_sensors_calibration()<class_Input_method_stop_joy_motion_sensors_calibration>`.
|
||||
That's because modern gyroscopes often need calibration. This is like how a weighing scale can need calibration to tell it what "zero" is.
|
||||
Like a weighing scale, only a correctly calibrated gyroscope will give an accurate reading.
|
||||
During calibration, the user sets the controller down on a flat surface.
|
||||
The controller then determines what values its gyroscope reports when it is actually not moving at all (its "bias"),
|
||||
and uses this information to make its rotation data more accurate.
|
||||
|
||||
See `the article on GyroWiki <http://gyrowiki.jibbsmart.com/blog:good-gyro-controls-part-1:the-gyro-is-a-mouse>`__
|
||||
for information on how to use gyroscope input as a mouse.
|
||||
|
||||
After the controller's gyroscope has been enabled and correctly calibrated,
|
||||
you can read its reported values by using :ref:`Input.get_joy_gyroscope()<class_Input_method_get_joy_gyroscope>`.
|
||||
|
||||
Accelerometer
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. warning::
|
||||
|
||||
Do not use accelerometer data to find the controller's position in 3D space;
|
||||
the accelerometers in general are not precise enough for this.
|
||||
|
||||
An **accelerometer** is a type of sensor that detects a controller's acceleration in m/s².
|
||||
For example, it can detect if the player quickly raises their controller, moves it to the side, or shakes it.
|
||||
|
||||
The acceleration that an accelerometer detects includes gravity by default.
|
||||
To get *only* the acceleration imparted by the user, subtract gravity from the detected acceleration:
|
||||
|
||||
.. code-block::
|
||||
|
||||
Input.get_joy_accelerometer(device) - Input.get_joy_gravity(device)
|
||||
|
||||
Due to how accelerometers work physically, after movement in one direction stops
|
||||
they almost immediately report movement in the opposite direction.
|
||||
After detecting movement in one direction, you may want to ignore further readings
|
||||
for a small period of time to avoid detecting this opposite movement.
|
||||
|
||||
The following example prints the controller movement when it's being quickly moved by using its accelerometer.
|
||||
If the sensitivity doesn't feel right for you,
|
||||
you can tweak the ``THRESHOLD`` constant or you can replace it by using a different value in the code below.
|
||||
|
||||
.. code-block::
|
||||
|
||||
var detect_accelerometer = true
|
||||
|
||||
# Change to make the game detect movement at different thresholds.
|
||||
# With a lower value, smaller movements will be detected, and with a
|
||||
# larger value, only big movements will be detected.
|
||||
const THRESHOLD = 10.0
|
||||
|
||||
func _ready():
|
||||
# In this example, we only use the first connected joypad (ID 0).
|
||||
if 0 not in Input.get_connected_joypads():
|
||||
return
|
||||
|
||||
if not Input.has_joy_motion_sensors(0):
|
||||
return
|
||||
|
||||
# We must enable the motion sensors before using them.
|
||||
Input.set_joy_motion_sensors_enabled(0, true)
|
||||
|
||||
func _process(delta):
|
||||
if Input.has_joy_motion_sensors(0):
|
||||
accelerometer_example()
|
||||
|
||||
func accelerometer_example():
|
||||
if not detect_accelerometer:
|
||||
return
|
||||
|
||||
var acceleration = Input.get_joy_accelerometer(0) - Input.get_joy_gravity(0)
|
||||
if acceleration.length() > THRESHOLD:
|
||||
if acceleration.x > THRESHOLD:
|
||||
print("Moved left")
|
||||
elif acceleration.x < -THRESHOLD:
|
||||
print("Moved right")
|
||||
if acceleration.y < -THRESHOLD:
|
||||
print("Moved up")
|
||||
elif acceleration.y > THRESHOLD:
|
||||
print("Moved down")
|
||||
if acceleration.z < -THRESHOLD:
|
||||
print("Moved closer to the player")
|
||||
elif acceleration.z > THRESHOLD:
|
||||
print("Moved away from the player")
|
||||
|
||||
# After detecting movement in one direction, the accelerometer sensor
|
||||
# will briefly report movement in the opposite direction, even though the controller only moved once.
|
||||
# So we need to ignore these reported values for a short amount of time.
|
||||
detect_accelerometer = false
|
||||
await get_tree().create_timer(0.5, false).timeout
|
||||
detect_accelerometer = true
|
||||
|
||||
BIN
tutorials/inputs/img/controller_axes.webp
Normal file
BIN
tutorials/inputs/img/controller_axes.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
Reference in New Issue
Block a user