Phân tích hệ thống máy tính cũng tựa như nuôi dạy trẻ, bạn có thể gây hư hỏng trầm trọng, nhưng không thể chắc chắn về thành công. Tom DeMarco
STDIO Tiếp tục loạt bài viết giới thiệu thư viện vật lý trò chơi Chipmunk. Tìm hiểu về một số khái niệm và thuật ngữ trong Chipmunk, cách di chuyển các bodies, va chạm giữa các bodies và hiện thực.
Nội dung bài viết

Giới thiệu

Trong bài viết Chipmunk - Phần 1: Giới Thiệu, tôi đã giới thiệu về khái niệm, cách làm việc, một số khái niệm và thuật ngữ cơ bản trong Chipmunk. Ở phần này tôi sẽ tiếp tục giới thiệu về một số thuật ngữ và khái niệm khác trong Chipmunk như cách làm cho các bodies di chuyển, cách kiểm tra khi có một va chạm.

Tiền đề bài viết

Cocos2d đã tích hợp cả hai thư viện vật lý trò chơi gồm có Box2D và Chipmunk. Tôi tin rằng sự hiệu quả của các thư viện vật lý trò chơi này trong trò chơi được thiết kế với cocos2d rất cao. Bạn có thể chọn một trong hai để sử dụng, tất nhiên trong bài viết này tôi giới thiệu về Chipmunk và với việc bạn làm việc với nó. Tôi tin rằng bạn sẽ có sự lựa chọn.

Đối tượng hướng đến

Bài viết này tôi hướng đến những bạn đã có kiến thức cơ bản về lập trình games với Cocos2-dx. Việc bạn có kinh nghiệm làm việc với Box2D là một lợi thế để có thể dễ dàng tìm hiểu về Chipmunk cũng như việc so sánh hai thư viện vật lý trò chơi này.

Bài viết nằm trong những loạt bài viết của chương trình Tự Học Cocos2d-x 3.x.x của STDIO.

Di chuyển một body

Implules và Force

Đây chính là hai cách tác động lực chính lên một body trong Chipmunk.

  • Impulse: Tác động vào body theo thời gian để thay đổi vận tốc của body.
  • Force: Tác động vào body để có thể thay đổi vận tốc ngay lập tức.

Chú ý: Tất cả các lực trên đều tác động vào trung tâm của body. Vì thế khi bạn tác động các lực này lên các body dạng rỗng, body sẽ không di chuyển.

Vect impulse = Vect(0.0f, 1010000.0f); 
Vect offset = Vect(1.0f, 0.0f);

ballBody->applyImpulse(impulse, offset);

Vect force = Vect(0.0f, 1010000.0f);
ballBody->applyForce(force, offset);
Phân tích:

Ở trên đây là các phương thức để tác động lực impules hay force. Ở đây có 3 tham số là implules, force, offset. 

  • implules force: Là lực tác động ban đầu. 
  • offset: Là lực tác động thêm. Giả sử với ballBody ở trên tôi thêm một giá trị offset có giá trị là (1,0) thì lúc này bars sẽ di chuyển lên đồng thời quay ngược chiều kim đồng hồ. Với giá trị (-1,0) thì sẽ quay ngược chiều kim đồng hồ,....
  • Giá trị mặc định của offset là (0,0).
  • Độ lớn lực ở đây thường rất lớn. Ở đây tôi giả sử giá trị mass của body là 1000, bạn tác động một lực impules có giá trị là 100000, điều này có nghĩa là là body của bạn sẽ di chuyển với tốc độ 100000/100 = 1000 đơn vị/giây. Nếu đơn vị này bằng với pixel trên thiết bị. Giả sử độ phân giải của màn hình là 1024px thì body của bạn cần hơn 10s để di chuyển hết màn hình. Bạn nên thử với việc set giá trị mass cho body khoảng 1-1000, từ đó bạn sẽ thấy.
  • Bạn có thể tính toán, sử dụng các công thức vật lý để thiết kế. Nhưng tôi thì lại thích việc thử nghiệm với việc thay đổi cho đến khi nào cảm thấy đúng với mục đích thiết kế.

Bạn có thể thiết lập một vận tốc ban đầu cho body để cho chúng di chuyển. Với cách này bạn có thể làm một đối tượng có body dạng rỗng di chuyển.

ballBody->setVelocity(Vec2(10.0f, 10.0f));

Collisions

Va chạm là một điều không thể thiếu trong thế giới vật lý. Trong Chipmunk, bạn muốn biết va chạm lúc nào để có thể thiết kế games theo mục đích của bạn, bạn cần tạo một contact listen:

auto contactListener = EventListenerPhysicsContact::create();
contactListener->onContactBegin = CC_CALLBACK_1(HelloWorld::onContactBegin, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);

Để bắt được lúc va chạm giữa hai shapes mới bắt đầu va chạm với nhau.

