読者です 読者をやめる 読者になる 読者になる

Flap◯ Birdを作ってみる。その2

鳥のアニメーションを表示する

予め lv1_bird_normal.png, lv1_bird_flyup.png, lv1_bird_flydown.png を用意します。
shoeboxを使って、画像を結合します。

別レイヤーを用意してそこに実装します

    auto birdSprite = Sprite::create();
    birdSprite->setPosition(0,0); // 中央に表示したい。相対参照なので(0,0)
    auto birdCache = SpriteFrameCache::getInstance();
    birdCache->addSpriteFramesWithFile("images/birds.plist");
    vector<string> birds = {
        "lv1_bird_normal.png",
        "lv1_bird_flyup.png",
        "lv1_bird_flydown.png",
    };
    
    auto birdAnimation = Animation::create();
    for(string str : birds){
        SpriteFrame *sprite = birdCache->getSpriteFrameByName(str);
        birdAnimation->addSpriteFrame(sprite);
    }
    birdAnimation->setDelayPerUnit(0.25f); // 遅延
    birdAnimation->setRestoreOriginalFrame(true); // 画像を元に戻す
    auto birdAnimate = Animate::create(birdAnimation);
    birdSprite->runAction(RepeatForever::create(birdAnimate)); // 繰り返す
鳥に重力を入れる

createScene関数のcreateWithPhysicsから下3行で重力の方向を入れてます。
また、body->setMassで重さ入れてます

#include "GameLayer.h"
using namespace std;

USING_NS_CC;

static const Vec2 GRAVITY = Vec2(0, -50);  // 重力
static const int BIRD_ROTATION_ANGLE = -10; // 鳥の角度
static const float BIRD_MASS = 5.0f;        //

Scene* GameLayer::createScene(){
    auto scene = Scene::createWithPhysics();
    auto world = scene->getPhysicsWorld();
    world->setGravity(GRAVITY);
  
    // DEBUG mode
    scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
    
    // 'layer' is an autorelease object
    auto layer = GameLayer::create();

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

    // return the scene
    return scene;
}

bool GameLayer::init(){
    if(!Layer::init()){
        return false;
    }
    
    Vec2 origin = Director::getInstance()->getVisibleOrigin();      // 0座標

    // 鳥のアニメーションの動き
    auto birdSprite = Sprite::create();
    birdSprite->setPosition(0,0);
    auto birdCache = SpriteFrameCache::getInstance();
    birdCache->addSpriteFramesWithFile("images/birds.plist");
    vector<string> birds = {
        "lv1_bird_normal.png",
        "lv1_bird_flyup.png",
        "lv1_bird_flydown.png",
    };
    
    auto birdAnimation = Animation::create();
    for(string str : birds){
        SpriteFrame *sprite = birdCache->getSpriteFrameByName(str);
        birdAnimation->addSpriteFrame(sprite);
    }
    birdAnimation->setDelayPerUnit(0.25f); // 遅延
    birdAnimation->setRestoreOriginalFrame(true); // 画像を元に戻す
    auto birdAnimate = Animate::create(birdAnimation);
    birdSprite->runAction(RepeatForever::create(birdAnimate)); // 繰り返す
    auto material = PHYSICSBODY_MATERIAL_DEFAULT;
    material.restitution = 0.0f;
    material.density = 1.0f;
    material.friction = 1.0f;
    auto body = PhysicsBody::createBox(birdSprite->getContentSize(), material);
    body->setRotationEnable(true);
    body->setMass(BIRD_MASS);
    body->setContactTestBitmask(true);
    birdSprite->setPhysicsBody(body);
    this->addChild(birdSprite,2);
    
    return true;
}
タッチイベント

上の一番最後のthis->addChildのところから

    // タッチイベント
    auto touchEventListener = EventListenerTouchOneByOne::create();
    touchEventListener->setSwallowTouches(true); // タッチイベントの上のレイヤーに影響を与えない
    // ラムダ関数 すべての外部変数は、もし使われれば暗黙的にコピーされる
    touchEventListener->onTouchBegan = [=] (Touch* touch, Event* event){
        log("call touch event");
        birdSprite->getPhysicsBody()->applyImpulse(Vect(0, 180.0f),
                                                   Vect(0, birdSprite->getContentSize().height * (-1)));
        // 角度を設定.
        birdSprite->setRotation(BIRD_ROTATION_ANGLE);
        return true;
        // もしかしたらこちらのほうがいいかもしれない.
//        // TODO: 落ちてる時の角度を戻す
//        birdSprite->runAction(MoveTo::create(0.16f, Vec2(birdSprite->getPositionX(), birdSprite->getPositionY()+BIRD_ADD_POSITION_Y)));
//        // TODO: 一番上に行った時の制御 -> いるかな?
//        return true;
    };
    this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(touchEventListener, birdSprite);
鳥をずっと下に行かないようにする

このままだと鳥がずっと下にいくので、地面で受け止めるようにします。
setDynamicをfalseにすることで、重力の影響を受けないようにしてます。また、setContactTestBitmaskで衝突するように設定してます。

    // 画面下の動き
    auto ground = Sprite::create("lv1_background_ground.png");
    ground->setPosition(Vec2(0, (-1) * (origin.y + visibleSize.height/4)));
    ground->setScale(0.85714f, 1.0f);
    auto groundPhysicsBody = PhysicsBody::createBox(ground->getContentSize());
    // 重力の影響を受けないようにする.
    groundPhysicsBody->setDynamic(false);
    groundPhysicsBody->setContactTestBitmask(true);
    groundPhysicsBody->setTag(1);
    ground->setPhysicsBody(groundPhysicsBody);
    this->addChild(ground, 1, 1);