Cocos2d-x 3.2 Final

Cập nhật lên phiên bản Cocos2d-x 3.2. Bổ sung 3D sprite, 3D animation, game controller, fast Tilemap,..v...v... Cập nhật thường xuyên nhé

Cocos2d-x 3.0 Final

Cocos2d-x là Engine lập trình game đa nền tảng phổ biến nhất trên thế giới. Tính năng mạnh mẽ, dễ sử dụng, miễn phí, mã nguồn mở.

Cocos2d-x V3.0 Final

Hướng dẫn chi tiết, đầy đủ bằng Video, Blog. Cộng đồng hỗ trợ rộng lớn. Sản phẩm phong phú mọi nền tảng

Game Badland

Một trong những game nổi tiếng nhất được tạo ra bởi Engine Cocos2d-x.

Cocos2d-x V3.1

Cập nhật phiên bản Engine Cocos2d-x V3.1 bổ sung thêm nhiều tính năng. Sửa các lỗi nhỏ của các phiên bản trước

Contra Evolution - KONAMI

1 Game rất hay không thể bỏ qua, 1 vé trở về với tuổi thơ.

Friday, July 11, 2014

Cách build Project cpp-tests của Cocos2d-x V3.x ra EXE (publish not debug)

Hi các bạn!

Dạo này mình tập trung nghiên cứu mấy project game lớn lớn 1 chút để tích kinh nghiệm và đào sâu hơn các thư viện mẫu của Engine nên cũng ít viết bài hơn. Mọi người thông cảm nhé. Càng đào sâu đọc kỹ càng thấy những hiểu biết trước đây có nhiều điểm chưa đúng, hoặc không còn đúng vào thời điểm hiện tại. Như thế là tốt, chứ cứ bảo thủ với kiến thức cũ của mình thì nguy. Chính vì thế mình đang chỉnh sửa lại những bài viết cũ trên Blog.

Trong 1 bài ngắn ngắn này mình sẽ chỉ cho các bạn cách Publish Project cpp-test của Engine ra file chạy Exe trong Window - có thể mở trực tiếp nhiều lần ko cần dùng VS. Không xét việc build APK nhé, bạn làm việc nhiều trên máy tính để code hơn mà.

Các bạn biết đấy, 1 project bình thường tạo bởi Engine, bạn có thể build ra exe bằng 2 cách :

+ Dùng lệnh cmd của window
+ Dùng VS2012, 2013 để tạo bản Release hoặc Debug

Nhưng với cách tạo Release hoặc Debug mình chạy trực tiếp file exe sẽ lỗi do thiếu Resource, và rất nhiều lib,obj, log, linh tinh khác trong thư mục. Mỗi lần chạy lại phải mở VS lên khá bất tiện. Có thể mình chưa biết cách Publish trong VS chăng. Có ai biết không - Cách build 1 lần rồi mở file Exe lên chạy cho các lần khác đó?

Với 1 bản Publish bạn sẽ dễ dàng sử dụng mọi lúc mọi nơi trên window, kể cả vác sang máy khác để chạy thử mà ko phải mở VS lên.

Thông thường khi bạn down Engine về, bạn build Project cpp-test bằng cách sau

+ Mở file cocos2d-win32.vc2012.sln theo đường dẫn Q:\ANDROID\Cocos2dx3\build, rồi cứ thế Debug và chạy thử, lần nào muốn xem ví dụ mẫu bạn cũng sẽ phải làm như vậy khá bất tiện nhỉ. Mình chuyển chế độ Release cũng vẫn phải làm vậy là sao. Nên loay hoay tìm ra cách build cmd cho cpp-tests kia. đơn giản thôi, chẳng cao siêu gì, nhưng có thể có người chưa biết như mình chẳng hạn.

Cách của mình là như thế này

+ Dùng lệnh cmd của window buil Project cpp-test như là 1 project thông thường các bạn tạo ra, nhưng trước hết các bạn phải chỉnh sửa 2 file sau.

1/ Copy file cocos2d-win32.vc2012.sln ở trên vào Project cpp-test theo đường dẫn Q:\ANDROID\Cocos2dx3\tests\cpp-tests\proj.win32, đổi tên lại thành cpp-tests.sln

2/ Quan trọng đây : Sửa path của các Libs trong file đó theo đúng đường dẫn mới ( do mình copy và thả vào thư mục khác với thư mục build mà ). Có chút kinh nghiệm là sửa được thôi. Mà DOWNLOAD file của mình cho nhanh . Trong này mình đã bỏ đi Lib và Project test khác nhé chỉ để cpp-tests thôi

3/ Mở file .cocos-project.json Xóa hết ( tốt hơn là lưu Save As đề phòng ) config trong đó và paste

{
    "project_type": "cpp"
}

Save lại

OK, giờ thì BUILD thử bằng commend sau

>cocos run -s (chỗ này bạn kéo thả thư mục cpp-tests vào đây nhé, vì path dài ngại gõ) -p win32

Kết quả sẽ ra thư mục Publish nằm trong thư mục Cpp-tests với đầy đủ Resource, dll, EXE.
Khi nào bạn cần chạy thử các ví dụ chỉ việc vào đây, hoặc tạo shortcut ngoài desktop mà run thôi. đỡ phải dùng đến VS nữa, và cũng ko phải tạo APK chạy trên điện thoại.

Bạn hoàn toàn có thể mang thư mục Publish này lên máy window khác để chạy nhé



Có thể có cách khác nữa nhưng mình chỉ biết các này thôi, ai biết cách ngắn gọn hơn thì share với

+ Bạn cũng có thể build lua-tests với cách tương tự nhưng nhớ chú ý file json là .lua nhé

Chào và hẹn gặp lại các bạn ở bài sau

Saturday, July 5, 2014

Bài 27: Học làm game thứ 4 - Game đập chuột ( Part 2)

Hi các bạn!

Mấy ngày xem bóng hoa mắt quá đi, cũng làm tí cá độ cho vui, rất may là chưa có cái gì ra đi cả hehe. Nay trở lại hoàn thành nốt phần 2 game đập chuột này nhé ( Máy tính vẫn còn mà ).

Nhiệm vụ chính trong phần 2 này bao gồm các công việc như sau:
+ Đập chuột.
+ Tính điểm + Game Over
+ Add âm thanh.
+ Làm một chút hiệu ứng animation.

Đi luôn nhé!

Bạn mở file HelloWorldScene.h ra, thêm vào đoạn code sau vào phần public

// Tạo 1 Animation với các thông số, Tên ảnh, thứ tự hình ảnh, số khung, trễ
Animation* createAnimation(string prefixName, int* pFramesOrder, int framesNum, float delay);
bool onTouchBegan(Touch *touch, Event *unused_event); // Sự kiện Touch
// Mở , khóa chế độ đập chuột
void unsetTappable(Object* pSender);
void setTappable(Object* pSender);

// Cười + Đánh chuột
Animation *laughAnim;
Animation *hitAnim;
// Label dùng để hiển thị điểm
LabelTTF *label;

// Điểm số
int score;
// Số chuột không bị đập để tính game over
int totalSpawns;
bool gameOver;

nhớ thêm using namespace std; ở đầu file nhé ( vì dùng string )

