Я потратил бесчисленные часы на чтение уроков и просмотр каждого вопроса, касающегося multiTouch, здесь и Stackoverflow. Но я просто не могу понять, как это сделать правильно. Я использую цикл, чтобы получить мой pointerId
, я не вижу, чтобы многие люди делали это, но это единственный способ, которым мне удалось заставить его работать.
У меня на экране два джойстика, один для перемещения и один для управления вращением моих спрайтов и углом, который он снимает, как в Monster Shooter. Оба эти прекрасно работают.
Моя проблема в том, что когда я двигаю свой спрайт одновременно со стрельбой, моя touchingPoint
для моего движения устанавливается на touchingPoint
мою стрельбу, так как x
и y
выше на touchingPoint
моей стрельбе ( moving-stick
на левой стороне экрана, shooting-stick
на правой стороне) , мой спрайт ускоряется, это создает нежелательное изменение скорости для моего спрайта.
Вот как я решил это с вашей помощью! это для тех, кто может столкнуться с подобной проблемой:
public void update(MotionEvent event) {
if (event == null && lastEvent == null) {
return;
} else if (event == null && lastEvent != null) {
event = lastEvent;
} else {
lastEvent = event;
}
int action = event.getAction();
int actionCode = action & MotionEvent.ACTION_MASK;
int pid = action >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
int x = (int) event.getX(pid);
int y = (int) event.getY(pid);
int index = event.getActionIndex();
int id = event.getPointerId(index);
String actionString = null;
switch (actionCode)
{
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
actionString = "DOWN";
try{
if(x > 0 && x < steeringxMesh + (joystick.get_joystickBg().getWidth() * 2)
&& y > yMesh - (joystick.get_joystickBg().getHeight()) && y < panel.getHeight()){
movingPoint.x = x;
movingPoint.y = y;
dragging = true;
draggingId = id;
}
else if(x > shootingxMesh - (joystick.get_joystickBg().getWidth()) && x < panel.getWidth()
&& y > yMesh - (joystick.get_joystickBg().getHeight()) && y < panel.getHeight()){
shootingPoint.x = x;
shootingPoint.y = y;
shooting=true;
shootingId=id;
}
}catch(Exception e){
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_OUTSIDE:
if(id == draggingId)
dragging = false;
if(id == shootingId)
shooting = false;
actionString = "UP";
break;
case MotionEvent.ACTION_MOVE:
for(index=0; index<event.getPointerCount(); index++) {
id=event.getPointerId(index);
int xx = (int) event.getX(index); //pro naming of variable
int yy = (int) event.getY(index);
if(dragging && id == draggingId) {
if(xx > 0 && xx < (steeringxMesh + joystick.get_joystickBg().getWidth() * 2)
&& yy > yMesh - (joystick.get_joystickBg().getHeight()) && yy < panel.getHeight()) {
movingPoint.x = xx;
movingPoint.y = yy;
}
else
dragging = false;
}
if(shooting && id == shootingId){
if(xx > shootingxMesh - (joystick.get_joystickBg().getWidth()) && xx < panel.getWidth()
&& yy > yMesh - (joystick.get_joystickBg().getHeight()) && yy < panel.getHeight()) {
shootingPoint.x = xx;
shootingPoint.y = yy;
}
else
shooting = false;
}
}
actionString = "MOVE";
break;
}
Log.d(TAG, "actionsString: " + actionString + ", pid: " + pid + ", x: " + x + ", y: " + y);
Не разместил бы столько кода, если бы не потерял абсолютно все, что я делаю неправильно. Я просто не могу понять, как работает multiTouching.
в основном movingPoint
меняется для моего первого и второго пальца. Я привязываю его к блоку, но пока я держу один палец в этом блоке, он меняет свое значение в зависимости от того, где касается мой второй палец. Он движется в правильном направлении и ничего не дает ошибки, проблема в изменении скорости, почти как если бы он складывал две точки касания.
Вы почти все понимаете правильно, но вы должны использовать идентификатор указателя, чтобы запросить X / Y вместо
i
Из документации MotionEvent:
event.getX/Y
Требуется идентификатор указателя, нетi
, потому что нет гарантии, что они будут в том же порядке.Кроме того, есть еще одна тонкая, но важная проблема. Обратите внимание, что семейство функций getAction () не принимает параметр. Это немного странно, правда? Для получения X / Y требуется идентификатор указателя, но не выполненное действие? Это намекает на пару важных вещей:
Таким образом, это означает, что вы получаете один вызов к вашему сенсорному обработчику за действие указателя (вниз / перемещение / вверх). Итак, два пальца двигаются = 2 звонка. Противный побочный эффект вашего кода в том, что он применяет действие одного события ко всем указателям ...
Таким образом, вместо циклического обхода трасс, просто получите действие pid / x / y / только для текущего события (для одновременного перемещения вы получите еще один вызов к вашему обработчику чуть позже, как я уже сказал)
Вот мой код для обработки событий:
}
Чтобы вернуться к своему коду, вы должны упростить его следующим образом. Цикл пропал, в противном случае, если у вас есть другие ограничения, которые вы не упомянули, вы всегда можете добавить его обратно. Он работает путем отслеживания того, какой идентификатор указателя используется для какого элемента управления (перемещение / стрельба) при запуске DOWN, и сброса их на UP. Поскольку вы не используете жесты, вы можете ограничить свой переключатель () до ВНИЗ, ВВЕРХ, ПЕРЕМЕЩЕНИЕ и СНАРУЖИ.
источник
sendTouchToGameEngine(pid, actionCode, (int)event.getX(pid), (int)event.getY(pid));
делает эта строка и когда вы ее называете?int pid = action >> MotionEvent.ACTION_POINTER_ID_SHIFT;
eclipse говорит мне, чтобы добавить supressWarning, это нормально? Извините за все вопросы после такого подробного ответа. MotionEvent очень нов для меня, и по какой-то причине неpid
, и цикл все еще там, не будет работать без него, так как мне нужно получитьi
.Там немного странности с этим кодом. Я не использую Android, так что, возможно, я думаю, что это что-то не так. Однако я заметил, что вы получаете позицию дважды, двумя разными способами:
Сначала вы получите это в начале
pointerCount
цикла:Затем, внутри вашего оператора switch вы получите это так:
Обратите внимание, что вы переключаетесь с использования
i
на использованиеid
.Я предполагаю, что это должен быть первый метод. Я рекомендую заменить все экземпляры
(int) event.getX(id)
и использовать значение, котороеx
вы установили в начале. Аналогично обмен(int) event.getY(id)
наy
.Попробуйте поменять местами эти части:
Тогда внутри вашего коммутатора используйте это:
источник
x
иy
, но вы все еще получаете позициюid
позже.x=event.getX(i)
), тоx
мне придется хранить 2 значения, когдаpointerCount
больше 1, правильно? И это неправильно.event
, действительно список событий. Вы получаете доступ к различным событиям, просматривая список, как и вы. Таким образом, чтобы получить доступ кx
позиции для второго события, которое вы используетеevent.getX(1)
(так как мы начинаем с 0). Есть несколькоx
s, вы используете параметр, чтобы указать, какой из них вы хотите. Вы перебираете все события с помощью своегоfor
цикла, поэтому используйте это число в качестве текущего интересующего вас события. См. Мое предложение по изменению кода.У меня когда-то была похожая проблема на Huawei U8150. Мультитач с двумя пальцами на этом устройстве был действительно плохим, с использованием мультитач-тестового приложения (может быть, это «Тестер телефона», но я не уверен), я смог увидеть, что касание вторым пальцем переместило 1-ю точку касания многих пикселей , Если это ваша проблема, то это связано с аппаратным обеспечением, и я не думаю, что вы можете многое сделать для этого :(
Извините за мой плохой английский
источник
Я полагаю, что ваша проблема заключается в том, что вы предполагаете, что между обновлениями порядок расположения указателей остается неизменным. Скорее всего, это не так.
Представьте себе ситуацию, когда вы касаетесь пальцем А. Указатель будет иметь значение 1, а А будет единственным элементом, о котором вы можете спросить. Если вы добавите второй палец, pointerCount () будет равен 2, A будет с индексом 0, B будет с индексом 1. Если вы поднимите палец A, pointerCount () снова будет равен 1, а B будет с индексом 0 , Если затем снова коснуться пальцем A, A будет с индексом 1, а B будет с индексом 0 .
Вот почему указатель ID предоставляется, чтобы вы могли отслеживать отдельные касания между обновлениями. Таким образом, если первому касанию пальца B назначается идентификатор 12, он всегда будет иметь этот идентификатор, даже когда палец A удален и повторно добавлен.
Поэтому, если ваш код идентифицирует касание рядом с джойстиком съемки, он должен проверить, не выполняется ли уже «стрельба». Если нет, то идентификатор касания должен быть запомнен в некоторой переменной-члене, которая сохраняется до следующего обновления. В последующих обновлениях, если у вас есть «стреляющее» касание, выполняйте итерацию по указателям и ищите указатель с правильным идентификатором, и именно этот указатель вам нужно использовать для отслеживания обновлений, а все остальные можно игнорировать. То же самое касается движения прикосновения. Когда касание отпущено, вы стираете идентификатор, связанный с этим джойстиком, чтобы новое касание могло управлять им.
Даже если касание, начинающееся рядом с одним джойстиком, отклоняется от исходного положения касания, по его идентификатору вы все равно можете правильно определить, каким джойстиком он управляет. И, как приятный побочный эффект, второй случайный палец рядом с конкретным джойстиком не будет иметь никакого эффекта, потому что джойстик будет привязан к первому пальцу, который сработал, до его отпускания.
источник