Browse Source

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 <temporaryemail4meh+github@gmail.com>
Co-authored-by: rubenwardy <rw@rubenwardy.com>
Muhammad Rifqi Priyo Susanto 1 year ago
parent
commit
3978b9b8ed

+ 0 - 4
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

+ 4 - 0
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

+ 18 - 9
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);

+ 1 - 1
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");

+ 28 - 10
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;

+ 2 - 0
src/gui/touchscreengui.h

@@ -194,6 +194,7 @@ public:
 	void step(float dtime);
 	void resetHud();
 	void registerHudItem(int index, const rect<s32> &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;