2013年9月27日金曜日

スプライトにタッチを実装

ヘッダー

@interface SpriteWithTouch : CCSprite <CCTouchOneByOneDelegate>

実装

- (void) onEnter {
    [super onEnter];
    [[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
}

- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
    
    CGPoint touchLocation = [touch locationInView:touch.view];
    CGPoint location = [[CCDirector sharedDirector] convertToGL:touchLocation];
    //CCSpriteの描画領域でタッチされているか判定
    if (CGRectContainsPoint(self.boundingBox, location)) {
        CCLOG(@"touch!");
        return YES;
    } else {
        return NO;
    }
}

- (void) onExit {
    [super onExit];
    [[[CCDirector sharedDirector] touchDispatcher] removeDelegate:self];
}

図形描画

矩形描画

- (void)draw {
    [super draw];
    ccDrawColor4B(255, 128, 0, 255);
    glLineWidth(5);
    ccDrawRect(ccp(0, 0), ccp(100, 100));
}

2013年9月26日木曜日

cocos2dでテクスチャアトラスを使う

スプライト

[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"sprite.plist"];
CCSprite *hoge = [[CCSprite node] initWithSpriteFrameName:@"hoge.png"];


アニメーション

CCAnimation *anime = [CCAnimation animation];
for (int cnt=1; cnt<=5; cnt++) {
    [anime addSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:@"hoge%02d.png", cnt]]];
}
anime.delayPerUnit = 0.1;
anime.loops = 1;
//キャッシュに追加
[[CCAnimationCache sharedAnimationCache] addAnimation:anime name:@"anime01"];

注意点

画像の最大サイズは各端末毎に異なる
端末最大サイズ
iPhone4, iPad2, iPodtouch 4th2048 * 2048
iPhone5, iPhone4S, iPad3, iPodtouch 5th4096 * 4096
iPhone3Gなど古い端末1024 * 1024

2013年9月25日水曜日

通知

送信
//通知送信
NSNotification *notification = [NSNotification notificationWithName:@"hoge" object:self];
[[NSNotificationCenter defaultCenter] postNotification:notification];


受信
//通知受信
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(test) name:@"hoge" object:nil];

//呼ばれる関数
- (void)test {
    NSLog(@"notification!");
}

