Hi, Rảnh rỗi tranh thủ viết cho xong game Space Ship này.
Bài trước chúng ta đã thiết kế sơ bộ xong phần màn chơi, song còn thiếu một số phần quan trọng trong game nên có mà chúng ta sẽ bổ sung ngay sau đây:
+ Bắn đạn khi Touch màn hình
+ Bắt sự kiện va chạm giữa đạn và thiên thạch
+ Tính điểm
+ Game Over
Đơn giản có thế thôi, chúng ta sẽ lướt nhanh!
B1: Bắn đạn khi Touch màn hình
Bạn mở file HelloWorldScene.h thêm vào dòng lệnh sau, trong public
// Hàm bắt sự kiện touch, dùng multiTouch, hoặc Touch thôi cũng được
void HelloWorld::onTouchesBegan(const std::vector<Touch*>& touches, Event *event)
Tiếp đó trong HelloWorldScene.cpp ta thiết kế hàm này như sau
void HelloWorld::onTouchesBegan(const std::vector<Touch*>& touches, Event *event)
{
SimpleAudioEngine::getInstance()->playEffect("laser_ship.wav"); // Âm thanh
Size winSize = Director::getInstance()->getWinSize();
Sprite *shipLaser = (Sprite *) _shipLasers->at(_nextShipLaser++);
if ( _nextShipLaser >=_shipLasers->size()) // Reset index laser
_nextShipLaser = 0;
// Đặt vị trí ở phía mũi tàu, và cho hiện lên shipLaser->setPosition(Point(_ship->getPosition().x + shipLaser->getContentSize().width/2, _ship->getPosition().y));
shipLaser->setVisible(true);
// set body auto laserbody = PhysicsBody::createBox(shipLaser->getContentSize()/2);
laserbody->setContactTestBitmask(0xf);
laserbody->setDynamic(true);
shipLaser->setPhysicsBody(laserbody);
shipLaser->stopAllActions();
shipLaser->runAction(Sequence::create(
MoveBy::create(0.5,Point(winSize.width, 0)),
CallFuncN::create(this, callfuncN_selector(HelloWorld::setInvisible)),
NULL
));
}
B2: Bắt sự kiện va chạm
Thêm hàm sau vào file HelloWorldScene.h
bool onContactBegin(const PhysicsContact &contact);
Và xây dựng nó trong file HelloWorldScene.cpp như sau
bool HelloWorld::onContactBegin(const PhysicsContact& contact)
{
auto laser = (Sprite*)contact.getShapeA()->getBody()->getNode();
int Tag1 = -1;
if(laser) {
Tag1 = laser->getTag();
auto asteroid = (Sprite*)contact.getShapeB()->getBody()->getNode();
int Tag2 = -1;
if(asteroid) Tag2 = asteroid->getTag();
if((Tag1==KLASER&Tag2==KASTEROID)||(Tag2==KLASER&Tag1==KASTEROID))
{
SimpleAudioEngine::sharedEngine()->playEffect("explosion_large.wav");
_world->removeBody(laser->getPhysicsBody());
laser->setVisible(false);
_world->removeBody(asteroid->getPhysicsBody());
asteroid->setVisible(false);
}
if((Tag1==KSHIP&Tag2==KASTEROID)||(Tag2==KSHIP&Tag1==KASTEROID))
{
_lives--;
}
}
return true;
}
Và không được quên đoạn code Listener ở init()
auto contactListener = EventListenerPhysicsContact::create();
contactListener->onContactBegin = CC_CALLBACK_1(HelloWorld::onContactBegin, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);
OK, giờ là tới phần Tính điểm và GameOver
B3: Tính điểm và GameOver
Trong hàm update() bạn thêm vào 1 đoạn sau đây
if (_lives <= 0) { // Kiểm tra không còn mạng nào thì game Over
_ship->stopAllActions();
_ship->setVisible(false);
_world->removeBody(_ship->getPhysicsBody());
this->endScene(KENDREASONLOSE); // Game Over
}
void HelloWorld::endScene( EndReason endReason ) {
if (_gameOver) // trạng thái game
return;
_gameOver = true;
Size winSize = Director::getInstance()->getWinSize();
char message[10] = "";
if ( endReason == KENDREASONLOSE)
strcpy(message,"You Lose");
LabelBMFont * label ;
label = LabelBMFont::create(message, "Arial.fnt");
label->setScale(0.1);
label->setPosition(Point(winSize.width/2 , winSize.height*0.6));
this->addChild(label);
LabelBMFont * restartLabel;
strcpy(message,"Restart");
restartLabel = LabelBMFont::create(message, "Arial.fnt");
MenuItemLabel *restartItem = MenuItemLabel::create(restartLabel,CC_CALLBACK_1(HelloWorld::resetGame,this));
restartItem->setScale(0.1);
restartItem->setPosition( Point(winSize.width/2, winSize.height*0.4));
Menu *menu = Menu::create(restartItem, NULL);
menu->setPosition(Point::ZERO);
this->addChild(menu);
restartItem->runAction(ScaleTo::create(0.5, 1.0));
label ->runAction(ScaleTo::create(0.5, 1.0));
this->unscheduleUpdate(); // dừng update Scene
}
Bổ sung hàm endScene() và resetGame() vào trong lớp HelloWorld, và hàm resetGame như sau
void HelloWorld::resetGame(Ref* pSender) {
auto scene = HelloWorld::createScene();
Director::getInstance()->replaceScene(TransitionZoomFlipY::create(0.5, scene));
Size winSize = Director::getInstance()->getVisibleSize();
}
Bạn thêm 1 thuộc tính int score, LabelBMFont * _scoreDisplay;vào lớp HelloWorldScene, và khi khởi tạo thêm đoạn code này
_scoreDisplay = LabelBMFont::create("Score: 0", "Arial.fnt",
visibaleSize.width * 0.3f);
_scoreDisplay->setAnchorPoint(Point(1, 0.5));
_scoreDisplay->setPosition(
Point(visibaleSize.width * 0.8f, visibaleSize.height * 0.94f));
this->addChild(_scoreDisplay);
Trong hàm kiểm tra va chạm chúng ta sẽ tính điểm bằng đoạn code nhỏ như thế này
score+=10;
char szValue[100] = { 0 }; // Lấy ra điểm qua mảng đệm char
sprintf(szValue, "Score: %i", score); // Chuyển sang chuỗi => chuỗi
_scoreDisplay->setString(szValue); // Hiện điểm lên
OK, Build thử xem kết quả thế nào nhé, cũng không tệ với 1 game "tự tui".
Và sau đây mình làm thêm 1 bước Bonus nữa là
Bonus: Điều khiển Ship bằng Accelerometer - gia tốc kế
Trước hết bạn copy 2 file VisibleRect.h, .cpp trong bài cpp-tests vào Class của chúng ta. sau đó trong phần init() thêm đoạn code này vào
#define FIX_POS(_pos, _min, _max) \
if (_pos < _min) \
_pos = _min; \
else if (_pos > _max) \
_pos = _max;
auto listener = EventListenerAcceleration::create([=](Acceleration* acc, Event* event){
auto shipSize = _ship->getContentSize();
auto ptNow = _ship->getPosition();
log("acc: x = %lf, y = %lf", acc->x, acc->y);
ptNow.x += acc->x * 9.81f;
ptNow.y += acc->y * 9.81f;
FIX_POS(ptNow.x, (VisibleRect::left().x+shipSize.width / 2.0), (VisibleRect::right().x - shipSize.width / 2.0));
FIX_POS(ptNow.y, (VisibleRect::bottom().y+shipSize.height / 2.0), (VisibleRect::top().y - shipSize.height / 2.0));
_ship->setPosition(ptNow);
});
auto dispathcher = Director::getInstance()->getEventDispatcher();
dispathcher->addEventListenerWithSceneGraphPriority(listener, this);
Kết thúc bài này, chúng ta cùng nghiên cứu 1 số vấn đề sau
+ Bắn đạn = Touche, duyệt vector
+ Va chạm
+ Tính điểm, game Over
+ Di chuyển Ship bằng gia tốc kế
Download Code
Mình dừng bài học ở đây nhé
Bài 31: Làm game gì bây giờ?
{ 0 nhận xét... read them below or add one }
Đăng nhận xét