Hi all!
Bài 15 Chúng ta đang tìm hiểu về Box2D, và xây dựng 1 ứng dụng nhỏ sử dụng physic Box2D. Ở bài này chúng ta nâng cao lên 1 chút, là điều khiển quả bóng, làm cho nó va đập với màn hình. Nội dung chính như sau:
+ Làm chuyển động quả bóng bằng vector + lực
+ Đoán trước hướng di chuyển của quả bóng
Mời bạn cùng theo dõi!
B1 - Làm chuyển động quả bóng bằng vector + lực
Các bạn mở Class đã làm ở bài 15 ra
* Mở file HelloWorldScene.h, phần Public thêm vào đoạn code sau:
// Các biến này, bạn xem các đoạn code dưới sẽ hiểu ý nghĩa
bool existBall;
float ballX;
float ballY;
int dragOffsetStartX;
int dragOffsetEndX;
int dragOffsetStartY;
int dragOffsetEndY;
float powerMultiplier; // :Lực
Sprite *points[32];
void defineBall(); // Tạo quả bóng theo Box2D
//Bắt các sự kiện Touch bool onTouchBegan(Touch* touch, Event* event);
void onTouchMoved(Touch* touch, Event* event);
void onTouchEnded(Touch* touch, Event* event);
* Mở file HelloWorldScene.cpp, Xóa hết code của bài cũ ( để đỡ nhầm lẫn chỉ trừ lại đoạn sau)
if ( !Layer::init() )
{
return false;
}
Size visibleSize = Director::getInstance()->getVisibleSize();
Point origin = Director::getInstance()->getVisibleOrigin();
// ĐÃ XÓA HẾT
return true;
+ Thêm vào chỗ xóa kia Các đoạn code sau:
b2Vec2 gravity = b2Vec2(0.0f, -10.0f); // Vector gia tốc
world = new b2World(gravity); // Tạo world
//Tạo 1 quả bóng, Lưu tọa độ các điểm đầu và cuối dragOffsetStartX = 0;
dragOffsetEndX = 0;
dragOffsetStartY = 0;
dragOffsetEndY = 0;
existBall= false;
ballX = 500;
ballY = 200;
powerMultiplier = 10; // Giá trị lực 10
ball =Sprite::create("ball.png");
ball->setPosition(Point(ballX,ballY));
this->addChild(ball);
// Dựng khung bao quanh 3 phía màn hình addWall(visibleSize.width ,10,(visibleSize.width / 2) ,0); // Sàn
addWall(10 ,visibleSize.height ,0,(visibleSize.height / 2) ); //Trái
addWall(10 ,visibleSize.height ,visibleSize.width,(visibleSize.height / 2) ); // Phải
//Bắt sự kiện Touch auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);
listener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
listener->onTouchMoved = CC_CALLBACK_2(HelloWorld::onTouchMoved, this);
listener->onTouchEnded = CC_CALLBACK_2(HelloWorld::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
scheduleUpdate(); // Update Scene theo Time
+ Xây dựng hàm addWall như sau, rất giống bài 15, thì vẫn là dựng khung physic body = Box2D mà
void HelloWorld::addWall(float w,float h,float px,float py) {
b2PolygonShape floorShape; // Hình dạng Sàn
floorShape.SetAsBox(w/ SCALE_RATIO,h/ SCALE_RATIO); // Hình vuông, hoặc chữ nhật
b2FixtureDef floorFixture;
floorFixture.density=0;
floorFixture.friction=10;
floorFixture.restitution=0.5;
floorFixture.shape=&floorShape;
b2BodyDef floorBodyDef;
floorBodyDef.position.Set(px/ SCALE_RATIO,py/ SCALE_RATIO);
b2Body *floorBody = world->CreateBody(&floorBodyDef);
floorBody->CreateFixture(&floorFixture);
}
+ Hàm defineBall(), thật ra là khai báo lại việc tạo body physic cho quả bóng ở bài 15, chuyển nó thành 1 hàm riêng thôi
void HelloWorld::defineBall(){
bodyShape.m_radius = 45 / SCALE_RATIO;
fixtureDef.density=10;
fixtureDef.friction=0.8;
fixtureDef.restitution=0.6;
fixtureDef.shape=&bodyShape;
bodyDef.type= b2_dynamicBody;
bodyDef.userData=ball;
bodyDef.position.Set(ball->getPosition().x/SCALE_RATIO,ball->getPosition().y/SCALE_RATIO);
ballBody = world->CreateBody(&bodyDef);
ballBody->CreateFixture(&fixtureDef);
ballBody->SetGravityScale(10);
}
bool HelloWorld::onTouchBegan(Touch* touch, Event* event)
{
// Lưu tọa độ điểm Touch đầu tiên dragOffsetStartX = touch->getLocation().x;
dragOffsetStartY = touch->getLocation().y;
Point touchLocation = touch->getLocation(); // Lấy tọa độ điểm Touch
// Lưu lại
ballX = touchLocation.x;
ballY = touchLocation.y;
// Kiểm tra nếu điểm Touch chưa có quả bóng, thì xóa body bóng đã tạo ở hàm defineBall()
if (existBall){
world->DestroyBody(ballBody);
}
ball->setPosition(Point(ballX ,ballY)); // Đặt vị trị mới ở ballX ,ballY
return true;
}
+ Hàm onTouchEnded
void HelloWorld::onTouchEnded(Touch* touch, Event* event)
{
existBall = true;
HelloWorld::defineBall(); // Tạo body quả bóng tại điểm Touch cuối
Point touchLocation = touch->getLocation(); // Lấy điểm Touch
// Lưu điểm Touch cuốidragOffsetEndX = touchLocation.x;
dragOffsetEndY = touchLocation.y;
// Khoảng di chuyển của bóngfloat dragDistanceX = dragOffsetStartX - dragOffsetEndX;
float dragDistanceY = dragOffsetStartY - dragOffsetEndY;
// Tạo chuyển động cho body với 1 vận tốc không đổi có phương và độ lớn = vector có điểm cuối, điểm đầu đã lưu, nhân thêm 1 lực = 10 = powerMultiplierballBody->SetLinearVelocity(b2Vec2((dragDistanceX*powerMultiplier)/SCALE_RATIO,(dragDistanceY*powerMultiplier)/SCALE_RATIO));
}
+ Hàm onTouchMoved
void HelloWorld::onTouchMoved(Touch* touch, Event* event)
{
}
Bạn build & run thử xem, có thành công ko?, thử kéo quả bóng và thả ra, sẽ thấy quả bóng bắn đi và va đập với thành màn hình, OK nha, sang ngay bước 2
B2 - Đoán hướng di chuyển của bóng
Bạn cần xây dựng 2 hàm sau đây
+ onTouchMoved
void HelloWorld::onTouchMoved(Touch* touch, Event* event)
{
Point touchLocation = touch->getLocation();
// Lưu lại điểm cuối dragOffsetEndX = touchLocation.x;
dragOffsetEndY = touchLocation.y;
// Khoảng di chuyển của bóng float dragDistanceX = dragOffsetStartX - dragOffsetEndX;
float dragDistanceY = dragOffsetStartY - dragOffsetEndY;
//Gọi hàm mô phỏng đường đi của bóng, vector nhân thêm 1 lực = 10 = powerMultiplier HelloWorld::simulateTrajectory(b2Vec2((dragDistanceX * powerMultiplier)/SCALE_RATIO,(dragDistanceY * powerMultiplier)/SCALE_RATIO));
}
+ simulateTrajectory
void HelloWorld::simulateTrajectory(b2Vec2 coord){
//Định nghĩa physics body bóng HelloWorld::defineBall();
// Tạo chuyển động cho body với 1 vận tốc không đổi có phương và độ lớn = vector truyền vào
ballBody->SetLinearVelocity(b2Vec2(coord.x,coord.y));
// Duyệt mảng point for (int i = 1; i <= 31; i++){
//Trong hàm Step, Giá trị đối số phải bằng gia tốc 10 và powerMultiplier (=10) world->Step(deltaTime,10,10);
points[i]->setPosition(Point(ballBody->GetPosition().x*SCALE_RATIO,ballBody->GetPosition().y*SCALE_RATIO));
world->ClearForces();
}
world->DestroyBody(ballBody);
}
+ Trong hàm init(), thêm vào đoạn code
// Khởi tạo mảng Sprite gồm 31 chấm nhỏ, để biểu diễn đường đi của bóng for (int i = 1 ; i <= 31; i++){
points[i] =Sprite::create("dot.png");
this->addChild(points[i]);
}
Build rồi chạy thử nào, Khi bạn kéo quả bóng sẽ thấy có 1 đường chấm chấm biểu diễn hướng đi của nó. Thả tay ra, quả bóng bay đúng theo hướng đó là thành công.
Vậy là đã xong bài 16, tổng kết lại trong bài này chúng ta học được cách:
+ Tạo lực chuyển động cho 1 đối tượng
+ Biểu diễn đường đi của nó trong world
Mở rộng bài này ra, ta có thể làm được trò chơi Bi-a đấy, các bạn ạ.
Thôi để dành các bài sau nghiên cứu tiếp
P/S: Qua bài 15, 16 các bạn thấy là trong Box2D, sprite bị phụ thuộc vào Body, thiết lập và di chuyển body trước, sau đó mới hiện sprite theo vị trí body. Còn trong Chipmunk thì ngược lại, cài đặt vị trí của Sprite trước, đặt body theo sau. Xem lại các bài trước về Physics.
Chào và hẹn gặp lại.
Bài 17: Game thứ 2 - Breakout ( Part 1)
hay quá. Box2D quá hay.
ReplyDeleteRất tuyệt vời... Hy vọng bạn duy trì trang web lâu dài để cho những người mới có thể học hỏi.
ReplyDeletemình đọc lướt qua, nhìn chung là hiểu sơ sơ, tuy nhiên để hiểu sâu và tự vít đc thì mình chưa làm đc, hic hic
ReplyDeleteBạn cho mình hỏi sao mình sử dụng box2d khi build trên win32 thì ok, nhưng khi build trên
ReplyDeleteandroid thì báo lỗi không tìm thấy thư viện box2d.h
Sửa file Android.MK, xem bài chú ý
DeleteMình ko add Box2D vào file CMakeLists.txt
ReplyDeleteGame vẫn chạy và build bằng cocos bình thường.
việc này là sao vậy bạn
Please upload resource and code for everyone, thanks you so much :D
ReplyDeleteBạn ơi cho mình hỏi, khi mình tạo thêm 1 Sprite ball nữa
ReplyDeletemình kéo quả bóng cho nó va chạm với nhau, thì trong lúc mình kéo quả bóng mới tạo cũng di chuyển theo (đáng lý thì phải thả ra và khi va chạm thì quả bóng mới tạo mới di chuyển)
Mục đích của mình là cho 2 quả bóng va chạm giống game bida đó
Ai giúp mình với
Bài này hay quá anh ạ.
ReplyDeleteAnh ơi hướng dẫn thêm phần collision sử dụng box2d được không ạ. Cái này khó quá.
Hello mọi người.
ReplyDelete