削除
- (void) dealloc {
    //通知受信の削除
    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
    [nc removeObserver:self name:@hoge" object:nil];
    [super dealloc];
}

2013年9月24日火曜日

プログレスバー

//initの処理
CCProgressTimer *timer = [CCProgressTimer progressWithSprite:[CCSprite spriteWithFile:@"test.png"]];
timer.type = kCCProgressTimerTypeRadial;
timer.percentage = 100;
timer.position = ccp(winSize.width/2, winSize.height/2);
[self addChild:timer z:2 tag:123];
[self scheduleUpdate];


- (void) update:(ccTime)delta {
    CCProgressTimer *timer = (CCProgressTimer*)[self getChildByTag:123];
    timer.percentage -= delta * 150;
    if (timer.percentage <= 0) {
        timer.percentage = 100;
    }
}

2013年9月19日木曜日

画像、アニメのキャッシュ削除

- (void) dealloc {
    //画像、アニメのキャッシュ削除
    [CCAnimationCache purgeSharedAnimationCache];
    [[CCTextureCache sharedTextureCache] removeAllTextures];
        
    [super dealloc];
}

アニメーションの逆再生、順次実行

スプライトアニメーションは逆再生(リバース)したり、順番に実行することができる

 CCAnimation* anime = [[CCAnimationCache sharedAnimationCache] animationByName:@"anime"];
 id action = [CCAnimate actionWithAnimation:anime];
 //リバース
 id back = [action reverse];
 //順番に実行
 CCSequence* seq = [CCSequence actions:action, back, nil];
 [self runAction:seq];

2013年9月17日火曜日

スプライトのテクニック


CCSpriteBatchNode


  • 同じテクスチャを使って多くのスプライトを描画する場合、効率的である
  • 追加されたスプライトはすべて同じ深度(Zオーダー)になる
  • スプライトを最初に全て生成し非表示にして、必要に応じてアクティブにする(オブジェクトプーリング)



テクスチャアトラス


  • テクスチャアトラスとは複数の画像を一つにまとめた大きな画像
  • 幅と高さは2の累乗(256,512)にする
  • .plistファイルにどの部分をスプライトとして使うのか定義する
  • スプライトアニメーションにテクスチャアトラスを使用すると効率的
  • カテゴリを使いアニメーションのヘルパーを作ると楽になる
  • テクスチャアトラスはZwoptexやTexturePackerProなどのツールを使用するとよい


ゲームの実装方法



  • 画面遷移にトランジションを使うとonEnterなどのタイミングが変わるので注意
  • onEnterなどでsuperのメソッドを呼び出さないと入力に反応しなくなる
  • onExitなどでsuperのメソッドを呼び出さないとメモリが解放されなくなる
  • 重い画面から重い画面に遷移する場合、その間に1つ軽い画面を挟むと良い
  • initメソッドではCCDireoctorのreplaceSceneを呼び出さないように注意
  • ccp○○○○メソッドでCGPointの差分などの計算ができる
  • CGRectContainsPoint(スプライトのバウンディングボックス,タッチ座標)で当たり判定できる



レイヤーを分ける


CCScene

initで複数のレイヤーをaddChildする
自分自身を変数に持ちsharedメソッドでそれを渡す半シングルトンとする
(deallocで自分自身を保持する変数をnilにする)
子レイヤーにはゲッターメソッドかreadonlyのプロパティを使用しアクセスする

CCLayer

registerWithTouchDispatcherのpriorityでタッチ入力の優先度をつける
(小さい値が優先となる)
ccTouchBeganでNOを返せば次の優先度のレイヤが入力を受ける

レベルの切り替えはシーンを変える、レイヤーを変えるのどちらかで行う
背景色はCCColorLayerクラスを使用する
CCColorLayer* colorLayer = [CCColorLayer layerWithColor:ccc4(255, 0, 255, 255)];
[self addChild:colorLayer z:0];



スプライトの実装


ゲームのキャラクターなどはサブクラス化よりコンポジションの方がよい

オートリリースイニシャライザで初期化
+(id) spiderWithParentNode:(CCNode*)parentNode
{
    return [[[self alloc] initWithParentNode:parentNode] autorelease];
}

CCSchedulerクラスを使用しupdateメソッドをスケジュールする
// initなどで更新をスケジュール
[[[CCDirector sharedDirector] scheduler] scheduleUpdateForTarget:self priority:0 paused:NO]
//[[CCScheduler sharedScheduler] scheduleUpdateForTarget:self priority:0 paused:NO];

//deallocで解除
[[[CCDirector sharedDirector] scheduler] unscheduleUpdateForTarget:self];
//[[CCScheduler sharedScheduler] unscheduleUpdateForTarget:self];

CCStandardTouchDelegateまたはCCTargetedTouchDelegateプロトコルを実装すればタッチを受け取れる
// initなどでこのクラスをターゲットタッチイベントのレシーバーとして追加する
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:-1 swallowsTouches:YES];
//deallocで解除
[[CCTouchDispatcher sharedDispatcher] removeDelegate:self];



CCNodeの派生クラス


CCProgressTimerでプログレスバーを追加できる
CCParallaxNodeでパララックス処理(多重スクロール)を表現できる
CCRibbonでドラッグの軌跡に画像を描く処理ができる
CCMotionStreakはCCRibbonの描画したものが数秒でフェードアウトするもの

2013年9月13日金曜日

加速度センサー入力

加速度センサーによるスプライトの移動
-(id) init
{
 if( (self=[super init]) ) {
  [self setAccelerometerEnabled:YES];
 }
}

- (void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
    CGPoint pos = sprite.position;
    pos.x += acceleration.x * 10;
    pos.y += acceleration.y * 10;
    sprite.position = pos;
}
だが、これでは反応が鈍い

