Search…

Làm Thế Nào Để Tạo Fixtures Cho Vật Có Hình Dạng Phức Tạp Trong Cocos2d-x?

28/09/20207 min read
Hướng dẫn sử dụng phần mềm Physics Editor dùng để tạo Fixtures cho vật có hình dạng phức tạp: Tạo hình dáng, thông số vật lý, anchor point, kiểu body,... Ví dụ sử dụng những Fixtures đã được tạo để tạo body cho các vật đó trong cocos2d-x 3.4.

Physics Editor

Physics Editor là một phần mềm hỗ trợ tạo ra textures cho những sprite có những hình dạng phức tạp. Physics Editor sẽ tạo ra một file format plist, các file format này được sử dụng để tạo fixtures cho body trong games. Nhiệm vụ lúc này là thiết lập các bodyDef cho body. Download và cài đặt phần mềm tại đây.

Tạo Physics Body cho Sprite

Sau khi cài đặt, khởi động PhysicsEditor, sử dụng Physics Editor để tạo fixtures cho sprite theo các bước sau:

  1. Thêm sprites: chọn sprite cần tạo body
  2. Theo dõi các phác thảo của sprites: tùy chọn để phác thảo ra các fixtures ưng ý.
  3. Đặt cấu hình các thông số vật lý: cài đặt một số thông số như density,...
  4. Exportes: chọn file format là plist.

Kết quả của việc tạo fixtures cho các sprite:

  • Tạo ra một file định dạng .plist.
  • Tạo ra một file định dạng .pes.

Giá trị đầu tiên

Sau khi cài đặt và mở phần mềm Physics Editor, chú ý những điểm chính sau:

  • Exporter: Định dạng file format. Ở ví dụ này, chọn Box2D generic (PLIST).
  • PTM: Box2D có bao nhiêu điểm giá trị PTM điểm ảnh là tương đương với 1 mét. Đây là đơn bị nội bộ đo lường của Box2D. Ở đây là 32 PTM.
  • Add Sprite: Thêm sprite cần tạo fixtures ở đây. Ngoài ra, có thể chọn các sprite bằng cách kéo thả từ ngoài thư mục vào nơi chứa sprite.
  • Publish As: Sau khi tạo xong các fixtures, chọn button để xuất ra file format.
  • Anchor Point: Anchor point của body.
  • Tool tạo Shapes: Chứa các button giúp tạo hình dáng cho body.
ss_1_editor

Tạo shapes thủ công

  • Trên thanh tool, tạo Shapes giúp hỗ trợ việc tạo hình dáng của body cho sprite, chọn Add Polygon hoặc Add Circle, lúc này trên màn hình trung tâm sẽ xuất hiện một tam giác có 3 điểm điểm nút trắng hoặc một đường tròn với một nút trắng. 1 body có thể có nhiều fixtures.
  • Kéo thả sao cho phù hợp với mục đích thiết kế hình dạng cho body. Khi muốn thêm một đỉnh để tăng số lượng cạnh của đa giác thì double click chuột vào gần một đoạn trong nó.
ss_2_editor

Tạo shapes bằng Tracer

Trên thanh tool tạo Shapes, chọn Shape tracer. Tracer giúp tự động tạo shape của body cho sprite. 

ss_3_editor

*Quan trọng nhất ở đây là Tolerance, giá trị này cho đánh dấu chính xác làm thế nào đa giác nên phù hợp với hình dạng của Sprite, có ảnh hưởng tới số lượng đỉnh trên đa giác.

Thiết lập category, mask và thông số vật lý

Category và mask

  • Category: mô phỏng các loại hình của một đối tượng. Ví dụ: nhóm đối tượng danger và nhóm đối tượng peave. Category không quyết định việc các đối tượng có va chạm với nhau.
  • Mask: mô tả mà các đối tượng có thể va chạm. Ví dụ: Category có 2 nhóm là danger và peace. Project game có một enemy thuộc nhóm danger, để enemy có thể va chạm với những đối tượng khác cùng nhóm, chọn Mask cùng nhóm và ngược lại. Tương tự với việc quyết định va chạm với nhóm peace.

Tìm hiểu rõ hơn về 2 thông số category và mask ở phần Collision filtering.