bool HelloWorld::onContactBegin(cocos2d::PhysicsContact& contact) {
    auto spriteA = (Sprite*)contact.getShapeA()->getBody()->getNode(); // 1
    auto spriteB = (Sprite*)contact.getShapeB()->getBody()->getNode(); // 2
   
    int tagA = spriteA->getTag();                                      // 3
    int tagB = spriteB->getTag();                                      // 4
   
    // logic                                                           // 5
    return true;
}
Phân tích:
  • Dòng 1-2: Lấy đối tượng đầu tiên và đối tượng thứ hai trong va chạm.
  • Dòng 4-5: Kiểm tra loại đối tượng đầu tiên và thứ hai là loại nào.

Chú ý: Trong Chipmunk, giả sử bạn có một va chạm giữa hai đối tượng A và B. Chipmunk không thể phân biệt được A là đối tượng thứ nhất hay là thứ hai, tương tự với B cũng vậy. Vậy nên trong logic của bạn, bạn luôn luôn kiểm tra trường hợp A là đối tượng thứ nhất và thứ hai.

if((tagA == typeA) || (tagB == typeA)) {
    // code 
}

Filtering collisions

Đôi khi trong trò chơi của bạn có sử dụng mô phỏng vật lý, bạn không muốn hai đối tượng nào đó xảy ra. Filtring collisions giúp bạn làm điều này. Bạn có thể tìm hiểu rõ hơn về khái niệm này tại mục Filtering collisons trong bài viết Box2D - Phần 2: Thuật Ngữ Và Khái Niệm.

Có 32 loại hỗ trợ cho va chạm kiểu này. Bạn có thể xác định các bodies va chạm với nhau, và các bodies không va chạm với nhau bằng cách xác định  masking bits.

auto sprite = addSpriteAtPosition(Vec2(s_centre.x - 150,s_centre.y));
sprite->getPhysicsBody()->setCategoryBitmask(0x02);    // 0010
sprite->getPhysicsBody()->setCollisionBitmask(0x01);   // 0001

sprite1 = addSpriteAtPosition(Vec2(s_centre.x - 150,s_centre.y + 100));
sprite1->getPhysicsBody()->setCategoryBitmask(0x02);    // 0010
sprite1->getPhysicsBody()->setCollisionBitmask(0x01);   // 0001

auto sprite2 = addSpriteAtPosition(Vec2(s_centre.x + 150,s_centre.y),1);
sprite2->getPhysicsBody()->setCategoryBitmask(0x01);    // 0001
sprite2->getPhysicsBody()->setCollisionBitmask(0x02);   // 0010

auto sprite3 = addSpriteAtPosition(Vec2(s_centre.x + 150,s_centre.y + 100),2);
sprite3->getPhysicsBody()->setCategoryBitmask(0x03);    // 0011
sprite3->getPhysicsBody()->setCollisionBitmask(0x03);   // 0011
Kết quả:
  • Body của sprite và body của sprite1 không va chạm với nhau (đi xuyên qua nhau). Body của sprite2 và body của sprite3 va chạm với nhau.
  • Body của sprite hoặc body của sprite1 đều có xảy ra va chạm với cả body của sprite2 và body của sprite3.

Bạn có thể kiểm tra va chạm đặc biệt là loại filtering collision bằng cách kiểm tra category và bit mask;

if ((shapeA->getCategoryBitmask() & shapeB->getCollisionBitmask()) == 0
   || (shapeB->getCategoryBitmask() & shapeA->getCollisionBitmask()) == 0)
{
    // code
}

Để bắt các sự kiệm quan tâm đến bodies, shapes hoặc groups bạn có thể sử dụng:

  • EventListenerPhysicsContactWithBodies.
  • EventListenerPhysicsContactWithShapes.
  • EvnetListenerPhysicsContactWithGroup.

Tổng kết

Qua bài viết này, tôi tin rằng bạn có thể:

  • Di chuyển một body.
  • Phát hiện va chạm giữa các bodies và xử lý chúng.

Ở Phần tiếp theo, tôi sẽ giới thiệu về Con-straints, con-straints tương đối giống với joint bên Box2D. Đây là một thành phần mà giúp cho việc mô phỏng vật lý ở mức cao hơn. Tôi tin nó sẽ mang lại nhiều điều thú vị. Mọi thắc mắc bạn có thể bình luận tại bài viết hoặc liên hệ với Trương Đạt.

Thao khảo

htpp://www.cocos2d-x.org

Bạn cần hỗ trợ các dự án kết nối không dây?

Quí doanh nghiệp, cá nhân cần hỗ trợ, hợp tác các dự án IoT, kết nối không dây. Vui lòng liên hệ, hoặc gọi trực tiếp 0942.111912.

  • TỪ KHÓA
  • Arduino
  • ESP32
  • ESP8266
  • Wifi
  • Bluetooth
  • Zigbee
  • Raspberry Pi
THẢO LUẬN
ĐÓNG