From 471051c626d95bc35e2272c6f9c67bc32c8bf830 Mon Sep 17 00:00:00 2001 From: Holger Schemel Date: Sun, 3 Dec 2017 12:35:49 +0100 Subject: [PATCH] added touch controls (follow finger) for MM game engine on Android --- src/events.c | 87 ++++++++++++++++++++++++++++++++++++++++++- src/game_mm/export.h | 2 + src/game_mm/mm_game.c | 78 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+), 1 deletion(-) diff --git a/src/events.c b/src/events.c index d1c4ff64..c8f7248f 100644 --- a/src/events.c +++ b/src/events.c @@ -1051,7 +1051,92 @@ static void HandleButtonOrFinger_WipeGestures_MM(int mx, int my, int button) static void HandleButtonOrFinger_FollowFinger_MM(int mx, int my, int button) { - // (not implemented yet) + static int old_mx = 0, old_my = 0; + static int last_button = MB_LEFTBUTTON; + static boolean touched = FALSE; + static boolean tapped = FALSE; + + // screen tile was tapped (but finger not touching the screen anymore) + // (this point will also be reached without receiving a touch event) + if (tapped && !touched) + { + SetPlayerMouseAction(old_mx, old_my, MB_RELEASED); + + tapped = FALSE; + } + + // stop here if this function was not triggered by a touch event + if (button == -1) + return; + + if (button == MB_PRESSED && IN_GFX_FIELD_PLAY(mx, my)) + { + // finger started touching the screen + + touched = TRUE; + tapped = TRUE; + + if (!motion_status) + { + old_mx = mx; + old_my = my; + + ClearPlayerMouseAction(); + + Error(ERR_DEBUG, "---------- TOUCH ACTION STARTED ----------"); + } + } + else if (button == MB_RELEASED && touched) + { + // finger stopped touching the screen + + touched = FALSE; + + if (tapped) + SetPlayerMouseAction(old_mx, old_my, last_button); + else + SetPlayerMouseAction(old_mx, old_my, MB_RELEASED); + + Error(ERR_DEBUG, "---------- TOUCH ACTION STOPPED ----------"); + } + + if (touched) + { + // finger moved while touching the screen + + int old_x = getLevelFromScreenX(old_mx); + int old_y = getLevelFromScreenY(old_my); + int new_x = getLevelFromScreenX(mx); + int new_y = getLevelFromScreenY(my); + + if (new_x != old_x || new_y != old_y) + { + // finger moved away from starting position + + int button_nr = getButtonFromTouchPosition(old_x, old_y, mx, my); + + // quickly alternate between clicking and releasing for maximum speed + if (FrameCounter % 2 == 0) + button_nr = MB_RELEASED; + + SetPlayerMouseAction(old_mx, old_my, button_nr); + + if (button_nr) + last_button = button_nr; + + tapped = FALSE; + + Error(ERR_DEBUG, "---------- TOUCH ACTION: ROTATING ----------"); + } + else + { + // finger stays at or returned to starting position + + SetPlayerMouseAction(old_mx, old_my, MB_RELEASED); + + Error(ERR_DEBUG, "---------- TOUCH ACTION PAUSED ----------"); + } + } } static void HandleButtonOrFinger_FollowFinger(int mx, int my, int button) diff --git a/src/game_mm/export.h b/src/game_mm/export.h index 65d2e3a5..5e6f6d40 100644 --- a/src/game_mm/export.h +++ b/src/game_mm/export.h @@ -250,4 +250,6 @@ extern void RedrawPlayfield_MM(); extern void LoadEngineSnapshotValues_MM(); extern void SaveEngineSnapshotValues_MM(ListNode **); +extern int getButtonFromTouchPosition(int, int, int, int); + #endif /* GAME_MM_EXPORT_H */ diff --git a/src/game_mm/mm_game.c b/src/game_mm/mm_game.c index 19439a84..3fcc8f8b 100644 --- a/src/game_mm/mm_game.c +++ b/src/game_mm/mm_game.c @@ -9,6 +9,8 @@ // mm_game.c // ============================================================================ +#include + #include "main_mm.h" #include "mm_main.h" @@ -4283,3 +4285,79 @@ void LoadEngineSnapshotValues_MM() RedrawPlayfield_MM(TRUE); } + +static int getAngleFromTouchDelta(int dx, int dy) +{ + double pi = 3.141592653; + double rad = atan2((double)-dy, (double)dx); + double rad2 = (rad < 0 ? rad + 2 * pi : rad); + double deg = rad2 * 180.0 / pi; + + return (int)(deg * 16.0 / 360.0 + 0.5) % 16; +} + +int getButtonFromTouchPosition(int x, int y, int dst_mx, int dst_my) +{ + // calculate start (source) position to be at the middle of the tile + int src_mx = SX + x * TILESIZE_VAR + TILESIZE_VAR / 2; + int src_my = SY + y * TILESIZE_VAR + TILESIZE_VAR / 2; + int dx = dst_mx - src_mx; + int dy = dst_my - src_my; + int element; + int angle_old = -1; + int angle_new = -1; + int button = 0; + int i; + + if (!IN_LEV_FIELD(x, y)) + return 0; + + element = Feld[x][y]; + + if (!IS_MCDUFFIN(element) && + !IS_LASER(element) && + !IS_MIRROR(element) && + !IS_BEAMER(element) && + !IS_POLAR(element) && + !IS_POLAR_CROSS(element) && + !IS_DF_MIRROR(element) && + !IS_DF_MIRROR_AUTO(element)) + return 0; + + if (IS_MCDUFFIN(element) || + IS_LASER(element)) + { + angle_old = laser.start_angle; + angle_new = (dx > 0 && ABS(dy) < ABS(dx) ? ANG_RAY_RIGHT : + dy < 0 && ABS(dx) < ABS(dy) ? ANG_RAY_UP : + dx < 0 && ABS(dy) < ABS(dx) ? ANG_RAY_LEFT : + dy > 0 && ABS(dx) < ABS(dy) ? ANG_RAY_DOWN : + -1); + } + else + { + for (i = 0; i < laser.num_damages; i++) + { + if (laser.damage[i].x == x && + laser.damage[i].y == y && + ObjHit(x, y, HIT_POS_CENTER)) + { + angle_old = laser.damage[i].angle; + + break; + } + } + + if (angle_old == -1) + return 0; + + angle_old = get_mirrored_angle(angle_old, get_element_angle(element)); + angle_new = getAngleFromTouchDelta(dx, dy); + } + + button = (angle_new == angle_old ? 0 : + (angle_new - angle_old + 16) % 16 < 8 ? MB_LEFTBUTTON : + MB_RIGHTBUTTON); + + return button; +} -- 2.34.1