Tiếp theo mở file HelloWorldScene.cpp ra

Include thêm #include "SimpleAudioEngine.h", và using namespace std;

Trong hàm init() thêm vào đoạn code sau ( trước return true )

auto visibleSize = Director::getInstance()->getWinSize();
auto visibleOrigin = Director::getInstance()->getVisibleOrigin();

//Tạo Animation chuột cười + Hit lên đầu chuột
int laughAnimOrder[6] = { 1, 2, 3, 2, 3, 1 }; // thứ tự các hình ảnh duyệt trong spritesheet
laughAnim = this->createAnimation("mole_laugh", laughAnimOrder, 6, 0.1f);
int hitAnimOrder[6] = { 1, 2, 3, 4 }; // Tương tụ trên
hitAnim = this->createAnimation("mole_thump", hitAnimOrder, 4, 0.02f);
// Nạp vào bộ đệm animation và đặt tên
AnimationCache::getInstance()->addAnimation(laughAnim, "laughAnim");
AnimationCache::getInstance()->addAnimation(hitAnim, "hitAnim");

//Touch
auto listener = EventListenerTouchOneByOne::create();
listener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);

//Tạo 1 Label hiển thị điểm số
float margin = 10;
label = LabelTTF::create("Score: 0", "fonts/Marker Felt.ttf", 14);
label->setAnchorPoint(Point(1, 0));
label->setPosition(visibleOrigin.x + visibleSize.width - margin, 
visibleOrigin.y + margin);
this->addChild(label, 10);

//Khởi tạo các giá trị : điểm, tổng số chuột, game over
gameOver = false;
totalSpawns = 0;
score = 0;

// Nạp trước Âm thanh, play nhạc nền
CocosDenshion::SimpleAudioEngine::getInstance()->preloadEffect("laugh.mp3");
CocosDenshion::SimpleAudioEngine::getInstance()->preloadEffect("ow.mp3");
CocosDenshion::SimpleAudioEngine::getInstance()->playBackgroundMusic("whack.mp3", true);

Hàm Touch

bool HelloWorld::onTouchBegan(Touch *touch, Event *unused_event)
{
// Lấy tọa độ điểm Touch
Point touchLocation = this->convertTouchToNodeSpace(touch);
// Duyệt vector molesVector
for (Sprite *mole : molesVector) 
{
if (0 == mole->getTag()) continue; // bỏ qua, do đã ko được phép đập
// Lấy đường bao của Sprite ( dạng Rectang ), nếu chứa điểm Touch - tức là đập trúng chuột thì
if ( mole->getBoundingBox().containsPoint(touchLocation) ) 
{
// Âm thanh
CocosDenshion::SimpleAudioEngine::getInstance()->playEffect("ow.mp3");
// Cộng điểm và gán tag - ko đập thêm được
mole->setTag(0);
score += 10;

mole->stopAllActions(); // Dừng tất cả Action
// Tạo hitAnimation từ Cache
Animate *hit = Animate::create(hitAnim);
// Thụt xuống + biến mất
MoveBy *moveDown = MoveBy::create(0.2f, Point(0, -mole->getContentSize().height));
EaseInOut *easeMoveDown = EaseInOut::create(moveDown, 3.0f);
// Thực hiện 2 Animation tuần tự, bị hit và thụt xuống
mole->runAction(Sequence::create(hit, easeMoveDown, NULL));
}
}

return true;
}


Hàm createAnimation

Animation* HelloWorld::createAnimation(string prefixName, 
  int* pFramesOrder, 
  int framesNum, 
  float delay)
{
// Hãy xem lại bài 19 về cách làm animation từ spritesheet, có 5 bước nhỏ như sau
Vector<SpriteFrame*> animFrames; //1
// Tạo frame
for (int i = 0; i < framesNum; i++) //2
{
char buffer[20] = { 0 }; //3
sprintf(buffer, "%d.png", pFramesOrder[i]); //3
string str = prefixName + buffer; //3 Chính là tên của ảnh trong spritesheet 
// tạo frame, add vào vector
auto frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(str); //4
animFrames.pushBack(frame); //4
}
// Trả về 1 animation
return Animation::createWithSpriteFrames(animFrames, delay); //5
}


Hàm tryPopMoles, sửa lại 1 chút, hàm này là hàm update Scene theo thời gian, mình sẽ làm các việc kiểm tra gameOver, tính điểm trong này, vì các sự kiện này luôn phụ thuộc thời gian mà.

void HelloWorld::tryPopMoles(float dt)
{

if (gameOver) return; // Game over rồi thì thôi

// Hiển thị điểm = Label, tất nhiên có cách hiển thị điểm = font, text, mình ko xét ở đây
char scoreStr[30] = { 0 };
sprintf(scoreStr, "Score: %d", score);
label->setString(scoreStr);

// Xuất hiện đủ 50 chú chuột thì kết thúc game
if (totalSpawns >= 50) {
Size winSize = Director::getInstance()->getWinSize();
// Kết thúc game
LabelTTF *goLabel = LabelTTF::create("Game Over!", "fonts/Marker Felt.ttf", 48.0f);
goLabel->setPosition(Point(winSize.width / 2, winSize.height / 2));
goLabel->setScale(0.1f);
this->addChild(goLabel, 10);
goLabel->runAction(ScaleTo::create(0.5f, 1.0f)); // Tạo hoạt cảnh 1 tí cho đẹp

gameOver = true; // gán game Over = true để timeline sau ko hiện ra label kết thúc game nữa, bạn test = false xem sẽ thấy
return;
}
//-----------
// Code vòng for ở bài trước vẫn thế nhé vẫn thế nhé

}

2 Hàm khóa và mở khóa trạng thái " được đập" và "ko được đập "

void HelloWorld::setTappable(Object* pSender) // được phép đập
{
Sprite *mole = (Sprite *)pSender;
mole->setTag(1); // cho phép đập
//Play âm thanh, --- Cứ cười đi rồi ăn đập nhá ku!
CocosDenshion::SimpleAudioEngine::getInstance()->playEffect("laugh.mp3");
}

void HelloWorld::unsetTappable(Object* pSender)
{
Sprite *mole = (Sprite *)pSender;
mole->setTag(0); // Ko cho phép đập
}

Giờ còn mỗi hàm PopMole này nữa là xong

void HelloWorld::popMole(Sprite *mole)
{
if (totalSpawns > 50) return; // Kết thúc khi đủ 50
totalSpawns++; // đếm số chuột thò lên

// Lệnh này ko rõ lắm, vì bỏ đi game vẫn chạy mole->setSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("mole_1.png"));

// Action của chuột, nhô lên, thụt xuống
auto moveUp = MoveBy::create(0.2f, Point(0, mole->getContentSize().height));  // 1
auto easeMoveUp = EaseInOut::create(moveUp, 3.0f); // 2
auto easeMoveDown = easeMoveUp->reverse(); // 3

// Aimaition Cười
Animate *laugh = Animate::create(laughAnim);

// Thực hiện tuần tự các Action: Thò lên, MỞ BỤP, Cười, KHÓA ĐẬP, Thụt xuống
mole->runAction(Sequence::create(easeMoveUp, 
CallFuncN::create(CC_CALLBACK_1(HelloWorld::setTappable, this)),
laugh,
CallFuncN::create(CC_CALLBACK_1(HelloWorld::unsetTappable, this)),
easeMoveDown, 
NULL)); // 5
}

