
Chào các bạn!
Cũng nhanh ghê nhỉ, 17 bài rồi đấy, hehe. Chúng ta đã cùng nhau làm xong 1 Project đầu tiên bằng Cocos2d-x v3 cơ đấy. Trong bài này mình sẽ giới thiệu với mọi người 1 Project game khác cũng hay ho không kém, đó là dạng game phá gạch nổi tiếng của điện tử 4 nút ngày xưa.
Hãy cùng tìm hiểu nhé!
Trong game này mình sẽ phải làm các công việc sau:
+ Thêm các đối tượng vào game
+ Thiết lập các thuộc tính vật lý ( dùng Chipmunk cho dễ )
+ Tạo chuyển động của bóng
+ Di chuyển thanh chắn
B1 - Thêm các đối tượng vào game - Thiết lập thuộc tính vật lý
Tạo 1 Project mới với lệnh quen thuộc
>cocos new breakout -p com.vn.breakout -l cpp -d f:android/project
Và nhớ thêm dòng lệnh USING_NS_CC; vào file
HelloWorldScene.h nhé
Mở file
HelloWorldScene.h thêm vào các dòng lệnh sau ở phần public
Sprite* ball;
// Bóng Sprite* paddle;
// Thanh chắn Sprite* edgeSp;
// Khung màn hình PhysicsWorld* m_world;
// World
void setPhyWorld(PhysicsWorld* world){ m_world = world; };
// Sự kiện Touch void onTouchMoved(Touch *touch, Event *event);
void onTouchEnded(Touch *touch, Event *event);
bool onTouchBegan(Touch *touch, Event *event);
OK
Mở file
HelloWorldScene.cpp, ta phải sửa hàm createScene() 1 chút như sau
// Các lệnh này chắc mình ko cần giải thích nhiều nhỉ auto scene = Scene::createWithPhysics();
scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
Vect gravity(0.0f, 0.0f);
// Vector gia tốc =0 scene->getPhysicsWorld()->setGravity(gravity);
auto layer = HelloWorld::create();
layer->setPhyWorld(scene->getPhysicsWorld());
Hàm init() xóa hết chỉ để lại các dòng này
if ( !Layer::init() )
{
return false;
}
auto visibleSize = Director::getInstance()->getVisibleSize();
auto origin = Director::getInstance()->getVisibleOrigin();
//---Xóa hếtreturn true;
Thêm vào giữa phần "Xóa hết" đoạn code dài sau
// Cũng rất quen thuộc nếu bạn đã đọc các bài trước về phần vật lý sử dụng Chipmunk, mình giải thích một số cái thôi nhé edgeSp = Sprite::create();
auto boundBody = PhysicsBody::createEdgeBox(visibleSize, PHYSICSBODY_MATERIAL_DEFAULT, 3);
// Tạo khung vật lý boundBody->getShape(0)->setRestitution(1.0f);
// Đàn hồi boundBody->getShape(0)->setFriction(0.0f);
// Ma sát boundBody->getShape(0)->setDensity(1.0f);
// Tỷ trọng, mật độ edgeSp->setPosition(Point(visibleSize.width / 2, visibleSize.height / 2));
// Đặt vị trí, tâm của Box trung giữa màn hình edgeSp->setPhysicsBody(boundBody);
// Đặt physicsBody boundBody->setContactTestBitmask(0x000001);
// Đây là lệnh quan trọng, nếu ko có nó, thì ko có điều gì xảy ra khi có va chạm hết this->addChild(edgeSp);
// Add vào Layer edgeSp->setTag(0);
// Tag==0, để kiểm tra đối tượng khi va chạm thuộc loại nào ball = Sprite::create("Ball.png", Rect(0, 0, 52, 52));
ball->setPosition(100, 100);
auto ballBody = PhysicsBody::createCircle(ball->getContentSize().width / 2.);
// Khung vật lý hình tròn ballBody->getShape(0)->setRestitution(1.0f);
ballBody->getShape(0)->setFriction(0.0f);
ballBody->getShape(0)->setDensity(1.0f);
ballBody->setGravityEnable(false);
// Không set Gia tốc Vect force = Vect(1010000.0f, 1010000.0f);
// Tạo 1 Vector lực tác động theo hướng 45 độ, vì x = y kìa ballBody->applyImpulse(force);
// Đẩy 1 lực vào khung quả bóng ball->setPhysicsBody(ballBody);
// Sét Physic body ballBody->setContactTestBitmask(0x000001); //
ball->setTag(1);
this->addChild(ball);
// Giải thích tương tự phần ball paddle = Sprite::create("Paddle.png");
auto paddleBody = PhysicsBody::createBox(paddle->getContentSize(), PHYSICSBODY_MATERIAL_DEFAULT);
paddleBody->getShape(0)->setRestitution(1.0f);
paddleBody->getShape(0)->setFriction(0.0f);
paddleBody->getShape(0)->setDensity(10.0f);
paddleBody->setGravityEnable(false);
paddleBody->setDynamic(false);
// Vật tĩnh khi tương tác, ko đàn hồi, ko đổi vị trí paddle->setPosition(visibleSize.width / 2, 50);
paddle->setPhysicsBody(paddleBody);
paddleBody->setContactTestBitmask(0x000001);
// Có tương tác ball->setTag(2);
this->addChild(paddle);
Thêm 1 đoạn code tạo 1 em Listener để bắt sự kiện Touch ( dùng cho điều khiển thanh chắn ) trước lệnh Return true;
// Quá quen thuộc rồi auto touchListener = EventListenerTouchOneByOne::create();
touchListener->setSwallowTouches(true);
touchListener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
touchListener->onTouchMoved = CC_CALLBACK_2(HelloWorld::onTouchMoved, this);
touchListener->onTouchEnded = CC_CALLBACK_2(HelloWorld::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
B2 - Tạo chuyển động của bóngTạo 1 chuyển động đầu cho quả bóng bằng lệnh sau ( ở hàm init() phía trên đã tạo rồi đó)
Vect force = Vect(1010000.0f, 1010000.0f);
// Tạo 1 Vector lực tác động theo hướng 45 độ, vì x = y kìaballBody->applyImpulse(force);
// Đẩy 1 lực vào khung quả bóng
B3 - Di chuyển thanh chắn
Xây dựng 3 hàm Touch, vì ta chỉ sử dụng hàm onTouchMoved để di chuyển nên các hàm Touch khác ta để rỗng nhé:
bool HelloWorld::onTouchBegan(Touch* touch, Event* event)
{
return true;
// Không dùng nhưng vẫn phải trả lại giá trị True}
void HelloWorld::onTouchEnded(Touch* touch, Event* event)
{
// Không dùng}
// Dùng để di chuyển thanh chắn sang ngang, 1 cách đơn giản nhất
void HelloWorld::onTouchMoved(Touch* touch, Event* event){
Point touchLocation = this->convertToWorldSpace(this->convertTouchToNodeSpace(touch));
// Để đơn giản thì dùng lệnh này cho dễ hiểu Point touchLocation = touch->getLocation();
paddle->setPositionX(touchLocation.x); // Đặt vị trí ngang của thanh chắn theo vị trí Touch
}
OK các men!
Chúng ta build và chạy thử luôn nhé,

Vậy là xong bài 17, rất đơn giản phải không, vì toàn kiến thức cơ bản chúng ta đã học phần trước. Tóm lại ở bài này chúng ta làm được một số việc sau:
+ Ôn lại kiến thức về Chipmunk Physics
+ Tạo quả bóng di chuyển = Vector lực, dễ vãi
+ Di chuyển đối tượng = onTouchMoved - Cái này hay và thiết thực nè
Download
Resource và
Class ở đây
Ở bài sau chúng ta sẽ tìm hiểu cách "đóng gạch" à, tạo gạch, và phá gạch, rồi game Over nữa
Chào các bạn và hẹn gặp lại ở bài sau!
Bài 18: Game thứ 2 - Breakout - Tạo và phá gạch ( Part 2)