]> git.lizzy.rs Git - minetest.git/commitdiff
Android: Replace movement buttons with joystick (#7126)
authorMuhammad Rifqi Priyo Susanto <muhammadrifqipriyosusanto@gmail.com>
Tue, 10 Apr 2018 20:55:17 +0000 (03:55 +0700)
committerSmallJoker <SmallJoker@users.noreply.github.com>
Tue, 10 Apr 2018 20:55:17 +0000 (22:55 +0200)
* Android: Replace movement buttons with joystick

Replace movement control buttons (arrows at bottom left screen) with virtual joystick.
Joystick has 8 directions (same as keyboard). Basically, just map it to keyboard input.
Joystick applies only on left 1/3 of screen.
Joystick's position can be fixed by enabling fixed_virtual_joystick setting.
Three new images:
(1) placeholder joystick,
(2) joystick container (background), and
(3) joystick cursor.
Remove unused images: movement control buttons (*_arrow.png).
New data type: touch_gui_joystick_move_id

Joystick's fixed position is spaced one button size from bottom and from left of screen.
Remove unused variable: m_joystick_downlocation

12 files changed:
builtin/settingtypes.txt
minetest.conf.example
src/defaultsettings.cpp
src/gui/touchscreengui.cpp
src/gui/touchscreengui.h
textures/base/pack/down_arrow.png [deleted file]
textures/base/pack/joystick_bg.png [new file with mode: 0755]
textures/base/pack/joystick_center.png [new file with mode: 0755]
textures/base/pack/joystick_off.png [new file with mode: 0755]
textures/base/pack/left_arrow.png [deleted file]
textures/base/pack/right_arrow.png [deleted file]
textures/base/pack/up_arrow.png [deleted file]

index 99febe1ef027a42bf0448458339be70cd5f3f250..080a57888fbaa7cd975c859805ac3beaa6cb4151 100644 (file)
@@ -118,6 +118,13 @@ random_input (Random input) bool false
 #    Continuous forward movement, toggled by autoforward key.
 continuous_forward (Continuous forward) bool false
 
+#    The length in pixels it takes for touch screen interaction to start.
+touchscreen_threshold (Touch screen threshold) int 20 0 100
+
+#    (Android) Fixes the position of virtual joystick.
+#    If disabled, virtual joystick will center to first-touch's position.
+fixed_virtual_joystick (Fixed virtual joystick) bool false
+
 #    Enable joysticks
 enable_joysticks (Enable joysticks) bool false
 
index 46d9ffe6557e16eb56cca7e105a749dea971a896..679f61dc1c72801a4054654a8fc3eb626a7c1126 100644 (file)
 #    type: bool
 # continuous_forward = false
 
+#    The length in pixels it takes for touch screen interaction to start.
+#    type: int
+# touchscreen_threshold = 20
+
+#    (Android) Fixes the position of virtual joystick.
+#    If disabled, virtual joystick will center to first-touch's position.
+#    type: int
+# fixed_virtual_joystick = false
+
 #    Enable Joysticks
 #    type: bool
 # enable_joysticks = false
index 586408dcf5acd30242c052d5cfe15408a68a8058..0c13e052d3a4ea2cf80e61adb20f7c7dac32303d 100644 (file)
@@ -408,6 +408,7 @@ void set_default_settings(Settings *settings)
        settings->setDefault("touchtarget", "true");
        settings->setDefault("TMPFolder","/sdcard/" PROJECT_NAME_C "/tmp/");
        settings->setDefault("touchscreen_threshold","20");
+       settings->setDefault("fixed_virtual_joystick", "false");
        settings->setDefault("smooth_lighting", "false");
        settings->setDefault("max_simultaneous_block_sends_per_client", "3");
        settings->setDefault("emergequeue_limit_diskonly", "8");
index e849b40530ee50435c7c2eff783e94720a8363f9..9b5731652e471920ab8e9c65e38238fa9f595d1a 100644 (file)
@@ -1,5 +1,7 @@
 /*
 Copyright (C) 2014 sapier
+Copyright (C) 2018 srifqi, Muhammad Rifqi Priyo Susanto
+               <muhammadrifqipriyosusanto@gmail.com>
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License as published by
@@ -37,15 +39,17 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 using namespace irr::core;
 
-const char** touchgui_button_imagenames = (const char*[]) {
-       "up_arrow.png",
-       "down_arrow.png",
-       "left_arrow.png",
-       "right_arrow.png",
+const char **touchgui_button_imagenames = (const char*[]) {
        "jump_btn.png",
        "down.png"
 };
 
+const char **touchgui_joystick_imagenames = (const char *[]) {
+       "joystick_off.png",
+       "joystick_bg.png",
+       "joystick_center.png"
+};
+
 static irr::EKEY_CODE id2keycode(touch_gui_button_id id)
 {
        std::string key = "";
@@ -143,7 +147,7 @@ void AutoHideButtonBar::init(ISimpleTextureSource* tsrc,
        m_upper_left = UpperLeft;
        m_lower_right = LowerRight;
 
-       /* init settings bar */
+       // init settings bar
 
        irr::core::rect<int> current_button = rect<s32>(UpperLeft.X, UpperLeft.Y,
                        LowerRight.X, LowerRight.Y);
@@ -258,7 +262,7 @@ bool AutoHideButtonBar::isButton(const SEvent &event)
        }
 
        if (m_active) {
-               /* check for all buttons in vector */
+               // check for all buttons in vector
 
                std::vector<button_info*>::iterator iter = m_buttons.begin();
 
@@ -273,11 +277,11 @@ bool AutoHideButtonBar::isButton(const SEvent &event)
                                translated->KeyInput.Shift       = false;
                                translated->KeyInput.Char        = 0;
 
-                               /* add this event */
+                               // add this event
                                translated->KeyInput.PressedDown = true;
                                m_receiver->OnEvent(*translated);
 
-                               /* remove this event */
+                               // remove this event
                                translated->KeyInput.PressedDown = false;
                                m_receiver->OnEvent(*translated);
 
@@ -292,7 +296,7 @@ bool AutoHideButtonBar::isButton(const SEvent &event)
                        ++iter;
                }
        } else {
-               /* check for starter button only */
+               // check for starter button only
                if (element == m_starter.guibutton) {
                        m_starter.ids.push_back(event.TouchInput.ID);
                        m_starter.guibutton->setVisible(false);
@@ -415,6 +419,8 @@ TouchScreenGUI::TouchScreenGUI(IrrlichtDevice *device, IEventReceiver* receiver)
                m_buttons[i].repeatdelay   = BUTTON_REPEAT_DELAY;
        }
 
+       m_touchscreen_threshold = g_settings->getU16("touchscreen_threshold");
+       m_fixed_joystick = g_settings->getBool("fixed_virtual_joystick");
        m_screensize = m_device->getVideoDriver()->getScreenSize();
 }
 
