Thursday, May 22, 2014

Bài 17: Game thứ 2 - Breakout ( Part 1)

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ết

return 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óng

Tạ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ìa

ballBody->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 ResourceClass ở đâ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)

14 comments:

  1. Cảm ơn bạn rất,
    Nhờ vào các tut của bạn mình đã có được căn bản, giờ nghiên cứu lên thấy dễ......

    ReplyDelete
    Replies
    1. Chưa tới phần khó đó thôi.

      Thanks mọi người đã theo dõi!

      Delete
  2. Mình không nói nó dễ... Ý mình là những phần bạn đã up, đã giải thích.. dễ hiểu..Nhờ đó mà lấy được căn bản :3

    ReplyDelete
  3. Bạn ơi cho mình hỏi sử dụng các thuộc tính vật lý là phải cài đặt gì đúng không bạn.

    ReplyDelete
    Replies
    1. Có 2 thư viện vật lý để dùng trong cocos2dx
      + Chipmunk: đơn giản, dễ cài đặt. Chỉ cần sử dụng các câu lệnh theo đúng cú pháp( trong các bài trước) là OK
      + Box 2D: Phức tạp trong việc khai báo sử dụng hơn 1 chút. Câu lệnh theo đúng cú pháp trong bài 15-16.

      Tùy theo yêu cầu và ý đồ game mà ta thêm bớt 1 vài thuộc tính vật lý phụ ( đàn hồi, ma sát, gia tốc,v..v..)..

      Delete
  4. 1 Một tutorial khá hay
    http://www.cocos2d-x.org/forums/6/topics/53301

    ReplyDelete
    Replies
    1. Mai mốt sẽ thử cái tut đó, mọi người có thời gian hãy nghiên cứu trước

      Delete
  5. Cho mình hỏi có điều kiện gì với cái hàm vector lực này không?
    Vect force = Vect(1010000.0f, 1010000.0f)
    - Mình cho giá trị nó to lên thì ball biến mất luôn. Không bị ngăn bởi khung chắn bao quanh nữa
    Thanks

    ReplyDelete
  6. ad cho minh hoi tao moi truong vat ly trong ban v2.2 ntn a.?

    ReplyDelete
    Replies
    1. Lời khuyên của mình nên chuyển sang V3 đi có nhiều cái mới hơn

      Còn về câu hỏi của bạn. V2.2 mình chưa từng xài bao giờ. Nhưng mình search api của nó thì ko có hàm setphysicsBody (Hàm này là hàm Physic built-in của Engine. Hệ physic riêng của Engine). Xem qua engine thì hình như chưa phát triển hệ PHysic riêng. Tuy nhiên bạn có thể dùng Box2D, chipmunk ( đã hỗ trợ ).
      V2. hay dùng boundingBox cho bài đơn giản

      Delete
    2. Thêm nữa các plugin, soft giờ hỗ trợ V3 nhiều, V2 sắp bỏ đi tới nơi rồi. V4 chuẩn bị ra nữa kìa

      Delete
    3. Chè giải thích hộ tớ cái lệnh này có nghĩa j ?PHYSICSBODY_MATERIAL_DEFAULT

      Delete
  7. Cảm ơn bài viết của bạn,
    Cho mình hỏi, mình gặp trường hợp như thế này, khi bóng bay thì nó bay vài vòng ok, sau đó nó tăng tốc và bay ra ngoài khung màn hình luôn, bay mất luôn.

    Không biết làm sao để tránh lỗi này vậy bạn

    Mình cảm ơn

    ReplyDelete