スムーズに動かすためには下記に修正
-(id) init
{
    if( (self=[super init]) ) {
        [self setAccelerometerEnabled:YES];
        //updateをフレーム毎に呼び出す
        [self scheduleUpdate];
    }
}

- (void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
    //速度の制御
    float deceleration = 0.4f; //減速の制御
    float sensitivity = 6.0f; //感度
    
    //速度調整
    moveSpeed.x = moveSpeed.x * deceleration + acceleration.x * sensitivity;
    moveSpeed.y = moveSpeed.y * deceleration + acceleration.y * sensitivity;
}

-(void)update:(ccTime)delta {
    
    CGPoint pos = sprite.position;
    pos.x += moveSpeed.x;
    pos.y += moveSpeed.y;
    sprite.position = pos;
}

アクション

どのノードでも利用可能。

CCMoveTo* move = [CCMoveTo actionWithDuration:3 postion:CGPointMake(100,200)];//(100,200)へ3秒以内に移動
[myNode runAction:move];
アクションにはインスタンスアクションとインターバルアクションの2種類がある。インスタンスアクションは、基本的にはvisibleやflipXのようなノードプロパティを設定するのと同じ。インターバルアクションは上の移動のように一定時間にわたって実行される。
アクションは終わると自動的にノードから削除され、メモリから解放される。

アクションを繰り返す

CCRotateBy* rotateBy = [CCRotateBy actionWithDuration:2 angle:360];
CCRepeateForever* repeat = [CCRepeatForever actionWithAction:rotateBy];
[myNode runAction:repeat];//永遠に回転

イーズアクション

一定の動きではなく徐々に変化させたりするアクション。

CCMoveTo* move = [CCMoveTo actionWithDuration:3 position:CGPointMake(100,200)];
CCEaseInOut* ease = [CCEaseInOut actionWithAction:move rate:4];//ゆっくりと加速したあと減速する
[myNode runAction:ease];

CCActionEase

  • CCEaseIn, CCEaseOut, CCEaseInOut
  • CCEaseBounceIn, CCEaseBounceOut, CCEaseBounceInOut
  • CCEaseElasticIn, CCEaseElasticOut, CCEaseElasticInOut
  • CCEaseExponentialIn, CCEaseExponentialOut, CCEaseExponentialInOut
  • CCEaseIn, CCEaseOut, CCEaseInOut
  • CCEaseSineIn, CCEaseSineOut, CCEaseSineInOut



アクションシーケンス

通常、複数のアクションを登録するとすべてのアクションがそれぞれのタスクを同時に実行する。アクションを順番に実行するにはシーケンスにする。
    CCTintTo *tint1 = [CCTintTo actionWithDuration:3 red:255 green:0 blue:0];
    CCTintTo *tint2 = [CCTintTo actionWithDuration:3 red:0 green:0 blue:255];
    CCTintTo *tint3 = [CCTintTo actionWithDuration:3 red:0 green:255 blue:0];
    CCSequence *sequence = [CCSequence actions:tint1, tint2, tint3, nil];
    [label runAction:sequence];
    
    //RepeatForeverを使う場合
    CCSequence *sequence2 = [CCSequence actions:tint1, tint2, tint3, nil];
    CCRepeatForever *repeat = [CCRepeatForever actionWithAction:sequence2];
    [label runAction:repeat];

インスタントアクション

プロパティでも変更可能な効果だがシーケンスに組み込める。
CCCallFuncアクション・・・シーケンス終了などのタイミングで通知メッセージを送信できる。
    CCTintTo *tint1 = [CCTintTo actionWithDuration:3 red:255 green:0 blue:0];
    CCTintTo *tint2 = [CCTintTo actionWithDuration:3 red:0 green:0 blue:255];
    CCTintTo *tint3 = [CCTintTo actionWithDuration:3 red:0 green:255 blue:0];
    
    CCCallFunc *func = [CCCallFunc actionWithTarget:self selector:@selector(onCallFunc)];
    CCCallFuncN *funcN = [CCCallFuncN actionWithTarget:self selector:@selector(onCallFuncN)];
    CCCallFuncND *funcND = [CCCallFuncND actionWithTarget:self selector:@selector(onCallFuncND:data:) data:background];
    
    CCSequence *sequence = [CCSequence actions:tint1, func, tint2, funcN tint3, funcND, nil];
    [label runAction:sequence];

