Passei inúmeras horas lendo tutoriais e analisando todas as perguntas relacionadas ao multiTouch daqui e ao Stackoverflow. Mas eu simplesmente não consigo descobrir como fazer isso corretamente. Eu uso um loop para obter o meu pointerId
, eu não vejo muitas pessoas fazendo isso, mas é a única maneira que eu consegui fazê-lo funcionar um pouco.
Tenho dois joysticks na tela, um para mover e outro para controlar a rotação dos sprites e o ângulo que ele dispara, como no Monster Shooter. Ambos funcionam bem.
Meu problema é que, quando movo meu sprite ao mesmo tempo que estou atirando, meu touchingPoint
movimento é definido como o touchingPoint
do meu disparo, já que o x
e y
é maior no touchingPoint
do meu disparo ( moving-stick
no lado esquerdo da tela, shooting-stick
no lado direito) , meu sprite acelera, isso cria uma alteração indesejada na velocidade do meu sprite.
foi assim que resolvi com a sua ajuda! isto é para qualquer um que possa ter um problema semelhante:
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);
Não postaria tanto código se não perdesse absolutamente o que estou fazendo de errado. Simplesmente não consigo entender bem como o multiTouching funciona.
movingPoint
muda basicamente para o meu primeiro e segundo dedo. Eu o vinculo a uma caixa, mas, enquanto eu seguro um dedo dentro dessa caixa, ele muda seu valor com base em onde meu segundo dedo toca. Ele se move na direção certa e nada dá erro, o problema é a mudança de velocidade, é quase como se somar os dois pontos de contato.
fonte
Você está quase acertando, mas deve usar o ID do ponteiro para solicitar o X / Y em vez de
i
Na documentação do MotionEvent:
event.getX/Y
exigem um ID de ponteiro, nãoi
, porque não há garantia de que eles estarão na mesma ordem.Além disso, há outro problema sutil, mas importante. Observe como a família de funções getAction () não aceita um parâmetro. Isso é meio estranho, certo? Obter X / Y requer o ID do ponteiro, mas não a ação executada? Isso está sugerindo algumas coisas importantes:
Isso significa que você recebe uma chamada para o manipulador de toque por ação do ponteiro (para baixo / mover / para cima). Então, dois dedos se movendo = 2 chamadas. Um efeito colateral desagradável do seu código é que ele aplica a ação de um evento a todos os ponteiros ...
Portanto, em vez de repetir os traços, basta obter a ação pid / x / y / apenas para o evento atual (para movimento simultâneo, você receberá outra chamada ao seu manipulador um pouquinho mais tarde, como eu disse)
Aqui está o meu código para manipular eventos:
}
Para voltar ao seu código, você poderá simplificá-lo da seguinte maneira. O loop desapareceu, caso contrário, se você tiver outras restrições que não mencionou, sempre poderá adicioná-lo novamente. Ele funciona rastreando qual ID de ponteiro é usado para qual controle (mover / disparar) quando DOWN é acionado e redefinindo-os em UP. Como você não usa gestos, você pode restringir sua troca () a ABAIXO, CIMA, MOVER e FORA.
fonte
sendTouchToGameEngine(pid, actionCode, (int)event.getX(pid), (int)event.getY(pid));
faz e quando você chama?int pid = action >> MotionEvent.ACTION_POINTER_ID_SHIFT;
eclipse me diz para adicionar um supressWarning, isso é normal? Desculpe por todas as perguntas após uma resposta tão detalhada. MotionEvent é muito novo para mim, e não consigo entender a lógica por algum motivopid
, e o loop ainda está lá, não funcionará sem ele, pois eu precisoi
.Há um pouco de estranheza nesse código. Eu não uso o Android, então talvez eu esteja pensando que isso é algo que não é. No entanto, notei que você está recebendo a posição duas vezes, de duas maneiras diferentes:
Primeiro você obtém assim no início do seu
pointerCount
loop:Em seguida, dentro da instrução switch, você obtém o seguinte:
Observe que você alterna de usar
i
para usarid
.Suponho que seja o método anterior. Eu recomendo substituir todas as instâncias
(int) event.getX(id)
e usar o valor quex
você definiu no início. Da mesma forma, trocando(int) event.getY(id)
paray
.Tente trocar essas partes:
Então, dentro do seu switch, use o seguinte:
fonte
x
ey
, mas você ainda está obtendo a posiçãoid
mais tarde.x=event.getX(i)
), entãox
terá que armazenar 2 valores sempre quepointerCount
for maior que 1, correto? E isso não parece certo.event
é realmente uma lista de eventos. Você acessa os diferentes eventos percorrendo a lista como está fazendo. Portanto, para acessar ax
posição do segundo evento que você usaevent.getX(1)
(já que estamos começando em 0). Existem váriosx
s, você está usando o parâmetro para dizer qual deseja. Você está percorrendo todos os eventos com seufor
loop, portanto, use esse número como o evento atual em que está interessado. Veja minha sugestão de alteração de código.Eu tive um problema semelhante uma vez em um Huawei U8150. O multitoque de dois dedos nesse dispositivo era muito ruim, usando um aplicativo de teste multitoque (talvez fosse "Phone Tester", mas não tenho certeza). Pude ver que o toque com o segundo dedo movia o primeiro ponto de toque de muitos pixels . Se esse é o seu problema, não está relacionado ao hardware e acho que você não pode fazer muito por isso :(
Desculpe pelo meu inglês ruim
fonte
Acredito que seu problema é que você está assumindo que, entre as atualizações, a ordem em que os ponteiros são organizados permanece a mesma. Provavelmente não será esse o caso.
Imagine uma situação em que você toque com o dedo A. Haverá um apontadorCount () igual a 1 e A será o único elemento que você poderá perguntar. Se você adicionar um segundo dedo, o pointerCount () será 2, A estará no índice 0, B estará no índice 1. Se você aumentar o dedo A, pointerCount () será 1 novamente e B estará no índice 0 . Se você tocar novamente com o dedo A, A estará no índice 1 e B estará no índice 0 .
É por isso que o ID do ponteiro é fornecido, para que você possa rastrear toques individuais entre as atualizações. Portanto, se o primeiro toque do dedo B receber o ID 12, ele sempre terá esse ID, mesmo quando o dedo A for removido e adicionado novamente.
Portanto, se o seu código identificar um toque próximo ao joystick de tiro, ele deverá verificar se já existe um toque de 'tiro' em andamento. Caso contrário, o ID do toque de tiro deve ser lembrado em alguma variável de membro que persista na próxima atualização. Nas atualizações subseqüentes, se você tiver um toque de 'disparo', percorra os ponteiros e procure o ponteiro com o ID correto; é esse ponteiro que você precisa usar para rastrear atualizações e todos os outros podem ser ignorados. O mesmo para o toque do movimento. Quando o toque é liberado, você limpa o ID associado a esse joystick para que um novo toque possa controlá-lo.
Mesmo que um toque que comece perto de um joystick se afaste da posição de toque original, por seu ID, você ainda poderá identificar corretamente o joystick que está controlando. E, como um bom efeito colateral, um segundo dedo perdido próximo a um joystick específico não terá efeito, porque o joystick será vinculado ao primeiro dedo que o acionou até que seja liberado.
fonte