Xong hết code rồi, BUILD & BỤP thôi anh em




  
OK. Vậy là chúng ta đã ngâm cứu xong 1 game nhẹ nhàng nữa rồi. Cũng không quá khó nhỉ, các bạn nhớ đọc lại code vài lần nhé để nhớ cho lâu.

Vì là bản game TUT nên vẫn còn một số hạn chế:

+ Không có búa đập cho đã tay
+ Đập vào đầu chuột hiệu ứng chưa đẹp, và rõ ràng lắm
+ Điểm số label, không đẹp bằng image
+ Hơi ít lỗ chuột, làm nhiều 1 chút là đập mỏi tay, hỏng màn hình như chơi
+ Thêm vài màn chơi nữa là đẹp
+ Thêm được phần Pause game cũng ko tồi

- Đó là một số phần mở rộng của game, các bạn có thể xây dựng thêm, và mở rộng tới đâu là tùy thuộc ý tưởng của mỗi người nữa. Mình chỉ tới đây thôi.

Chào và hẹn gặp lại các bạn ở những bài sau.

Thursday, July 3, 2014

Bài 26: Học làm game thứ 4 - Game đập chuột ( Part 1)

Hi cả nhà!

Lâu lâu lại lười viết bài, vì thật ra cũng càng ngày càng khó, và project cũng dài nữa nên.... Và mình cũng đang bí ở phần áp dụng Box2D body cho Animation SpriteSheet, và Box2D body cho CocoStudio, Spine. Tìm hiểu mãi mà chưa có cách làm. Bạn nào đã từng code với bản 2.x có đoạn code áp cho 1 trong 3 cái trên thì chia sẻ giúp nhé, cám ơn.

Hôm nay mình tìm được 1 game khá thú vị, đưa lên đây cho mọi người cùng tìm hiểu, code khá đơn giản, chủ yếu là ôn tập lại các kiến thức đã học thôi, không phức tạp lắm đâu. Đó là game Đập chuột ( Whack Hole ).

Trong này có 1 -3 chú chuột chũi nhô lên, thụt xuống ở 3 cái lỗ, nhiệm vụ của bạn là đập vào đầu nó để ghi điểm thôi. Trong Part 1 ngày, chúng ta nghiên cứu những vấn đề sau

+ Thay đổi tỉ lệ màn hình với từng loại thiết bị
+ Dựng Scene
+ Action của Chuột

Thế thôi nhỉ, ta bắt đầu!

B1 - Thay đổi tỉ lệ màn hình theo từng loại thiết bị

Bạn tạo mới Project dapchuot, mở file AppDelegate.cpp ra, thêm vào đoạn code sau, bên dưới lệnh director->setAnimationInterval(1.0 / 60);

    // Màn hình thiết bị
    Size frameSize = glview->getFrameSize();  
    auto designSize = Size(512, 384);  // Khung hình thiết kế

    // Độ phân giải thiết kế
    glview->setDesignResolutionSize(designSize.width, designSize.height, ResolutionPolicy::NO_BORDER);

    // Vector <string> lưu thông tin đường dẫn Resource
    std::vector<std::string> searchPaths;
    if (frameSize.height > 480)  // Nếu màn hình > 480
    {
        searchPaths.push_back("hd"); // đường dẫn là ("hd");
        Size resourceSize = Size(1024, 768); // Đặt kích thước = 1024,768


        // Tăng kích thước content để phù hợp với màn hình
        director->setContentScaleFactor(MIN(resourceSize.height/designSize.height,
                                            resourceSize.width/designSize.width));
    }
    else //  Chọn sd< 480px
    {
        searchPaths.push_back("sd");
    }

    // Chọn Resource
    FileUtils::getInstance()->setSearchPaths(searchPaths);

B2 - Dựng màn chơi 

Bạn mở file HelloWorldScene.h, thêm vào đoạn code sau

void tryPopMoles(float dt);  // 1 hàm rất giống hàm update ( float dt ) đúng ko, thì chức năng cũng giống thế mà, update scene theo thời gian
void popMole(Sprite *mole); // Hàm acction cho chuột

Vector<Sprite*> molesVector; // Vector Sprite lưu các chú chuột

Mở HelloWorldScene.cpp

Trong hàm init (), thêm 1 đoạn code khá dài sau ( xóa phần code thừa bên trong, chỉ chừa lại phần super init() và return true nhé)

    // Đặt tên cho các file Resource, lưu ý 1 chút với string nó thuộc lớp std nên phải khai báo dạng std::string. Nếu không muốn thế này bạn phải dùng namespace: using namespce std; ở đầu file
    
    // Các dạng file này .pvr.ccz, .plist nhìn có vẻ ghê ghớm nhưng thực ra không có gì cả. File .plist chứa thông tin tọa độ, tên gọi, kích thước của các ảnh png đơn lẻ được pack trong file .pvr.ccz. Còn file .pvr.ccz là 1 dạng nén ảnh để giảm kích thước lưu trữ và bộ nhớ trong game. Bạn dùng phần mềm TexturePacker 3.3.x trong Blog này mình có bài rồi để thực hiện pack nhé

    std::string bgSheet = "background.pvr.ccz";
    std::string bgPlist = "background.plist";
    std::string fgSheet = "foreground.pvr.ccz";
    std::string fgPlist = "foreground.plist";
    std::string sSheet  = "sprites.pvr.ccz";
    std::string sPlist  = "sprites.plist";
    
    // Nạp background + foreground
    SpriteFrameCache::getInstance()->addSpriteFramesWithFile(bgPlist);
    SpriteFrameCache::getInstance()->addSpriteFramesWithFile(fgPlist);
    
    // Add background, bg_dirt.png được lấy từ background.pvr.ccz (  dựa trên thông số của background.plist)
    Sprite *dirt = Sprite::createWithSpriteFrame(
                        SpriteFrameCache::getInstance()->getSpriteFrameByName("bg_dirt.png"));
    dirt->setScale(2.0); // Phóng to lên
    dirt->setPosition(winSize.width/2, winSize.height/2);
    this->addChild(dirt, -2);

    // Add foreground, grass_lower.png lấy trong foreground.pvr.ccz ( dựa trên thông số của foreground.plist )
    // Nửa dưới
    Sprite *lower = Sprite::createWithSpriteFrame(
                        SpriteFrameCache::getInstance()->getSpriteFrameByName("grass_lower.png"));

    // Bạn chú ý chỗ này, 1 hình ảnh có nhiều AnchorPoint ( là điểm engine sẽ lấy để đặt trên màn hình vào tọa độ xác định. thường có 9 AnchorPoint hay dùng là các điểm sau: 4 góc hình + 1 tâm + 4 trung điểm 4 cạnh của khung ảnh png
    //Như thế này 
    //Point(0,0) = góc trái-dưới
    //Point(0,1) = góc trên-trái
    //Point(1,0) = góc phải-dưới
    //Point(1,1) = góc trên-phải
    //Point(0.5,0.5) = Tâm
    //Point(0.5,0) = giữa cạnh dưới
    //Point(0,0.5) = giữa cạnh trái
    //Point(0.5,1) = giữa cạnh trên
    //Point(1,0.5) = giữa cạnh phải
    // Với hình đặc biệt trong CocoStudio, Spine, SpriteSheet, ta có thể chỉnh được điểm neo này = tay
    // Tùy vào từng trường hợp mà ta set AnchoPoint hợp lý sẽ khiến việc căn đối tượng dễ dàng hơn

    lower->setAnchorPoint(Point(0.5, 1));
    lower->setPosition(winSize.width/2, winSize.height/2 + 1); // Tách 2 nửa ra 1 chút để nhận biết, trong game bạn xóa + 1 đi
    this->addChild(lower, 1);

    // Nửa trên, tại sao có nửa dưới và trên ? khi bạn build xong sẽ hiểu, vì nửa trên set index -1, nửa dưới =1 để cho chuột có index ở giữa = 0 sẽ hiện bên trên nửa trên và bị che một phần do nửa dưới. giá trị index có tác dụng sắp sếp đối tượng như thế.

    Sprite *upper = Sprite::createWithSpriteFrame(
                        SpriteFrameCache::getInstance()->getSpriteFrameByName("grass_upper.png"));
    upper->setAnchorPoint(Point(0.5, 0));
    upper->setPosition(winSize.width/2, winSize.height/2 - 1); // Tách 2 nửa ra 1 chút để nhận biết, trong game bạn xóa - 1 đi
    this->addChild(upper, -1);
    
