2012-10-03 37 views
5

Tôi đang sử dụng Box2D lần đầu tiên một cách nghiêm túc trong một Trò chơi Flash có kích thước trung bình mà tôi đang làm việc. Kinh nghiệm hiện tại của tôi với Box2D bị hạn chế trong việc tạo ra một thế giới, cơ thể và thêm những cơ thể đó vào thế giới theo cách thức hoạt động.Làm thế nào tôi có thể theo dõi tất cả các va chạm Box2D của tôi một cách sạch sẽ, dễ quản lý?

Tôi đang tìm thấy nó dễ dàng, đủ để tích hợp Box2D vào môi trường trò chơi của tôi, duy trì mã được viết tốt và đã hoàn thành một vài hướng dẫn đi qua đối phó với va chạm. Vấn đề mà tôi đang phải đối mặt bây giờ là trò chơi của tôi sẽ có nhiều thi thể, mỗi người tương tác với các cơ quan khác theo nhiều cách khác nhau, và tôi thấy khó để viết lớp con b2ContactListener của riêng mình mà không bị lộn xộn.

Dựa trên hướng dẫn tôi đã sử dụng, tôi đã tạo lớp con của riêng mình là b2ContactListener và thêm ghi đè phương thức BeginContact(). Đối số rằng BeginContact() nhận được khi nó được gọi là sẽ tham chiếu một thể hiện của b2Contact, thông qua đó tôi có thể truy cập hai trường hợp b2Fixture (hai trường hợp đã va chạm). Sau đó, tôi có thể truy cập cá thể b2Body được liên kết với mỗi số trong số b2Fixture giây đó.

  • Vấn đề: Hiện nay tôi có một cách vòng xoay tìm ra những gì hai điều va chạm (tức là cho dù họ đang một bức tường và một tên lửa, hay máy nghe nhạc và một cây, vv) trong đó sử dụng GetUserData() và vẻ như ví dụ này:

    var f1Player:Boolean = contact.GetFixtureA().GetBody().GetUserData() is Player 
    var f2Player:Boolean = contact.GetFixtureB().GetBody().GetUserData() is Player 
    var f1Tree:Boolean = contact.GetFixtureA().GetBody().GetUserData() is Tree 
    var f2Tree:Boolean = contact.GetFixtureB().GetBody().GetUserData() is Tree 
    // ... continutes with all possible combinations. 
    
    
    // Example of managing a collision: 
    if(f1Player && f2Tree) 
    { 
        // Player (FixtureA) and Tree (FixtureB) 
    } 
    
    if(f2Player && f1Tree) 
    { 
        // Player (FixtureB) and Tree (FixtureA) 
    } 
    

    Như bạn có thể thấy, điều này sẽ kết thúc cực kỳ dài và không thể quản lý được. Tôi cũng phải viết từng bộ hành động để thực hiện hai lần để phục vụ cho một phần tử nhất định là FixtureA hoặc FixtureB, hoặc ngược lại (rõ ràng dưới dạng một cuộc gọi hàm với các tham số được hoán đổi thay vì viết lại theo nghĩa đen).

Đây rõ ràng không phải là cách tiếp cận chính xác, nhưng tôi chưa tìm được tài nguyên giải thích kỹ hơn về quản lý phát hiện va chạm.

Có ai có kinh nghiệm quản lý phát hiện va chạm bằng cách sử dụng Box2D mà họ có thể chia sẻ không? Ngoài ra, đang sử dụng SetUserData(entityThatOwnsTheBody); cách chính xác để sử dụng phương pháp đó?

Trả lời

1

Tôi đã nghĩ ra điều gì đó đẹp hơn bản gốc.

Thứ nhất, tôi chỉ có lớp Being (sở hữu b2Body) thiết lập chính nó làm cơ quan 'UserData. Lớp này cũng sẽ chứa một phương pháp onContact() và trông giống như dưới đây:

public class Being 
{ 

    private var _body:b2Body; 


    public function Being() 
    { 
     // Define the body here. 
     // ... 

     _body.SetUserData(this); 
    } 


    public function onCollision(being:Being = null):void 
    { 
     // 
    } 

} 

