thanks for visiting my post.
in my solution, i wrote a module “mobile_ui.py” to achieve multi-touch.
i define class MobileControls like this:
class MobileControls():
def __init__(self):
self.fingers = {}
self.is_android = _detect_android() # my custom method
self._primary_pid = None
#(achieve the virtual controller)
if self.is_android: #as a constant
self.accept("multi-touch-down", self._mt_down)
self.accept("multi-touch-up", self._mt_up)
self.accept("multi-touch-move", self._mt_move)
self._task = taskMgr.add(self._android_block_task, "mobile_gesture_update")
else: # for desktop
self.accept("mouse1", ....
as the result, events we’ve defined are now tied to our custom functions. let’s check for the functions.
def _mt_down(self, pid, x, y):
nx, ny = self._to_render2d(x, y)
self._press(pid, nx, ny)
def _mt_move(self, pid, x, y):
nx, ny = self._to_render2d(x, y)
if self._tri_tap_enabled():
self._tri_move(pid, nx, ny)
self._move(pid, nx, ny)
def _mt_up(self, pid, x, y):
nx, ny = self._to_render2d(x, y)
if self._tri_tap_enabled():
self._tri_up(pid, nx, ny)
self._release(pid, nx, ny)
in these cases, we accepted the position from events, and processed it with “_to_render2d”. it is becaused that the position ndk returned is started from the left top, but in p3d (0, 0) is center. and, in android platform, y runs down, but we need it runs up. for _to_render2d:(dont pay attention to _tri_tap_enabled, it’s only for my project to achieve three fingers touch)
def _to_render2d(self, x, y):
win_w = base.win.getXSize() or 1
win_h = base.win.getYSize() or 1
nx = (x / win_w) * 2.0 - 1.0
ny = -((y / win_h) * 2.0 - 1.0)
return nx, ny
then let’s check for _press and so on.
def _press(self, pid, x, y):
if self._primary_pid is None:
self._primary_pid = pid
mw = base.mouseWatcherNode
over_region = mw.getOverRegion(x, y) if mw is not None else None
if over_region is not None:
if pid != self._primary_pid:
self._gui_click(over_region)
return
if self._blocked():
return
self.fingers[pid] = {
'sx': x, 'sy': y, 'cx': x, 'cy': y,
't0': globalClock.getFrameTime(),
'zone': 'left' if x < 0 else 'right',
'mode': 'tap',
}
in this method, we get finger press event into the fingers[]. first we check for _primary_pid(androidGraphicsWindow: ACTION_DOWN → _primary_pointer_down). then we used _gui_click function. lets check it.
def _gui_click(self, region):
try:
gui_id = region.get_name()
except Exception:
return
if not gui_id:
return
now = globalClock.getFrameTime()
last = self._last_gui_click
if last is not None and last[0] == gui_id and (now - last[1]) < 0.2:
return
self._last_gui_click = (gui_id, now)
try:
base.messenger.send("click-mouse1-" + gui_id, [None])
except Exception:
pass
this method is to accept the second finger touching the gui(like button). it’s important for modern mobile games. if player is moving by touching virtual controller and also touches the skill button, we need to make the two events run in the same time.
(about virtual controller, also named virtual joystick, u can find lots of solution in the Internet. in my case, the different is u need to get touch events from fingers. )
uh, as u know, my english is not good. so if u read these words with troubles, i’m very sorry. u can ask me for the solution any time, i’ll reply to u as soon as possible.