メニュー

CCMenuクラス
CCMenuItemノードを追加してメニューを設定する

CCSprite

//ファイルからCCSprite作成
CCSprite *sprite = [CCSprite spriteWithFile:@"Default.png"];]
[self addChild:sprite];
※iOSデバイス上ではファイル名の大文字と小文字が区別されるので注意

アンカーポイント
テクスチャのオフセット。デフォルトは0.5

テクスチャのサイズ
4,8,16,32,64,128,256,512,1024ピクセルのいずれか
第三世代では2048が加わる。テクスチャは正方形でなくてもいい。

シーンとレイヤ


CCSceneとCCLayerはCCNodeと同様ビジュアル表現を持たない抽象概念
シーングラフの出発点はCCScene
CCLayerはノードのグループ化、入力の処理など

CCScene

[[CCDirector sharedDirector] runWithScene:[HelloWorld scene]]; //最初のシーン登録
[[CCDirector sharedDirector] replaceScene:[HelloWorld scene]]; //置き換え
新しいシーンを読み込むときは古いシーンが破棄される前なので一時的にメモリが増大する
シーンの作成と破棄でログを吐くといい。切替時にdeallocのログメッセージが送信されていなかったらシーン全体がメモリリークしていることになる。
ノードのメモリ管理はcocos2dに任せないと危険。

シーンのプッシュとポップ

pushSceneとpopScene。古いシーンを破棄せずに新しいシーンを実行
複数の場所で使われる共通のシーン、ボリュームなどの設定画面の呼び出しなどに使う。
素早く変更できる反面メモリを食う。
スタックに積むので気をつけないと積み過ぎになったり取り過ぎになったりしてしまう。

[[CCDirector sharedDirector] pushScene:[Stettings scene]]; //プッシュ
[[CCDirector sharedDirector] popScene]; //ポップ

CCTransitionScene

見た目は良いが切り替えに時間が掛かる。1秒以内か使わないのが妥当。

//3秒で赤にフェード
CCTransitionFade *tran = [CCTransitionFate transitionWithDuration:3 scene:[HelloWorld scene] withColor:ccRED]; 
[[CCDirector sharedDirector] replaceScene:tran];
replaceSceneやpushSceneで使えるがpopSceneでは別のテクニックが必要

Transitionの種類
  • CCTransitionFade
  • CCTransitionFlipAngular
  • CCTransitionShrinkGrow
  • CCTransitionMoveInB
  • CCTransitionMoveInT
  • CCTransitionMoveInL
  • CCTransitionMoveInR
  • CCTransitionFadeTR
  • CCTransitionFadeUp
  • CCTransitionFlipX
  • CCTransitionFlipY
  • CCTransitionPageTurn
  • CCTransitionCrossFade



CCLayer

シーンによっては複数のCCLayerが必要になることがある。その場合はシーンの作成時にレイヤを追加する必要がある。
たとえば静的なフレームの下にスクロールする背景がある場合など。背景レイヤを動かすとそのレイヤにある要素は追従するので簡単に移動できる。またレイヤのZオーダーに応じて同じレイヤのオブジェクトが前面、背面に移動可能
レイヤはグループ化の概念。まとめて移動、回転、拡縮。
いくつ作ってもいいが、タッチ入力や加速度センサーを受け取るレイヤを作り過ぎないようにする。必要に応じて転送するなど

タッチイベントの受け取り

タッチの開始、移動、終了、中止が報告されるが、中止はほとんど無いので無視するか終了に転送する。
タッチイベントはCocoaTouchAPIによって受け取られるため、OpenGL座標に変換する必要がある