// Tạo SpriteSheet... lưu chuột
SpriteBatchNode *spriteNode = SpriteBatchNode::create(sSheet);
this->addChild(spriteNode, 0);
SpriteFrameCache::getInstance()->addSpriteFramesWithFile(sPlist);

// Nạp 3 chuột
Sprite *mole1 = Sprite::createWithSpriteFrameName("mole_1.png");
mole1->setPosition(99, winSize.height / 2 - 75);
spriteNode->addChild(mole1); // Thêm vào spritesheet
molesVector.pushBack(mole1); // Thêm vào Vector

Sprite *mole2 = Sprite::createWithSpriteFrameName("mole_1.png");
mole2->setPosition(winSize.width / 2, winSize.height / 2 - 75);
spriteNode->addChild(mole2);
molesVector.pushBack(mole2);

Sprite *mole3 = Sprite::createWithSpriteFrameName("mole_1.png");
mole3->setPosition(winSize.width - 102, winSize.height / 2 - 75);
spriteNode->addChild(mole3);
molesVector.pushBack(mole3);

// Update scene trong thời gian 0.5 giây
this->schedule(schedule_selector(HelloWorld::tryPopMoles), 0.5);

Hàm tryPopMoles như sau

void HelloWorld::tryPopMoles(float dt) // hàm này nhận đối số thời gian giống hàm update (float dt)
{
for (Sprite *mole : molesVector) // duyệt vector
{
int temp = CCRANDOM_0_1()*10000; // Tạo số random
if ( temp % 3 == 0)  // chia hết cho 3, thì ....
{
if (mole->getNumberOfRunningActions() == 0)  // Nếu ko có Action nào
{
this->popMole(mole); // Thò đầu lên và ăn đập : ))
}
}
}
}

B3 - Hành động của chuột

void HelloWorld::popMole(Sprite *mole)
{
// Lên 
auto moveUp = MoveBy::create(0.2f, Point(0, mole->getContentSize().height));  // 1
auto easeMoveUp = EaseInOut::create(moveUp, 3.0f); // 2

auto easeMoveDown = easeMoveUp->reverse(); // 3
auto delay = DelayTime::create(0.5f); // 4

// Thực hiện chuỗi hành động, Lên, đứng đó, Xuống, ko làm gì cả 
mole->runAction(Sequence::create(easeMoveUp, delay, easeMoveDown, NULL)); // 5
}

Xong rồi, Build chạy thử xem có ra gì không, ngon rồi!




Vậy là trong bài này chúng ta cùng nhau ôn lại 1 vài kiến thức sau:

+ SpriteSheet
+ Nạp Resource từ file Pvr, plist
+ Vector
+ Action

Đơn giản thế thôi, bài sau chúng ta sẽ thực hiện nốt công việc là, đập chuột, tính điểm.

Dowload Resoucrce, Class

Chào và hẹn gặp lại các bạn ở bài sau!

Bài 27: Học làm game thứ 4 - Game đập chuột ( Part 2) 

Bài 25 - Tìm hiểu về hiệu ứng Parallax Scrolling trong Cocos2d-x 3.x

Hi các bạn! 

Lang thang trên trang chủ của cocos2d-x gặp được 1 bài TUT về Parallax Crolling khá hay, mình mang về Blog này để mọi người cùng ngâm cứu. Có thể nhiều bạn sẽ nghĩ mình đang "ăn cắp" bài viết của người khác làm bài của mình. Oh no, biết nói thế nào nhỉ, ngay từ ban đầu blog ( bài 1,2 gì đó) mình đã nói rõ, Code, Resource trong Blog này mình ko hề Code ra, mà chỉ nhặt nhạnh trên mạng, rồi đem về trình bày và diễn giải lại trên Blog để tự học và mọi người cùng đọc. Có nhiều bài mình thực hành code xong viết lại thành TUT, hoặc có 1 vài bài mình lấy Tut người khác, nhưng sẽ trình bày lại theo cách hiểu của mình sao cho dễ hiểu và gần gũi với cả người mới bắt đầu tìm hiểu về Engine, và đây là 1 bài như thế. Sẽ không có gì quá đáng phải không, mà thôi, ai đánh giá thế nào thì kệ chứ, việc của chúng ta là HỌC, là NGÂM CỨU làm game chứ ko phải VIẾT SÁCH, VIẾT TUT! 

OK, trước tiên chúng ta cùng tìm hiểu 1 hiện tượng vật lý cực kỳ hay gặp trong cuộc sống, đó là Parallax Scrolling

Parallax Scrolling  là gì? Dùng trong trường hợp nào?

Từ Parallax có nghĩa là Thị sai trong tiếng Việt đó
Bạn gõ Parallax hoặc Thị sai lên Google là sẽ có kết quả trả về lập tức, đây là trang Wiki

Hiện tượng Parallax Scrolling là hệ quả được tạo ra bởi thị sai ( Parallax ) của mắt với các vật thể xa, gần, Vật càng xa, góc nhìn càng nhỏ, vật càng gần thì góc nhìn càng rộng, nêu khi 2 vật xa gần di chuyển cùng 1 vận tốc ( hoặc khác vận tốc ), thì ta sẽ thấy vật ở gần (có vẻ ) di chuyển nhanh hơn vật ở xa.

Chúng ta có thể hiểu Hiệu ứng Parallax Scrolling là hiệu ứng các vật chuyển động tương đối với vận tốc tỷ lệ nghịch với khoảng cách từ vật tới mắt người quan sát, Vật gần di chuyển nhanh, vật xa di chuyển chậm

