doğru multiTouch kimliğini döndürme


9

Dersleri okumak ve multiTouch ve Stackoverflow ile ilgili her soruya bakmak için sayısız saat geçirdim. Ama bunu nasıl doğru yapacağımı anlayamıyorum. Benim almak için bir döngü kullanın pointerId, ben bunu yapan bir sürü insan görmüyorum ama onun biraz çalışma elde etmeyi başardı tek yolu.

Ekranımda biri hareket etmek, diğeri sprite dönümü ve atış açısını kontrol etmek için iki oyun çubuğu var, Monster Shooter'daki gibi. Her ikisi de iyi çalışıyor.

Benim sorunum Im çekim ile aynı anda benim sprite Taşı zaman, benim ki touchingPointbenim hareket için ayarlandığında touchingPointberi, benim çekim xve ydaha üsttedir touchingPoint(benim çekim moving-stick, ekranın sol tarafında shooting-sticksağ tarafta) , sprite hızlanır, bu sprite için hızda istenmeyen bir değişiklik yaratır.

bu şekilde sizin yardımınızla çözdüm! bu benzer bir sorunla karşılaşabilecek herkes içindir:

    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);

Yanlış yaptığımın mutlak kaybına uğramasaydım bu kadar kod göndermezdim. MultiTouching'in nasıl çalıştığını iyi anlayamıyorum.

temel movingPointolarak hem birinci hem de ikinci parmağım için değişir. Bir kutuya bağlarım, ancak bu kutunun içinde bir parmağımı tuttuğum sürece, ikinci parmağımın dokunduğu yere göre değerini değiştirir. Doğru yönde hareket eder ve hiçbir şey hata vermez, sorun hız değişimidir, neredeyse iki dokunma noktasını toplar gibi.

Yanıtlar:


4

Bunun sizin için çalışacağını düşünüyorum.

Yaptığınız bir hata, her etkinlik için tüm göstergeleri tekrarlamaktı. Yalnızca taşıma etkinlikleri için gereklidir.

İkincisi, aslında indeks değerini getX ve getY fonksiyonlarına koymanız gerekir, ancak oyun nesnelerinize referans olarak kullanmak için bu indeksle ilişkili kimliği alırsınız. Aşağı Olay sırasında joystickinize bir kimlik atarsınız ve daha sonra işaretçi indekslerinizden tekrarlarken, indeksin Aşağı olay sırasında joystick'e atadığınız işaretçi kimliğiyle ilişkili olup olmadığını kontrol edin. Öyleyse, hala sınırlarda olup olmadığını kontrol edin ve güncelleyin veya devre dışı bırakın.

Bu kodu test değilim, ama kendi kodumda yöntemi kullandığım için kavram olarak çalıştığını biliyorum. Anlayamadığınız herhangi bir sorun olup olmadığını bana bildirin.

İlk olarak, joystick sınıfınıza aşağıdakileri eklemeniz gerekecektir.

boolean dragging=false;
int draggingId;
boolean shooting=false;
int shootingId;

OnTouchEvent öğenizi bu şekilde değiştirin.

public boolean onTouchEvent(MotionEvent event) {


    int index = event.getActionIndex();
    int id = event.getPointerId(index);
    String actionString;

    switch (event.getActionMasked()) {
        case MotionEvent.ACTION_DOWN:
            try{
                    if(x > 0 && x < steeringxMesh + joystick.get_joystickBg().getWidth() * 2)
                        && y > yMesh - (joystick.get_joystickBg().getHeight()) && y < panel.getHeight()
                        && !joystick.dragging) {
                            movingPoint.x = x;
                            movingPoint.y = y;
                            joystick.dragging = true;
                            joystick.draggingId = id;
                    }
                    else if(x > shootingxMesh - (joystick.get_joystickBg().getWidth()) && x < panel.getWidth()
                        && y > yMesh - (joystick.get_joystickBg().getHeight()) && y < panel.getHeight()
                        && !joystick.shooting) { 
                            shootingPoint.x = x;
                            shootingPoint.y = y;
                            joystick.shooting=true;
                            joystick.shootingId=id;
                    }
              }
              catch(Exception e){

              }

            actionString = "DOWN";
            break;
        case MotionEvent.ACTION_UP:
            if(id == draggingID)
                joystick.dragging = false;
            if(id ==  shootingID)
                joystick.shooting = false;
            actionString = "UP";
            break;  
        case MotionEvent.ACTION_POINTER_DOWN:
            try{
                    if(x > 0 && x < steeringxMesh + joystick.get_joystickBg().getWidth() * 2)
                        && y > yMesh - (joystick.get_joystickBg().getHeight()) && y < panel.getHeight()
                        && !joystick.dragging) {
                            movingPoint.x = x;
                            movingPoint.y = y;
                            joystick.dragging = true;
                            joystick.draggingId = id;
                    }
                    else if(x > shootingxMesh - (joystick.get_joystickBg().getWidth()) && x < panel.getWidth()
                        && y > yMesh - (joystick.get_joystickBg().getHeight()) && y < panel.getHeight()
                        && !joystick.shooting) { 
                            shootingPoint.x = x;
                            shootingPoint.y = y;
                            joystick.shooting=true;
                            joystick.shootingId=id;
                    }
              }
              catch(Exception e){

              }

            actionString = "PNTR DOWN";
            break;
        case MotionEvent.ACTION_POINTER_UP:
            if(id == joystick.draggingID)
                joystick.dragging = false;
            if(id ==  joystick.shootingID)
                joystick.shooting = false;
            actionString = "PNTR UP";
            break;
        case MotionEvent.ACTION_CANCEL:
            if(id == joystick.draggingID)
                joystick.dragging = false;
            if(id ==  joystick.shootingID)
                joystick.shooting = false;
            actionString = "CANCEL";
            break;
        case MotionEvent.ACTION_MOVE:
            for(index=0; index<e.getPointerCount(); index++) {
                id=e.getPointerId(index);
                int x = (int) event.getX(index);
                int y = (int) event.getY(index); 
                if(joystick.dragging && id == joystick.draggingId) {
                    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;
                    }
                    else
                        dragging = false;
                    }
                }
                else if(joystick.shooting && id == joystick.shootingId){
                    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;                            
                    }
                    else
                        shooting = false;
                    }
                }
            }
            actionString = "MOVE";
            break;
        }
    }