Thông số vật lý

  • Density là giá trị liên quan đến khối lượng.
  • Friction là giá trị ma sát dùng cho các vật trượt lên nhau.
  • Restitution là giá trị về đàn hồi.

Tìm hiểu rõ hơn về các thông số vật lý ở phần Fixtures.

ss_4_editor

Sau khi tạo shape body cho sprite, tiến hành Publish, Exit và tạo ra 2 file định dạng .plist và .pes.

ss_5_editor
ss_6_editor

* Khi tạo body cho những đối tượng có hình dạng phức tạp, hãy đảm bảo kích thước sử dụng sprite là không thay đổi.

Ví dụ

Tạo project mới:

  • Copy file định dạng .plist và .pes vào Resource trong project.
  • Download và copy vào Class trong dự án, bộ nạp GB2ShapeCache-x để có thể sử dụng các định dạng .plist là .pes vừa tạo.
  • Download và copy vào Class trong dự án của bạn GLES-Render để vẽ hình dáng body của đối tượng lên màn hình

GB2ShapeCache-x:

GLES-Render:

Header

#include "cocos2d.h"

#include "Box2D\Box2D.h"
#include "GB2ShapeCache-x.h"
#include "GLES-Render.h"


USING_NS_CC;

class HelloWorld : public cocos2d::Layer {
public:

    static cocos2d::Scene* createScene();

    virtual bool init();

    void menuCloseCallback(cocos2d::Ref* pSender);

    // Tạo sprite
	void addNewSpriteWithCoords();

    // Vẽ shapes của body
    virtual void draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) override;

	void update(float dt);

	CREATE_FUNC(HelloWorld)

private:

	 b2World* world;
     
     //dùng để vẽ shapes body
	 GLESDebugDraw *debugDraw;
};

#endif // __HELLOWORLD_SCENE_H__

Source

#include "HelloWorldScene.h"

USING_NS_CC;

using namespace std;
#define PTM_RATIO 32  

//chuỗi chứa tên các sprite
string names[] = {
	"obstacle_1",
	"obstacle_2",
	"obstacle_3",
	"tank_enemi_1",
	"tank_enemi_2",
	"tank_enemi_3",
	"tank_player"
};

Scene* HelloWorld::createScene()
{
    // 'scene' is an autorelease object
    auto scene = Scene::create();
    
    // 'layer' is an autorelease object
    auto layer = HelloWorld::create();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}

bool HelloWorld::init() {

	if (!Layer::init())
	{
		return false;
	}

	Size visibleSize = Director::getInstance()->getVisibleSize();
	Vec2 origin = Director::getInstance()->getVisibleOrigin();

	Size screenSize = Director::getInstance()->getWinSize();

    // Khởi tạo physics world
	b2Vec2 gravity;
	gravity.Set(0.0f, -10.0f);
	bool doSleep = true;
	world = new b2World(gravity);
	world->SetAllowSleeping(doSleep);
	world->SetContinuousPhysics(true);

    //debug khung body
    this->debugDraw = new GLESDebugDraw(PTM_RATIO);
	this->world->SetDebugDraw(debugDraw);
    
    uint32  flags = 0;
	flags += b2Draw::e_shapeBit;                          
    flags += b2Draw::e_jointBit;
	//flags += b2Draw :: e_aabbBit; 
	//flags += b2Draw :: e_pairBit;
	//flags += b2Draw::e_centerOfMassBit;

    //bạn thử bỏ comment và xem thử nó vẽ shapes body như thế nào
	this->debugDraw->SetFlags(flags);

    //*******************************************************

	//Tạo Ground bao quanh màn hình
    b2BodyDef groundBodyDef;

	groundBodyDef.position.Set(screenSize.width / 2 / PTM_RATIO,
	screenSize.height / 2 / PTM_RATIO)
	b2Body* groundBody = world->CreateBody(&groundBodyDef);
	b2PolygonShape groundBox;

	// bottom
	groundBox.SetAsBox(screenSize.width / 2 / PTM_RATIO, 0, b2Vec2(0, -screenSize.height / 2 / PTM_RATIO), 0);
	groundBody->CreateFixture(&groundBox, 0);

	// left
	groundBox.SetAsBox(0, screenSize.height / 2 / PTM_RATIO, b2Vec2(-screenSize.width / 2 / PTM_RATIO, 0), 0);
	groundBody->CreateFixture(&groundBox, 0);

	// right
	groundBox.SetAsBox(0, screenSize.height / 2 / PTM_RATIO, b2Vec2(screenSize.width / 2 / PTM_RATIO, 0), 0);
	groundBody->CreateFixture(&groundBox, 0);

	//Nạp file sprite sheet của các sprite bên trên đã được tạo body
	SpriteFrameCache::getInstance()->addSpriteFramesWithFile("SpriteSheet.plist", "SpriteSheet.png");

    //nạp file .plist chứa các body mới tạo ở trên. 
    //chú ý là file .plist và .pes phải cùng tên với nhau
	GB2ShapeCache::sharedGB2ShapeCache()->addShapesWithFile("shapedefs.plist");

    schedule(schedule_selector(HelloWorld::update));

	return true;
}

