From 3978b9b8ed1c318c3f9a088beb331c26bca6de6b Mon Sep 17 00:00:00 2001 From: Muhammad Rifqi Priyo Susanto Date: Fri, 30 Sep 2022 01:30:33 +0700 Subject: [PATCH] Add crosshair support for Android (#7865) If enabled, a crosshair will be shown to select object. This will give Android players a way to play like they play on desktop. On third-person back camera mode, player is forced to use crosshair. On third-person front camera mode, player is unable to select anything. Co-authored-by: ROllerozxa Co-authored-by: rubenwardy --- builtin/mainmenu/tab_settings.lua | 4 ---- builtin/settingtypes.txt | 4 ++++ src/client/game.cpp | 27 ++++++++++++++-------- src/defaultsettings.cpp | 2 +- src/gui/touchscreengui.cpp | 38 +++++++++++++++++++++++-------- src/gui/touchscreengui.h | 2 ++ 6 files changed, 53 insertions(+), 24 deletions(-) diff --git a/builtin/mainmenu/tab_settings.lua b/builtin/mainmenu/tab_settings.lua index 21c77aa8e..ec2d7b1f5 100644 --- a/builtin/mainmenu/tab_settings.lua +++ b/builtin/mainmenu/tab_settings.lua @@ -308,10 +308,6 @@ local function handle_settings_buttons(this, fields, tabname, tabdata) core.show_keys_menu() return true end - if fields["cb_touchscreen_target"] then - core.settings:set("touchtarget", fields["cb_touchscreen_target"]) - return true - end --Note dropdowns have to be handled LAST! local ddhandled = false diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index 7376c0cb7..91cc3ec32 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -117,6 +117,10 @@ mouse_sensitivity (Mouse sensitivity) float 0.2 0.001 10.0 # The length in pixels it takes for touch screen interaction to start. touchscreen_threshold (Touch screen threshold) int 20 0 100 +# Use crosshair to select object instead of whole screen. +# If enabled, a crosshair will be shown and will be used for selecting object. +touch_use_crosshair (Use crosshair for touch screen) bool false + # (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 diff --git a/src/client/game.cpp b/src/client/game.cpp index acf54d557..d484e8193 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -920,6 +920,10 @@ private: #ifdef HAVE_TOUCHSCREENGUI bool m_cache_hold_aux1; + bool m_touch_use_crosshair; + inline bool isNoCrosshairAllowed() { + return !m_touch_use_crosshair && camera->getCameraMode() == CAMERA_MODE_FIRST; + } #endif #ifdef __ANDROID__ bool m_android_chat_open; @@ -1051,6 +1055,10 @@ bool Game::startup(bool *kill, m_invert_mouse = g_settings->getBool("invert_mouse"); m_first_loop_after_window_activation = true; +#ifdef HAVE_TOUCHSCREENGUI + m_touch_use_crosshair = g_settings->getBool("touch_use_crosshair"); +#endif + g_client_translations->clear(); // address can change if simple_singleplayer_mode @@ -2981,6 +2989,11 @@ void Game::updateCamera(f32 dtime) camera->toggleCameraMode(); +#ifdef HAVE_TOUCHSCREENGUI + if (g_touchscreengui) + g_touchscreengui->setUseCrosshair(!isNoCrosshairAllowed()); +#endif + // Make the player visible depending on camera mode. playercao->updateMeshCulling(); playercao->setChildrenVisible(camera->getCameraMode() > CAMERA_MODE_FIRST); @@ -3091,16 +3104,14 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud) shootline.end = shootline.start + camera_direction * BS * d; #ifdef HAVE_TOUCHSCREENGUI - - if ((g_settings->getBool("touchtarget")) && (g_touchscreengui)) { + if (g_touchscreengui && isNoCrosshairAllowed()) { shootline = g_touchscreengui->getShootline(); // Scale shootline to the acual distance the player can reach - shootline.end = shootline.start - + shootline.getVector().normalize() * BS * d; + shootline.end = shootline.start + + shootline.getVector().normalize() * BS * d; shootline.start += intToFloat(camera_offset, BS); shootline.end += intToFloat(camera_offset, BS); } - #endif PointedThing pointed = updatePointedThing(shootline, @@ -3991,10 +4002,8 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, (player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE) && (camera->getCameraMode() != CAMERA_MODE_THIRD_FRONT)); #ifdef HAVE_TOUCHSCREENGUI - try { - draw_crosshair = !g_settings->getBool("touchtarget"); - } catch (SettingNotFoundException) { - } + if (isNoCrosshairAllowed()) + draw_crosshair = false; #endif m_rendering_engine->draw_scene(skycolor, m_game_ui->m_flags.show_hud, m_game_ui->m_flags.show_minimap, draw_wield_tool, draw_crosshair); diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index f96149070..bc1c98988 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -465,8 +465,8 @@ void set_default_settings() #endif #ifdef HAVE_TOUCHSCREENGUI - settings->setDefault("touchtarget", "true"); settings->setDefault("touchscreen_threshold","20"); + settings->setDefault("touch_use_crosshair", "false"); settings->setDefault("fixed_virtual_joystick", "false"); settings->setDefault("virtual_joystick_triggers_aux1", "false"); settings->setDefault("clickable_chat_weblinks", "false"); diff --git a/src/gui/touchscreengui.cpp b/src/gui/touchscreengui.cpp index d483c136e..b2a4b489a 100644 --- a/src/gui/touchscreengui.cpp +++ b/src/gui/touchscreengui.cpp @@ -684,6 +684,10 @@ void TouchScreenGUI::handleReleaseEvent(size_t evt_id) translated->MouseInput.Control = false; translated->MouseInput.ButtonStates = 0; translated->MouseInput.Event = EMIE_LMOUSE_LEFT_UP; + if (m_draw_crosshair) { + translated->MouseInput.X = m_screensize.X / 2; + translated->MouseInput.Y = m_screensize.Y / 2; + } m_receiver->OnEvent(*translated); delete translated; } else { @@ -805,6 +809,8 @@ void TouchScreenGUI::translateEvent(const SEvent &event) m_move_downtime = porting::getTimeMs(); m_move_downlocation = v2s32(event.TouchInput.X, event.TouchInput.Y); m_move_sent_as_mouse_event = false; + if (m_draw_crosshair) + m_move_downlocation = v2s32(m_screensize.X / 2, m_screensize.Y / 2); } } } @@ -823,9 +829,8 @@ void TouchScreenGUI::translateEvent(const SEvent &event) return; if (m_has_move_id) { - if ((event.TouchInput.ID == m_move_id) && - (!m_move_sent_as_mouse_event)) { - + if (event.TouchInput.ID == m_move_id && + (!m_move_sent_as_mouse_event || m_draw_crosshair)) { double distance = sqrt( (m_pointerpos[event.TouchInput.ID].X - event.TouchInput.X) * (m_pointerpos[event.TouchInput.ID].X - event.TouchInput.X) + @@ -841,6 +846,7 @@ void TouchScreenGUI::translateEvent(const SEvent &event) // update camera_yaw and camera_pitch s32 dx = X - m_pointerpos[event.TouchInput.ID].X; s32 dy = Y - m_pointerpos[event.TouchInput.ID].Y; + m_pointerpos[event.TouchInput.ID] = v2s32(X, Y); // adapt to similar behaviour as pc screen const double d = g_settings->getFloat("mouse_sensitivity", 0.001f, 10.0f) * 3.0f; @@ -849,11 +855,11 @@ void TouchScreenGUI::translateEvent(const SEvent &event) m_camera_pitch = MYMIN(MYMAX(m_camera_pitch + (dy * d), -180), 180); // update shootline + // no need to update (X, Y) when using crosshair since the shootline is not used m_shootline = m_device ->getSceneManager() ->getSceneCollisionManager() ->getRayFromScreenCoordinates(v2s32(X, Y)); - m_pointerpos[event.TouchInput.ID] = v2s32(X, Y); } } else if ((event.TouchInput.ID == m_move_id) && (m_move_sent_as_mouse_event)) { @@ -1010,11 +1016,17 @@ bool TouchScreenGUI::doubleTapDetection() if (distance > (20 + m_touchscreen_threshold)) return false; + v2s32 mPos = v2s32(m_key_events[0].x, m_key_events[0].y); + if (m_draw_crosshair) { + mPos.X = m_screensize.X / 2; + mPos.Y = m_screensize.Y / 2; + } + auto *translated = new SEvent(); memset(translated, 0, sizeof(SEvent)); translated->EventType = EET_MOUSE_INPUT_EVENT; - translated->MouseInput.X = m_key_events[0].x; - translated->MouseInput.Y = m_key_events[0].y; + translated->MouseInput.X = mPos.X; + translated->MouseInput.Y = mPos.Y; translated->MouseInput.Shift = false; translated->MouseInput.Control = false; translated->MouseInput.ButtonStates = EMBSM_RIGHT; @@ -1023,7 +1035,7 @@ bool TouchScreenGUI::doubleTapDetection() m_shootline = m_device ->getSceneManager() ->getSceneCollisionManager() - ->getRayFromScreenCoordinates(v2s32(m_key_events[0].x, m_key_events[0].y)); + ->getRayFromScreenCoordinates(mPos); translated->MouseInput.Event = EMIE_RMOUSE_PRESSED_DOWN; verbosestream << "TouchScreenGUI::translateEvent right click press" << std::endl; @@ -1124,17 +1136,23 @@ void TouchScreenGUI::step(float dtime) u64 delta = porting::getDeltaMs(m_move_downtime, porting::getTimeMs()); if (delta > MIN_DIG_TIME_MS) { + s32 mX = m_move_downlocation.X; + s32 mY = m_move_downlocation.Y; + if (m_draw_crosshair) { + mX = m_screensize.X / 2; + mY = m_screensize.Y / 2; + } m_shootline = m_device ->getSceneManager() ->getSceneCollisionManager() ->getRayFromScreenCoordinates( - v2s32(m_move_downlocation.X,m_move_downlocation.Y)); + v2s32(mX, mY)); SEvent translated; memset(&translated, 0, sizeof(SEvent)); translated.EventType = EET_MOUSE_INPUT_EVENT; - translated.MouseInput.X = m_move_downlocation.X; - translated.MouseInput.Y = m_move_downlocation.Y; + translated.MouseInput.X = mX; + translated.MouseInput.Y = mY; translated.MouseInput.Shift = false; translated.MouseInput.Control = false; translated.MouseInput.ButtonStates = EMBSM_LEFT; diff --git a/src/gui/touchscreengui.h b/src/gui/touchscreengui.h index 6b36c0d59..82d6a4a9c 100644 --- a/src/gui/touchscreengui.h +++ b/src/gui/touchscreengui.h @@ -194,6 +194,7 @@ public: void step(float dtime); void resetHud(); void registerHudItem(int index, const rect &rect); + inline void setUseCrosshair(bool use_crosshair) { m_draw_crosshair = use_crosshair; } void Toggle(bool visible); void hide(); @@ -240,6 +241,7 @@ private: bool m_joystick_has_really_moved = false; bool m_fixed_joystick = false; bool m_joystick_triggers_aux1 = false; + bool m_draw_crosshair = false; button_info *m_joystick_btn_off = nullptr; button_info *m_joystick_btn_bg = nullptr; button_info *m_joystick_btn_center = nullptr;