Siz efendim, benim kahramanımsınız. Güncellenmiş kodu soruma ekleyeceğim, böylece yardımınızla nasıl çözdüğümü görebilirsiniz! şimdi sonunda
oyunumu

7

Neredeyse doğru yapıyorsunuz, ancak X / Y istemek yerine işaretçi kimliğinizi kullanmalısınız. i

    int id = event.getPointerId(i);
    int x = (int) event.getX(id);
    int y = (int) event.getY(id);

MotionEvent belgelerinden:

Bir motion olayında ayrı ayrı işaretçilerin görünme sırası tanımlanmamıştır. Böylece, bir işaretçinin işaretçi dizini bir olaydan diğerine değişebilir, ancak işaretçinin işaretçi kimliğinin, işaretçi etkin kaldığı sürece sabit kalması garanti edilir. Bir hareketin izleyen tüm hareket olaylarında izlemek üzere bir işaretçinin işaretçi kimliğini elde etmek için getPointerId (int) yöntemini kullanın. Daha sonra ardışık hareket olayları için, bu hareket olayında belirli bir işaretçi kimliği için işaretçi dizini elde etmek üzere findPointerIndex (int) yöntemini kullanın.

event.getX/Ybir işaretçi kimliği gerektirir, değil i, çünkü aynı sırada olacakları garanti edilmez .

Ayrıca, başka bir ince ama önemli sorun daha var. GetAction () işlev ailesinin nasıl parametre almadığına dikkat edin. Bu biraz garip, değil mi? X / Y için işaretçi kimliği gerekiyor, ancak gerçekleştirilen eylem değil mi? Bu birkaç önemli şeye işaret ediyor:

  • tüm işaretçiler için çerçeve başına tek bir çağrı değil, her işaretçinin her eylemi için dokunmatik işleyiciye bir çağrı alırsınız
  • getX / Y şu ana kadar işaretçinin izine bakar ve en son değeri döndürürken, getAction yalnızca geçerli olayı sorgular

Bu, işaretçi eylemi başına (aşağı / taşıma / yukarı) dokunmatik işleyicinize bir çağrı alacağınız anlamına gelir . Yani iki parmak hareket ediyor = 2 çağrı. Kodunuzun kötü bir yan etkisi, bir etkinliğin eylemini tüm işaretçilere uygulamasıdır ...

Yani, izler üzerinde döngü yapmak yerine, sadece mevcut olay için pid / x / y / eylemini al (eşzamanlı hareket için, dediğim gibi biraz sonra işleyicinize başka bir çağrı alacaksınız)

İşte olayları işlemek için benim kod:

 public static boolean sendTouchToGameEngine (MotionEvent event)
 {
  int action = event.getAction();
  int actionCode = action & MotionEvent.ACTION_MASK;
  int pid = action >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;

  [...]
  sendTouchToGameEngine(pid, actionCode, (int)event.getX(pid), (int)event.getY(pid));
  [...]

  return true;

}

Kodunuza geri dönmek için, kodu aşağıdaki şekilde basitleştirebilmeniz gerekir. Döngü kayboldu, aksi takdirde, bahsetmediğiniz başka çelişkileriniz varsa, her zaman geri ekleyebilirsiniz. AŞAĞI tetiklendiğinde hangi işaretçi kimliğinin hangi kontrol için kullanılacağını (taşı / çek) izleyerek ve bunları YUKARI üzerinde sıfırlayarak çalışır. Hareketleri kullanmadığınız için, anahtarınızı () AŞAĞI, YUKARI, TAŞI ve DIŞINDA sınırlayabilirsiniz.

