2009-05-26 24 views
14

Tôi có câu hỏi nhanh về việc theo dõi chạm trên iPhone và dường như tôi không thể đi đến kết luận về điều này, vì vậy bất kỳ đề xuất/ý tưởng nào được đánh giá cao:iPhone: Theo dõi/Xác định các chạm riêng lẻ

I muốn có thể theo dõi và xác định các chạm trên iphone, tức là. về cơ bản mọi liên lạc đều có vị trí bắt đầu và vị trí hiện tại/được di chuyển. Chạm được lưu trữ trong một std :: vector và chúng sẽ được loại bỏ khỏi container, một khi chúng đã kết thúc. Vị trí của họ sẽ được cập nhật khi họ di chuyển, nhưng tôi vẫn muốn theo dõi vị trí ban đầu của họ (nhận dạng cử chỉ).

Tôi nhận được sự cố từ [allTouches sự kiện], có nghĩa là, NSSet bị hủy và dường như tôi không thể xác định các chạm đã được lưu trữ trong std :: vector và tham khảo các thao tác trong NSSet (vì vậy tôi biết cái nào đã kết thúc và sẽ bị loại bỏ, hoặc đã bị di chuyển, vv)

Đây là mã của tôi, chỉ hoạt động hoàn hảo với một ngón tay trên màn hình cảm ứng, nhưng với nhiều ngón tay , Tôi nhận được kết quả không thể đoán trước ...

- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event 
{ 
    [self handleTouches:[event allTouches]]; 
} 

- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event 
{ 
    [self handleTouches:[event allTouches]]; 
} 

- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event 
{ 
    [self handleTouches:[event allTouches]]; 
} 

- (void) touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event 
{ 
    [self handleTouches:[event allTouches]]; 
} 

- (void) handleTouches:(NSSet*)allTouches 
{ 
    for(int i = 0; i < (int)[allTouches count]; ++i) 
    { 
     UITouch* touch = [[allTouches allObjects] objectAtIndex:i]; 
     NSTimeInterval timestamp = [touch timestamp]; 

     CGPoint currentLocation = [touch locationInView:self]; 
     CGPoint previousLocation = [touch previousLocationInView:self]; 

     if([touch phase] == UITouchPhaseBegan) 
     { 
      Finger finger; 
      finger.start.x = currentLocation.x; 
      finger.start.y = currentLocation.y; 
      finger.end = finger.start; 
      finger.hasMoved = false; 
      finger.hasEnded = false; 

      touchScreen->AddFinger(finger); 
     } 
     else if([touch phase] == UITouchPhaseEnded || [touch phase] == UITouchPhaseCancelled) 
     { 
      Finger& finger = touchScreen->GetFingerHandle(i); 

      finger.hasEnded = true; 
     } 
     else if([touch phase] == UITouchPhaseMoved) 
     { 
      Finger& finger = touchScreen->GetFingerHandle(i); 

      finger.end.x = currentLocation.x; 
      finger.end.y = currentLocation.y; 
      finger.hasMoved = true; 
     } 
    } 

    touchScreen->RemoveEnded(); 
} 

Cảm ơn!

Trả lời

7

Để khắc phục sự cố, hãy giải quyết phương thức "handleTouches" của bạn. Điều đầu tiên bạn làm trong phương thức handleTouches, là chuyển nó trên touchPhase, nhưng điều đó đã được trao cho bạn. Nếu bạn nhận được các liên lạc trong touchesBegan, bạn biết liên lạc là trong UITouchPhaseBegan. Bằng cách liên lạc phễu từ bốn phương pháp chạm vào một phương pháp, bạn đang đánh bại mục đích của việc có bốn phương thức đại biểu.

Trong mỗi phương pháp đó, Apple cung cấp cho bạn cơ hội để xử lý một giai đoạn khác của cảm ứng hiện tại.