Ví dụ về Prallax trên HTML5 
Ví dụ trong cuộc sống hàng ngày
+ Khi bạn đi tàu, xe, nhìn ra ngoài cửa sổ sẽ thấy, Cột điện "lùi lại rất nhanh", cánh đồng "lùi lại vừa phải", Mây "lùi lại chậm" Mặt trời "lùi lại rất chậm". Nghĩa là vật càng gần mắt người quan sát thì chuyển động càng nhanh, càng ở xa thì chuyển động càng chậm. ( mặc dù các vật trên có thể coi là cùng vận tốc - đứng im - so với mắt người đang đứng im ) đừng ai bắt bẻ về "sự đứng im" và chuyển động nhé. cũng chỉ tương đối thôi, quan trọng là mắt người quan sát thấy thế nào thôi.

Ứng dụng trong game:

Hiệu ứng Parallax Scrolling hay dùng trong game 2D để tạo chiều sâu cho game, bạn hãy vào trang web bên trên trải nghiệm nhé, 

Tạo hiệu ứng này như thế nào?

Dựa vào định nghĩa trên, về lý thuyết thì ta có thể làm như sau trong game

+ Ta tạo ra Các layer chồng lên nhau
+ Layer nào ta định nghĩa ở xa thì ta cho dịch chuyển với tốc độ chậm
+ Layer nào định nghĩa ở gần thì ta dịch chuyển với tốc độ nhanh hơn
+ Các vận tốc này thường cùng phương cùng chiều, độ lớn tỷ lệ với khoảng cách đến mắt quan sát

Lý thuyết có vẻ đơn giản, thực tế Code thì sao?

Chúng ta cùng bắt đầu nào!


Bạn tạo 1 Project mới đặt tên Parallax

Xây dựng Class InfiniteParallaxNode như sau

InfiniteParallaxNode.h

class InfiniteParallaxNode : public ParallaxNode
{
public:
    static InfiniteParallaxNode* create(); // Tạo InfiniteParallaxNode
    void updatePosition(); // Update lại vị trí
};

InfiniteParallaxNode.cpp

class PointObject : public Ref // Dựng 1 lớp PointObject
{
public:

    // Các hàm inline thiết lập, và lấy về các thuộc tính
    inline void setRation(Point ratio) {_ratio = ratio;}
    inline void setOffset(Point offset) {_offset = offset;}
    inline void setChild(Node *var) {_child = var;}
    inline Point getOffset() const {return _offset;}
    inline Node* getChild() const {return _child;}

private:
    Point _ratio; // Tỉ lệ
    Point _offset; // Độ lệch
    Node* _child; // Node con
};

InfiniteParallaxNode* InfiniteParallaxNode::create()
{
    // Tạo mới 1 đối tượng InfiniteParallaxNode*
    InfiniteParallaxNode* node = new InfiniteParallaxNode();
    if(node) {
        node->autorelease();
    } else {
        delete node;
        node = 0;
    }
    return node;
}

void InfiniteParallaxNode::updatePosition()
{
    int safeOffset = -10;

    Size visibleSize = Director::getInstance()->getVisibleSize();
    // 1. Duyệt các con của chuỗi parallax

    for(int i = 0; i < _children.size(); i++)
    {
        auto node = _children.at(i); // Node i
        // 2. Kiểm tra node đó có ra ngoài màn hình ko, convertToWorldSpace bạn tham khảo tại đây http://www.cocos2d-x.org/wiki/Coordinate_System.
        if(convertToWorldSpace(node->getPosition()).x + node->getContentSize().width < safeOffset)
            // 3. Tìm PointObject tương ứng với node hiện tại
            for(int j = 0; j < _parallaxArray->num; j++)
            {
                auto po = (PointObject*)_parallaxArray->arr[j];
                // Nếu có thì tăng thêm độ lệch ra thêm 1 màn hình, tức xuất hiện lại thêm lần nữa
                if(po->getChild() == node)
                    po->setOffset(po->getOffset() +
                                  Point(visibleSize.width + node->getContentSize().width,0));
            }
    }
}

Trong file HelloWorldScene.h

Thêm include

    #include "InfiniteParallaxNode.h"
    InfiniteParallaxNode* _backgroundElements; // 1 con trỏ InfiniteParallaxNode
    float randomValueBetween(float low, float high); // random trong 1 khoảng
    void update(float delta); 

Trong file HelloWorldScenecpp

Phần Include

#include <climits>
#include <cstdlib>
#include <iostream>
using namespace std;

2 Hàm phụ

void HelloWorld::update(float delta)
{
    Point scrollDecrement = Point(5, 0); // Tốc độ Scroll, càng lớn cuộn càng nhanh
    _backgroundElements->setPosition(_backgroundElements->getPosition() - scrollDecrement);
    _backgroundElements->updatePosition();
}

// Giá trị ngẫu nhiên trong 1 khoảng
float HelloWorld::randomValueBetween(float low, float high)
{
    return (((float) rand() / RAND_MAX) * (high - low)) + low;
}

Hàm init()

    // Tạo màu nền cho background
    auto backgroundColor = LayerColor::create(
                Color4B(173, 255, 250, 255),
                visibleSize.width,
                visibleSize.height);
    backgroundColor->setPosition(Point::ZERO);
    addChild(backgroundColor, 0);
    // Ảnh Background
    auto ground = Sprite::create("ground.png");
    ground->setAnchorPoint(Point(0,0));
    ground->setPosition(Point::ZERO);
    addChild(ground, 1);
    
    // Tạo 1 đối tượng Parallax
    _backgroundElements = InfiniteParallaxNode::create();

    // Thêm 7 đối tượng (núi tuyết) vào Parallax
    unsigned int rocksQuantity = 7;
    for(unsigned int i = 0; i < rocksQuantity; i++)
    {
        auto rock = Sprite::create("rock.png");
        rock->setAnchorPoint(Point::ZERO);
        // Đặt độ lớn theo tỷ lệ ngẫu nhiên
        rock->setScale(randomValueBetween(0.6, 0.75));
        // Thêm vào Parallax
        _backgroundElements->addChild(rock,
                                     // Z-index, index lớn thì nằm chồng lên index nhỏ
                                     randomValueBetween(-10, -6),
                                     // Tỉ lệ tốc độ ( sẽ nhân với tốc độ Paralax)
                                     Point(0.05, 1),
                                     // Đặt vị trí của đối tượng, các đối tượng sẽ đặt cách nhau 1 khoảng tính theo công thức như bên dưới
                                     Point(
                                         (visibleSize.width / 5) * (i + 1) + randomValueBetween(0, 100),
                                         ground->getContentSize().height - 5));
    }

    // Thêm 35 cái cây vào Parralax
    unsigned int treesQuantity = 35;
    for(unsigned int i = 0; i < treesQuantity; i++)
    {
        auto tree = Sprite::create("tree.png");
        tree->setAnchorPoint(Point::ZERO);
        tree->setScale(randomValueBetween(0.5, 0.75));
        _backgroundElements->addChild(
                    tree,
                    randomValueBetween(-5, -1),
                    Point(0.5, 1),
                    Point(visibleSize.width / (treesQuantity - 5) * (i + 1) + randomValueBetween(25,50),
                          ground->getContentSize().height - 8));
    }

    // Thêm Parallax vào :Layer, update Scene
    addChild(_backgroundElements, 2);

    schedule(schedule_selector(HelloWorld::update), 0.01);

    // Thêm cha mặt trời vào 
    auto sun = Sprite::create("sun.png");
    sun->setAnchorPoint(Point(0.5,0.5));
    sun->setScale(0.25);
    sun->setPosition(Point(visibleSize.width * 2.0 / 3, visibleSize.height * 6.0 / 7));
    addChild(sun, 3);