int movePointerId = -1;
int shootingPointerId = -1;

void TouchEventHandler(MotionEvent event) {   
    // grab the pointer id 
    int pid = action >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
    int x = (int) event.getX(pid);
    int y = (int) event.getY(pid); 
    int action = event.getAction();
    int actionCode = action & MotionEvent.ACTION_MASK;
    int actionIndex = event.getActionIndex();
    String actionString;


    switch (actionCode)
    {
        case MotionEvent.ACTION_DOWN:
        // on DOWN, figure out whether the player used the moving or shooting control, if any.
        // if so, kept track of which pointer was used, because all following call about that
        // finger touches will use the same pointer id. Also record the current point coordinates.
            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;
                        movePointerId = pid;
                    }
                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;
                        shootingPointerId = pid;
                    }
                }catch(Exception e){

                }
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_OUTSIDE:
        // whether the player lift the finger or moves it out of bounds
        // figure out which pointer that was and reset it. You can add additional
        // processing here as required
           if( pid == movePointerId )
              movePointerId = -1;
           else if( pid == shootingPointerId )
              shootingPointerId = -1;
            actionString = "UP";
            break;  
        case MotionEvent.ACTION_MOVE:
        // when the player move their finger, it is simply a matter of comparing the pid
        // to know which one it is
          if( pid == movePointerId ) {
                        movingPoint.x = x;
                        movingPoint.y = y;
          } else if( pid == shootingPointerId ) {
                        shootingPoint.x = x;
                        shootingPoint.y = y;
          }
                actionString = "MOVE";

    }
}

Bu harika cevap için teşekkürler, gerçekten birkaç şeyi temizler. Bu hattın ne yaptığını sendTouchToGameEngine(pid, actionCode, (int)event.getX(pid), (int)event.getY(pid));ve ne zaman aradığınızı açıklar mısınız?
Green_qaue

ayrıca bu satırı kullandığımda: int pid = action >> MotionEvent.ACTION_POINTER_ID_SHIFT;eclipse bana bir supress eklememi söylüyorUyarı, bu normal mi? Böyle ayrıntılı bir cevaptan sonra tüm sorular için özür dilerim. MotionEvent benim için çok yeni ve bir nedenden dolayı mantığı anlayamıyorum
Green_qaue

gördüğünüz gibi gerçekten ne yapacağımı bilmiyorum pidve döngü hala orada, onsuz çalışmayacağım, çünkü almak gerekir beri eklendi i.
Green_qaue

@ Max: sendTouchToGameEngine, bir sonraki güncelleme sırasında işlenecek oyun motoru kuyruğuma bu etkinliği eklemek için yapılan bir çağrıdır. Giriş etkinliğinizi yoklamak için bir sıra kullanmazsanız, TouchEvent kullanıcı arabirimi iş parçacığından ve muhtemelen oyun motoru güncellemenizden geldiğinden, arama işlevinizin oyun motorunun durumuyla karıştırılması riskini beklenmedik şekillerde çalıştırırsınız. farklı bir iş parçacığında çalışır
ADB

@ Max: Uyarı ne yazık ki bilmiyorum. Bize hangisinin olduğunu söyleyebilir misiniz?
ADB

0

Bu kodda biraz gariplik var. Android kullanmıyorum, belki de bunun böyle bir şey olmadığını düşünüyorum. Ancak pozisyonu iki farklı şekilde iki farklı şekilde elde ettiğinizi fark ettim:

İlk önce pointerCountdöngünüzün başlangıcında şu şekilde elde edersiniz :

(int) event.getX(i)

Daha sonra, anahtar ifadenizin içinde şöyle olur:

(int) event.getX(id)

Uyarı kullandığınız geçiş yapması ikullanarak id.

Bunun eski yöntem olması gerektiğini varsayıyorum. Tüm örneklerini değiştirmenizi ve başlangıçta ayarladığınız (int) event.getX(id)değeri kullanmanızı öneririm x. Benzer şekilde pompalanması (int) event.getY(id)için y.

Bu parçaları değiştirmeyi deneyin:

