Added support for multitouch steering.

It will be used for steering on Android.

There are some limitations:
- currently it works only in single player mode (but I don't see any reason to make it working for multiplayer)
- speedometer is not available in race GUI because there is no place for it

TODO:
- add DPI support (race GUI should have probably different proportions on smaller devices for comfortable playing)
- make nice button images
- make nitro button that changes its look depending on collected nitro (a kind of nitro bar)

Touch input events must be handled in android device to make use of it. It can be simulated for debugging on non-android devices using standard mouse.
This commit is contained in:
deve 2016-11-10 02:42:56 +01:00
parent 78c1c5e14a
commit 4bb0405a32
13 changed files with 794 additions and 67 deletions

View File

@ -34,8 +34,8 @@ namespace irr
IrrlichtDevice::postEventFromUser. They take the same path as mouse events. */
EET_KEY_INPUT_EVENT,
//! A multi touch event.
EET_MULTI_TOUCH_EVENT,
//! A touch input event.
EET_TOUCH_INPUT_EVENT,
//! A accelerometer event.
EET_ACCELEROMETER_EVENT,
@ -177,22 +177,19 @@ namespace irr
#endif
//! Enumeration for all touch input events
enum EMULTI_TOUCH_INPUT_EVENT
enum ETOUCH_INPUT_EVENT
{
//! Max multi touch count
NUMBER_OF_MULTI_TOUCHES = 10,
//! Touch was pressed down.
EMTIE_PRESSED_DOWN = 0,
ETIE_PRESSED_DOWN = 0,
//! Touch was left up.
EMTIE_LEFT_UP,
ETIE_LEFT_UP,
//! The touch changed its position.
EMTIE_MOVED,
ETIE_MOVED,
//! No real event. Just for convenience to get number of events
EMTIE_COUNT
ETIE_COUNT
};
namespace gui
@ -384,54 +381,22 @@ struct SEvent
bool Control:1;
};
//! Any kind of multi touch event.
struct SMultiTouchInput
//! Any kind of touch event.
struct STouchInput
{
//! A helper function to check if a button is pressed.
u32 touchedCount() const
{
u32 count = 0;
for (u16 i = 0; i < NUMBER_OF_MULTI_TOUCHES; ++i)
{
if (Touched[i])
count++;
}
return count;
}
//! Reset variables.
void clear()
{
for (u16 i = 0; i < NUMBER_OF_MULTI_TOUCHES; ++i)
{
Touched[i] = 0;
X[i] = 0;
Y[i] = 0;
PrevX[i] = 0;
PrevY[i] = 0;
}
}
// Status of simple touch.
u8 Touched[NUMBER_OF_MULTI_TOUCHES];
// Touch ID.
size_t ID;
// X position of simple touch.
s32 X[NUMBER_OF_MULTI_TOUCHES];
s32 X;
// Y position of simple touch.
s32 Y[NUMBER_OF_MULTI_TOUCHES];
// Previous X position of simple touch.
s32 PrevX[NUMBER_OF_MULTI_TOUCHES];
// Previous Y position of simple touch.
s32 PrevY[NUMBER_OF_MULTI_TOUCHES];
//! Type of multi touch event
EMULTI_TOUCH_INPUT_EVENT Event;
s32 Y;
//! Type of touch event.
ETOUCH_INPUT_EVENT Event;
};
//! Any kind of accelerometer event.
struct SAccelerometerEvent
@ -575,7 +540,7 @@ struct SEvent
struct SGUIEvent GUIEvent;
struct SMouseInput MouseInput;
struct SKeyInput KeyInput;
struct SMultiTouchInput MultiTouchInput;
struct STouchInput TouchInput;
struct SAccelerometerEvent AccelerometerEvent;
struct SGyroscopeEvent GyroscopeEvent;
struct SDeviceMotionEvent DeviceMotionEvent;

View File