@@ -435,6 +441,21 @@ void TouchScreenGUI::initButton(touch_gui_button_id id, rect<s32> button_rect,
                        m_texturesource, m_device->getVideoDriver());
 }
 
+button_info *TouchScreenGUI::initJoystickButton(touch_gui_button_id id, rect<s32> button_rect,
+               int texture_id, bool visible)
+{
+       button_info *btn = new button_info();
+       btn->guibutton   = m_guienv->addButton(button_rect, 0, id, L"O");
+       btn->guibutton->setVisible(visible);
+       btn->guibutton->grab();
+       btn->ids.clear();
+
+       load_button_texture(btn, touchgui_joystick_imagenames[texture_id], button_rect,
+                       m_texturesource, m_device->getVideoDriver());
+
+       return btn;
+}
+
 static int getMaxControlPadSize(float density) {
        return 200 * density * g_settings->getFloat("hud_scaling");
 }
@@ -449,50 +470,40 @@ int TouchScreenGUI::getGuiButtonSize()
 
 void TouchScreenGUI::init(ISimpleTextureSource* tsrc)
 {
-       assert(tsrc != 0);
-
-       u32 button_size      = getGuiButtonSize();
-       m_visible            = true;
-       m_texturesource      = tsrc;
-       /*
-       draw control pad
-       0 1 2
-       3 4 5
-       for now only 0, 1, 2, and 4 are used
-       */
-       int number = 0;
-       for (int y = 0; y < 2; ++y)
-               for (int x = 0; x < 3; ++x, ++number) {
-                       rect<s32> button_rect(
-                                       x * button_size, m_screensize.Y - button_size * (2 - y),
-                                       (x + 1) * button_size, m_screensize.Y - button_size * (1 - y)
-                       );
-                       touch_gui_button_id id = after_last_element_id;
-                       std::wstring caption;
-                       switch (number) {
-                       case 0:
-                               id = left_id;
-                               caption = L"<";
-                               break;
-                       case 1:
-                               id = forward_id;
-                               caption = L"^";
-                               break;
-                       case 2:
-                               id = right_id;
-                               caption = L">";
-                               break;
-                       case 4:
-                               id = backward_id;
-                               caption = L"v";
-                               break;
-                       }
-                       if (id != after_last_element_id) {
-                               initButton(id, button_rect, caption, false);
-                               }
-               }
+       assert(tsrc);
 
-       /* init jump button */
+       u32 button_size = getGuiButtonSize();
+       m_visible       = true;
+       m_texturesource = tsrc;
+
+       /* Init joystick display "button"
+        * Joystick is placed on bottom left of screen.
+        */
+       if (m_fixed_joystick) {
+               m_joystick_btn_off = initJoystickButton(joystick_off_id,
+                               rect<s32>(button_size,
+                                               m_screensize.Y - button_size * 4,
+                                               button_size * 4,
+                                               m_screensize.Y - button_size), 0);
+       } else {
+               m_joystick_btn_off = initJoystickButton(joystick_off_id,
+                               rect<s32>(button_size,
+                                               m_screensize.Y - button_size * 3,
+                                               button_size * 3,
+                                               m_screensize.Y - button_size), 0);
+       }
+
+       m_joystick_btn_bg = initJoystickButton(joystick_bg_id,
+                       rect<s32>(button_size,
+                                       m_screensize.Y - button_size * 4,
+                                       button_size * 4,
+                                       m_screensize.Y - button_size),
+                       1, false);
+
+       m_joystick_btn_center = initJoystickButton(joystick_center_id,
+                       rect<s32>(0, 0, button_size, button_size), 2, false);
+
+       // init jump button
        initButton(jump_id,
                        rect<s32>(m_screensize.X-(1.75*button_size),
                                        m_screensize.Y - (0.5*button_size),
@@ -500,7 +511,7 @@ void TouchScreenGUI::init(ISimpleTextureSource* tsrc)
                                        m_screensize.Y),
                        L"x",false);
 
-       /* init crunch button */
+       // init crunch button
        initButton(crunch_id,
                        rect<s32>(m_screensize.X-(3.25*button_size),
                                        m_screensize.Y - (0.5*button_size),
@@ -634,7 +645,7 @@ void TouchScreenGUI::handleButtonEvent(touch_gui_button_id button,
        translated->KeyInput.Shift       = false;
        translated->KeyInput.Char        = 0;
 
-       /* add this event */
+       // add this event
        if (action) {
                assert(std::find(btn->ids.begin(),btn->ids.end(), eventID) == btn->ids.end());
 
@@ -647,12 +658,12 @@ void TouchScreenGUI::handleButtonEvent(touch_gui_button_id button,
                translated->KeyInput.Key = btn->keycode;
                m_receiver->OnEvent(*translated);
        }
-       /* remove event */
+       // remove event
        if ((!action) || (btn->immediate_release)) {
 
                std::vector<int>::iterator pos =
                                std::find(btn->ids.begin(),btn->ids.end(), eventID);
-               /* has to be in touch list */
+               // has to be in touch list
                assert(pos != btn->ids.end());
                btn->ids.erase(pos);
 
@@ -670,23 +681,23 @@ void TouchScreenGUI::handleReleaseEvent(int evt_id)
 {
        touch_gui_button_id button = getButtonID(evt_id);
 
-       /* handle button events */
+       // handle button events
        if (button != after_last_element_id) {
                handleButtonEvent(button, evt_id, false);
        }
-       /* handle hud button events */
+       // handle hud button events
        else if (isReleaseHUDButton(evt_id)) {
-               /* nothing to do here */
+               // nothing to do here
        } else if (m_settingsbar.isReleaseButton(evt_id)) {
-               /* nothing to do here */
+               // nothing to do here
        } else if (m_rarecontrolsbar.isReleaseButton(evt_id)) {
-               /* nothing to do here */
+               // nothing to do here
        }
-       /* handle the point used for moving view */
+       // handle the point used for moving view
        else if (evt_id == m_move_id) {
                m_move_id = -1;
 
-               /* if this pointer issued a mouse event issue symmetric release here */
+               // if this pointer issued a mouse event issue symmetric release here
                if (m_move_sent_as_mouse_event) {
                        SEvent* translated = new SEvent;
                        memset(translated,0,sizeof(SEvent));
@@ -701,10 +712,23 @@ void TouchScreenGUI::handleReleaseEvent(int evt_id)
                        delete translated;
                }
                else {
-                       /* do double tap detection */
+                       // do double tap detection
                        doubleTapDetection();
                }
        }
+       // handle joystick
+       else if (evt_id == m_joystick_id) {
+               m_joystick_id = -1;
+
+               // reset joystick
+               for (unsigned int i = 0; i < 4; i ++)
+                       m_joystick_status[i] = false;
+               applyJoystickStatus();
+
+               m_joystick_btn_off->guibutton->setVisible(true);
+               m_joystick_btn_bg->guibutton->setVisible(false);
+               m_joystick_btn_center->guibutton->setVisible(false);
+       }
        else {
                infostream
                        << "TouchScreenGUI::translateEvent released unknown button: "
@@ -748,7 +772,7 @@ void TouchScreenGUI::translateEvent(const SEvent &event)
                touch_gui_button_id button =
                                getButtonID(event.TouchInput.X, event.TouchInput.Y);
 
-               /* handle button events */
+               // handle button events
                if (button != after_last_element_id) {
                        handleButtonEvent(button, eventID, true);
                        m_settingsbar.deactivate();
@@ -756,25 +780,56 @@ void TouchScreenGUI::translateEvent(const SEvent &event)
                } else if (isHUDButton(event)) {
                        m_settingsbar.deactivate();
                        m_rarecontrolsbar.deactivate();
-                       /* already handled in isHUDButton() */
+                       // already handled in isHUDButton()
                } else if (m_settingsbar.isButton(event)) {
                        m_rarecontrolsbar.deactivate();
-                       /* already handled in isSettingsBarButton() */
+                       // already handled in isSettingsBarButton()
                } else if (m_rarecontrolsbar.isButton(event)) {
                        m_settingsbar.deactivate();
-                       /* already handled in isSettingsBarButton() */
+                       // already handled in isSettingsBarButton()
                }
-               /* handle non button events */
+               // handle non button events
                else {
                        m_settingsbar.deactivate();
                        m_rarecontrolsbar.deactivate();
-                       /* if we don't already have a moving point make this the moving one */
-                       if (m_move_id == -1) {
-                               m_move_id                  = event.TouchInput.ID;
-                               m_move_has_really_moved    = false;
-                               m_move_downtime            = porting::getTimeMs();
-                               m_move_downlocation        = v2s32(event.TouchInput.X, event.TouchInput.Y);
-                               m_move_sent_as_mouse_event = false;
+
+                       u32 button_size = getGuiButtonSize();
+                       s32 dxj = event.TouchInput.X - button_size * 5 / 2;
+                       s32 dyj = event.TouchInput.Y - m_screensize.Y + button_size * 5 / 2;
+
+                       /* Select joystick when left 1/3 of screen dragged or
+                        * when joystick tapped (fixed joystick position)
+                        */
+                       if ((m_fixed_joystick && dxj * dxj + dyj * dyj <= button_size * button_size * 1.5 * 1.5) ||
+                                       (!m_fixed_joystick && event.TouchInput.X < m_screensize.X / 3)) {
+                               // If we don't already have a starting point for joystick make this the one.
+                               if (m_joystick_id == -1) {
+                                       m_joystick_id               = event.TouchInput.ID;
+                                       m_joystick_has_really_moved = false;
+
+                                       m_joystick_btn_off->guibutton->setVisible(false);
+                                       m_joystick_btn_bg->guibutton->setVisible(true);
+                                       m_joystick_btn_center->guibutton->setVisible(true);
+
+                                       // If it's a fixed joystick, don't move the joystick "button".
+                                       if (!m_fixed_joystick) {
+                                               m_joystick_btn_bg->guibutton->setRelativePosition(v2s32(
+                                                               event.TouchInput.X - button_size * 3 / 2,
+                                                               event.TouchInput.Y - button_size * 3 / 2));
+                                       }
+                                       m_joystick_btn_center->guibutton->setRelativePosition(v2s32(
+                                                       event.TouchInput.X - button_size / 2,
+                                                       event.TouchInput.Y - button_size / 2));
+                               }
+                       } else {
+                               // If we don't already have a moving point make this the moving one.
+                               if (m_move_id == -1) {
+                                       m_move_id                  = event.TouchInput.ID;
+                                       m_move_has_really_moved    = false;
+                                       m_move_downtime            = porting::getTimeMs();
+                                       m_move_downlocation        = v2s32(event.TouchInput.X, event.TouchInput.Y);
+                                       m_move_sent_as_mouse_event = false;
+                               }
                        }
                }
 
@@ -803,7 +858,7 @@ void TouchScreenGUI::translateEvent(const SEvent &event)
                                                (m_pointerpos[event.TouchInput.ID].Y - event.TouchInput.Y) *
                                                (m_pointerpos[event.TouchInput.ID].Y - event.TouchInput.Y));
 
-                               if ((distance > g_settings->getU16("touchscreen_threshold")) ||
+                               if ((distance > m_touchscreen_threshold) ||
                                                (m_move_has_really_moved)) {
                                        m_move_has_really_moved = true;
                                        s32 X = event.TouchInput.X;
@@ -813,8 +868,8 @@ void TouchScreenGUI::translateEvent(const SEvent &event)
                                        s32 dx = X - m_pointerpos[event.TouchInput.ID].X;
                                        s32 dy = Y - m_pointerpos[event.TouchInput.ID].Y;
 
-                                       /* adapt to similar behaviour as pc screen */
-                                       double d         = g_settings->getFloat("mouse_sensitivity") *4;
+                                       // adapt to similar behaviour as pc screen
+                                       double d         = g_settings->getFloat("mouse_sensitivity") * 4;
                                        double old_yaw   = m_camera_yaw_change;
                                        double old_pitch = m_camera_pitch;
 
@@ -835,9 +890,91 @@ void TouchScreenGUI::translateEvent(const SEvent &event)
                                                ->getSceneManager()
                                                ->getSceneCollisionManager()
                                                ->getRayFromScreenCoordinates(
-                                                               v2s32(event.TouchInput.X,event.TouchInput.Y));
+                                                               v2s32(event.TouchInput.X, event.TouchInput.Y));
                        }
-               } else {
+               }
+
+               if (m_joystick_id != -1 && event.TouchInput.ID == m_joystick_id) {
+                       u32 button_size = getGuiButtonSize();
+                       s32 X = event.TouchInput.X;
+                       s32 Y = event.TouchInput.Y;
+
+                       s32 dx = X - m_pointerpos[event.TouchInput.ID].X;
+                       s32 dy = Y - m_pointerpos[event.TouchInput.ID].Y;
+                       if (m_fixed_joystick) {
+                               dx = X - button_size * 5 / 2;
+                               dy = Y - m_screensize.Y + button_size * 5 / 2;
+                       }
+
+                       double distance_sq = dx * dx + dy * dy;
+
+                       s32 dxj = event.TouchInput.X - button_size * 5 / 2;
+                       s32 dyj = event.TouchInput.Y - m_screensize.Y + button_size * 5 / 2;
+                       bool inside_joystick = (dxj * dxj + dyj * dyj <= button_size * button_size * 1.5 * 1.5);
+
+                       if (m_joystick_has_really_moved ||
+                                       (!m_joystick_has_really_moved && inside_joystick) ||
+                                       (!m_fixed_joystick &&
+                                       distance_sq > m_touchscreen_threshold * m_touchscreen_threshold)) {
+                               m_joystick_has_really_moved = true;
+                               double distance = sqrt(distance_sq);
+
+                               // angle in degrees
+                               double angle = acos(dx / distance) * 180 / M_PI;
+                               if (dy < 0)
+                                       angle *= -1;
+                               // rotate to make comparing easier
+                               angle = fmod(angle + 180 + 22.5, 360);
+
+                               // reset state before applying
+                               for (unsigned int i = 0; i < 4; i ++)
+                                       m_joystick_status[i] = false;
+
+                               if (distance <= m_touchscreen_threshold) {
+                                       // do nothing
+                               } else if (angle < 45)
+                                       m_joystick_status[j_left] = true;
+                               else if (angle < 90) {
+                                       m_joystick_status[j_forward] = true;
+                                       m_joystick_status[j_left] = true;
+                               } else if (angle < 135)
+                                       m_joystick_status[j_forward] = true;
+                               else if (angle < 180) {
+                                       m_joystick_status[j_forward] = true;
+                                       m_joystick_status[j_right] = true;
+                               } else if (angle < 225)
+                                       m_joystick_status[j_right] = true;
+                               else if (angle < 270) {
+                                       m_joystick_status[j_backward] = true;
+                                       m_joystick_status[j_right] = true;
+                               } else if (angle < 315)
+                                       m_joystick_status[j_backward] = true;
+                               else if (angle <= 360) {
+                                       m_joystick_status[j_backward] = true;
+                                       m_joystick_status[j_left] = true;
+                               }
+
+                               // move joystick "button"
+                               if (distance > button_size) {
+                                       s32 ndx = (s32) button_size * dx / distance - (s32) button_size / 2;
+                                       s32 ndy = (s32) button_size * dy / distance - (s32) button_size / 2;
+                                       if (m_fixed_joystick) {
+                                               m_joystick_btn_center->guibutton->setRelativePosition(v2s32(
+                                                       button_size * 5 / 2 + ndx,
+                                                       m_screensize.Y - button_size * 5 / 2 + ndy));
+                                       } else {
+                                               m_joystick_btn_center->guibutton->setRelativePosition(v2s32(
+                                                       m_pointerpos[event.TouchInput.ID].X + ndx,
+                                                       m_pointerpos[event.TouchInput.ID].Y + ndy));
+                                       }
+                               } else {
+                                       m_joystick_btn_center->guibutton->setRelativePosition(v2s32(
+                                               X - button_size / 2, Y - button_size / 2));
+                               }
+                       }
+               }
+
+               if (m_move_id == -1 && m_joystick_id == -1) {
                        handleChangedButton(event);
                }
        }
@@ -862,7 +999,7 @@ void TouchScreenGUI::handleChangedButton(const SEvent &event)
                                        continue;
                                }
 
-                               /* remove old button */
+                               // remove old button
                                handleButtonEvent((touch_gui_button_id) i,*iter,false);
 
                                if (current_button_id == after_last_element_id) {
@@ -909,7 +1046,7 @@ bool TouchScreenGUI::doubleTapDetection()
                        (m_key_events[0].y - m_key_events[1].y) * (m_key_events[0].y - m_key_events[1].y));
 
 
-       if (distance > (20 + g_settings->getU16("touchscreen_threshold")))
+       if (distance > (20 + m_touchscreen_threshold))
                return false;
 
        SEvent* translated = new SEvent();
@@ -940,27 +1077,58 @@ bool TouchScreenGUI::doubleTapDetection()
 
 }
 
+void TouchScreenGUI::applyJoystickStatus()
+{
+       for (unsigned int i = 0; i < 4; i ++) {
+               SEvent translated{};
+               translated.EventType            = irr::EET_KEY_INPUT_EVENT;
+               translated.KeyInput.Key         = id2keycode(m_joystick_names[i]);
+               translated.KeyInput.PressedDown = false;
+               m_receiver->OnEvent(translated);
+
+               if (m_joystick_status[i]) {
+                       translated.KeyInput.PressedDown = true;
+                       m_receiver->OnEvent(translated);
+               }
+       }
+}
+
 TouchScreenGUI::~TouchScreenGUI()
 {
        for (unsigned int i = 0; i < after_last_element_id; i++) {
                button_info* btn = &m_buttons[i];
-               if (btn->guibutton != 0) {
+               if (btn->guibutton) {
                        btn->guibutton->drop();
                        btn->guibutton = NULL;
                }
        }
+
+       if (m_joystick_btn_off->guibutton) {
+               m_joystick_btn_off->guibutton->drop();
+               m_joystick_btn_off->guibutton = NULL;
+       }
+
+       if (m_joystick_btn_bg->guibutton) {
+               m_joystick_btn_bg->guibutton->drop();
+               m_joystick_btn_bg->guibutton = NULL;
+       }
+
+       if (m_joystick_btn_center->guibutton) {
+               m_joystick_btn_center->guibutton->drop();
+               m_joystick_btn_center->guibutton = NULL;
+       }
 }
 
 void TouchScreenGUI::step(float dtime)
 {
-       /* simulate keyboard repeats */
+       // simulate keyboard repeats
        for (unsigned int i = 0; i < after_last_element_id; i++) {
                button_info* btn = &m_buttons[i];
 
                if (btn->ids.size() > 0) {
                        btn->repeatcounter += dtime;
 
-                       /* in case we're moving around digging does not happen */
+                       // in case we're moving around digging does not happen
                        if (m_move_id != -1)
                                m_move_has_really_moved = true;
 
@@ -979,7 +1147,10 @@ void TouchScreenGUI::step(float dtime)
                }
        }
 
-       /* if a new placed pointer isn't moved for some time start digging */
+       // joystick
+       applyJoystickStatus();
+
+       // if a new placed pointer isn't moved for some time start digging
        if ((m_move_id != -1) &&
                        (!m_move_has_really_moved) &&
                        (!m_move_sent_as_mouse_event)) {
@@ -1027,12 +1198,16 @@ void TouchScreenGUI::Toggle(bool visible)
        m_visible = visible;
        for (unsigned int i = 0; i < after_last_element_id; i++) {
                button_info* btn = &m_buttons[i];
-               if (btn->guibutton != 0) {
+               if (btn->guibutton) {
                        btn->guibutton->setVisible(visible);
                }
        }
 
-       /* clear all active buttons */
+       if (m_joystick_btn_off->guibutton) {
+               m_joystick_btn_off->guibutton->setVisible(visible);
+       }
+
+       // clear all active buttons
        if (!visible) {
                while (m_known_ids.size() > 0) {
                        handleReleaseEvent(m_known_ids.begin()->id);
index 9d4150ea64a5f6e914ab51e3c59fbed88c3ece6d..21c52f756e4e4dc656438481679371f0af5ea1cf 100644 (file)
@@ -34,11 +34,7 @@ using namespace irr::core;
 using namespace irr::gui;
 
 typedef enum {
-       forward_id = 0,
-       backward_id,
-       left_id,
-       right_id,
-       jump_id,
+       jump_id = 0,
        crunch_id,
        after_last_element_id,
        settings_starter_id,
@@ -51,9 +47,18 @@ typedef enum {
        range_id,
        chat_id,
        inventory_id,
-       drop_id
+       drop_id,
+       forward_id,
+       backward_id,
+       left_id,
+       right_id,
+       joystick_off_id,
+       joystick_bg_id,
+       joystick_center_id
 } touch_gui_button_id;
 
+typedef enum { j_forward = 0, j_backward, j_left, j_right } touch_gui_joystick_move_id;
+
 typedef enum {
        AHBB_Dir_Top_Bottom,
        AHBB_Dir_Bottom_Top,
@@ -69,6 +74,7 @@ typedef enum {
 #define RARE_CONTROLS_BAR_Y_OFFSET 4
 
 extern const char **touchgui_button_imagenames;
+extern const char **touchgui_joystick_imagenames;
 
 struct button_info
 {
@@ -91,26 +97,26 @@ class AutoHideButtonBar
 
        ~AutoHideButtonBar();
 
-       /* add button to be shown */
+       // add button to be shown
        void addButton(touch_gui_button_id id, const wchar_t *caption,
                        const char *btn_image);
 
-       /* detect settings bar button events */
+       // detect settings bar button events
        bool isButton(const SEvent &event);
 
-       /* handle released hud buttons */
+       // handle released hud buttons
        bool isReleaseButton(int eventID);
 
-       /* step handler */
+       // step handler
        void step(float dtime);
 
-       /* deactivate button bar */
+       // deactivate button bar
        void deactivate();
 
-       /* hide the whole buttonbar */
+       // hide the whole buttonbar
        void hide();
 
-       /* unhide the buttonbar */
+       // unhide the buttonbar
        void show();
 
 private:
@@ -124,12 +130,12 @@ class AutoHideButtonBar
        v2s32 m_upper_left;
        v2s32 m_lower_right;
 
-       /* show settings bar */
+       // show settings bar
        bool m_active = false;
 
        bool m_visible = true;
 
-       /* settings bar timeout */
+       // settings bar timeout
        float m_timeout = 0.0f;
        float m_timeout_value = 3.0f;
        bool m_initialized = false;
@@ -179,14 +185,20 @@ class TouchScreenGUI
        IEventReceiver *m_receiver;
        ISimpleTextureSource *m_texturesource;
        v2u32 m_screensize;
+       double m_touchscreen_threshold;
        std::map<int, rect<s32>> m_hud_rects;
        std::map<int, irr::EKEY_CODE> m_hud_ids;
        bool m_visible; // is the gui visible
 
-       /* value in degree */
+       // value in degree
        double m_camera_yaw_change = 0.0;
        double m_camera_pitch = 0.0;
 
+       // forward, backward, left, right
+       touch_gui_button_id m_joystick_names[4] = {
+                       forward_id, backward_id, left_id, right_id};
+       bool m_joystick_status[4] = {false, false, false, false};
+
        /*!
         * A line starting at the camera and pointing towards the
         * selected object.
@@ -201,22 +213,33 @@ class TouchScreenGUI
        bool m_move_sent_as_mouse_event = false;
        v2s32 m_move_downlocation = v2s32(-10000, -10000);
 
+       int m_joystick_id = -1;
+       bool m_joystick_has_really_moved = false;
+       bool m_fixed_joystick = false;
+       button_info *m_joystick_btn_off = nullptr;
+       button_info *m_joystick_btn_bg = nullptr;
+       button_info *m_joystick_btn_center = nullptr;
+
        button_info m_buttons[after_last_element_id];
 
-       /* gui button detection */
+       // gui button detection
        touch_gui_button_id getButtonID(s32 x, s32 y);
 
-       /* gui button by eventID */
+       // gui button by eventID
        touch_gui_button_id getButtonID(int eventID);
 
-       /* check if a button has changed */
+       // check if a button has changed
        void handleChangedButton(const SEvent &event);
 
-       /* initialize a button */
+       // initialize a button
        void initButton(touch_gui_button_id id, rect<s32> button_rect,
                        std::wstring caption, bool immediate_release,
                        float repeat_delay = BUTTON_REPEAT_DELAY);
 
+       // initialize a joystick button
+       button_info *initJoystickButton(touch_gui_button_id id, rect<s32> button_rect,
+                       int texture_id, bool visible = true);
+
        struct id_status
        {
                int id;
@@ -224,28 +247,31 @@ class TouchScreenGUI
                int Y;
        };
 
-       /* vector to store known ids and their initial touch positions*/
+       // vector to store known ids and their initial touch positions
        std::vector<id_status> m_known_ids;
 
-       /* handle a button event */
+       // handle a button event
        void handleButtonEvent(touch_gui_button_id bID, int eventID, bool action);
 
-       /* handle pressed hud buttons */
+       // handle pressed hud buttons
        bool isHUDButton(const SEvent &event);
 
-       /* handle released hud buttons */
+       // handle released hud buttons
        bool isReleaseHUDButton(int eventID);
 
-       /* handle double taps */
+       // handle double taps
        bool doubleTapDetection();
 
-       /* handle release event */
+       // handle release event
        void handleReleaseEvent(int evt_id);
 
-       /* get size of regular gui control button */
+       // apply joystick status
+       void applyJoystickStatus();
+
+       // get size of regular gui control button
        int getGuiButtonSize();
 
-       /* doubleclick detection variables */
+       // doubleclick detection variables
        struct key_event
        {
                unsigned int down_time;
@@ -253,16 +279,16 @@ class TouchScreenGUI
                s32 y;
        };
 
-       /* array for saving last known position of a pointer */
+       // array for saving last known position of a pointer
        v2s32 m_pointerpos[MAX_TOUCH_COUNT];
 
-       /* array for doubletap detection */
+       // array for doubletap detection
        key_event m_key_events[2];
 
-       /* settings bar */
+       // settings bar
        AutoHideButtonBar m_settingsbar;
 
-       /* rare controls bar */
+       // rare controls bar
        AutoHideButtonBar m_rarecontrolsbar;
 };
 extern TouchScreenGUI *g_touchscreengui;
diff --git a/textures/base/pack/down_arrow.png b/textures/base/pack/down_arrow.png
deleted file mode 100644 (file)
index 60ac497..0000000
Binary files a/textures/base/pack/down_arrow.png and /dev/null differ
diff --git a/textures/base/pack/joystick_bg.png b/textures/base/pack/joystick_bg.png
new file mode 100755 (executable)
index 0000000..15d3ff8
Binary files /dev/null and b/textures/base/pack/joystick_bg.png differ
diff --git a/textures/base/pack/joystick_center.png b/textures/base/pack/joystick_center.png
new file mode 100755 (executable)
index 0000000..fad012c
Binary files /dev/null and b/textures/base/pack/joystick_center.png differ
diff --git a/textures/base/pack/joystick_off.png b/textures/base/pack/joystick_off.png
new file mode 100755 (executable)
index 0000000..6eef488
Binary files /dev/null and b/textures/base/pack/joystick_off.png differ
diff --git a/textures/base/pack/left_arrow.png b/textures/base/pack/left_arrow.png
deleted file mode 100644 (file)
index 6076241..0000000
Binary files a/textures/base/pack/left_arrow.png and /dev/null differ
diff --git a/textures/base/pack/right_arrow.png b/textures/base/pack/right_arrow.png
deleted file mode 100644 (file)
index dc90674..0000000
Binary files a/textures/base/pack/right_arrow.png and /dev/null differ
diff --git a/textures/base/pack/up_arrow.png b/textures/base/pack/up_arrow.png
deleted file mode 100644 (file)
index 840040f..0000000
Binary files a/textures/base/pack/up_arrow.png and /dev/null differ