OK rồi, giờ build và chạy thử xem thế nào



Vậy là trong bài này, chúng ta đã cùng nhau tìm hiểu về hiệu ứng Parallax Scrolling rồi đó. Bạn có thể áp dụng vào các game Running..X nào đó để làm game có chiều sâu hơn.

Một số hạn chế: 
+ Bạn phải ước lượng tỉ lệ vận tốc giữa các "Layer" Parallax ( vì thực sự đâu có nhiều Layer đâu - Chỉ có 1 Paralax ) do không biết được "khoảng cách" giữa các lớp này. 
+ Khi mô phỏng bạn làm sao cho các đối tượng gần thì chuyển động nhanh, các đối tượng xa thì chuyển động chậm hơn. Vậy thôi.

Dowload Resource, Code

Mình kết thúc bài này ỏ đây nhé, hẹn gặp lại trong các bài sau

Bài 26 : Học làm game 4 - Đập chuột ( Part 1 )

Tuesday, June 24, 2014

Bài 24 Giới thiệu CocoStudio - Công cụ tạo Animation cực cool - Import game (Part 2)


Hi đầu tuần!
Ở bài 23, mình đã giới thiệu sơ qua với mọi người về CocoStudio - 1 Tool khá hay để tạo Animation. Các bạn đã biết cách dựng khung xương, gắn xương với nhau, gắn ảnh Texture với xương rồi phải không, tuy lúc đầu sẽ gặp chút khó khăn ( thậm chí là bực mình ) khi thao tác nhưng chỉ cần bỏ ra 1 tiếng là bạn sẽ quen ngay với công việc "xương xẩu" này.

Trong bài tiếp theo này, mình sẽ hướng dẫn mọi người cách để tạo Animation cho nhân vật. Nếu ai đã từng học Flash rồi thì bước này thật sự dễ dàng nhé, vì nó khá giống. Tuy giống là vậy nhưng mình thấy Flash có một cái hơn đó là có thể can thiệp sâu bằng mã AS mà trong CocoStudio không thể can thiệp bằng script được ( Ai học Flash + AS rồi thì cho mình so sánh nhé, vì mình ko học ). Nhưng, vâng lại nhưng, CocoStudio lại có thể IMPORT Flash Project vào trong Studio, và hơn nữa Import được cả file Plist ( Particle - hiệu ứng, Physics ?? ) có sẵn từ bên ngoài vào. Vậy là bạn không phải lo Studio không thể tạo được Animation và Effect đẹp mắt nha.

Trong bài này mình sẽ hướng dẫn các bạn các công việc sau:

+ Sử dụng Timeline tạo Animation với Animation Mode
+ Xuất ra dịnh Resource phù hợp với Coco2d-x V3
+ Import vào game, QUAN TRỌNG nha

Bắt đầu nào!!!

B1 - Sử dụng Timeline tạo Animation + Export Resource

Bạn mở project MyAnimation của bài trước ra, với khung xương, texture đã được tạo sẵn ( Các bạn hãy nghiên cứu lại bài 23 một chút để chuẩn bị tốt cho bài này - Nhất là các thao tác với chuột ). OK?

Bạn bật sang chế độ Animation, sẽ hiện ra bảng Timeline như hình dưới




Trong ô Animation List, là danh sách các cử động - chuyển động của nhân vật, bạn có thể xóa, tạo mới, đổi tên, copy bằng menu chuột phải.


Tại ô Timeline bên cạnh liệt kê ra các Layer tạo nên nhân vật. Ở đây bạn sẽ dùng Timeline + Keyframe + di chuyển các đoạn xương để tạo nên chuyển động của Nhân vật. Các điểm cần lưu ý liên quan tới Animation:


+ Mỗi Layer được tạo chuyển động bằng 1 đường Timeline, màu trắng ( bên phải ). 
+ Layer nào ko có timeline có nghĩa là không xuất hiện trong chuyển động
+ Các số 0,5,10,15 là số khung hình / giây. Có thể ngầm hiểu là Thời gian luôn cũng được
+ Các dấu tròn là các Keyframe. Keyframe là gì, chính là những Frame đánh dấu sự thay đổi của hướng  chuyển động, hoặc thay đổi cách chuyển động ( hiệu ứng - tốc độ )

Hướng chuyển động: 
- Bạn hãy hình dung khi di chuyển từ A tới B, rồi tới C ( A,B,C không thẳng hàng) thì ta sẽ đặt 3 Keyframe tại thời điểm chuyển động qua A, B, C. 
- Hoặc khi chuyển động từ A tới B, rồi quay lại A thì sao? Bạn cũng sẽ phải đặt 3 Keyframe tại thời điểm chuyển động qua A, B, A. Nghĩa là khi có sự đổi hướng, đảo chiều chuyển động, thay đổi vận tốc, hiệu ứng thì thường đặt Keyframe tại điểm thay đổi đó. 
- Vậy với cung tròn thì sao, bạn hãy cố gắng chia cung tròn ra làm các đoạn ngắn rồi thêm Keyframe vào các đoạn chuyển hướng đó. 

Cách chuyển động:
Tạm hiểu là hiệu ứng hoặc tốc độ chuyển động ( bạn nhìn thấy ở bảng nhỏ bên phải Timeline là Custom Curve ko - chính hắn ). Bạn đặt con trỏ vào Keyframe, rồi chọn 1 hiệu ứng, rồi chạy thử xem, sẽ thấy khác biệt.

Tất nhiên trên 1 đường chuyển động thẳng, bạn có thể đặt nhiều hơn 2 Keyframe cũng ko sao, khi đó hướng chuyển động là ko đổi, nhưng kiểu cách chuyển động sẽ thay đổi ( bằng cách áp dụng Custom Curve) hoặc vận tốc thay đổi ( thay đổi số khung hình ). Bạn sẽ thấy cùng 1 đường thằng nhưng cách chuyển động - vận tốc chuyển động có khác nhau.

* Một số lưu ý với Keyframe
+ Layer ko có Keyframe nào, sẽ không hiện lên trong chuyển động.
+ Keyframe hide ( màu đỏ ) để ẩn Layer tại timeline đặt Keyframe cho tới khi gặp 1 Keyframe hiện ( màu trắng ) . Bạn dùng menu chuột phải để Set thuộc tính.
+ Chuyển động giữa 2 Key gọi là Tween Frame
+ 1 Chuyển động được tạo nên bởi >=2 Keyframe.
+ Số khung hình giữa 2 Keyframe càng lớn, chuyển động càng mượt, và càng chậm ( với cùng 1 đoạn đường ) - Dựa vào đây bạn có thể chỉnh vận tốc nhanh chậm của chuyển động. Tăng số khung hình sẽ cho vận tốc chậm và ngược lại. 

