Rumble on collisions (#4532)

This commit is contained in:
Mary 2021-05-21 11:45:35 -04:00 committed by GitHub
parent 10da6285fc
commit 7bf9a0a4a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 141 additions and 4 deletions

View File

@ -118,6 +118,14 @@ InputManager::InputManager() : m_mode(BOOTSTRAP),
Log::error("InputManager", "Failed to init SDL game controller: %s",
SDL_GetError());
}
#if SDL_VERSION_ATLEAST(1,3,0)
if (SDL_InitSubSystem(SDL_INIT_HAPTIC) != 0)
{
Log::error("InputManager", "Failed to init SDL haptics: %s",
SDL_GetError());
}
#endif
#endif // SERVER_ONLY
}
@ -217,6 +225,14 @@ void InputManager::handleJoystick(SDL_Event& event)
Log::error("SDLController", "Error in handleJoystick() %s", e.what());
}
} // handleJoystick
SDLController* InputManager::getSDLController(unsigned i) {
assert(i < m_sdl_controller.size());
auto it = m_sdl_controller.begin();
for(unsigned j = 0; j < i; ++j)
it++;
return it->second.get();
}
#endif
// -----------------------------------------------------------------------------

View File

@ -120,6 +120,8 @@ public:
const irr::SEvent& getEventForGamePad(unsigned i) const;
void handleJoystick(SDL_Event& event);
SDLController* getSDLController(unsigned i);
#endif
void dispatchInput(Input::InputType, int deviceID, int btnID,

View File

@ -43,6 +43,7 @@ SDLController::SDLController(int device_id)
irr::SEvent::SJoystickEvent::NUMBER_OF_AXES * sizeof(int16_t));
m_game_controller = NULL;
m_joystick = NULL;
m_haptic = NULL;
m_id = -1;
if (SDL_IsGameController(device_id))
@ -177,6 +178,13 @@ SDLController::SDLController(int device_id)
if (created)
cfg->initSDLMapping();
cfg->setPlugged();
#if SDL_VERSION_ATLEAST(1,3,0)
m_haptic = SDL_HapticOpenFromJoystick(m_joystick);
if (m_haptic)
SDL_HapticRumbleInit(m_haptic);
#endif
for (int i = 0; i < dm->getGamePadAmount(); i++)
{
GamePadDevice* d = dm->getGamePad(i);
@ -206,6 +214,10 @@ SDLController::~SDLController()
SDL_GameControllerClose(m_game_controller);
else
SDL_JoystickClose(m_joystick);
#if SDL_VERSION_ATLEAST(1,3,0)
if (m_haptic)
SDL_HapticClose(m_haptic);
#endif
m_gamepad->getConfiguration()->unPlugged();
m_gamepad->setIrrIndex(-1);
m_gamepad->setConnected(false);
@ -247,6 +259,22 @@ void SDLController::checkPowerLevel()
#endif
} // checkPowerLevel
void SDLController::doRumble(float strength_low, float strength_high, uint32_t duration_ms)
{
#if SDL_VERSION_ATLEAST(1,3,0)
if (m_haptic)
{
SDL_HapticRumblePlay(m_haptic, (strength_low + strength_high) / 2, duration_ms);
}
else
#endif
{
uint16_t scaled_low = strength_low * pow(2, 16);
uint16_t scaled_high = strength_high * pow(2, 16);
SDL_GameControllerRumble(m_game_controller, scaled_low, scaled_high, duration_ms);
}
}
// ----------------------------------------------------------------------------
#ifdef ANDROID
void SDLController::handleDirectScanCode(const SDL_Event& event)

View File

@ -27,6 +27,11 @@
#include <bitset>
#include "utils/types.hpp"
#include <SDL_version.h>
#if SDL_VERSION_ATLEAST(1,3,0)
#include <SDL_haptic.h>
#endif
class GamePadDevice;
class SDLController
@ -38,6 +43,10 @@ private:
GamePadDevice* m_gamepad;
#if SDL_VERSION_ATLEAST(1,3,0)
SDL_Haptic* m_haptic;
#endif
int m_buttons;
int m_axes;
@ -152,6 +161,9 @@ public:
SDL_GameController* getGameController() const { return m_game_controller; }
// ------------------------------------------------------------------------
void checkPowerLevel();
// ------------------------------------------------------------------------
void doRumble(float strength_low, float strength_high, uint32_t duration_ms);
GamePadDevice* getGamePadDevice() const { return m_gamepad; }
};
#endif

View File

@ -309,6 +309,12 @@ void Attachment::hitBanana(ItemState *item_state)
{
HitEffect* he = new Explosion(m_kart->getXYZ(), "explosion",
"explosion_bomb.xml");
// Rumble!
Controller* controller = m_kart->getController();
if (controller && controller->isLocalPlayerController())
{
controller->rumble(0, 0.8f, 500);
}
if (m_kart->getController()->isLocalPlayerController())
he->setLocalPlayerKartHit();
ProjectileManager::get()->addHitEffect(he);
@ -520,6 +526,12 @@ void Attachment::update(int ticks)
{
HitEffect* he = new Explosion(m_kart->getXYZ(), "explosion",
"explosion_bomb.xml");
// Rumble!
Controller* controller = m_kart->getController();
if (controller && controller->isLocalPlayerController())
{
controller->rumble(0, 0.8f, 500);
}
if (m_kart->getController()->isLocalPlayerController())
he->setLocalPlayerKartHit();
ProjectileManager::get()->addHitEffect(he);

View File

@ -612,6 +612,13 @@ void Flyable::explode(AbstractKart *kart_hit, PhysicalObject *object,
if (RaceManager::get()->isLinearRaceMode())
PlayerManager::increaseAchievement(AchievementsStatus::ALL_HITS_1RACE, 1);
}
// Rumble!
Controller* controller = kart->getController();
if (controller && controller->isLocalPlayerController())
{
controller->rumble(0, 0.8f, 500);
}
}
}
}

