Hi cả nhà!
Thời gian qua nhanh quá mà chả làm được cái gì, chán ghê. Cũng tại mình vừa vấp phải mấy vấn đề khó giải quyết trong cocos2dx - V3 nên tìm hiểu mãi mới ra. Trong bài này mình cũng trình bày luôn vấn đề đó là gì. Bây giờ chúng ta cùng tiếp tục bài trước về Physics nhé
Ở bài trước chúng ta đã tạo mới 1 Project Ball rồi đúng không, bây giờ là phần code thể hiện physics trong đó.
Let's go!
Các bạn theo đường dẫn sau: Q/android/project/ball/class, mở file HelloWorldScene.h lên. Code của file đó sẽ như vầy:
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
USING_NS_CC;
class HelloWorld : public cocos2d::Layer
{
public:
Sprite* _ball;
PhysicsWorld* m_world;
void setPhyWorld(PhysicsWorld* world){ m_world = world; };
static cocos2d::Scene* createScene();
virtual bool init();
virtual void onAcceleration(Acceleration* acc, Event* unused_event);
bool onContactBegin(const PhysicsContact &contact);
CREATE_FUNC(HelloWorld);
};
#endif // __HELLOWORLD_SCENE_H__
Các bạn không phải sửa đổi gì nhé, mình sẽ giải thích 1 chút về mấy thứ "là lạ trong đó"cho mọi người"
Sprite* _ball; // là 1 con trỏ kiểu Sprite tên là _ball, con trỏ này để quản lý cái gọi là quả bóng trong chương trình chúng ta.
PhysicsWorld* m_world; // Con trỏ kiểu PhysicsWorld tên m_world, gán cho nó các thuộc tính vật lý
void setPhyWorld(PhysicsWorld* world){ m_world = world; }; //hàm gán thuộc tính vật lý cho m_world,
virtual void onAcceleration(Acceleration* acc, Event* unused_event); // hàm này liên quan tới gia tốc kế thì phải
bool onContactBegin(const PhysicsContact &contact); // Hàm này để phát hiện va chạm giữa 2 quả bóng
Tiếp đến các bạn mở file HelloWorldScene.cpp lên nào (file nguồn các bạn down ở bên dưới nhé, vì mình dán vào đây thì bài dài dòng quá), trong đó bạn chú ý một số đoạn sau,
Trong hàm tạo Scene : Scene* HelloWorld::createScene(){}
auto scene = Scene::createWithPhysics(); // Câu lệnh này tạo 1 Scene gắn thuộc tính Physics
---
auto layer = HelloWorld::create(); // Tạo 1 layer của lớp HelloWorld
layer->setPhyWorld(scene->getPhysicsWorld()); // đặt thuộc tính Physics cho biết m_world của đối tượng layer,
scene->getPhysicsWorld() //nghĩa là lấy Physics của scene rồi gán cho m_world của layer
tiếp theo, hàm init()
_ball = Sprite::create("Ball.jpg", Rect(0, 0, 52, 52)); // Tạo 1 quả bóng nằm trong hình vuông 52 pixel
_ball->setPosition(Point(400,600)); // đặt ở vị trí 400, 600
auto ballBody = PhysicsBody::createCircle(_ball->getContentSize().width / 2); // Tạo 1 khung body có đặc tính vật lý để phát hiện va chạm, khung này dạng tròn có đường kính = nội dung của _ball chia 2.
ballBody->setContactTestBitmask(0x1); // Cái này rất quan trọng, nếu ko có thì hàm onContactBegin ko có tác dụng, tìm trên mạng mãi mới sửa được lỗi này
_ball->setPhysicsBody(ballBody); // Gán body cho _ball
this->addChild(_ball); // thêm vào layer HelloWorld đã tạo ở trên
ball2 được tạo ra tương tự
tiếp theo, đoạn này sẽ tạo ra 1 khung bao quanh màn hình, khi quả bóng chạm vào sẽ dừng lại. nó giống một bức tường ( 1 cái hộp ) vậy thôi, không cần giải thích nhiều nhé, cứ code mà đập thôi
auto edgeSp = Sprite::create();
auto boundBody = PhysicsBody::createEdgeBox(visibleSize, PHYSICSBODY_MATERIAL_DEFAULT, 3);
edgeSp->setPosition(Point(visibleSize.width / 2, visibleSize.height / 2));
edgeSp->setPhysicsBody(boundBody);
this->addChild(edgeSp);
edgeSp->setTag(0);
Tiếp theo, quan trọng nè
auto Listener = EventListenerPhysicsContact::create(); // Biến này để "lắng nghe" các tương tác vật lý xảy ra
Listener->onContactBegin=CC_CALLBACK_1(HelloWorld::onContactBegin,this); // gọi hàm onContactBegin, hàm này sẽ xử lý khi va chạm xảy ra, hàm này là hàm chồng lên( gọi là hàm overide của 1 hàm mẫu đã có của thư viện - bạn nào học C++ sẽ hiểu rõ).
_eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);
// dòng này để xử lý ông Listener bên trên kia,
Túm lại đoạn trên đây để phát hiện ra tương tác giữa 2 quả bóng bạn tạo ra, rồi gọi hàm onContactBegin để xử lý.
Bạn mới học thì cứ dập khuôn từng đoạn code, tạm thời đừng hỏi sao phải viết thế, viết khác được không ( Haizzz, ko biết giải đáp thế nào nhỉ). Viết khác được, nhưng hãy nắm chắc cái ban đầu đi đã rồi phát triển sau.
Bây giờ tới hàm onContactBegin{}, format của nó chắc chắn phải viết như sau, sau đó thêm gì thì thêm vào trong 2 dấu ngoặc
bool HelloWorld::onContactBegin(const PhysicsContact &contact)
{
return true;
}
thêm đoạn này vào để xóa 2 quả bóng khi chạm nhau
auto ObjA = (Sprite*)contact.getShapeA()->getBody()->getNode();
auto ObjB = (Sprite*)contact.getShapeB()->getBody()->getNode();
this->removeChild(ObjB,true);
this->removeChild(ObjA,true);
tiếp theo, hàm này this->setAccelerometerEnabled(true); // Gia tốc kế của máy điện thoại
Chạy thử nhé, các bạn đừng quên lệnh này nhé
cocos run -s q:android/project/ball -p win32
Nếu bạn thấy 2 quả bóng đập vào nhau và biến mất là đã thành công
Bạn thử bỏ dòng lệnh ballBody->setContactTestBitmask(0x1); đi xem, 2 quả bóng có va vào nhau nhưng ko có gì xảy ra phải không. Hehe, mỗi dòng lệnh này mà mình tìm kiếm mất gần tuần. HIX
Vấn đề Physic đã giải quyết xong
Nâng cao lên 1 chút nào
Xóa dòng this->setAccelerometerEnabled(true); và layer->setPhyWorld(scene->getPhysicsWorld());, Xóa tiếp hàm onAcceleration, kết quả ko đổi đúng ko, tốc độ rơi vẫn thế (trên win), 2 quả bóng chạm nhau vẫn biến mất. Lệnh này hình như thiết lập gia tốc kế. Các bạn thử thiết lập và xoay màn hình điện thoại xem nhé. Quả bóng sẽ lăn theo hướng rơi xuống cạnh đáy màn hình
Nhưng thử xóa dòng _ball->setPhysicsBody(ballBody); ball2->setPhysicsBody(ball2Body); Bạn sẽ thấy 2 quả bóng đứng im luôn. Có thể thấy hàm này giống như việc đặt vào quả bóng 1 khối lượng nào đó vậy ( chắc tương đương với bán kính). Quên mất vật nặng nhẹ đều rơi như nhau với gia tốc G mà
Bây giờ thêm lại 2 lệnh setPhysicsBody bên trên, rồi thêm dòng lệnh sau: scene->getPhysicsWorld()->setGravity(Vect(0.0f,-5000.0f)); Bạn sẽ thấy quả bóng rơi rất nhanh, đó, chỗ này chính là thiết lập gia tốc trọng lực, sét càng cao thì rơi càng nhanh.
Như vậy qua bài này, bạn đã biết làm thế nào để thiết lập 1 Physics cơ bản cho chương trình rồi nhé. Sang phiên bản mới ( mình đang xài V3 RC2) bạn chỉ cần nắm mấy lệnh cơ bản sau
auto scene = Scene::createWithPhysics(); // Tạo 1 Scene có thuộc tính Physics ( đã bao gồm gia tốc )
scene->getPhysicsWorld()->setGravity(Vect(0.0f,-3000.0f)); // Thay đổi gia tốc, nhớ là phải có dấu "-"
auto ballBody = PhysicsBody::createCircle(_ball->getContentSize().width);
_ball->setPhysicsBody(ballBody); // thiết lập thuộc tính vật lý ( cụ thể là khối lượng và ranh giới của vật thể )
ballBody->setContactTestBitmask(0x1); // Thiết lập sự phát hiện va chạm giữa 2 vật
// và đoạn này để lắng nghe sự va chạm nếu có
auto contactListener = EventListenerPhysicsContact::create();
contactListener->onContactBegin = CC_CALLBACK_1(HelloWorld::onContactBegin, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);
DOWN Mã nguồn và file Resource
Bài 7: Menu - Từ cơ bản tới phức tạp (Part 1)
{ 0 nhận xét... read them below or add one }
Đăng nhận xét