self.isTouchEnabled = YES;
-(CGPoint) locationFromTouch:(UITouch *t)touch{
  CGPoint touchLocation = [touch locationInView: [touch view]];
  return [[CCDirector sharedDirector] convertToGL:touchLocation];
}
※マルチタッチに対応するには[glView setMultipleTouchEnabled:YES]する必要がある
・ターゲットタッチハンドラは一連のタッチを別々のイベントに分割する。
特定のタッチをイベントキューから削除することで他のレイヤに転送しないようにできる。
ターゲットハンドラを有効にするには
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:INT_MIN+1 swallowsTouches:YES];
タッチ入力メソッドはtouchesではなくtouch

加速度センサー

self.isAccelerometerEnabled = YES;

- (void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
    //3方向の加速度
    CCLOG(@"acceleration x:%f / y:%f / z:%f",acceleration.x,acceleration.y,acceleration.z);
}

CCNodeクラス


CCNodeはすべてのノードの親クラス

ノードを操作する

CCNode* childNode = [CCNode node]; //新しいノード作成
[myNode addChild:childNode z:0 tag:123]; //子を追加。zの小さいものから順に描画。zが同じ場合は追加順
CCNode* retrievedNode = [myNode getChildByTag:123]; //子を取得
[myNode removeChildByTag:123 cleanup:YES]; //タグで子を削除。cleanupは実行中のアクションも全て停止
[myNode removeChild:retrievedNode]; //ノードポインタで削除
[myNode removeAllChildrenWithCleanup:YES]; //すべての子ノード削除
[myNode removeFromParentAndCleanup:YES]; //親ノード(myNode)を削除
同じタグをつけるとその中から最初のノードしか取り出せない
ノードとアクションのタグは競合しない

アクションを操作する

ノードではアクションも実行できる。移動、回転、拡大縮小など

CCAction* action = [CCBlink actionWithDuration:10 blinks:20]; //アクションを宣言する
action.tag = 234;
[myNOde runAction:action]; //ノードを点滅させるアクションを実行
CCAction* retrievedAction = [myNode getActionByTag:234]; //タグを使ってアクションを取得
[myNode stopActionByTag:234]; //タグを使って停止
[myNode stopAction:action]; //ポインタで停止
[myNode stopAllActions]; //ノードのすべてのアクションを停止

スケジュールされたメッセージ

[self scheduleUpdate]でupdateを設定すると
-(void) update:(ccTime)delta
が各フレームで呼び出される。

別のメソッド、あるいは別の間隔で呼び出したい場合は
[self schedule:@selector(updateTenTimesPerSecond:) interval:0.1f];とすると
-(void) updateTenTimesPerSecond:(ccTime)delta
が0.1秒おきに呼び出される

ノードのすべてのセレクタを停止させるには
[self unscheduleAllSelectors];

特定のメッセージを停止するには
[self unschedule:@selector(updateTenTimesPerSecond:)];//セレクタを指定した場合
[self unscheduleUpdate];//scheduleUpdateで呼び出した場合

セレクタ内で停止させるには
[self unschedule:_cmd];//_cmdは現在のメソッドを表す省略表記

ノードごとにupdateに優先順位を付けられる
[self scheduleUpdateWithPriority:-1];//デフォルトは0なので-1が先に呼び出される


シーングラフ


現在アクティブなすべてのcocos2dノードからなる階層
シーンそのものを除くすべてのノードが親ノードを1つだけ持ち、子ノードをいくつでも持つことができる
配下のノードは移動、回転、拡大縮小の影響を受ける

Director

Directorには以下の用途がある
  • シーンへのアクセスと変更
  • cocos2dの設定情報へのアクセス
  • ビュー(OpenGL,UIView,UIWindow)へのアクセス
  • ゲームの一時停止、再開、終了
  • UIKitおよびOpenGL座標の変換


4種類のDirectorから選択可能(細部が異なる)
最もよく使われるのはCCDirectorDisplayLink(iOS3.1以降のバージョンでしか利用できない)
CocoaTouchと並行する場合はCCDirectorFastThreaded

シングルトン

cocos2dは以下のようにシングルトンがよく使われている

