mirror of
https://github.com/minetest/minetest.git
synced 2024-08-20 13:34:17 +02:00
Joystick sensitivity for player movement (#11262)
This commit deprecates the forward, backward, left, and right binary inputs currently used for player movement in the PlayerControl struct. In their place, it adds the movement_speed and movement_direction values, which represents the player movement is a polar coordinate system. movement_speed is a scalar from 0.0 to 1.0. movement_direction is an angle from 0 to +-Pi: FWD 0 _ LFT / \ RGT -Pi/2 | | +Pi/2 \_/ +-Pi BCK Boolean movement bits will still be set for server telegrams and Lua script invocations to provide full backward compatibility. When generating these values from an analog input, a direction is considered active when it is 22.5 degrees away from either orthogonal axis. Co-authored-by: Markus Koch <markus@notsyncing.net> Co-authored-by: sfan5 <sfan5@live.de>
This commit is contained in:
parent
149d8fc8d6
commit
1d69a23ba4
@ -998,9 +998,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
|
||||
const PlayerControl &controls = player->getPlayerControl();
|
||||
|
||||
bool walking = false;
|
||||
if (controls.up || controls.down || controls.left || controls.right ||
|
||||
controls.forw_move_joystick_axis != 0.f ||
|
||||
controls.sidew_move_joystick_axis != 0.f)
|
||||
if (controls.movement_speed > 0.001f)
|
||||
walking = true;
|
||||
|
||||
f32 new_speed = player->local_animation_speed;
|
||||
@ -1015,9 +1013,10 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
|
||||
g_settings->getBool("free_move") &&
|
||||
m_client->checkLocalPrivilege("fly"))))
|
||||
new_speed *= 1.5;
|
||||
// slowdown speed if sneeking
|
||||
// slowdown speed if sneaking
|
||||
if (controls.sneak && walking)
|
||||
new_speed /= 2;
|
||||
new_speed *= controls.movement_speed;
|
||||
|
||||
if (walking && (controls.dig || controls.place)) {
|
||||
new_anim = player->local_animations[3];
|
||||
|
@ -2460,7 +2460,7 @@ void Game::updateCameraOrientation(CameraOrientation *cam, float dtime)
|
||||
|
||||
if (m_cache_enable_joysticks) {
|
||||
f32 sens_scale = getSensitivityScaleFactor();
|
||||
f32 c = m_cache_joystick_frustum_sensitivity * (1.f / 32767.f) * dtime * sens_scale;
|
||||
f32 c = m_cache_joystick_frustum_sensitivity * dtime * sens_scale;
|
||||
cam->camera_yaw -= input->joystick.getAxisWithoutDead(JA_FRUSTUM_HORIZONTAL) * c;
|
||||
cam->camera_pitch += input->joystick.getAxisWithoutDead(JA_FRUSTUM_VERTICAL) * c;
|
||||
}
|
||||
@ -2471,18 +2471,12 @@ void Game::updateCameraOrientation(CameraOrientation *cam, float dtime)
|
||||
|
||||
void Game::updatePlayerControl(const CameraOrientation &cam)
|
||||
{
|
||||
LocalPlayer *player = client->getEnv().getLocalPlayer();
|
||||
|
||||
//TimeTaker tt("update player control", NULL, PRECISION_NANO);
|
||||
|
||||
// DO NOT use the isKeyDown method for the forward, backward, left, right
|
||||
// buttons, as the code that uses the controls needs to be able to
|
||||
// distinguish between the two in order to know when to use joysticks.
|
||||
|
||||
PlayerControl control(
|
||||
input->isKeyDown(KeyType::FORWARD),
|
||||
input->isKeyDown(KeyType::BACKWARD),
|
||||
input->isKeyDown(KeyType::LEFT),
|
||||
input->isKeyDown(KeyType::RIGHT),
|
||||
isKeyDown(KeyType::JUMP),
|
||||
isKeyDown(KeyType::JUMP) || player->getAutojump(),
|
||||
isKeyDown(KeyType::AUX1),
|
||||
isKeyDown(KeyType::SNEAK),
|
||||
isKeyDown(KeyType::ZOOM),
|
||||
@ -2490,22 +2484,16 @@ void Game::updatePlayerControl(const CameraOrientation &cam)
|
||||
isKeyDown(KeyType::PLACE),
|
||||
cam.camera_pitch,
|
||||
cam.camera_yaw,
|
||||
input->joystick.getAxisWithoutDead(JA_SIDEWARD_MOVE),
|
||||
input->joystick.getAxisWithoutDead(JA_FORWARD_MOVE)
|
||||
input->getMovementSpeed(),
|
||||
input->getMovementDirection()
|
||||
);
|
||||
|
||||
u32 keypress_bits = (
|
||||
( (u32)(isKeyDown(KeyType::FORWARD) & 0x1) << 0) |
|
||||
( (u32)(isKeyDown(KeyType::BACKWARD) & 0x1) << 1) |
|
||||
( (u32)(isKeyDown(KeyType::LEFT) & 0x1) << 2) |
|
||||
( (u32)(isKeyDown(KeyType::RIGHT) & 0x1) << 3) |
|
||||
( (u32)(isKeyDown(KeyType::JUMP) & 0x1) << 4) |
|
||||
( (u32)(isKeyDown(KeyType::AUX1) & 0x1) << 5) |
|
||||
( (u32)(isKeyDown(KeyType::SNEAK) & 0x1) << 6) |
|
||||
( (u32)(isKeyDown(KeyType::DIG) & 0x1) << 7) |
|
||||
( (u32)(isKeyDown(KeyType::PLACE) & 0x1) << 8) |
|
||||
( (u32)(isKeyDown(KeyType::ZOOM) & 0x1) << 9)
|
||||
);
|
||||
// autoforward if set: move towards pointed position at maximum speed
|
||||
if (player->getPlayerSettings().continuous_forward &&
|
||||
client->activeObjectsReceived() && !player->isDead()) {
|
||||
control.movement_speed = 1.0f;
|
||||
control.movement_direction = 0.0f;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
/* For Android, simulate holding down AUX1 (fast move) if the user has
|
||||
@ -2515,23 +2503,38 @@ void Game::updatePlayerControl(const CameraOrientation &cam)
|
||||
*/
|
||||
if (m_cache_hold_aux1) {
|
||||
control.aux1 = control.aux1 ^ true;
|
||||
keypress_bits ^= ((u32)(1U << 5));
|
||||
}
|
||||
#endif
|
||||
|
||||
LocalPlayer *player = client->getEnv().getLocalPlayer();
|
||||
u32 keypress_bits = (
|
||||
( (u32)(control.jump & 0x1) << 4) |
|
||||
( (u32)(control.aux1 & 0x1) << 5) |
|
||||
( (u32)(control.sneak & 0x1) << 6) |
|
||||
( (u32)(control.dig & 0x1) << 7) |
|
||||
( (u32)(control.place & 0x1) << 8) |
|
||||
( (u32)(control.zoom & 0x1) << 9)
|
||||
);
|
||||
|
||||
// autojump if set: simulate "jump" key
|
||||
if (player->getAutojump()) {
|
||||
control.jump = true;
|
||||
keypress_bits |= 1U << 4;
|
||||
}
|
||||
// Set direction keys to ensure mod compatibility
|
||||
if (control.movement_speed > 0.001f) {
|
||||
float absolute_direction;
|
||||
|
||||
// autoforward if set: simulate "up" key
|
||||
if (player->getPlayerSettings().continuous_forward &&
|
||||
client->activeObjectsReceived() && !player->isDead()) {
|
||||
control.up = true;
|
||||
keypress_bits |= 1U << 0;
|
||||
// Check in original orientation (absolute value indicates forward / backward)
|
||||
absolute_direction = abs(control.movement_direction);
|
||||
if (absolute_direction < (3.0f / 8.0f * M_PI))
|
||||
keypress_bits |= (u32)(0x1 << 0); // Forward
|
||||
if (absolute_direction > (5.0f / 8.0f * M_PI))
|
||||
keypress_bits |= (u32)(0x1 << 1); // Backward
|
||||
|
||||
// Rotate entire coordinate system by 90 degrees (absolute value indicates left / right)
|
||||
absolute_direction = control.movement_direction + M_PI_2;
|
||||
if (absolute_direction >= M_PI)
|
||||
absolute_direction -= 2 * M_PI;
|
||||
absolute_direction = abs(absolute_direction);
|
||||
if (absolute_direction < (3.0f / 8.0f * M_PI))
|
||||
keypress_bits |= (u32)(0x1 << 2); // Left
|
||||
if (absolute_direction > (5.0f / 8.0f * M_PI))
|
||||
keypress_bits |= (u32)(0x1 << 3); // Right
|
||||
}
|
||||
|
||||
client->setPlayerControl(control);
|
||||
|
@ -240,6 +240,9 @@ public:
|
||||
virtual bool wasKeyReleased(GameKeyType k) = 0;
|
||||
virtual bool cancelPressed() = 0;
|
||||
|
||||
virtual float getMovementSpeed() = 0;
|
||||
virtual float getMovementDirection() = 0;
|
||||
|
||||
virtual void clearWasKeyPressed() {}
|
||||
virtual void clearWasKeyReleased() {}
|
||||
|
||||
@ -285,6 +288,44 @@ public:
|
||||
{
|
||||
return m_receiver->WasKeyReleased(keycache.key[k]) || joystick.wasKeyReleased(k);
|
||||
}
|
||||
virtual float getMovementSpeed()
|
||||
{
|
||||
bool f = m_receiver->IsKeyDown(keycache.key[KeyType::FORWARD]),
|
||||
b = m_receiver->IsKeyDown(keycache.key[KeyType::BACKWARD]),
|
||||
l = m_receiver->IsKeyDown(keycache.key[KeyType::LEFT]),
|
||||
r = m_receiver->IsKeyDown(keycache.key[KeyType::RIGHT]);
|
||||
if (f || b || l || r)
|
||||
{
|
||||
// if contradictory keys pressed, stay still
|
||||
if (f && b && l && r)
|
||||
return 0.0f;
|
||||
else if (f && b && !l && !r)
|
||||
return 0.0f;
|
||||
else if (!f && !b && l && r)
|
||||
return 0.0f;
|
||||
return 1.0f; // If there is a keyboard event, assume maximum speed
|
||||
}
|
||||
return joystick.getMovementSpeed();
|
||||
}
|
||||
virtual float getMovementDirection()
|
||||
{
|
||||
float x = 0, z = 0;
|
||||
|
||||
/* Check keyboard for input */
|
||||
if (m_receiver->IsKeyDown(keycache.key[KeyType::FORWARD]))
|
||||
z += 1;
|
||||
if (m_receiver->IsKeyDown(keycache.key[KeyType::BACKWARD]))
|
||||
z -= 1;
|
||||
if (m_receiver->IsKeyDown(keycache.key[KeyType::RIGHT]))
|
||||
x += 1;
|
||||
if (m_receiver->IsKeyDown(keycache.key[KeyType::LEFT]))
|
||||
x -= 1;
|
||||
|
||||
if (x != 0 || z != 0) /* If there is a keyboard event, it takes priority */
|
||||
return atan2(x, z);
|
||||
else
|
||||
return joystick.getMovementDirection();
|
||||
}
|
||||
virtual bool cancelPressed()
|
||||
{
|
||||
return wasKeyDown(KeyType::ESC) || m_receiver->WasKeyDown(CancelKey);
|
||||
@ -352,6 +393,8 @@ public:
|
||||
virtual bool wasKeyPressed(GameKeyType k) { return false; }
|
||||
virtual bool wasKeyReleased(GameKeyType k) { return false; }
|
||||
virtual bool cancelPressed() { return false; }
|
||||
virtual float getMovementSpeed() {return 0.0f;}
|
||||
virtual float getMovementDirection() {return 0.0f;}
|
||||
virtual v2s32 getMousePos() { return mousepos; }
|
||||
virtual void setMousePos(s32 x, s32 y) { mousepos = v2s32(x, y); }
|
||||
|
||||
|
@ -160,6 +160,7 @@ JoystickController::JoystickController() :
|
||||
for (float &i : m_past_pressed_time) {
|
||||
i = 0;
|
||||
}
|
||||
m_layout.axes_deadzone = 0;
|
||||
clear();
|
||||
}
|
||||
|
||||
@ -251,10 +252,27 @@ void JoystickController::clear()
|
||||
memset(m_axes_vals, 0, sizeof(m_axes_vals));
|
||||
}
|
||||
|
||||
s16 JoystickController::getAxisWithoutDead(JoystickAxis axis)
|
||||
float JoystickController::getAxisWithoutDead(JoystickAxis axis)
|
||||
{
|
||||
s16 v = m_axes_vals[axis];
|
||||
|
||||
if (abs(v) < m_layout.axes_deadzone)
|
||||
return 0;
|
||||
return v;
|
||||
return 0.0f;
|
||||
|
||||
v += (v < 0 ? m_layout.axes_deadzone : -m_layout.axes_deadzone);
|
||||
|
||||
return (float)v / ((float)(INT16_MAX - m_layout.axes_deadzone));
|
||||
}
|
||||
|
||||
float JoystickController::getMovementDirection()
|
||||
{
|
||||
return atan2(getAxisWithoutDead(JA_SIDEWARD_MOVE), -getAxisWithoutDead(JA_FORWARD_MOVE));
|
||||
}
|
||||
|
||||
float JoystickController::getMovementSpeed()
|
||||
{
|
||||
float speed = sqrt(pow(getAxisWithoutDead(JA_FORWARD_MOVE), 2) + pow(getAxisWithoutDead(JA_SIDEWARD_MOVE), 2));
|
||||
if (speed > 1.0f)
|
||||
speed = 1.0f;
|
||||
return speed;
|
||||
}
|
||||
|
@ -144,7 +144,10 @@ public:
|
||||
return m_axes_vals[axis];
|
||||
}
|
||||
|
||||
s16 getAxisWithoutDead(JoystickAxis axis);
|
||||
float getAxisWithoutDead(JoystickAxis axis);
|
||||
|
||||
float getMovementDirection();
|
||||
float getMovementSpeed();
|
||||
|
||||
f32 doubling_dtime;
|
||||
|
||||
|
@ -566,23 +566,7 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
|
||||
}
|
||||
}
|
||||
|
||||
if (control.up)
|
||||
speedH += v3f(0.0f, 0.0f, 1.0f);
|
||||
|
||||
if (control.down)
|
||||
speedH -= v3f(0.0f, 0.0f, 1.0f);
|
||||
|
||||
if (!control.up && !control.down)
|
||||
speedH -= v3f(0.0f, 0.0f, 1.0f) * (control.forw_move_joystick_axis / 32767.f);
|
||||
|
||||
if (control.left)
|
||||
speedH += v3f(-1.0f, 0.0f, 0.0f);
|
||||
|
||||
if (control.right)
|
||||
speedH += v3f(1.0f, 0.0f, 0.0f);
|
||||
|
||||
if (!control.left && !control.right)
|
||||
speedH += v3f(1.0f, 0.0f, 0.0f) * (control.sidew_move_joystick_axis / 32767.f);
|
||||
speedH = v3f(sin(control.movement_direction), 0.0f, cos(control.movement_direction));
|
||||
|
||||
if (m_autojump) {
|
||||
// release autojump after a given time
|
||||
@ -639,6 +623,8 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
|
||||
else
|
||||
speedH = speedH.normalize() * movement_speed_walk;
|
||||
|
||||
speedH *= control.movement_speed; /* Apply analog input */
|
||||
|
||||
// Acceleration increase
|
||||
f32 incH = 0.0f; // Horizontal (X, Z)
|
||||
f32 incV = 0.0f; // Vertical (Y)
|
||||
@ -1106,9 +1092,7 @@ void LocalPlayer::handleAutojump(f32 dtime, Environment *env,
|
||||
if (m_autojump)
|
||||
return;
|
||||
|
||||
bool control_forward = control.up ||
|
||||
(!control.up && !control.down &&
|
||||
control.forw_move_joystick_axis < -0.05f);
|
||||
bool control_forward = keyPressed & (1 << 0);
|
||||
|
||||
bool could_autojump =
|
||||
m_can_jump && !control.jump && !control.sneak && control_forward;
|
||||
|
@ -510,10 +510,6 @@ void Server::process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao,
|
||||
playersao->setWantedRange(wanted_range);
|
||||
|
||||
player->keyPressed = keyPressed;
|
||||
player->control.up = (keyPressed & (0x1 << 0));
|
||||
player->control.down = (keyPressed & (0x1 << 1));
|
||||
player->control.left = (keyPressed & (0x1 << 2));
|
||||
player->control.right = (keyPressed & (0x1 << 3));
|
||||
player->control.jump = (keyPressed & (0x1 << 4));
|
||||
player->control.aux1 = (keyPressed & (0x1 << 5));
|
||||
player->control.sneak = (keyPressed & (0x1 << 6));
|
||||
|
25
src/player.h
25
src/player.h
@ -49,10 +49,6 @@ struct PlayerControl
|
||||
PlayerControl() = default;
|
||||
|
||||
PlayerControl(
|
||||
bool a_up,
|
||||
bool a_down,
|
||||
bool a_left,
|
||||
bool a_right,
|
||||
bool a_jump,
|
||||
bool a_aux1,
|
||||
bool a_sneak,
|
||||
@ -61,14 +57,10 @@ struct PlayerControl
|
||||
bool a_place,
|
||||
float a_pitch,
|
||||
float a_yaw,
|
||||
float a_sidew_move_joystick_axis,
|
||||
float a_forw_move_joystick_axis
|
||||
float a_movement_speed,
|
||||
float a_movement_direction
|
||||
)
|
||||
{
|
||||
up = a_up;
|
||||
down = a_down;
|
||||
left = a_left;
|
||||
right = a_right;
|
||||
jump = a_jump;
|
||||
aux1 = a_aux1;
|
||||
sneak = a_sneak;
|
||||
@ -77,13 +69,9 @@ struct PlayerControl
|
||||
place = a_place;
|
||||
pitch = a_pitch;
|
||||
yaw = a_yaw;
|
||||
sidew_move_joystick_axis = a_sidew_move_joystick_axis;
|
||||
forw_move_joystick_axis = a_forw_move_joystick_axis;
|
||||
movement_speed = a_movement_speed;
|
||||
movement_direction = a_movement_direction;
|
||||
}
|
||||
bool up = false;
|
||||
bool down = false;
|
||||
bool left = false;
|
||||
bool right = false;
|
||||
bool jump = false;
|
||||
bool aux1 = false;
|
||||
bool sneak = false;
|
||||
@ -92,8 +80,9 @@ struct PlayerControl
|
||||
bool place = false;
|
||||
float pitch = 0.0f;
|
||||
float yaw = 0.0f;
|
||||
float sidew_move_joystick_axis = 0.0f;
|
||||
float forw_move_joystick_axis = 0.0f;
|
||||
// Note: These two are NOT available on the server
|
||||
float movement_speed = 0.0f;
|
||||
float movement_direction = 0.0f;
|
||||
};
|
||||
|
||||
struct PlayerSettings
|
||||
|
@ -223,16 +223,20 @@ int LuaLocalPlayer::l_get_control(lua_State *L)
|
||||
};
|
||||
|
||||
lua_createtable(L, 0, 12);
|
||||
set("up", c.up);
|
||||
set("down", c.down);
|
||||
set("left", c.left);
|
||||
set("right", c.right);
|
||||
set("jump", c.jump);
|
||||
set("aux1", c.aux1);
|
||||
set("jump", c.jump);
|
||||
set("aux1", c.aux1);
|
||||
set("sneak", c.sneak);
|
||||
set("zoom", c.zoom);
|
||||
set("dig", c.dig);
|
||||
set("zoom", c.zoom);
|
||||
set("dig", c.dig);
|
||||
set("place", c.place);
|
||||
// Player movement in polar coordinates and non-binary speed
|
||||
set("movement_speed", c.movement_speed);
|
||||
set("movement_direction", c.movement_direction);
|
||||
// Provide direction keys to ensure compatibility
|
||||
set("up", player->keyPressed & (1 << 0)); // Up, down, left, and right were removed in favor of
|
||||
set("down", player->keyPressed & (1 << 1)); // analog direction indicators and are therefore not
|
||||
set("left", player->keyPressed & (1 << 2)); // available as booleans anymore. The corresponding values
|
||||
set("right", player->keyPressed & (1 << 3)); // can still be read from the keyPressed bits though.
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -1392,13 +1392,13 @@ int ObjectRef::l_get_player_control(lua_State *L)
|
||||
|
||||
const PlayerControl &control = player->getPlayerControl();
|
||||
lua_newtable(L);
|
||||
lua_pushboolean(L, control.up);
|
||||
lua_pushboolean(L, player->keyPressed & (1 << 0));
|
||||
lua_setfield(L, -2, "up");
|
||||
lua_pushboolean(L, control.down);
|
||||
lua_pushboolean(L, player->keyPressed & (1 << 1));
|
||||
lua_setfield(L, -2, "down");
|
||||
lua_pushboolean(L, control.left);
|
||||
lua_pushboolean(L, player->keyPressed & (1 << 2));
|
||||
lua_setfield(L, -2, "left");
|
||||
lua_pushboolean(L, control.right);
|
||||
lua_pushboolean(L, player->keyPressed & (1 << 3));
|
||||
lua_setfield(L, -2, "right");
|
||||
lua_pushboolean(L, control.jump);
|
||||
lua_setfield(L, -2, "jump");
|
||||
|
Loading…
Reference in New Issue
Block a user