View File

@ -79,7 +79,7 @@ public:
virtual bool disableSlipstreamBonus() const = 0;
virtual bool saveState(BareNetworkString *buffer) const = 0;
virtual void rewindTo(BareNetworkString *buffer) = 0;
virtual void rumble(float strength_low, float strength_high, uint16_t duration) {}
// ---------------------------------------------------------------------------
/** Sets the controller name for this controller. */
virtual void setControllerName(const std::string &name)

View File

@ -50,6 +50,10 @@
#include "utils/string_utils.hpp"
#include "utils/translation.hpp"
#include "input/device_manager.hpp"
#include "input/gamepad_device.hpp"
#include "input/sdl_controller.hpp"
/** The constructor for a loca player kart, i.e. a player that is playing
* on this machine (non-local player would be network clients).
* \param kart_name Name of the kart.
@ -62,6 +66,7 @@ LocalPlayerController::LocalPlayerController(AbstractKart *kart,
HandicapLevel h)
: PlayerController(kart)
{
m_last_crash = 0;
m_has_started = false;
m_handicap = h;
m_player = StateManager::get()->getActivePlayer(local_player_id);
@ -128,6 +133,7 @@ void LocalPlayerController::initParticleEmitter()
void LocalPlayerController::reset()
{
PlayerController::reset();
m_last_crash = 0;
m_sound_schedule = false;
m_has_started = false;
} // reset
@ -225,7 +231,7 @@ void LocalPlayerController::steer(int ticks, int steer_val)
video::SColor(255, 255, 0, 255), false);
}
PlayerController::steer(ticks, steer_val);
if(UserConfigParams::m_gamepad_debug)
{
Log::debug("LocalPlayerController", " set to: %f\n",
@ -414,7 +420,7 @@ void LocalPlayerController::collectedItem(const ItemState &item_state,
} // collectedItem
//-----------------------------------------------------------------------------
/** If the nitro level has gone under the nitro goal, play a bad effect sound
/** If the nitro level has gone under the nitro goal, play a bad effect sound
*/
void LocalPlayerController::nitroNotFullSound()
{
@ -429,7 +435,7 @@ void LocalPlayerController::nitroNotFullSound()
* collect achievements - synching to online account will happen
* next time the account gets online.
*/
bool LocalPlayerController::canGetAchievements() const
bool LocalPlayerController::canGetAchievements() const
{
return !RewindManager::get()->isRewinding() &&
m_player->getConstProfile() == PlayerManager::getCurrentPlayer();
@ -447,3 +453,48 @@ core::stringw LocalPlayerController::getName(bool include_handicap_string) const
return name;
} // getName
void LocalPlayerController::doCrashHaptics() {
#ifndef SERVER_ONLY
if (RewindManager::get()->isRewinding())
return;
int now = World::getWorld()->getTicksSinceStart();
int lastCrash = m_last_crash;
m_last_crash = now;
if ((now - lastCrash) < stk_config->time2Ticks(0.2f))
return;
float strength =
pow(2, (abs(m_player->getKart()->getVelocity().length())) / 15.0f) - 1.0f;
rumble(strength, strength, 200);
#endif
}
void LocalPlayerController::rumble(float strength_low, float strength_high, uint16_t duration) {
#ifndef SERVER_ONLY
if (RewindManager::get()->isRewinding())
return;
int count = input_manager->getGamepadCount();
while(count--)
{
SDLController* controller = input_manager->getSDLController(count);
if (controller && controller->getGamePadDevice()->getPlayer() == m_player)
{
controller->doRumble(strength_low, strength_high, duration);
break;
}
}
#endif
}
void LocalPlayerController::crashed(const AbstractKart* k) {
doCrashHaptics();
PlayerController::crashed(k);
}
void LocalPlayerController::crashed(const Material *m) {
doCrashHaptics();
PlayerController::crashed(m);
}

View File

@ -51,6 +51,8 @@ private:
* camera object is managed in the Camera class, so no need to free it. */
int m_camera_index;
int m_last_crash;
HandicapLevel m_handicap;
SFXBase *m_wee_sound;
@ -65,6 +67,8 @@ private:
virtual void displayPenaltyWarning() OVERRIDE;
void nitroNotFullSound();
void doCrashHaptics();
public:
LocalPlayerController(AbstractKart *kart,
const int local_player_id,
@ -83,6 +87,11 @@ public:
virtual void resetInputState () OVERRIDE;
virtual bool canGetAchievements() const OVERRIDE;
virtual void crashed(const AbstractKart *k) OVERRIDE;
virtual void crashed(const Material *m) OVERRIDE;
virtual void rumble(float strength_low, float strength_high, uint16_t duration) OVERRIDE;
// ------------------------------------------------------------------------
virtual bool isPlayerController() const OVERRIDE {return true;}
// ------------------------------------------------------------------------