Bạn Test thế này:
- Tại Key 1 (timeline 0) bạn đặt đối tượng ( 1 xương gắn 1 texture cho dễ nhìn ) tại vị trí A.
- Kéo đối tượng ra vị trí B khác A ( xa xa vào cho dễ nhìn ), đặt con trỏ tại timeline 40, chuột phải/Add frame - Hoặc bạn dùng nút Record Frame bên dưới nút Play ấy, đây sẽ là Key2
- Nhấn Play xem kết quả
- Bây giờ kéo Key2 lại gần Key1 ( về timeline 10 ), nhấn Play xem kết quả,
- Giờ lại kéo Key2 ra timeline 80, nhấn Play
- Giờ đặt chuột vào Key1, chọn Custom Curve tùy ý, rồi nhấn Play, bạn thấy chuyển động có tí hiệu ứng chưa.

OK, xong phần lý thuyết, Bây giờ chúng ta thực hành chút, Mình sẽ tạo chuyển động bước đi của nhân vật, đặt tên là walk
Bạn làm như sau:

1/ Chuột phải trong ô Animation List, chọn Add Animation, đặt tên là walk
2/ Key1: bạn đặt chuột vào cột Timeline0 của Layer trên cùng, chuột phải / Add Frame. Các Layer bên dưới cũng làm như thế. Vậy là tất cả Layer đều hiện trong chuyển động