CCActionManager* sharedManager = [CCActionManager sharedManager];
CCDirector* sharedDirector = [CCDirector sharedDirector];
CCSpriteFrameCache* sharedCache = [CCSpriteFrameCache sharedSpriteFrameCache];
CCTextureCache* sharedTexCache = [CCTextureCache sharedTextureCache];
CCTouchDispatcher* sharedDispatcher = [CCTouchDispatcher sharedDispatcher];
CDAudioManager* sharedManager = [CDAudioManager sharedManager];
SimpleAudioEngine* sharedEngine = [SimpleAudioEngine sharedEngine];



シングルトン実装例

static MyManager *sharedManager = nil;

+ (MyManager*) sharedManager {
    if (sharedManager == nil) {
        sharedManager = [[MyManager alloc] init];
    }
    return sharedManager;
}

selectorの記述

- (void) example:(ccTime)delta sender:(id)sender flag:(bool)aBool


上記メソッドに対応する@selectorは以下

@selector(example:sender:flag:)

シーン階層

ノードを階層的に構築できる

-(id) init
{
    if ((self=[super init]) ) {
        CCSprite *hoge = [CCSprite spriteWithFile:@"hoge.png"];
        hoge.tag = 13;
        [self addChild:hoge];
        //hogeの子要素
        CCSprite *sub = [CCSprite spriteWithFile:@"sub.png"];
        [hoge addChild:sub];
    }
}

- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
    CCSprite *hoge = (CCSprite*)[self getChildByTag:13];
    //hogeとsubの両方縮小される
    hoge.scale = 0.5;
    
    return YES;
}

NSAssert

条件が真でないときにログを出力し、実行を止める
Releaseビルドで削除されるのでデバッグとして使用できる

NSAssert(0 > val, @"想定外の値です");

ログ

DebugビルドのみコンパイルされるCCLOGを使う

    //NSLog(@"%s", __func__);
    CCLOG(@"%s", __func__);

オートリリースを使用する

CCNodeの派生クラスのオブジェクトはオートリリースで使用できる


以下のように記述すればインスタンス変数が不要となる

- (void) init {
 CCSprite *hoge = [CCSprite spriteWithFile:@"hoge.png"];
 hoge.position =  ccp(100, 00);
 //検索用のタグ(数字)
 hoge.tag = 13;
 [self addChild:hoge];
}

- (void) update:(ccTime)delta {
 //タグをキーに取得
    CCSprite *hoge = (CCSprite*)[self getChildByTag:13];
}


Objective-Cの記述

以下の記述は同じ

if ((self=[super init]) ) {
    //
}


self = [super init];
if (self != nil) {
    //
}

2013年9月12日木曜日

アクション後に次の処理を実行

移動後に画像切り替えの例


        CCMoveBy* moveBy = [CCMoveBy actionWithDuration:1.0 position:ccp(100, 100)];
        CCCallBlock* block = [CCCallBlock actionWithBlock:^{
            //アクション後に画像切り替え
            CCTexture2D *texture = [[CCTextureCache sharedTextureCache] addImage:@"image.png"];
            [sprite setTexture:texture];
            [sprite setTextureRect:CGRectMake(0, 0, texture.contentSize.width, texture.contentSize.height)];
        }];
        CCSequence* seq = [CCSequence actions:moveBy, block, nil];
        [sprite runAction:seq];

2013年9月11日水曜日

タッチメソッド