void HelloWorld::update(float dt) {

    //cứ 1s là tạo một sprite
    scheduleOnce(schedule_selection(HelloWorldScene::addObject), 1.0f);

	int velocityIterations = 8;
	int positionIterations = 1;
	world->Step(dt, velocityIterations, positionIterations);

	for (b2Body *body = world->GetBodyList(); body != NULL; body = body->GetNext())
	if (body->GetUserData()) {
		Sprite *sprite = (Sprite *)body->GetUserData();
		sprite->setPosition(Point(body->GetPosition().x * PTM_RATIO, body->GetPosition().y * PTM_RATIO));
		sprite->setRotation(-1 * CC_RADIANS_TO_DEGREES(body->GetAngle()));
	}

	world->ClearForces();
	world->DrawDebugData();
}

void HelloWorld::addObject() {

	string name = names[rand() % 7]; // 

    //khởi tạo sprite, set position và thêm vào scene hiện tại
	auto sprite = Sprite::createWithSpriteFrameName((name + ".png").c_str());
	sprite->setPosition(Point(visibleSize.width/2, visibleSize.height/2));
	addChild(sprite);

	// Tạo b2BodyDef
    b2BodyDef bodyDef;
	bodyDef.type = b2_dynamicBody;
	bodyDef.position.Set(p.x / PTM_RATIO, p.y / PTM_RATIO);
	bodyDef.userData = sprite;

	b2Body *body = world->CreateBody(&bodyDef);

	//tạo fixture cho body, bằng cách sử dụng GB2ShapeCache
	GB2ShapeCache *fixtureBody = GB2ShapeCache::sharedGB2ShapeCache();
	fixtureBody->addFixturesToBody(body, name.c_str()); 
    sprite->setAnchorPoint(fixtureBody->anchorPointForShape(name.c_str())); // Đặt cùng 1 điển neo với body
}


void HelloWorld::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) {

	Layer::draw(renderer, transform, flags);
	Director* director = Director::getInstance();
	GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POSITION );
	director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
	world->DrawDebugData();
	director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
}

void HelloWorld::menuCloseCallback(Ref* pSender) {

#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
	MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
    return;
#endif

    Director::getInstance()->end();

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    exit(0);
#endif
}
ss_7_editor

Tổng kết

Physics Editor hỗ trợ tạo ra body cho đối tượng có hình dạng phức tạp, nhờ đó:

  • Source code được tinh gọn hơn.
  • Công việc thiết kế games tiết kiệm được thời gian.
  • Việc mô phỏng va chạm giữa các đối tượng chính xác hơn.
  • Đặc biệt là công việc thiết kế collision filtering được nhanh chóng.

Tham khảo

http://www.codeandweb.com

IO Stream

IO Stream Co., Ltd

30 Trinh Dinh Thao, Hoa Thanh ward, Tan Phu district, Ho Chi Minh city, Vietnam
+84 28 22 00 11 12
developer@iostream.co

383/1 Quang Trung, ward 10, Go Vap district, Ho Chi Minh city
Business license number: 0311563559 issued by the Department of Planning and Investment of Ho Chi Minh City on February 23, 2012

©IO Stream, 2013 - 2024