Điều thứ hai là bạn không cần phải tìm kiếm sự kiện cho lần chạm hiện tại, nó được cung cấp cho bạn dưới dạng tham số: chạm vào.

Sự kiện bao gồm bộ chạm. Đối với sự liên tục, bạn được cung cấp các chạm hiện tại mặc dù nó cũng có thể được tìm thấy trong sự kiện.

Vì vậy, khi chạm vàoBắt đầu, bạn bắt đầu theo dõi một lần chạm.

- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event{ 


     NSString *startPoint = NSStringFromCGPoint([[touches anyObject] locationInView:self]); 

     NSDictionary * touchData = [NSDictionary dictionaryWithObjectsandKeys: startPoint, @"location", touches, @"touch"] 

     [startingLocations addObject:touchData]; 

     } 

Tôi đang sử dụng một loạt từ điển để giữ dữ liệu cảm ứng của mình.

Cố gắng tách riêng mã của bạn và di chuyển mã đó vào phương thức chạm thích hợp. Để được hướng dẫn, Apple có một vài dự án mẫu tập trung vào việc chạm và chỉ cho bạn cách thiết lập các phương pháp đó.

Hãy nhớ rằng, các phương pháp này sẽ tự động được gọi cho mỗi lần chạm trong mỗi giai đoạn, bạn không cần phải xoay vòng sự kiện để tìm hiểu điều gì đã xảy ra.

Con trỏ tới từng bộ chạm vẫn không đổi, chỉ thay đổi dữ liệu.

Ngoài ra, tôi sẽ đọc phần hướng dẫn lập trình hệ điều hành iPhone về xử lý sự kiện đi sâu hơn vào những gì tôi đã nói ở trên với một số biểu đồ giải thích mối quan hệ chạm vào các sự kiện theo thời gian.

Một đoạn trích:

Trong iPhone OS, một đối tượng UITouch đại diện cho một liên lạc, và một đối tượng UIEvent đại diện cho một sự kiện. Đối tượng sự kiện chứa tất cả các đối tượng cảm ứng cho trình tự đa chạm hiện tại và có thể cung cấp các đối tượng cảm ứng cụ thể cho chế độ xem hoặc cửa sổ (xem Hình 3-2). Đối tượng cảm ứng liên tục cho một ngón tay cho trước trong một chuỗi, và UIKit biến đổi nó khi nó theo dõi ngón tay trong suốt nó. Các thuộc tính cảm ứng thay đổi đó là giai đoạn của liên lạc , vị trí của nó ở chế độ xem, vị trí trước đó là và dấu thời gian của nó. Mã xử lý sự kiện đánh giá các thuộc tính này để xác định cách phản hồi cho sự kiện.

+1

Tôi đồng ý với bạn. Tôi chia mã của tôi thành các phương thức thích hợp. Tuy nhiên, vấn đề của tôi là tôi cần phải tạo một liên kết giữa Obj-C và C++ và kiến ​​trúc trò chơi của tôi yêu cầu đầu vào được thăm dò thay vì được xử lý một khi các sự kiện được kích hoạt. Đó là lý do tại sao tôi lưu trữ các chạm trong một vector STL. Dù sao, thông tin của bạn về đối tượng UITouch liên tục theo thời gian đã giúp ích rất nhiều. Bây giờ, tôi đang sử dụng địa chỉ cho đối tượng làm chìa khóa để nhận dạng duy nhất một liên lạc. Làm việc như một say mê. Cảm ơn bạn. – FlorianZ

+0

"Nếu bạn nhận được các liên lạc trong touchesBegan, bạn biết liên lạc là trong UITouchPhaseBegan" - thực sự? Điều đó nghe có vẻ sai với tôi - từ tài liệu của Apple, họ dường như nói điều ngược lại: với MultiTouch, một liên lạc từ touchesBegan có thể ở bất kỳ giai đoạn nào. – Adam

+0

