Trong các bài trước, mình đã giới thiệu với mọi người về các physics cơ bản của Cocos2d-x 3.x, và các physics này mặc định sử dụng thư viện của Cocos2d-x 3.x đơn giản, đễ hiểu, gần gũi và dễ dùng. Hệ thống physics này được phát triển trên nền tảng của hệ thống physics Chipmunk ( bạn search GG nhé )
Ngoài ra bạn có thể sử dụng Chipmunk một cách độc lập với hệ thống Physics của cocos2d-x 3.x ( tất nhiên là nếu bạn đã quen sử dụng cú pháp, hàm của Chipmunk rồi ). Và ngoài Chipmunk bạn còn có 1 thư viện Vật lý khác cũng rất phổ biến là Box2D. Nếu để so sánh thì thật khó, vì mỗi thằng có 1 lợi điểm riêng, thôi thì 50 - 50 cho lành. Chừng nào lên Pro rồi thì so sánh ko muộn
Thể nào cũng có bạn thắc mắc, sao mà lắm Physic thế, sao ko phải là cái khác đi. Hix, thật không biết phải trả lời sao. Theo mình thì Physic là 1 phần cơ bản và quan trọng của game, có lẽ nó xếp đằng sau ý tưởng + thuật toán - tính toán để giải quyết vấn đề, rồi cuối cùng là các phần mắm muối như âm thanh, hiệu ứng, v.v... Cứ nên tìm hiểu đủ 2 thư viện Box2D và Chipmunk kỹ vào, ko thừa chút nào. 3 Thư viện vật lý này chỉ khác nhau về tập lệnh, còn lại thì khá giống nhau trong cách mô phỏng thế giới vật lý thật.
Thể nào cũng có bạn thắc mắc, sao mà lắm Physic thế, sao ko phải là cái khác đi. Hix, thật không biết phải trả lời sao. Theo mình thì Physic là 1 phần cơ bản và quan trọng của game, có lẽ nó xếp đằng sau ý tưởng + thuật toán - tính toán để giải quyết vấn đề, rồi cuối cùng là các phần mắm muối như âm thanh, hiệu ứng, v.v... Cứ nên tìm hiểu đủ 2 thư viện Box2D và Chipmunk kỹ vào, ko thừa chút nào. 3 Thư viện vật lý này chỉ khác nhau về tập lệnh, còn lại thì khá giống nhau trong cách mô phỏng thế giới vật lý thật.
Sau đây, mình sẽ giới thiệu với các bạn cách để sử dụng Box2D trong Cocos2d-x. Mặc định Cocos2d-x cài đặt cho người dùng sử dụng thư viện của Cocos2d-x + Chipmunk, nếu muốn sử dụng Box2D bạn phải làm một số công việc cụ thể để import nó vào trình biên dịch.
Nội dung chủ yếu của phần này là:
+ Cách thiết lập để sử dụng Box2D
+ Một bài tập physic nhỏ, áp dụng Box2D physic
Bắt đầu chém nào!
B1 - Thiết lập sử dụng Box2D
1/ Mở file CMakeLists.txt trong Project của chúng ta ( dùng NotePad++ nhé để nó hiện số dòng ). Tìm đến dòng 162, rồi thêm vào "Box2D" như hình đưới
(Ban đầu)
(Thêm vào box2d)
2/ Mở file physics.sln ( physics là tên Project của mình ) bằng VS2012 theo đường dẫn sau physics\proj.win32\physics.sln,
Hãy làm theo các bước sau
* FILE -> Add -> Existing Project
* Chuột phải vào Project physics chọn References, hiện lên bảng project Properties Page, Click tiếp vào nút Add New References, và tick vào ô Box2D, rồi OK là xong
* Cuối cùng bạn phải SAVE cái Solution này lại = Ctrl + S nhé, rồi kiểm tra bước cuối cùng Mở file physics.vcxproj theo đường dẫn sau physics\proj.win32\physics.vcxproj
Nếu thấy dòng sau thì nghĩa là Box2D đã được nạp vào Project Physics, bạn search "Box2D"
Sẽ có bạn thắc mắc là sao ko mở trực tiếp file này rồi add dòng trên vào, Bạn để ý thấy là có 1 dòng <Project>xyz ở dưới là 1 đoạn mã, mình cũng ko biết lấy ở đâu ra, chắc do VS quy định, nên khá khó tìm thông số này ở đâu. Thống nhất làm theo cách trên nhé, làm mấy lần quen ấy mà
Khi cần import 1 Thư viện nào đó, bạn cũng làm theo cách trên nhé.
B2 - 1 Bài physic nhỏ nhỏ thực hành
Tạo 1 Project mới mang tên Box2Dtest, ( bạn không nên đặt project là Box2D nhé, vì sẽ không import Box2D vào project = VS được)
>cocos new Box2Dtest -p com.vn.box2dtest -l cpp -d f:android/project
Mở file HelloWorldScene.h lên, làm những việc sau
+ Thêm vào #include "Box2D/Box2D.h" tại phần #include
+ Thêm USING_NS_CC;
+ Thêm đoạn code sau vào phần Public:
b2World *world; // World với physic
b2Body *ballBody ; // Body của bóng
b2BodyDef bodyDef; // Định nghĩa cái Body trên
b2FixtureDef fixtureDef; // Định nghĩa một số thuộc tính tĩnh: ma sát, độ đàn hồi, trọng lượng,v.v.
b2CircleShape bodyShape; // Hình khối của body
Sprite *ball; // Hình quả bóng
void addWall(float w,float h,float px,float py); // Tạo 1 khung Wall bao quanh màn hình để cho quả bóng va chạm
void update(float dt); // Update scene theo thời gian
// Đoạn này quan trọng nhất để app body trong Box2D
//---------------------KHUNG VAT LY BOX2D--------------------
//bodyDef
//ballBody
//-----------------------------------------------------------
scheduleUpdate(); // Update lại scene theo thời gian, phải có cái này nhé
Mở file HelloWorldScene.cpp, làm những việc sau
+ Thêm vào lệnh #define SCALE_RATIO 32.0 ( vì Box2D dùng đơn vị mm nên ta phải có hệ số chuyển đổi này từ pixel sang mm)
+ Trong hàm init() Xóa từ đoạn code this->addChild(label, 1); đến return true; sau đó thêm đoạn code này vào
b2Vec2 gravity = b2Vec2(0.0f,-10.0f); // Vector gia tốc ( dấu - là chỉ hướng xuống, vì trục y hướng lên trên)
world = new b2World(gravity); // Tạo world với vector gia tốc
// Tạo 1 Sprite quả bóng
ball = Sprite::create("ball.png");
// Đặt vị trí giữa màn hình
ball->setPosition(Point(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
//---------------------KHUNG VAT LY BOX2D--------------------
bodyShape.m_radius = 45 / SCALE_RATIO; // Bán kính của khối body
//fixtureDef
fixtureDef.density=10; // Trọng lượng
fixtureDef.friction=0.8; // Ma sát
fixtureDef.restitution=0.6; // Đàn hồi
fixtureDef.shape=&bodyShape; // Trỏ vào bodyShape
bodyDef.type = b2_dynamicBody; // Va chạm động
bodyDef.userData = ball; // gắn với Sprite ball
// Đặt vị trí, và nhớ chuyển đổi đơn vị
bodyDef.position.Set(ball->getPosition().x/SCALE_RATIO,ball->getPosition().y/SCALE_RATIO);
ballBody = world->CreateBody(&bodyDef); // Tạo Body
ballBody->CreateFixture(&fixtureDef); // Tạo các thuộc tính tĩnh
ballBody->SetGravityScale(10); // Đặt tỷ lệ gia tốc, càng cao rơi càng nhanh
// Đặt quả bóng vào layer của Scene
this->addChild(ball, 0);
void HelloWorld::update(float dt){
int positionIterations = 10; // Vị trí
int velocityIterations = 10; // Vận tốc
deltaTime = dt; // Bước thời gian
// Mô phỏng chuyển động vật lý theo thời gian, hãy nghiên cứu ở đây http://www.box2d.org/manual.html và đây http://www.iforce2d.net/b2dtut/worlds\
// Có thể hiểu thế này, mỗi Step xảy ra trong dt giây , dt này trong file AppDelegate.cpp định nghĩa = dòng lệnh director->setAnimationInterval(1.0 / 60); Bạn thử thay 1/60 = 1/1 xem, rơi cực chậm theo từng giây
world->Step(dt, velocityIterations, positionIterations);
for (b2Body *body = world->GetBodyList(); body != NULL; body = body->GetNext())
// Xét những body có gắn vào Sprite if (body->GetUserData())
{
// Trả về sprite quả bóng ( có mỗi sprite trong bài này )
Sprite *sprite = (Sprite *) body->GetUserData();
// Đặt lại vị trí của Sprite này theo vị trí của body ( body sẽ bị rơi dần theo time), nhớ nhân RATIO để chuyển sang tọa độ pixel sprite->setPosition(Point(body->GetPosition().x * SCALE_RATIO,body->GetPosition().y * SCALE_RATIO));
// Đặt khả năng quay tròn
sprite->setRotation(-1 * CC_RADIANS_TO_DEGREES(body->GetAngle()));
}
world->ClearForces(); // Xóa mọi áp đặt cho Body
world->DrawDebugData(); // Không hiểu, chắc là debug
}
Build rồi chạy thử thôi, nếu bạn thấy 1 quả bóng rơi xuống đáy màn hình là đã thành công, chúc mừng nhé
Vậy là trong bài này chúng ta đã làm quen với Box2D và cách thiết lập physics body trong Box2D. Các bài sau mình sẽ hướng dẫn cụ thể hơn bằng các game nhỏ áp dụng Box2D nhé.
P/S: 1 số lưu ý nho nhỏ trong Box2D
+ Phải có 1 hàm có tham số vào là thời gian, trong này là update (float dt)
+ Khi gắn body cho sprite thì vị trí của sprite luôn bị phụ thuộc vào vị trí của body
+ Cách nhớ Quy đổi tỷ lệ, ở đây ta có 2 hệ tọa độ: Tọa độ của màn hình, và hệ tọa độ của Box2D ( khó hình dung đấy, và hay nhầm ). Hãy nhớ như sau
- Khi thiết lập vị trí ( Position ), kích thước cho các đối tượng, thành phần của Box2D (body, shape) nếu tham số vào là tọa độ màn hình thì phải chia cho tỷ lệ ( "/SCALE_RATIO" ), ví dụ:
bodyDef.position.Set(ball->getPosition().x/SCALE_RATIO,ball->getPosition().y/SCALE_RATIO);
- Ngượi lại để thiết lập vị trí, kích thước cho các đối tượng thành phần của màn hình ( sprite, label,v..v..) nếu tham số vào là tọa độ Box2D thì luôn nhân với tỷ lệ (*SCALE_RATIO), ví dụ
sprite->setPosition(Point(body->GetPosition().x * SCALE_RATIO,body->GetPosition().y * SCALE_RATIO));
Chào và hẹn gặp lại ở bài sau!
Bài 16: Box2D - Một thư viện vật lý khác của Cocos2d-x - Nâng cao ( Part 2 )
{ 0 nhận xét... read them below or add one }
Đăng nhận xét