int pointerCount = event.getPointerCount(); 
for (int i = 0; i < pointerCount; i++)
{       
    int x = (int) event.getX(i);
    int y = (int) event.getY(i);

Sonra anahtarınızın içinde bunu kullanın:

    try{
        if(x > 0 && x < touchingBox &&
              y > touchingBox && y < view.getHeight()){
            movingPoint.x = x;
            movingPoint.y = y;
            dragging = true;
        }
        else if(x > touchingBox && x < view.getWidth() &&
                   y > touchingBox && y < view.getHeight()){
            shootingPoint.x = x;
            shootingPoint.y = y;
            shooting=true;
        }else{
            shooting=false;
            dragging=false;
        }

2
Bunun neden yararlı olmadığını ve bir alt oylamaya layık olmadığını yorumlamak ister misiniz? Yapılacak kibar bir şey.
MichaelHouse

Aşağı oy kullanırsanız, kabul etti. Nedenini ona bildirin. Eski bir yöntemden haklısın. Yaklaşık bir milyon farklı şey denedim, bu yüzden kaldırmayı unuttum.
Green_qaue

Sorunuzdaki kodu bunu yansıtacak şekilde güncelleyebilir misiniz? Sana ayarını kaldırıldı bakınız xve yfakat yine de tarafından konumunu alıyorsanız idsonrası.
MichaelHouse

aah, cevabını anlamam biraz zaman aldı. ama bu nasıl olacak? Ben aynı değişkeni ( x=event.getX(i)) kullanırsanız, o xzaman pointerCount1'den fazla olduğunda 2 değer saklamak zorunda kalacak , doğru mu? Ve bu doğru hissettiriyor.
Green_qaue

1
Anladığım kadarıyla eventgerçekten olayların bir listesi. Farklı etkinliklere, yaptığınız gibi listeyi gözden geçirerek erişirsiniz. Böylece, xkullandığınız ikinci etkinliğin konumuna erişmek için event.getX(1)(0'dan başladığımız için). Birden fazla xs var, parametreyi istediğinizi söylemek için kullanıyorsunuz. Döngünüzle tüm olayları fordöngüye sokuyorsunuz, bu yüzden o sayıyı ilgilendiğiniz güncel olay olarak kullanın. Kod değişikliği önerimi görün.
MichaelHouse

0

Bir kez Huawei U8150'de benzer bir sorun yaşadım. Bu cihazdaki iki parmak çoklu dokunma, çok dokunuşlu bir test uygulaması (gerçekten "Telefon Test Cihazı" idi, ancak emin değilim) kullanarak gerçekten kötüydü. . Donanımla ilgili sorununuz buysa ve bunun için çok şey yapabileceğinizi sanmıyorum :(

Kötü ingilizcem için özür dilerim


sorun değil
Green_qaue

Tamam, sadece bir düşünceliydi
Marco Martinelli

0

Sorununuz, güncellemeler arasında, işaretçilerin düzenlendiği sıralamanın aynı kaldığını varsaydığınızdır. Büyük olasılıkla durum böyle olmayacak.

A parmağınızla dokunduğunuz bir durum düşünün. 1 olan bir pointerCount () olacak ve A sorabileceğiniz tek unsur olacaktır. İkinci bir parmak eklerseniz, pointerCount () 2, A indeks 0'da, B indeks 1'de olacaktır. A parmağını kaldırırsanız, pointerCount () tekrar 1 ve B indeks 0'da olacaktır. . Daha sonra tekrar A parmağınızla dokunursanız, A indeks 1'de ve B indeks 0'da olacaktır .

Bu nedenle işaretçi kimliği sağlanır, böylece güncellemeler arasındaki bireysel dokunuşları izleyebilirsiniz. Dolayısıyla, B parmağına ilk dokunuşta Kimlik 12 atanırsa, A parmağı çıkarılıp yeniden eklendiğinde bile her zaman bu tanıtıcıya sahip olacaktır.

Dolayısıyla, kodunuz çekim joystickinizin yanında bir dokunuş tanımladıysa, devam eden bir 'çekim' dokunuşu olup olmadığını kontrol etmelidir. Değilse, bir sonraki güncellemeye devam eden bazı üye değişkenlerde çekim dokunuşunun kimliği hatırlanmalıdır. Sonraki güncellemelerde, devam eden bir 'çekim' dokunuşunuz varsa, işaretçiler arasında yineleyin ve doğru kimliğe sahip işaretçiyi arayın ve güncellemeleri izlemek için kullanmanız gereken işaretçidir ve diğer tüm öğeler yok sayılabilir. Hareket dokunuşu için aynı. Dokunma serbest bırakıldığında, yeni bir dokunuşun kontrolünü ele alabilmesi için bu joystick ile ilişkili kimliği temizlersiniz.

Bir joystick'in yakınında başlayan bir dokunuş orijinal dokunma konumundan çok uzaklaşsa bile, kimliğiyle hangi joystick'i kontrol ettiğini hala doğru şekilde belirleyebilirsiniz. Ve hoş bir yan etki olarak, belirli bir oyun çubuğunun yakınındaki ikinci bir sokak parmağının herhangi bir etkisi olmaz, çünkü oyun çubuğu serbest bırakılıncaya kadar tetikleyen ilk parmağa bağlanır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.