-(BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
 
-(void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event

-(void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event

スプライトの当たり判定

タップ時の判定


- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
    
    //座標を取得
    CGPoint location =[touch locationInView:[touch view]];
    //OpenGL系の座標に変換
    location =[[CCDirector sharedDirector] convertToGL:location];
    //スプライトの当たり判定
    if (CGRectContainsPoint(hito.boundingBox, location)) {
        NSlog(@"hit!");
    }
}

アニメーション

CCAnimationを使う



        CCAnimation *danceAnime = [CCAnimation animation];
        [danceAnime addSpriteFrameWithFilename:@"dance01.png"];
        [danceAnime addSpriteFrameWithFilename:@"dance02.png"];

        //画像1枚毎の表示時間
        danceAnime.delayPerUnit = 0.1;
        //ループ回数(-1で無限)
        danceAnime.loops = 1;
        
        [dancerSprite runAction:[CCAnimate actionWithAnimation:danceAnime]];



iOSデバイス解像度

デバイス名称 画面サイズ 解像度 (px) 解像度 (dpi)
iPhone3G / 3GS 3.5 inch 320 * 480 163 dpi
iPhone4 / 4S 3.5 inch 640 * 960 326 dpi
iPhone5 4 inch 640 * 1136 326 dpi
iPad / iPad2 9.7 inch 768 * 1024 132 dpi
iPad 第3世代 9.7 inch 1,536 * 2048 264 dpi
iPad mini 7.9 inch 768 * 1024 163 dpi

2013年9月10日火曜日

enum

typedef enum status : NSUInteger {
    START,
    END
} status;

スプライトの画像切り替え

setTextureを使う



CCTexture2D *texture = [[CCTextureCache sharedTextureCache] addImage:@"hoge.png"];
[hoge setTexture:texture];
//新しい画像にサイズを合わせる
[hoge setTextureRect:CGRectMake(0, 0, texture.contentSize.width, texture.contentSize.height)];

※hogeはCCSprite


テクスチャアトラスを使用している場合

[hoge setDisplayFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"hoge.png"]];

2013年9月9日月曜日

iOSシミュレーターの解像度

iPhoneシミュレーターのデフォルト画面サイズは320×460なので、iPhone4や5に解像度を合わせたい場合は変更する


メニュー→ハードウェア→デバイス

superクラスのメソッド

init,onEnter,deallocなどのメソッドでは必ずsuperクラスのメソッドを呼ぶ
- (void) dealloc
{
 [super dealloc];
}

シェイク

accelerometerEnabled設定


[self setAccelerometerEnabled:YES];


accelerometerメソッド追加


- (void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
    if (abs(acceleration.x-oldX) > 0.7 || abs(acceleration.y - oldY) > 0.7) {
        NSLog(@"shake!!!");
        
    }
    oldX = acceleration.x;
    oldY = acceleration.y;
}
※oldX,oldYはインスタンス変数
だが、このやり方では一回のシェイクで何度もログが表示される


accelerometerEnabled編集


- (void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
    float THRSHOLD = 2.0;
    if (acceleration.x > THRSHOLD || acceleration.x < -THRSHOLD || acceleration.y > THRSHOLD || acceleration.y < -THRSHOLD || acceleration.z > THRSHOLD || acceleration.z < -THRSHOLD ) {
        if (!shakedOnce) {
            shakedOnce = YES;
            NSLog(@"shake!!!");
        } else {
            shakedOnce = NO;
        }
    }
}

※shakedOnceはインスタンス変数
こうすれば何度も呼ばれることは少なくなる


2013年9月6日金曜日

サウンド

インポート


#import "SimpleAudioEngine.h"


preload


[[SimpleAudioEngine sharedEngine] preloadBackgroundMusic:@"BGM.mp3"];
[[SimpleAudioEngine sharedEngine] preloadEffect:@"soundEffect.mp3"];


SE


[[SimpleAudioEngine sharedEngine] playEffect:@"soundEffect.mp3"];
[[SimpleAudioEngine sharedEngine] playEffect:@"soundEffect.mp3" pitch:1.0f pan:0.0f gain:1.0f];


BGM


[[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"BGM.mp3"]; 
[[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"BGM.mp3" loop:YES];

//停止、一時停止、再開
[[SimpleAudioEngine sharedEngine] stopBackgroundMusic];
[[SimpleAudioEngine sharedEngine] pauseBackgroundMusic];
[[SimpleAudioEngine sharedEngine] resumeBackgroundMusic];

//先頭へ戻す
[[SimpleAudioEngine sharedEngine] rewindBackgroundMusic];

//音量
[[SimpleAudioEngine sharedEngine] setBackgroundMusicVolume:1];

備考

ロードできる曲数は32曲まで それを超える場合はunloadしてから追加する

画面遷移

画面遷移


[[CCDirector sharedDirector] replaceScene:[HogeLayer scene]];


トランジションを使って遷移


[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:1.0 scene:[HogeLayer scene] ]];


画面回転対応

Info.plist


Supported interface orientationsにサポートする向きを入れる
プロジェクトを選択→TARGETS→Summary→Supported interface orientations
※item0が初期表示


AppDelegate


iOS4 / 5
shouldAutorotateToInterfaceOrientationを修正
※全部の向きOKの場合は return YES


iOS6
supportedInterfaceOrientationsを修正
※全部の向きOKの場合は return UIInterfaceOrientationMaskAll

2013年9月5日木曜日

新規Layerの追加

プロジェクトにCCNode classを追加


CCLayerを継承する


ヘッダーファイル


クラスメソッドsceneを追加

 
#import "cocos2d.h"

@interface TitleLayer : CCLayer {
    
}

+ (CCScene *) scene;

@end
  • 「 #import <Foundation/Foundation.h> 」は消す
(これがあるとdeallocが呼ばれない等の不具合あり)




実装ファイル


クラスメソッドsceneを実装

+ (CCScene *) scene {
    
    CCScene *scene = [CCScene node];
    TitleLayer *layer = [TitleLayer node];
    [scene addChild:layer];
    
    return scene;
}



画面左下の性能表示を消す

AppDeletate.mを修正する


 [director_ setDisplayStats:NO];

iOSアプリ実機動作

iOSアプリを実機動作させる


前提として「iOS Developer Program」の登録必須


Xcodeで実機動作可能になるまで


以下のサイト参照

流れ
  1. 証明書作成
  2. デバイス登録
  3. App ID作成
  4. Provisioning Profileの作成
  5. Xcodeの設定
備考
  • App IDを開発などで使い回す場合はWildcard App IDが便利
  • ProjectのBundle IdentifierとApp IDを合わせる

iOS Developer Program 登録

iOS Developer Program


iOSアプリを実記で動作確認するには登録必須


登録


以下のサイトを参照


流れ
  1. iOS Dev Center のサイトでApple ID(英語)を作成
  2. 同じサイトでiOS Developer Programを申し込み
  3. Apple Storeに飛ぶのでそこで注文(日本語)、支払いはカード or 銀行振込
  4. Activation Codeがメールで送られてくるのでそこのリンクをクリック
  • Activationでエラーが出る場合はDev Center の「contact us」から問い合わせ

iOS開発環境構築

Apple IDの作成


英語で情報入力したIDを作成する
  • 日本語で情報が入力されている場合、色々と不都合が起こるため


Xcodeのダウンロード


App Storeよりインストール

  • 新規のApple IDだとクレジットカード情報入力を求められるが、既に無料アプリなどを落としたことのあるIDを使用すれば回避できる



2013年9月4日水曜日

タッチされた場所にスプライトを移動する


ccTouchBeganメソッド編集

    CGPoint location = [self convertTouchToNodeSpace:touch];
    [hoge stopAllActions];
    id move = [CCMoveTo actionWithDuration:0.5f position:location];
    [hoge runAction:move];

このコードは以下の処理を実施している

  1. touchオブジェクトから、タッチされた座標を取得
  2. hogeが実行しているすべてのアクションをストップ
  3. タッチした場所へ0.5秒かけて移動するアクションmoveを作成
  4. アクションmoveを、スプライトhogeに実行させる

タッチを有効にする


registerWithTouchDispatcherメソッド追加

- (void) registerWithTouchDispatcher {
    [[[CCDirector sharedDirector] touchDispatcher]
      addTargetedDelegate:self priority:0 swallowsTouches:YES];
}

ccTouchBeganメソッド追加

- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
    return YES;
}



touchEnabled設定

        self.touchEnabled = YES;


スプライト表示

画像の追加


Xcodeにドラッグ&ドロップで画像を追加する

インスタンス変数の追加

    CCSprite *hoge;

スプライト表示

    hoge = [[CCSprite alloc] initWithFile:@"hoge.png"];
    [self addChild:hoge];