Sau đó, trong b2ContactListener thực hiện của riêng tôi, tôi chỉ đơn giản là vượt qua va chạm Being (hoặc null, nếu không có Being gán cho va chạm b2Body ' s UserData) cho đối Being 's onCollision():

override public function BeginContact(contact:b2Contact):void 
{ 
    var bodyA:b2Body = contact.GetFixtureA().GetBody(); 
    var bodyB:b2Body = contact.GetFixtureB().GetBody(); 

    var beingA:Being = bodyA.GetUserData() as Being || null; 
    var beingB:Being = bodyB.GetUserData() as Being || null; 

    beingA && beingA.onCollision(beingB); 
    beingB && beingB.onCollision(beingA); 
} 

Và cuối cùng trong mỗi lớp con của tôi về Being, tôi có thể dễ dàng chuẩn bị logic thích hợp cho một collisi ở giữa các loại khác Being s thuộc một loại nhất định:

class Zombie extends Being 
{ 
    override public function onCollision(being:Being = null):void 
    { 
     if(being && being is Bullet) 
     { 
      // Damage this Zombie and remove the bullet. 
      // ... 
     } 
    } 
} 
+1

Có vẻ như câu lệnh 'if' dài được chuyển vào lớp Đang. Làm thế nào về chế biến mà chỉ nên được thực hiện một lần cho vụ va chạm, ví dụ như. chơi một âm thanh hoặc tăng điểm. – iforce2d

+0

@ iforce2d Đó là sự thật, tôi có nghĩa là sẽ phải có các câu lệnh 'if()' để thêm tiêu chí cho mỗi kết hợp va chạm, nhưng điều này có vẻ được tổ chức hơn là có mọi thứ trong một tệp. Nó cung cấp cho tôi khả năng dễ dàng xác định vị trí một va chạm giữa hai điều thông qua các lớp học có liên quan và tôi không phải kiểm tra xem đó là cái nào cho mọi va chạm bằng tay. – Marty

+0

Đối với các lần xuất hiện đơn lẻ, có thể được quản lý bởi cá nhân cũng bằng cách sử dụng boolean 'hasBeenTouched' đơn giản hoặc tương tự. – Marty

1

Tôi đã sử dụng c++ phiên bản Box2d, nhưng tôi nghĩ rằng cách tiếp cận tương tự sẽ hoạt động trong ActionScript. Tôi tạo ra một lớp Object, có chứa một con trỏ b2Body *_body và một con trỏ đến biểu diễn đồ họa. _body 's UserData được thiết lập để trỏ đến Object *. lớp Object có các phương pháp sau:

virtual bool acceptsContacts (); 
virtual void onContactBegin  (const ContactData &data); 
virtual void onContactEnded  (const ContactData &data); 
virtual void onContactPreSolve (const ContactData &data); 
virtual void onContactPostSolve (const ContactData &data); 

Khi va chạm đã được phát hiện trong b2ContactListener lớp con, nó kiểm tra nếu cơ quan va chạm có dữ liệu người dùng. Nếu có, nó sẽ đưa dữ liệu người dùng của họ đến Object* và nếu bất kỳ đối tượng va chạm nào chấp nhận địa chỉ liên hệ - nó đã tạo ra ContactData (một lớp có tất cả thông tin bắt buộc về va chạm) và đặt nó vào trong đó list để phân phối sau.

Khi phương thức b2World::update được trả lại, ContactListener cung cấp tất cả thông tin liên hệ cho các đối tượng để xử lý.Giao hàng đã bị trì hoãn để bạn có thể tạo ra các vật thể mới, khớp và vân vân, ngay khi xử lý va chạm (không được phép khi đang cập nhật)

Bạn cũng phải thông báo ContactListener (chỉ cần đặt con trỏ vào bên trong ContactData) nếu một trong những cơ thể va chạm đã bị xóa trong quá trình xử lý va chạm, vì vậy nó có thể làm mất hiệu lực các địa chỉ liên lạc thích hợp và không phân phối chúng

2

Vâng, thực sự là một chút phiền toái. Trên thực tế tôi nghĩ rằng cách bạn có nó là khá điển hình.

fwiw Box2D chính nó phải đối phó với một vấn đề tương tự khi kiểm tra xem đồ đạc chồng lên nhau hay không. Có một loạt các chức năng như b2CollideCircles, b2CollidePolygonAndCircle, b2CollidePolygons vv, và khi hai đồ đạc đến gần nhau, động cơ chọn các chức năng này nên được sử dụng.

Thực hiện điều này bằng cách đặt con trỏ hàm trong mảng 2 chiều, sau đó tìm kiếm hàm thích hợp trong mảng này bằng cách sử dụng hai loại hình dạng làm chỉ mục. Xem ba hàm đầu tiên trong b2Contact.cpp để biết chi tiết. Tất nhiên, nếu bạn không thể vượt qua các tham chiếu hàm như thế này trong AS3 thì tôi đoán câu trả lời này không giúp được gì nhiều, nhưng tôi nghĩ rằng tôi sẽ đăng bài khi người dùng C/C++/JS có thể ghé qua.