3/ Bước này khó nè: Bạn phải xác định trong chuyển động walk thì bộ phận nào ( layer ) chuyển động nhiều nhất, phức tạp nhất thì bộ phận đó sẽ có nhiều Keyframe nhất. Ví dụ là 2 chân và 2 tay. Và bạn phải hình dung cách bước đi của nhân vật như thế nào cho chuẩn: Chân trái + tay phải cùng đưa lên, sau đó thu về, sau đó chân phải + tay trái đưa lên, rồi lại thu về. Chả thấy ai chân và tay cùng 1 bên đưa lên, đưa về cả trừ ông dị dạng. :-((

4/ Ví dụ cái cánh tay trái ( Layer 19 ) sẽ có 5 vị trí Keyframe như sau ( bạn nhớ chọn vào nút Xoay xương - Inverse Kinematics nhé)
+ Key 1 : duỗi thẳng - Timeline 0
+ Key 2: đưa lên trước - Timeline 10
+ Key 3: về vị trí Key1 - Timeline 20, bạn copy Key1 rồi paste vào timeline 20 để đảm bảo đúng vị trí cũ của tay
+ Key 4: đưa về sau - Timeline 30
+ Key 5: về vị trí giống Key1 - Timeline 40, bạn copy Key1 rồi paste vào timeline 40 để đảm bảo đúng vị trí cũ của tay
Thử nhấn Play xem

5/ Cánh tay cầm súng - phải ( Layer 20 ) Cũng tương tự với 5 vị trí Keyframe
+ Key1 : duỗi - TL0
+ Key2 : đưa về sau - TL10
+ Key3: duỗi: Copy Key1 - TL20
+ Key4: đưa lên trước - TL 30
+ Key5: duỗi: Copy Key1 - TL40
* Tay này gồm 2 xương gắn nhau, nên bạn phải di chuyển sau cho khéo 1 tý cho tay hơi cong ở phần khuỷu tay nhé

6/ Chân Phải ( Layer 16 ) Cũng tương tự với 5 vị trí Keyframe , di chuyển giống tay Trái
+ Key1 : đứng thẳng- TL0
+ Key2 : đưa lên Trước- TL10
+ Key3: duỗi: Copy Key1 - TL20
+ Key4: đưa về Sau - TL 30
+ Key5: duỗi: Copy Key1 - TL40
* Chân này gồm 2 xương gắn nhau, nên bạn phải di chuyển sau cho khéo 1 tý cho chân hơi cong ở phần đầu gối nhé

7/ Chân Trái ( Layer 26 ) Cũng tương tự với 5 vị trí Keyframe , di chuyển giống tay Trái
+ Key1 : đứng thẳng - TL0
+ Key2 : đưa về Sau- TL10
+ Key3: duỗi: Copy Key1 - TL20
+ Key4: đưa lên trước- TL 30
+ Key5: duỗi: Copy Key1 - TL40
* Chân này gồm 2 xương gắn nhau, nên bạn phải di chuyển sau cho khéo 1 tý cho chân hơi cong ở phần đầu gối nhé.

8/ Cái đầu ( Layer 14) Chỉ cần 3 Key
+ Key1: ngả về trước
+ Key2: ngả về sau
+ Key3: Copy Key1

9/ Các bộ phận còn lại, như 2 bàn chân ( 27, 17) sẽ chia 5 key giống 2 chân, bạn cũng chỉnh vị trí sao cho bước đi mềm mại chút
Layer 21, là bắp tay phải, cũng giống tay phải cầm súng
* Thân người (15) hầu như không di chuyển, nhưng bạn cũng chia 5 key, với các vị trí đứng thẳng ( 2 chân thẳng ) thì trọng tâm cao  + Và khi bước đi, thì kéo cả khung xương xuống 1 đoạn, nhớ đặt Ruler ở vị trí bàn trân để căn chỉnh giả làm mặt đất, chỉnh cho chuẩn.

Của mình tạo đây



Nếu bạn làm theo 9 bước nhỏ trên đảm bảo không Animation nào làm khó được bạn, mình cam đoan đấy ( trừ Animation của F.A hoặc FAP thì..... :-))

Sau khi chỉnh, bạn thấy ưng ý thì Export ra thôi, chọn File / Export, để các thông số mặc định, chọn đường dẫn rồi nhấn OK. sau đó Copy toàn bộ các file trong thư mục Export đó quăng vào Resource của game là xong. Có 3 file ( plist, ExportJson, png ).

Không biết mình chỉ dùng Text mà ko có ảnh mỉnh họa, mọi người theo dõi có hiểu không?

Còn bây giờ chúng ta đi vào phần quan trọng không kém trong việc tạo Animation, đó là..

B2 - Import vào game

Bạn tạo 1 Project mới, đặt tên WalkMan nhé

Bạn mở file HelloWorldScene.h, thêm vào đoạn code sau:

Phần Include, bổ sung thêm các thư viện Extensions, CocoStudio, và UI

#include "cocos2d.h"
#include "extensions/cocos-ext.h" 
#include "cocostudio/CocoStudio.h"
#include "UI/CocosGUI.h"

USING_NS_CC;
using namespace cocostudio;

Trong Class:
   
private:
cocostudio::Armature* armature; // Cái này mình chịu ko biết giải thích thế nào, tra từ điển cũng ko có nghĩa nào hợp lý.

Trong file  HelloWorldScene.cpp, Ta thêm code như sau

USING_NS_CC;
using namespace cocostudio;

Trong hàm init ()

// Nạp 3 file tài nguyên được xuất bởi CocoStudio, đoạn này xin ko giải thích thêm, hãy đọc thuộc cú pháp này nhé.

ArmatureDataManager::sharedArmatureDataManager()->addArmatureFileInfo("DemoPlayer0.png","DemoPlayer0.plist","DemoPlayer.ExportJson");
armature = Armature::create("DemoPlayer");
armature->setPosition(ccp(visibleSize.width * 0.8,visibleSize.height * 0.5));
armature->getAnimation()->playByIndex(0);
armature->setScale(0.25);
this->addChild(armature);


Việc nạp tài nguyên từ CocoStudio đơn giản như vậy đó, Nhưng việc build ra không hề đơn giản nhé, mình cũng đã phải loay hay mất nửa ngày để tìm hiểu cách Build. Đã thế việc Build Android, và Win32 lại rất khác nhau. ( WP8 chắc tương tự Win32, còn IOS + MAC thì ko có máy ). Sau đây mình trình bày cách làm cho các bạn nhé.

1/ Build Android 

Vâng, các bạn để ý thấy đoạn Include sau
#include "extensions/cocos-ext.h" 
#include "cocostudio/CocoStudio.h"
#include "UI/CocosGUI.h"

Lệnh Import file này dùng chung cho Cocos2d-x, và để build Android. bạn phải chỉnh sửa file Android.MK nằm trong đường dẫn walkman\proj.android\jni, như sau

Thêm dòng code

Với phiên bản Engine 3.0
LOCAL_WHOLE_STATIC_LIBRARIES += cocostudio_static
LOCAL_WHOLE_STATIC_LIBRARIES += cocos_extension_static
vào bên dưới của
LOCAL_WHOLE_STATIC_LIBRARIES += cocosdenshion_static


$(call import-module,editor-support/cocostudio)
$(call import-module,extensions)

vào dưới lệnh
include $(BUILD_SHARED_LIBRARY)


Với phiên bản Engine 3.1.x, bạn chỉ việc xóa dấu # trước 24dòng
cocostudio_static, 
cocos_extension_static,
$(call import-module,extensions), 
$(call import-module,editor-support/cocostudio)

là ok,

Nếu bạn có thêm Class mới nhớ phải thêm Class vào đoạn này

LOCAL_SRC_FILES := hellocpp/main.cpp \ 


Xong rồi, Build Android thôi, các bạn tự làm nhé, xong rồi quẳng vào Máy ĐT để chạy nhé, ko nên xài máy ảo.

* Có  chút lưu ý, file Android.MK ở 2 phiên bản 3.0 và 3.1.x có 1 chút khác biệt 
+ 3.1.x bổ sung sẵn các mở rộng và đóng dấu #, và có dòng này
$(call import-module,.) khác với bản 3.0 là $(call import-module,2d). Bạn đừng cố sửa đổi thành 2d khi đang xài Engine 3.1.x
+ 3.0 thì cung cấp phần mở rộng ít hơn, và ko có gợi ý trong dấu #, bạn phải có chút kinh nghiệm mới biết thêm gì vào chỗ này khi dùng thêm thư viện.

2/ Build Window

Build cha này phức tạp hơn 1 chút, và nếu có xảy ra lỗi thì quả thật rất khó tìm, liên quan tới code thì không sao, nhưng liên quan tới thư viện thì khó tìm lắm. Mày mò cũng mất khá nhiều thời gian. Và đây là kết quả mày mò của mình sau nửa ngày.

Bạn để ý phần Include

#include "extensions/cocos-ext.h" 
#include "cocostudio/CocoStudio.h"
#include "UI/CocosGUI.h"

Ở trường hợp Android, bạn thêm 2 dòng code vào Android.MK, vậy thì với window bạn phải thêm dòng code tương tự vào đâu. Chính là file walkman.vcxproj ( file VCXPROJ này rất quan trọng nhé, các bạn lưu ý). 

Đầu tiên: 
Bạn hãy xem lại bài 15, cách mình thêm thư viện Box2D vào VS2012 nhé. Ở bài này chúng ta cũng làm tương tự như vậy nhưng ko phải là Box2D mà là 3 thư viện nêu trong INCLUDE kia, quan trọng là bạn phải biết IMPORT đúng thư viện nào, mình chỉ luôn:

+ libExtensions.vcxproj nằm trong đường dẫn walkman\cocos2d\extensions\proj.win32
+ libCocosStudio.vcxproj nằm trong walkman\cocos2d\cocos\editor-support\cocostudio\proj.win32
libGUI.vcxproj nằm trong walkman\cocos2d\cocos\ui\proj.win32

Và kết quả mình thêm đây


Đã có 3 lib kể trên ( Nhớ xem lại cách làm ở bài 15 - QUAN TRỌNG nhé). bạn phải nhớ SAVE solution đấy, sau đó bạn mở file walkman.vcxproj trong đường dẫn ( walkman\proj.win32 ) lên xem kết quả


Đã chứa 3 Lib ( và có mã ID ở dưới, vì thế bạn ko thể Add = tay nhé)

Tiếp theo: 

Các bạn search trong file walkman.vcxproj cụm từ AdditionalIncludeDirectories

và tìm tới dòng 72 + 105 (2 vị trí): thêm vào đoạn code sau ngay phía đầu

$(EngineRoot)cocos;$(EngineRoot)cocos\editor-support;$(EngineRoot);

Hoặc bạn có thể thêm các dòng trên ( EnginRoot) bằng VS2012 như sau

+ Chuột phải vào project walkman trong cửa sổ Solution Explorer / References / Configuration Properties / Additional Include Directories ( Ngay dòng đầu tiên ) có các thông số ở ô bên phải. Bạn Click vào đó và chọn Edit nhé, rồi chọn nút New Line - nút đầu tiên ( hình thư mục ). Add 3 cái EngineRoot vào là Xong

OK, chỉ như vậy thôi, là BUILD thành công, có phức tạp quá không nhỉ ???

Kết quả đây, 1 chú Cowboy đang bước đi tại chỗ, hehe. Nếu mình xây dựng hàm Touch cho move tới vị trí Touch thì sẽ có nhân vật bước đi thôi. Để sau vậy






OK, Vậy là đã xong 1 bài khá công phu. Trong bài này chúng ta học được những gì? Rất nhiều cái hay ho:

+ Sử dụng chức năng Animation của CocoStudio thành thạo.
+ Cách Import tài nguyên vào game qua đoạn code đơn giản.
+ Cách Build với Android, Window khi thêm thư viện mới.

Một số điểm còn hạn chế:

+ Mới học được 1/4 chức năng của CocoStudio thôi nhé, Nhân vật mới chỉ có 1 chuyển động. Vậy nếu nhân vật có nhiều chuyển động thì sao? Import Particle, Vật lý vào thế nào đây? Các bài sau hi vọng sẽ có.

+ Mới chỉ có cách build trên 2 Platform Android, Window, còn Mac + IOS, WP8 thì mình ko có máy MAC + Win8 nên chịu, các bạn mò vào proj.ios_mac, proj.wp8-xaml xem có soi được gì ko.

Mình dừng bài ở đây thôi, dài quá rồi.

Hẹn gặp lại các bạn ở những bài sau.

Dowload Source:

+ Cocostudio Project
+ Class
+ Export Resource

À, vào thời điểm mình viết xong bài này, CocoStudio có phiên bản mới 1.5 nhé. Mọi người nghiên cứu có gì HOT

Bài 25: Hiệu ứng Parallax Scrolling