@ -3,4 +3,4 @@
file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp")
file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")
file(GLOB_RECURSE STK_RESOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${PROJECT_BINARY_DIR}/tmp/*.rc")
file(GLOB_RECURSE STK_RESOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${PROJECT_BINARY_DIR}/tmp/*.rc")

View File

@ -389,6 +389,28 @@ namespace UserConfigParams
&m_wiimote_group,
"A weight applied to the sin component of mapping wiimote angle to steering angle"));
// ---- Multitouch device
PARAM_PREFIX GroupUserConfigParam m_multitouch_group
PARAM_DEFAULT( GroupUserConfigParam("Multitouch",
"Settings for the multitouch device") );
PARAM_PREFIX BoolUserConfigParam m_multitouch_enabled
PARAM_DEFAULT( BoolUserConfigParam(false, "multitouch_enabled",
&m_multitouch_group,
"Enable multitouch support.") );
PARAM_PREFIX FloatUserConfigParam m_multitouch_deadzone_center
PARAM_DEFAULT( FloatUserConfigParam(0.15f, "multitouch_deadzone_center",
&m_multitouch_group,
"A parameter in range [0, 0.5] that determines the zone that is "
"considered as centered in steering button."));
PARAM_PREFIX FloatUserConfigParam m_multitouch_deadzone_edge
PARAM_DEFAULT( FloatUserConfigParam(0.15f, "multitouch_deadzone_edge",
&m_multitouch_group,
"A parameter in range [0, 0.5] that determines the zone that is "
"considered as max value in steering button."));
// ---- GP start order
PARAM_PREFIX GroupUserConfigParam m_gp_start_order
PARAM_DEFAULT( GroupUserConfigParam("GpStartOrder",

View File

@ -143,6 +143,35 @@ bool EventHandler::OnEvent (const SEvent &event)
{
DemoWorld::resetIdleTime();
}
// Simulate mouse event for first finger on multitouch device.
// This allows to click on GUI elements.
if (event.EventType == EET_TOUCH_INPUT_EVENT)
{
if (event.TouchInput.ID == 0)
{
if (event.TouchInput.Event == ETIE_PRESSED_DOWN)
{
SEvent irrevent;
irrevent.EventType = EET_MOUSE_INPUT_EVENT;
irrevent.MouseInput.X = event.TouchInput.X;
irrevent.MouseInput.Y = event.TouchInput.Y;
irrevent.MouseInput.Event = EMIE_LMOUSE_PRESSED_DOWN;
irr_driver->getDevice()->postEventFromUser(irrevent);
}
else if (event.TouchInput.Event == ETIE_LEFT_UP)
{
SEvent irrevent;
irrevent.EventType = EET_MOUSE_INPUT_EVENT;
irrevent.MouseInput.X = event.TouchInput.X;
irrevent.MouseInput.Y = event.TouchInput.Y;
irrevent.MouseInput.Event = EMIE_LMOUSE_LEFT_UP;
irr_driver->getDevice()->postEventFromUser(irrevent);
}
}
}
if (event.EventType == EET_GUI_EVENT)
{
@ -155,6 +184,7 @@ bool EventHandler::OnEvent (const SEvent &event)
return false; // EVENT_LET
}
else if (event.EventType == EET_MOUSE_INPUT_EVENT ||
event.EventType == EET_TOUCH_INPUT_EVENT ||
event.EventType == EET_KEY_INPUT_EVENT ||
event.EventType == EET_JOYSTICK_INPUT_EVENT)
{

View File

@ -25,6 +25,7 @@
#include "graphics/irr_driver.hpp"
#include "input/gamepad_device.hpp"
#include "input/keyboard_device.hpp"
#include "input/multitouch_device.hpp"
#include "input/wiimote_manager.hpp"
#include "io/file_manager.hpp"
#include "states_screens/kart_selection.hpp"
@ -43,6 +44,7 @@ DeviceManager::DeviceManager()
m_latest_used_device = NULL;
m_assign_mode = NO_ASSIGN;
m_single_player = NULL;
m_multitouch_device = NULL;
} // DeviceManager
// -----------------------------------------------------------------------------
@ -138,6 +140,11 @@ bool DeviceManager::initialize()
addGamepad(gamepadDevice);
} // end for
if (UserConfigParams::m_multitouch_enabled)
{
m_multitouch_device = new MultitouchDevice();
}
if (created) save();
return created;
@ -154,6 +161,12 @@ void DeviceManager::clearGamepads()
{
m_gamepads.clearAndDeleteAll();
} // clearGamepads
// -----------------------------------------------------------------------------
void DeviceManager::clearMultitouchDevices()
{
delete m_multitouch_device;
m_multitouch_device = NULL;
} // clearMultitouchDevices
// -----------------------------------------------------------------------------
void DeviceManager::setAssignMode(const PlayerAssignMode assignMode)
@ -177,6 +190,9 @@ void DeviceManager::setAssignMode(const PlayerAssignMode assignMode)
{
m_keyboards[i].setPlayer(NULL);
}
if (m_multitouch_device != NULL)
m_multitouch_device->setPlayer(NULL);
}
} // setAssignMode
@ -391,6 +407,25 @@ InputDevice *DeviceManager::mapGamepadInput(Input::InputType type,
//-----------------------------------------------------------------------------
void DeviceManager::updateMultitouchDevice()
{
if (m_multitouch_device == NULL)
return;
if (m_single_player != NULL)
{
// in single-player mode, assign the gamepad as needed
if (m_multitouch_device->getPlayer() != m_single_player)
m_multitouch_device->setPlayer(m_single_player);
}
else if (m_assign_mode == NO_ASSIGN) // Don't set the player in NO_ASSIGN mode
{
m_multitouch_device->setPlayer(NULL);
}
} // updateMultitouchDevice
//-----------------------------------------------------------------------------
bool DeviceManager::translateInput( Input::InputType type,
int device_id,
int button_id,
@ -604,5 +639,7 @@ void DeviceManager::shutdown()
m_keyboards.clearAndDeleteAll();
m_gamepad_configs.clearAndDeleteAll();
m_keyboard_configs.clearAndDeleteAll();
delete m_multitouch_device;
m_multitouch_device = NULL;
m_latest_used_device = NULL;
} // shutdown

View File

@ -34,6 +34,7 @@ class DeviceConfig;
class InputDevice;
class GamePadDevice;
class KeyboardDevice;
class MultitouchDevice;
enum PlayerAssignMode
@ -66,6 +67,7 @@ private:
PtrVector<GamePadDevice, HOLD> m_gamepads;
PtrVector<KeyboardConfig, HOLD> m_keyboard_configs;
PtrVector<GamepadConfig, HOLD> m_gamepad_configs;
MultitouchDevice* m_multitouch_device;
/** The list of all joysticks that were found and activated. */
core::array<SJoystickInfo> m_irrlicht_gamepads;
@ -129,6 +131,11 @@ public:
KeyboardConfig* getKeyboardConfig(const int i) { return m_keyboard_configs.get(i); }
KeyboardDevice* getKeyboardFromBtnID(const int btnID);
// ---- Multitouch device ----
MultitouchDevice* getMultitouchDevice() { return m_multitouch_device; }
void clearMultitouchDevices();
void updateMultitouchDevice();
/**
* \brief Delete the given config and removes DeviceManager references to it.

View File

@ -36,7 +36,8 @@ class DeviceConfig;
enum DeviceType
{
DT_KEYBOARD,
DT_GAMEPAD
DT_GAMEPAD,
DT_MULTITOUCH
};
/**

View File

@ -28,6 +28,7 @@
#include "input/device_manager.hpp"
#include "input/gamepad_device.hpp"
#include "input/keyboard_device.hpp"
#include "input/multitouch_device.hpp"
#include "input/input.hpp"
#include "karts/controller/controller.hpp"
#include "karts/abstract_kart.hpp"
@ -113,7 +114,7 @@ void InputManager::handleStaticAction(int key, int value)
}
if (world != NULL && UserConfigParams::m_artist_debug_mode &&
if (world != NULL && UserConfigParams::m_artist_debug_mode &&
control_is_pressed && value > 0)
{
if (Debug::handleStaticAction(key))
@ -283,7 +284,7 @@ void InputManager::handleStaticAction(int key, int value)
float t;
StringUtils::fromString(s,t);
RewindManager::get()->rewindTo(t);
Log::info("Rewind", "Rewinding from %f to %f",
Log::info("Rewind", "Rewinding from %f to %f",
world->getTime(), t);
}
break;
@ -650,7 +651,7 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID,
else if (button == KEY_RIGHT) action = PA_MENU_RIGHT;
else if (button == KEY_SPACE) action = PA_MENU_SELECT;
else if (button == KEY_RETURN) action = PA_MENU_SELECT;
else if (button == KEY_TAB)
else if (button == KEY_TAB)
{
if (shift_mask)
{
@ -1014,6 +1015,30 @@ EventPropagation InputManager::input(const SEvent& event)
return EVENT_BLOCK; // Don't propagate key up events
}
}
else if (event.EventType == EET_TOUCH_INPUT_EVENT)
{
MultitouchDevice* device = m_device_manager->getMultitouchDevice();
unsigned int id = event.TouchInput.ID;
if (device != NULL && id < device->m_events.size())
{
device->m_events[id].id = id;
device->m_events[id].x = event.TouchInput.X;
device->m_events[id].y = event.TouchInput.Y;
if (event.TouchInput.Event == ETIE_PRESSED_DOWN)
{
device->m_events[id].touched = true;
}
else if (event.TouchInput.Event == ETIE_LEFT_UP)
{
device->m_events[id].touched = false;
}
m_device_manager->updateMultitouchDevice();
device->updateDeviceState(id);
}
}
// Use the mouse to change the looking direction when first person view is activated
else if (event.EventType == EET_MOUSE_INPUT_EVENT)
{
@ -1096,6 +1121,35 @@ EventPropagation InputManager::input(const SEvent& event)
}
}
// Simulate touch event on non-android devices
#if !defined(ANDROID)
if (UserConfigParams::m_multitouch_enabled == true &&
(type == EMIE_LMOUSE_PRESSED_DOWN || type == EMIE_LMOUSE_LEFT_UP ||
type == EMIE_MOUSE_MOVED))
{
MultitouchDevice* device = m_device_manager->getMultitouchDevice();
if (device != NULL)
{
device->m_events[0].id = 0;
device->m_events[0].x = event.MouseInput.X;
device->m_events[0].y = event.MouseInput.Y;
if (type == EMIE_LMOUSE_PRESSED_DOWN)
{
device->m_events[0].touched = true;
}
else if (type == EMIE_LMOUSE_LEFT_UP)
{
device->m_events[0].touched = false;
}
m_device_manager->updateMultitouchDevice();
device->updateDeviceState(0);
}
}
#endif
/*
EMIE_LMOUSE_PRESSED_DOWN Left mouse button was pressed down.
EMIE_RMOUSE_PRESSED_DOWN Right mouse button was pressed down.

View File

@ -0,0 +1,306 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013-2015 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License: or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <cassert>
#include <algorithm>
#include "config/user_config.hpp"
#include "input/multitouch_device.hpp"
#include "karts/abstract_kart.hpp"
#include "karts/controller/controller.hpp"
#include "graphics/irr_driver.hpp"
#include "guiengine/modaldialog.hpp"
// ----------------------------------------------------------------------------
/** The multitouch device constructor
*/
MultitouchDevice::MultitouchDevice()
{
m_configuration = NULL;
m_type = DT_MULTITOUCH;
m_name = "Multitouch";
m_player = NULL;
for (MultitouchEvent& event : m_events)
{
event.id = 0;
event.touched = false;
event.x = 0;
event.y = 0;
}
m_deadzone_center = UserConfigParams::m_multitouch_deadzone_center;
m_deadzone_center = std::min(std::max(m_deadzone_center, 0.0f), 0.5f);
m_deadzone_edge = UserConfigParams::m_multitouch_deadzone_edge;
m_deadzone_edge = std::min(std::max(m_deadzone_edge, 0.0f), 0.5f);
} // MultitouchDevice
// ----------------------------------------------------------------------------
/** The multitouch device destructor
*/
MultitouchDevice::~MultitouchDevice()
{
clearButtons();
}
// ----------------------------------------------------------------------------
/** Returns a number of fingers that are currently in use
*/
unsigned int MultitouchDevice::getActiveTouchesCount()
{
unsigned int count = 0;
for (MultitouchEvent event : m_events)
{
if (event.touched)
count++;
}
return count;
} // getActiveTouchesCount
// ----------------------------------------------------------------------------
/** Creates a button of specified type and position. The button is then updated
* when touch event occurs and proper action is sent to player controller.
* Note that it just determines the screen area that is considered as button
* and it doesn't draw the GUI element on a screen.
* \param type The button type that determines its behaviour.
* \param x Vertical position of the button.
* \param y Horizontal position of the button.
* \param width Width of the button.
* \param height Height of the button.
*/
void MultitouchDevice::addButton(MultitouchButtonType type, int x, int y,
int width, int height)
{
assert(width > 0 && height > 0);
MultitouchButton* button = new MultitouchButton();
button->type = type;
button->event_id = 0;
button->pressed = false;
button->x = x;
button->y = y;
button->width = width;
button->height = height;
button->axis_x = 0.0f;
button->axis_y = 0.0f;
switch (button->type)
{
case MultitouchButtonType::BUTTON_FIRE:
button->action = PA_FIRE;
break;
case MultitouchButtonType::BUTTON_NITRO:
button->action = PA_NITRO;
break;
case MultitouchButtonType::BUTTON_SKIDDING:
button->action = PA_DRIFT;
break;
case MultitouchButtonType::BUTTON_LOOK_BACKWARDS:
button->action = PA_LOOK_BACK;
break;
case MultitouchButtonType::BUTTON_RESCUE:
button->action = PA_RESCUE;
break;
case MultitouchButtonType::BUTTON_ESCAPE:
button->action = PA_PAUSE_RACE;
break;
case MultitouchButtonType::BUTTON_UP:
button->action = PA_ACCEL;
break;
case MultitouchButtonType::BUTTON_DOWN:
button->action = PA_BRAKE;
break;
case MultitouchButtonType::BUTTON_LEFT:
button->action = PA_STEER_LEFT;
break;
case MultitouchButtonType::BUTTON_RIGHT:
button->action = PA_STEER_RIGHT;
break;
default:
button->action = PA_BEFORE_FIRST;
break;
}
m_buttons.push_back(button);
} // addButton
// ----------------------------------------------------------------------------
/** Deletes all previously created buttons
*/
void MultitouchDevice::clearButtons()
{
for (MultitouchButton* button : m_buttons)
{
delete button;
}
m_buttons.clear();
} // clearButtons
// ----------------------------------------------------------------------------
/** The function that is executed when touch event occurs. It updates the
* buttons state when it's needed.
* \param event_id The id of touch event that should be processed.
*/
void MultitouchDevice::updateDeviceState(unsigned int event_id)
{
assert(event_id < m_events.size());
MultitouchEvent event = m_events[event_id];
for (MultitouchButton* button : m_buttons)
{
bool update_controls = false;
bool prev_button_state = button->pressed;
float prev_axis_x = button->axis_x;
float prev_axis_y = button->axis_y;
if (event.x < button->x || event.x > button->x + button->width ||
event.y < button->y || event.y > button->y + button->height)
{
if (button->event_id == event_id)
{
button->pressed = false;
button->event_id = 0;
button->axis_x = 0.0f;
button->axis_y = 0.0f;
update_controls = true;
}
}
else
{
button->pressed = event.touched;
button->event_id = event_id;
if (button->type == MultitouchButtonType::BUTTON_STEERING)
{
if (button->pressed == true)
{
button->axis_x = (float)(event.x - button->x) /
(button->width/2) - 1;
button->axis_y = (float)(event.y - button->y) /
(button->height/2) - 1;
}
else
{
button->axis_x = 0.0f;
button->axis_y = 0.0f;
}
if (prev_axis_x != button->axis_x ||
prev_axis_y != button->axis_y)
{
update_controls = true;
}
}
else if (prev_button_state != button->pressed)
{
update_controls = true;
}
}
if (update_controls)
{
handleControls(button);
}
}
} // updateDeviceState
// ----------------------------------------------------------------------------
/** Sends proper action for player controller depending on the button type
* and state.
* \param button The button that should be handled.
*/
void MultitouchDevice::handleControls(MultitouchButton* button)
{
if (m_player == NULL)
return;
// Handle multitouch events only when race is running. It avoids to process
// it when pause dialog is active during the race. And there is no reason
// to use it for GUI navigation.
if (StateManager::get()->getGameState() != GUIEngine::GAME ||
GUIEngine::ModalDialog::isADialogActive() ||
race_manager->isWatchingReplay())
return;
AbstractKart* pk = m_player->getKart();
if (pk == NULL)
return;
Controller* controller = pk->getController();
if (controller == NULL)
return;
if (button->type == MultitouchButtonType::BUTTON_STEERING)
{
assert(m_deadzone_edge != 1.0f);
if (button->axis_y < -m_deadzone_center)
{
float factor = std::min(std::abs(button->axis_y) / (1 -
m_deadzone_edge), 1.0f);
controller->action(PA_ACCEL, factor * Input::MAX_VALUE);
}
else if (button->axis_y > m_deadzone_center)
{
float factor = std::min(std::abs(button->axis_y) / (1 -
m_deadzone_edge), 1.0f);
controller->action(PA_BRAKE, factor * Input::MAX_VALUE);
}
else
{
controller->action(PA_BRAKE, 0);
controller->action(PA_ACCEL, 0);
}
if (button->axis_x < -m_deadzone_center)
{
float factor = std::min(std::abs(button->axis_x) / (1 -
m_deadzone_edge), 1.0f);
controller->action(PA_STEER_LEFT, factor * Input::MAX_VALUE);
}
else if (button->axis_x > m_deadzone_center)
{
float factor = std::min(std::abs(button->axis_x) / (1 -
m_deadzone_edge), 1.0f);
controller->action(PA_STEER_RIGHT, factor * Input::MAX_VALUE);
}
else
{
controller->action(PA_STEER_LEFT, 0);
controller->action(PA_STEER_RIGHT, 0);
}
}
else
{
if (button->action != PA_BEFORE_FIRST)
{
int value = button->pressed ? Input::MAX_VALUE : 0;
controller->action(button->action, value);
}
}
} // handleControls
// ----------------------------------------------------------------------------

View File

@ -0,0 +1,111 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013-2015 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_MULTITOUCH_DEVICE_HPP
#define HEADER_MULTITOUCH_DEVICE_HPP
#include <array>
#include <vector>
#include "input/input_device.hpp"
#include "IEventReceiver.h"
#define NUMBER_OF_MULTI_TOUCHES 10
enum MultitouchButtonType
{
BUTTON_STEERING,
BUTTON_FIRE,
BUTTON_NITRO,
BUTTON_SKIDDING,
BUTTON_LOOK_BACKWARDS,
BUTTON_RESCUE,
BUTTON_ESCAPE,
BUTTON_UP,
BUTTON_DOWN,
BUTTON_LEFT,
BUTTON_RIGHT
};
struct MultitouchEvent
{
int id;
bool touched;
int x;
int y;
};
struct MultitouchButton
{
MultitouchButtonType type;
PlayerAction action;
bool pressed;
unsigned int event_id;
int x;
int y;
int width;
int height;
float axis_x;
float axis_y;
};
class MultitouchDevice : public InputDevice
{
private:
/** The list of pointers to all created buttons */
std::vector<MultitouchButton*> m_buttons;
/** The parameter that is used for steering button and determines dead area
* in a center of button */
float m_deadzone_center;
/** The parameter that is used for steering button and determines dead area
* at the edge of button */
float m_deadzone_edge;
public:
/** The array that contains data for all multitouch input events */
std::array<MultitouchEvent, NUMBER_OF_MULTI_TOUCHES> m_events;
MultitouchDevice();
virtual ~MultitouchDevice();
/** Unused function */
bool processAndMapInput(Input::InputType type, const int id,
InputManager::InputDriverMode mode,
PlayerAction *action, int* value = NULL)
{return true;}
unsigned int getActiveTouchesCount();
void addButton(MultitouchButtonType type, int x, int y, int width,
int height);
void clearButtons();
/** Returns the number of created buttons */
unsigned int getButtonsCount() {return m_buttons.size();}
/** Returns pointer to the selected button */
MultitouchButton* getButton(unsigned int i) {return m_buttons.at(i);}
void updateDeviceState(unsigned int event_id);
void handleControls(MultitouchButton* button);
}; // MultitouchDevice
#endif

View File

@ -35,10 +35,13 @@ using namespace irr;
#include "io/file_manager.hpp"
#include "input/input.hpp"
#include "input/input_manager.hpp"
#include "input/device_manager.hpp"
#include "input/multitouch_device.hpp"
#include "items/attachment.hpp"
#include "items/attachment_manager.hpp"
#include "items/powerup_manager.hpp"
#include "karts/abstract_kart.hpp"
#include "karts/controller/controller.hpp"
#include "karts/controller/spare_tire_ai.hpp"
#include "karts/kart_properties.hpp"
#include "karts/kart_properties_manager.hpp"
@ -83,6 +86,11 @@ RaceGUI::RaceGUI()
{
m_map_left = irr_driver->getActualScreenSize().Width - m_map_width;
}
else if (UserConfigParams::m_multitouch_enabled)
{
m_map_left = irr_driver->getActualScreenSize().Width - m_map_width;
m_map_bottom = irr_driver->getActualScreenSize().Height * 0.55f;
}
m_is_tutorial = (race_manager->getTrackName() == "tutorial");
@ -104,11 +112,22 @@ RaceGUI::RaceGUI()
else
m_lap_width = font->getDimension(L"9/9").Width;
if (UserConfigParams::m_multitouch_enabled)
{
initMultitouchSteering();
}
} // RaceGUI
//-----------------------------------------------------------------------------
RaceGUI::~RaceGUI()
{
MultitouchDevice* device = input_manager->getDeviceManager()->
getMultitouchDevice();
if (device != NULL)
{
device->clearButtons();
}
} // ~Racegui
@ -216,10 +235,19 @@ void RaceGUI::renderPlayerView(const Camera *camera, float dt)
scaling *= viewport.getWidth()/800.0f; // scale race GUI along screen size
drawAllMessages(kart, viewport, scaling);
if (UserConfigParams::m_multitouch_enabled)
{
drawMultitouchSteering(kart, viewport, scaling);
}
if(!World::getWorld()->isRacePhase()) return;
drawPowerupIcons (kart, viewport, scaling);
drawSpeedEnergyRank(kart, viewport, scaling, dt);
drawPowerupIcons(kart, viewport, scaling);
if (!UserConfigParams::m_multitouch_enabled)
{
drawSpeedEnergyRank(kart, viewport, scaling, dt);
}
if (!m_is_tutorial)
drawLap(kart, viewport, scaling);
@ -878,3 +906,157 @@ void RaceGUI::drawLap(const AbstractKart* kart,
font->setScale(1.0f);
} // drawLap
//-----------------------------------------------------------------------------
/** Makes some initializations and determines the look of multitouch steering
* interface
*/
void RaceGUI::initMultitouchSteering()
{
MultitouchDevice* device = input_manager->getDeviceManager()->
getMultitouchDevice();
if (device == NULL)
return;
const int w = irr_driver->getActualScreenSize().Width;
const int h = irr_driver->getActualScreenSize().Height;
const float btn_size = 0.1f * h;
const float btn2_size = 0.35f * h;
const float margin = 0.1f * h;
const float top_margin = 0.3f * h;
const float col_size = btn_size + margin;
const float small_ratio = 0.6f;
device->addButton(BUTTON_STEERING,
0.5f * margin, h - 0.5f * margin - btn2_size,
btn2_size, btn2_size);
device->addButton(BUTTON_ESCAPE,
top_margin, small_ratio * margin,
small_ratio * btn_size, small_ratio * btn_size);
device->addButton(BUTTON_RESCUE,
top_margin + small_ratio * col_size, small_ratio * margin,
small_ratio * btn_size, small_ratio * btn_size);
device->addButton(BUTTON_NITRO,
w - 1 * col_size, h - 2 * col_size,
btn_size, btn_size);
device->addButton(BUTTON_SKIDDING,
w - 1 * col_size, h - 1 * col_size,
btn_size, btn_size);
device->addButton(BUTTON_FIRE,
w - 2 * col_size, h - 2 * col_size,
btn_size, btn_size);
device->addButton(BUTTON_LOOK_BACKWARDS,
w - 2 * col_size, h - 1 * col_size,
btn_size, btn_size);
} // initMultitouchSteering
//-----------------------------------------------------------------------------
/** Draws the buttons for multitouch steering.
* \param kart The kart for which to show the data.
* \param viewport The viewport to use.
* \param scaling Which scaling to apply to the buttons.
*/
void RaceGUI::drawMultitouchSteering(const AbstractKart* kart,
const core::recti &viewport,
const core::vector2df &scaling)
{
MultitouchDevice* device = input_manager->getDeviceManager()->
getMultitouchDevice();
if (device == NULL)
return;
for (unsigned int i = 0; i < device->getButtonsCount(); i++)
{
MultitouchButton* button = device->getButton(i);
core::rect<s32> pos(button->x, button->y, button->x + button->width,
button->y + button->height);
if (button->type == MultitouchButtonType::BUTTON_STEERING)
{
video::ITexture* tex = irr_driver->getTexture(FileManager::GUI,
"blue_plus.png");
core::rect<s32> coords(core::position2d<s32>(0,0), tex->getSize());
draw2DImage(tex, pos, coords, NULL, NULL, true);
float x = (float)(button->x) + (float)(button->width) / 2.0f *
(button->axis_x + 1.0f);
float y = (float)(button->y) + (float)(button->height) / 2.0f *
(button->axis_y + 1.0f);
float w = (float)(button->width) / 20.0f;
float h = (float)(button->height) / 20.0f;
core::rect<s32> pos2(round(x - w), round(y - h),
round(x + w), round(y + h));
draw2DImage(tex, pos2, coords, NULL, NULL, true);
}
else
{
if (button->pressed)
{
core::rect<s32> pos2(button->x - button->width * 0.2f,
button->y - button->height * 0.2f,
button->x + button->width * 1.2f,
button->y + button->height * 1.2f);
video::ITexture* tex = irr_driver->getTexture(FileManager::GUI,
"icons-frame.png");
core::rect<s32> coords(core::position2d<s32>(0,0), tex->getSize());
draw2DImage(tex, pos2, coords, NULL, NULL, true);
}
video::ITexture* tex;
if (button->type == MultitouchButtonType::BUTTON_SKIDDING)
{
tex = irr_driver->getTexture(FileManager::TEXTURE,
"skid-particle1.png");
}
else
{
std::string name = "gui_lock.png";
switch (button->type)
{
case MultitouchButtonType::BUTTON_ESCAPE:
name = "back.png";
break;
case MultitouchButtonType::BUTTON_FIRE:
name = "banana.png";
break;
case MultitouchButtonType::BUTTON_NITRO:
name = "nitro.png";
break;
case MultitouchButtonType::BUTTON_LOOK_BACKWARDS:
name = "down.png";
break;
case MultitouchButtonType::BUTTON_RESCUE:
name = "restart.png";
break;
default:
break;
}
tex = irr_driver->getTexture(FileManager::GUI, name);
}
core::rect<s32> coords(core::position2d<s32>(0,0), tex->getSize());
draw2DImage(tex, pos, coords, NULL, NULL, true);
if (button->type == MultitouchButtonType::BUTTON_NITRO)
{
float scale = (float)(irr_driver->
getActualScreenSize().Height) / 1600.0f;
drawEnergyMeter(button->x + button->width,
button->y + button->height,
kart, viewport, core::vector2df(scale, scale));
}
}
}
} // drawMultitouchSteering

