Vậy là chúng ta đã đi được 1 chặng đường kha khá của Cocos2d-x V3 rồi. Cũng chuẩn bị xong Project thứ 2 đấy chứ. Trong phần này mình sẽ hướng dẫn các bạn nốt công việc đơn giản là "xếp gạch và phá gạch" nhé. Sẽ rất đơn giản thôi.
Những công việc trong bài này:
+ Tạo gạch
+ Xử lý va chạm vật lý
+ Kiểm tra việc phá gạch, hết thì WINGAME
+ Kiểm tra GameOver khi bóng rơi không trúng thanh chắn
- Nhìn có vẻ nhiều việc vậy thôi, nhưng mà đơn giản lắm, vì cũng khá giống Game đầu tiên
Bắt đầu luôn nhé! À, file Resource và Class các bạn down hết ở bài 17 rồi đó
B1 - Tạo gạch
Vì Class mình up ở bài 17 dùng cho cả bài 18 ( Mình comment những đoạn code chưa dùng, bạn chỉ việc phá comment ra thôi)
Mở file HelloWorldScene.cpp thêm vào đoạn code sau
for (int i = 0; i < 5; i++) {
static int padding = 100;
auto block = Sprite::create("blocks.png");
auto blockBody = PhysicsBody::createBox(block->getContentSize(), PHYSICSBODY_MATERIAL_DEFAULT);
blockBody->getShape(0)->setDensity(10.0f);
blockBody->getShape(0)->setFriction(0.0f);
blockBody->getShape(0)->setRestitution(1.f);
blockBody->setDynamic(false);
// Tạo khoảng cách đều nhau giữa cách khối gạch
int xOffset = padding + block->getContentSize().width / 2 +
((block->getContentSize().width + padding)*i);
block->setPosition(xOffset, 450);
blockBody->setContactTestBitmask(0x000001);
block->setPhysicsBody(blockBody);
block->setTag(3);
this->addChild(block);
}
B2 - Xử lý va chạm - Phá gạch, Game Over
* Thêm ContactListener
auto dispatcher = Director::getInstance()->getEventDispatcher();
auto contactListener = EventListenerPhysicsContact::create();
contactListener->onContactBegin = CC_CALLBACK_1(HelloWorld::onContactBegin, this);
dispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);
* Dựng 1 hàm onContactBegin
bool HelloWorld::onContactBegin(PhysicsContact& contact)
{
// Lấy 2 đối tượng va chạm
auto spriteA = (Sprite*)contact.getShapeA()->getBody()->getNode();
auto spriteB = (Sprite*)contact.getShapeB()->getBody()->getNode();
// Kiểm tra loại đối tượng
int tagA = spriteA->getTag();
int tagB = spriteB->getTag();
if (tagA == 3) // Là gạch
{
this->removeChild(spriteA,true); // Xóa gạch
//spriteA->removeFromParentAndCleanup(true);
}
if (tagB == 3) // Là gạch
{
this->removeChild(spriteB,true); // Xóa gạch
//spriteB->removeFromParentAndCleanup(true);
}
// Nếu bóng va chạm với sạn mà tọa độ Y của bóng nhỏ hơn thanh chắn thì Game Over
if ((tagA == 0 || tagB == 0 )& (ball->getPositionY() <= paddle->getPositionY()))
{
auto gameOverScene = GameOverScene::create();
gameOverScene->getLayer()->getLabel()->setString("You Lose!");
Director::getInstance()->replaceScene(gameOverScene);
}
return true;
}
Lớp GameOverScene này giống với Project đầu tiên nhé
B2 - Kiểm tra Win game
Xây dựng hàm Tick() như sau, nhớ khai báo nguyên mẫu hàm
void HelloWorld::tick(float dt)
{
// 1 biến bool xác nhận Win game ban đầu gán = true;
bool isWin = true;
// Vector bodies lấy tất cả các bodies của world ( ball, edge, paddle body), về vector bạn nghiên cứu thêm C++ nâng cao nhé, cũng gần giống mảng, và cũng khá giống Stack. Khai báo vector thì như này Vector<Kiểu biến> tên_biến
Vector<PhysicsBody*> bodies = m_world->getAllBodies();
// Duyệt từng phần tử của vector trên, kiếm tra loại đối tượng = Tag, Bạn nên tìm hiểu lại lệnh for nhé, nó có nhiều biến thể cho từng loại lớp đặc biệt, đọc phần C++ nâng cao phần list, vector, queue,v..
// Đừng dập khuôn for chỉ có dạng for( int i=0; i<N; i++) nhé
// Đừng dập khuôn for chỉ có dạng for( int i=0; i<N; i++) nhé
for each(PhysicsBody* body in bodies) // Câu lệnh này lỗi Khi build android, bạn hãy sửa lại thành for (auto body : bodies) nhé, đây là chuẩn mới C++ 11
{
if (body->getNode()->getTag() == 3) // Nếu còn body của "gạch", tức là chưa phá hết
{
isWin = false; // Chưa Win
}
}
// Duyệt hết mà isWin vẫn ko đổi thì xử lý Win game
if (isWin == true)
{
auto gameOverScene = GameOverScene::create();
gameOverScene->getLayer()->getLabel()->setString("You Win!");
Director::getInstance()->replaceScene(gameOverScene);
}
}
Để gọi hàm Tich() này bạn thêm 1 dòng lệnh này
this->schedule(schedule_selector(HelloWorld::tick),0); vào cuối hàm init() là xong,
Nếu bạn dùng scheduleUpdate() thì build hàm update(float dt) nhé
this->schedule(schedule_selector(HelloWorld::tick),0); vào cuối hàm init() là xong,
Nếu bạn dùng scheduleUpdate() thì build hàm update(float dt) nhé
Build and Run nào
Chúng ta kết thúc bài 18 ở đây nhé. Tóm lại trong cả bài 17 và 18 chúng ta học được gì?
+ Tạo world vật lý với Chipmunk
+ Move đối tượng = kéo, drag trên màn hình
+ Xử lý va chạm,
+ Win game, Over Game
+ Biết thêm 1 chút về Vector, để dành các bài sau nhé
Những hạn chế của game này
+ Thiếu phần tính điểm, để những bài sau
+ Thiếu âm thanh ( bạn có thể thêm vào như Game trước nhé )
+ Thiếu phần Level chơi
+ Thiếu phần menu
+ Đồ họa hơi cùi mía.
* Lưu ý khi build Android, bạn phải khai báo các file cpp mới tạo vào file Android.MK trong thư mục prj.android, như sau, chú ý dấu \
Dòng cuối ko có dấu \
Các dòng trên đều có
GameOverScene.cpp là Class mới tạo, phải khai báo vào đây, file .h thì ko cần
OK, và chú ý sửa lỗi code theo đúng chuẩn C++11 là build APK thành công thôi. Đã test và rút ra EXP nhé
Các bạn thấy đấy, 1 bài quá dễ đúng không. Nhưng nếu không đọc qua những bài phía trước thì chắc hẳn bài này ko dễ nuốt đâu nhỉ. Mong mọi người đừng ỷ vào những gì đã biết mà coi thường những thứ dễ dàng. Hãy học từ dễ đến khó, từ chưa biết đến biết, từ biết thành PRO. từ pro tới SÁNG TẠO nha, đó mới là đích tới của chúng ta. Thực ra đâu có đích nào là cuối.
Các bạn có thể phát triển thêm game này nếu có thời gian nhé.
Nếu không chúng ta cùng đi tiếp nào.
{ 0 nhận xét... read them below or add one }
Đăng nhận xét