@Adam bạn có thể đang hiểu sai. Mặc dù các chạm được chứa trong sự kiện có thể ở trong một pha khác. Tất cả các lần chạm trong thông số "chạm" được đảm bảo ở trong giai đoạn được chỉ định. Từ Hướng dẫn xử lý sự kiện: "Nếu vì một lý do nào đó bạn quan tâm đến việc chạm vào chuỗi multitouch hiện tại không thay đổi kể từ giai đoạn cuối hoặc trong giai đoạn khác với giai đoạn trong tập hợp được truyền, bạn có thể yêu cầu chúng từ đối tượng UIEvent được truyền vào. " –

0

Bạn sẽ có thể đối chiếu chính xác các chạm của mình bằng cách lưu trữ vị trí trước đó của tất cả các lần chạm và sau đó so sánh các vị trí trước đó khi phát hiện thấy các chạm mới.

Trong phương pháp -handleTouches của bạn, bạn có thể đặt một cái gì đó như thế này trong vòng lặp for của bạn:

// ..existing code.. 
CGPoint previousLocation = [touch previousLocationInView:self]; 

// Loop through previous touches 
for (int j = 0; j < [previousTouchLocationArray count]; j++) { 
    if (previousLocation == [previousTouchLocationArray objectAtIndex:j]) { 
    // Current touch matches - retrieve from finger handle j and update position 
    } 
} 

// If touch was not found, create a new Finger and associated entry 

Rõ ràng bạn sẽ cần phải làm một số công việc để tích hợp này vào mã của bạn, nhưng tôi khá chắc chắn bạn có thể sử dụng ý tưởng này để xác định chính xác các lần chạm khi chúng di chuyển xung quanh màn hình. Ngoài ra tôi chỉ nhận ra CGPoint sẽ không phù hợp độc đáo vào một NSArray - bạn sẽ cần phải bọc chúng trong các đối tượng NSValue (hoặc sử dụng một loại khác nhau của mảng).

+0

tốt ý tưởng này. Tuy nhiên, vì lý do nào đó, điều này không hiệu quả đối với tôi. Có vẻ như các vị trí đôi khi bị tắt. Điều này có thể là do hiệu suất giảm, khi tôi kết xuất với bối cảnh OpenGL (Tôi đang làm việc trên một trò chơi). Có thể các sự kiện liên lạc bị loại bỏ sau đó và các vị trí trước đó không còn tương ứng với các vị trí được lưu trữ nữa? Cảm ơn bạn mặc dù! – FlorianZ

+2

Điều này cũng gây ra sự cố cho tôi. Đặc biệt là khi bạn di chuyển rất nhiều ngón tay trên màn hình. Đôi khi bạn nhận được vị trí không khớp với bất kỳ vị trí nào trước đó. – Nosredna

8

Có vẻ như cách "thích hợp" để theo dõi nhiều lần chạm là giá trị con trỏ của sự kiện UITouch.

Bạn có thể tìm thêm chi tiết trong mục "Xử lý một Multi-Touch trình tự phức tạp" của Apple Developer Documentation

+1

Nếu bạn chỉ theo dõi các vị trí trước đó và sử dụng vị trí đó để tìm các liên lạc có liên quan, bạn sẽ không thành công. Thông thường, chạm sẽ được truyền theo một vị trí khác với tất cả các giá trị được lưu trong bộ nhớ cache của bạn. Google cho "Xử lý chuỗi đa chạm phức tạp" để tìm tài liệu; liên kết di chuyển xung quanh. Erica Sadun đã viết về điều này: http://blogs.oreilly.com/iphone/2008/10/recovering-multiple-touches.html và cũng cung cấp một số mã: http://github.com/erica/iphone-3.0 -cookbook-/blob/master/C08-Cử chỉ/14-Thay đổi kích thước% 20Và% 20Rotate/main.m Tôi đoán Apple muốn nó có thể làm lại API cảm ứng để vượt qua NSArray thay vì NSSet. –

Các vấn đề liên quan