View File

@ -94,6 +94,8 @@ private:
bool m_is_tutorial;
void initMultitouchSteering();
/* Display informat for one player on the screen. */
void drawEnergyMeter (int x, int y, const AbstractKart *kart,
const core::recti &viewport,
@ -108,6 +110,9 @@ private:
const core::vector2df &offset,
float min_ratio, int meter_width,
int meter_height, float dt);
void drawMultitouchSteering (const AbstractKart* kart,
const core::recti &viewport,
const core::vector2df &scaling);
/** Display items that are shown once only (for all karts). */
void drawGlobalMiniMap ();

View File

@ -693,9 +693,16 @@ void RaceGUIBase::drawGlobalPlayerIcons(int bottom_margin)
const unsigned int kart_amount = world->getNumKarts() - sta;
//where is the limit to hide last icons
int y_icons_limit=irr_driver->getActualScreenSize().Height-bottom_margin-ICON_PLAYER_WIDTH;
int y_icons_limit = irr_driver->getActualScreenSize().Height -
bottom_margin - ICON_PLAYER_WIDTH;
if (race_manager->getNumLocalPlayers() == 3)
y_icons_limit=irr_driver->getActualScreenSize().Height-ICON_WIDTH;
{
y_icons_limit = irr_driver->getActualScreenSize().Height - ICON_WIDTH;
}
else if (UserConfigParams::m_multitouch_enabled)
{
y_icons_limit = irr_driver->getActualScreenSize().Height / 2;
}
world->getKartsDisplayInfo(&m_kart_display_infos);