2014年7月18日金曜日

cocos2d v3.1非互換:CCCallFunc系メソッド置き換えでの留意事項

<留意事項>

  • CCCallFunc系クラス名を単純にCCActionCallFuncに置き換える事でコンパイルエラーは消すことが出来ますが実行時にSender値がNullのためアプリが異常停止する場合がありました。
    (原因)
    ・cocos2d v.3.1ではARC機能が有効になっているため、funcMenuHide:メソッドを呼び出したタイミングで既にオブジェクトが開放されていてエラーになる。
    (対応)
    ・CCActionCallBlockメソッドに置き換える。
  • CCActionCallFuncメソッドは極力使わず、CCActionCallBlockへの置き換えを検討した方が良いと思います。

// Actionメニュー非表示
    [actionMenu runAction:[CCSequence actions:
                            [CCFadeOut actionWithDuration:ACTION_DURATION / 2.0],
                            [CCCallFuncN actionWithTarget:self selector:@selector(_funcMenuHide:)],
                            nil]];

// Actionメニュー非表示
    [actionMenu runAction:[CCActionSequence actions:
                            [CCActionFadeOut actionWithDuration:ACTION_DURATION / 2.0],
                            [CCActionCallBlock actionWithBlock:
                             ^{
                                 [self _funcMenuHide:_actionMenu];
                             }],
                            nil]];




ではまた〜

2014年7月17日木曜日

cocos2d v3.1非互換:CCLayer → CCNodeクラス置き換え時の留意事項

<留意事項>

  • CCLayer → CCNodeクラス置き換え時、継承元クラスを変更するだけではタッチイベントを受け取ることが出来ずハマったんで留意事項としてまとめておきます。
    1.initメソッド:コンテンツサイズ設定
    ・CCNodeクラス生成後は「self.contentSize」がwidth=0,height=0の状態。
    ・初期状態ではタッチイベントが領域外のため発生しない。
    ・コンテンツサイズ設定として画面全体を設定するとタッチイベント取得可能。
    2.initメソッド:タッチイベント有効化
    ・タッチイベントを明示的に有効にする。
    3.touchBeganメソッドは必須
    ・touchMovedイベントのみ使う場合でもtouchBeganメソッドを記述する必要あり。
    ・touchBeganメソッドを書かないとtouchMovedイベントを取得できない。

#import <Foundation/Foundation.h>
#import "cocos2d.h"


@interface TitleEffectLayer : CCNode {
}


@end

#import "TitleEffectLayer.h"

@implementation TitleEffectLayer

// ----- イニシャライザ --------------------------------------------
-(id) init
{
 if( (self = [super init]) ) {
        // コンテンツサイズ設定
        self.contentSize = [[CCDirector sharedDirector] viewSize];
        
        // タッチイベント有効化
        self.userInteractionEnabled = YES;
 }
 return self;
}

//----- アクションメソッド -----------------------------------------
- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
    CGPoint touchLocation = [touch locationInNode:self];
 
    DEBUG_NSLog(@"touchBegan[BEGIN](x=%f , y=%f , cnt=%d)",touchLocation.x,touchLocation.y,touch.tapCount);
}

- (void)touchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
    CGPoint touchLocation = [touch locationInNode:self];
 
    DEBUG_NSLog(@"touchMoved[MOVE](x=%f , y=%f , cnt=%d)",touchLocation.x,touchLocation.y,touch.tapCount);
}


@end



ではまた〜

cocos2d v3.1新機能:座標位置設定、コンテンツサイズ設定方法に待ちわびた機能が。。。(^o^)

<新機能項目>

  • 座標位置設定:positionTypeプロパティ
    ・このプロパティで画面座標位置指定方法を変更できます。
    1.CCPositionTypePoints:従来通り(デフォルト)
    2.CCPositionTypeUIPoints:UIKit座標系 - 左上原点
    3.CCPositionTypeNormalized:親ノードの最大値を1.0とした割合指定
  • コンテンツサイズ設定:contentSizeTypeプロパティ
    ・このプロパティでコンテンツサイズ指定方法を変更できます。
    1.CCSizeTypePoints:従来通り(デフォルト)
    2.CCSizeTypeUIPoints:UIKit座標系 - 左上原点
    3.CCSizeTypeNormalized:親ノードの最大値を1.0とした割合指定

    <positionTypeプロパティ設定サンプル>
        // create and initialize a Label
        CCLabelTTF *label = [CCLabelTTF labelWithString:@"Hello World"
                                               fontName:@"Marker Felt" fontSize:64];
    
        // ask director for the window size
        CGSize size = [[CCDirector sharedDirector] winSize];
    
        // position the label on the center of the screen
        label.position =  ccp( size.width /2 , size.height/2 );
    
        // add the label as a child to this Layer
        [self addChild: label];
      
    
        // Hello world
        CCLabelTTF *label = [CCLabelTTF labelWithString:@"Hello World"
                                               fontName:@"Chalkduster" fontSize:36.0f];
        label.positionType = CCPositionTypeNormalized;
        label.color = [CCColor redColor];
        label.position = ccp(0.5f, 0.5f); // Middle of screen
        [self addChild:label];
        
    


    <所感>

    • cocos2d v3系の目玉機能と言えそうな新機能です。 うーん素晴らしい(^o^)
    • 上記プロパティを「……TypeNormalized」に設定することで相対位置(割合)で設定可能になりますので、画面サイズに依存しない位置指定やサイズ指定が可能となり柔軟な配置が実現できます。
      └ iPhone 5以降での4インチ画面サイズ(1,136 x 640 px)対応にも使えそうです
    • CCLayout、CCLayoutBox等の配置用ノードと組み合わせて全てのノードを相対配置にしておけば今後新たな画面サイズが登場しても大丈夫そうですね。


    ではまた〜

    cocos2d v3.1新機能:便利そうなCCActionが追加されてる〜

    <新機能項目>

    1. CCActionRemove
      ・CCSprite等のノードオブジェクト消去(cleanup:YES固定)
    2. CCActionSoundEffect
      ・サウンド再生
    3. CCActionSpriteFrame
      ・Spriteフレーム画像の変更
    4. CCActionProgressFromTo
      ・プログレスバーアニメーション:簡単に進捗率バー表示できそう

      <CCActionRemoveサンプル>
          // ダブルタップエフェクトアニメーション
          [animeNode runAction:[CCSequence actions:
                                [CCEaseBackIn actionWithAction:
                                 [CCScaleTo actionWithDuration:0.5 scale:0.2]],
                                [CCCallFuncND actionWithTarget:animeNode
                                                      selector:@selector(removeFromParentAndCleanup:)
                                                          data:(void *)YES],
                                  nil]];
      
      
          // ダブルタップエフェクトアニメーション
          [animeNode runAction:[CCActionSequence actions:
                                [CCActionEaseBackIn actionWithAction:
                                 [CCActionScaleTo actionWithDuration:0.5 scale:0.2]],
                                [CCActionRemove action],
                                nil]];
      
      


      <所感>

      • 今まで「CCCallFunc」で個別に実現していた機能が簡単に実装できますので、かなり便利になってますね。
      • 上記以外にも新しく加わったCCActionもありますのでいろいろと試してみたいと思います。


      ではまた〜

      2014年7月16日水曜日

      cocos2d v3.1非互換:シーン切り替え方法・トランジションの変更

      <非互換項目>

      • シーンから別のシーンへ切り替える方法(replaceScene:メソッド)の使い方が変更になっている。
      • シーン切り替え時のトランジション(切り替えエフェクト)も変更になっている。
        └ トランジションの種類が少なっているような。。。

            // Game画面へ切り替え
            [[CCDirector sharedDirector] replaceScene:
             [CCTransitionZoomFlipAngular transitionWithDuration:1.0
                                                           scene:[GameScene node]]];
        
        
            // Game画面へ切り替え
            [[CCDirector sharedDirector] replaceScene:[GameScene node]
                                       withTransition:[CCTransition transitionFadeWithDuration:1.0]];
        
        


        <対応方法>

        • 上記、コードサンプルの通りシーン切り替え方法を改修する。
        • 「CCTransitionZoomFlipAngular」トランジションが無くなっているので取り敢えずは別のトランジションに置き換えています。

        <所感>

        • トランジションタイプとして「CCTransitionZoomFlipAngular」を使っていましたが、どうもcocos2d v3.1ではこのトランジションが存在していないようです。
          └ cocos2dフォルダを「Angular」文字列で検索してもヒットしない…(^^ゞ
        • cocos2d v3.0のCCTransition.mファイルには「CCTransitionZoomFlipAngular」も存在しているみたいなのですが、v3.1では無くなっている!?
          └ また、トランジション種類自体もかなり減っているみたいです。。。
        • 「CCTransitionZoomFlipAngular」トランジションを置き換える事が可能なのかについては引き続き調査したいと思います。


        ではまた〜

        2014年7月15日火曜日

        cocos2d v3.1非互換:CCMenu,CCMenuItemが無くなっている(^^ゞ

        <非互換項目>

        • CCMenu,CCMenuItemが無くなっており、メニュー操作については完全に書き換えになります。(^_^;)

        <対応方法>

        • CCMenuItemの代わりには新規クラスであるCCButtonで置き換える。
        • CCMenuの代わりには新規クラスであるCCLayoutで置き換える。
          └ CCLayoutの利用な必須では無くメニューアイテム自動配置機能の代替。

                // メニューボタン生成
                _menuItemGamePlay = [CCMenuItemImage itemWithNormalImage:@"Button_GamePlay.png"
                                                           selectedImage:@"Button_GamePlay_Sel.png"
                                                                  target:self
                                                                selector:@selector(tappedGamePlayButton:)];
                CCMenuItem *menuItemNextStage = [CCMenuItemImage itemWithNormalImage:@"Button_NextStage.png"
                                                                       selectedImage:@"Button_NextStage_Sel.png"
                                                                              target:self
                                                                            selector:@selector(tappedNextShapeButton:)];
                CCMenuItem *menuItemPriorStage = [CCMenuItemImage itemWithNormalImage:@"Button_PriorStage.png"
                                                                        selectedImage:@"Button_PriorStage_Sel.png"
                                                                               target:self
                                                                             selector:@selector(tappedPriorShapeButton:)];
                _menuItemHowToPlay = [CCMenuItemImage itemWithNormalImage:@"Button_HowToPlay.png"
                                                            selectedImage:@"Button_HowToPlay_Sel.png"
                                                                   target:self
                                                                 selector:@selector(tappedHowToPlayButton:)];
                // メニュー生成
                CCMenu *topMenu = [CCMenu menuWithItems:_menuItemGamePlay, menuItemNextStage, menuItemPriorStage,
                                   _menuItemHowToPlay, nil];
                
                // メニュー位置設定
                topMenu.position = CGPointZero;
                _menuItemGamePlay.position = ccp(self.contentSize.width/2, self.contentSize.height/2-290);
                menuItemNextStage.position = ccp(self.contentSize.width/2+384, self.contentSize.height/2-291);
                menuItemPriorStage.position = ccp(self.contentSize.width/2-384, self.contentSize.height/2-291);
                _menuItemHowToPlay.position = ccp(38, self.contentSize.height - 38);
                
                [self addChild:topMenu z:1];
                
        
                // メニューボタン生成
                _btnGamePlay = [CCButton buttonWithTitle:@""
                                             spriteFrame:[CCSpriteFrame frameWithImageNamed:@"Button_GamePlay.png"]
                                  highlightedSpriteFrame:[CCSpriteFrame frameWithImageNamed:@"Button_GamePlay_Sel.png"]
                                     disabledSpriteFrame:nil];
                [_btnGamePlay setTarget:self selector:@selector(tappedGamePlayButton:)];
                
                CCButton *btnNextStage = [CCButton buttonWithTitle:@""
                                                       spriteFrame:[CCSpriteFrame frameWithImageNamed:@"Button_NextStage.png"]
                                            highlightedSpriteFrame:[CCSpriteFrame frameWithImageNamed:@"Button_NextStage_Sel.png"]
                                               disabledSpriteFrame:nil];
                [btnNextStage setTarget:self selector:@selector(tappedNextShapeButton:)];
                
                CCButton *btnPriorStage = [CCButton buttonWithTitle:@""
                                                        spriteFrame:[CCSpriteFrame frameWithImageNamed:@"Button_PriorStage.png"]
                                             highlightedSpriteFrame:[CCSpriteFrame frameWithImageNamed:@"Button_PriorStage_Sel.png"]
                                                disabledSpriteFrame:nil];
                [btnPriorStage setTarget:self selector:@selector(tappedPriorShapeButton:)];
                
                _btnHowToPlay = [CCButton buttonWithTitle:@""
                                              spriteFrame:[CCSpriteFrame frameWithImageNamed:@"Button_HowToPlay.png"]
                                   highlightedSpriteFrame:[CCSpriteFrame frameWithImageNamed:@"Button_HowToPlay_Sel.png"]
                                      disabledSpriteFrame:nil];
                [_btnHowToPlay setTarget:self selector:@selector(tappedHowToPlayButton:)];
        
                // メニューボタン登録
                [self addChild:_btnGamePlay z:1];
                [self addChild:btnNextStage z:1];
                [self addChild:btnPriorStage z:1];
                [self addChild:_btnHowToPlay z:1];
                
                // メニューボタン位置設定
                _btnGamePlay.position = ccp(self.contentSize.width/2, self.contentSize.height/2-290);
                btnNextStage.position = ccp(self.contentSize.width/2+384, self.contentSize.height/2-291);
                btnPriorStage.position = ccp(self.contentSize.width/2-384, self.contentSize.height/2-291);
                _btnHowToPlay.position = ccp(38, self.contentSize.height - 38);
                
        


        <所感>

        • ほとんど全てのプログラムで利用していたであろうメニュークラス(CCMenu,CCMenuItem)の改変ですので影響範囲が広く、改変内容も互換性の無い変更(文字列置換では対応できない)ですので、多くのプログラマが「なんでやねん」と突っ込んでいるのではないでしょうかw
        • この改変もSpriteBuilder対応なんでしょうかね!? ここまで既存クラスを変更しまくったんですから、その分はSpriteBuilderから恩恵を受けたいものです。


        ではまた〜

        cocos2d v3.1非互換:CCLabelTTF生成メソッドの引数が変わってる

        <非互換項目>

        • CCLabelTTF生成メソッドの引数が変わっている。
          └ 文字位置揃え指定「hAlignment」が無くなり、プロパティ設定になっています。

        CCLabelTTF *labelVersion = [CCLabelTTF labelWithString:theVersion
                                                      fontName:kFontCopyright
                                                      fontSize:16.0
                                                    dimensions:CGSizeMake(200, 20)
                                                    hAlignment:kCCTextAlignmentRight];
        
        
        CCLabelTTF *labelVersion = [CCLabelTTF labelWithString:theVersion
                                                      fontName:kFontCopyright
                                                      fontSize:16.0
                                                    dimensions:CGSizeMake(200, 20)];
        labelVersion.horizontalAlignment = CCTextAlignmentRight;
        
        


        <対応方法>

        • 上記、コードサンプルの通り文字位置揃え指定プロパティで設定するよう改修する。

        <所感>

        • CCLabelTTF生成メソッドの引数ってバージョンアップの度に変更になっているって言って良い位変更になっており、良く使うメソッドですし毎回修正している感じがします。(^^ゞ
        • CCLabelTTF以外のラベル系クラスでも同様に変更となっている可能性が考えられますね〜。


        ではまた〜

        cocos2d v3.1非互換:ccDrawLine等の直接描画関数が無くなっている!?

        <非互換項目>

        • cocos2dで画面に線や円等の図形を直接描画する関数群(ccDrawXXXX)が利用できなくなっていると思われます。
        • Google検索して関連情報を集めてみましたが"CCDrawingPrimitives.h"ヘッダーをインポート云々の書き込みを見つけましたがv3.1ではこのヘッダーファイル自体存在せず、どうもccDrawLine等の直接描画関数は使えなくなっている感じですね。


        <対応方法>

        • CCDrawNodeクラスを用いた線や円等の図形描画に書き換える。

        -(void)draw{
            // 線の色設定
            ccDrawColor4B(64, 64, 64, 255);
            
            // 線の太さ設定
            glLineWidth(1.0);
            
            // 線の描画幅の設定
            CGFloat gap = kTriLineLength;
            
            // 三角形の高さ計算
            CGFloat takasa = gap * (sqrt(3.0) / 2.0);
            
            // 描画開始Y座標
            CGFloat baseY = -4.0f;
            
            // 横線の描画
            CGPoint p1, p2;
            for (CGFloat y=baseY+takasa; y<self.contentSize.height; y=y+takasa) {
                p1=CGPointMake(0, y);
                p2=CGPointMake(self.contentSize.width, y);
                ccDrawLine(p1, p2);
            }
        }
            
        
        -(id) init
        {
         if( (self=[super init] )) {
                // 画面サイズ取得
                CGSize viewSize = [[CCDirector sharedDirector] viewSize];
                
                // 背景描画ノード生成
                CCDrawNode *drawNode = [CCDrawNode node];
          [self addChild:drawNode z:0];
                
                // --- 背景描画処理 ------------------------------------------
                // 線の色設定
                CCColor *colorLine = [CCColor colorWithCcColor4b:ccc4(64, 64, 64, 255)];
                
                // 線の太さ設定
                CGFloat thickness = 1.0;
                
                // 線の描画幅の設定
                CGFloat gap = kTriLineLength;
                
                // 三角形の高さ計算
                CGFloat takasa = gap * (sqrt(3.0) / 2.0);
                
                // 描画開始Y座標
                CGFloat baseY = -4.0f;
                
                // 横線の描画
                CGPoint p1, p2;
                for (CGFloat y=baseY+takasa; y= 0 && x <= viewSize.width) ||
                        (x-zure >= 0 && x-zure <= viewSize.width)) {
                        p2=CGPointMake(x-zure, viewSize.height);
                        [drawNode drawSegmentFrom:p1 to:p2 radius:thickness color:colorLine];
                    }
                    
                    // 右斜線
                    if ((x >= 0 && x <= viewSize.width) ||
                        (x+zure >= 0 && x+zure <= viewSize.width)) {
                        p2=CGPointMake(x+zure, viewSize.height);
                        [drawNode drawSegmentFrom:p1 to:p2 radius:thickness color:colorLine];
                    }
                }
            }
         return self;
        }
            
        

        <所感>

        • 直接描画関数(ccDrawXXXX)を多用しているプログラムでは対応がかなり大変になると思います。(描画タイミングも変わっちゃいますし)
        • CCDrawNodeクラスでも置き換えが困難なケースでは別の方法を探す事になると思いますが、今回のプログラムではCCDrawNodeクラスでの対応が可能でしたのでそれ以上は調べておりません。  └ 代替策等の情報をお持ちの方はコメントを付けていただければ幸いです。
        ではまた〜

        2014年7月14日月曜日

        cocos2d v3.1非互換:CCLayerクラスが無くなっている(^^ゞ

        <非互換項目>

        • タッチイベントを処理する重要なクラスと位置付けられていると思っていたCCLayerクラスが無くなっている。
        • タッチイベント有効化やイベント名自体も変更されている。


        <対応方法>

        • CCLayerクラスの置き換え
          ・CCLayer → CCNodeクラスへ置き換えます。
        • タッチイベント有効化
          ・「self.touchEnabled = YES;」→「self.userInteractionEnabled = YES;」へ変更
        • タッチイベント処理オーバーライドメソッドの変更
          ・下記、対応例を参照。

        // タッチイベント有効化
        self.touchEnabled = YES;
        
        // タッチイベント処理オーバーライドメソッド
        -(BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event{}
        -(void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event{}
        -(void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event{}
        -(void)ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event{}
            
        // タッチ開始処理
        -(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
        {
            // タッチ位置取得&変換
            UITouch *touch = [touches anyObject];
            CGPoint location = [touch locationInView: [touch view]];
            location = [[CCDirector sharedDirector] convertToGL:location];
        
        }
        
        // タッチイベント有効化
        self.userInteractionEnabled = YES;
        
        // タッチイベント処理オーバーライドメソッド
        -(void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event{}
        -(void)touchMoved:(UITouch *)touch withEvent:(UIEvent *)event{}
        -(void)touchEnded:(UITouch *)touch withEvent:(UIEvent *)event{}
        -(void)touchCancelled:(UITouch *)touch withEvent:(UIEvent *)event{}
            
        // タッチ開始処理
        - (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event
        {
            // タッチ位置取得
            CGPoint location = [touch locationInNode:self];
        
        }
        



        <所感>

        • SpriteBuilder開発ツール採用による影響と推測していますが、CCLayerクラスを消しちゃうなんて思い切った事を判断をしたものだと関心します。(^^ゞ
        • CCLayerを機能拡張しているクラスとかどうすんだろって思いますよね〜!?
           CCScrollLayer,CCTMXLayerとか。。。


        ではまた〜

        cocos2d v3.1非互換:画面サイズ取得([[CCDirector sharedDirector] winSize])が変わってる

        <非互換項目>

        • cocos2dで画面サイズを取得するメソッドが変更になっている。
          └取得メソッド名:winSize → viewSize


            // 画面サイズ取得
            CGSize winSize =[[CCDirector sharedDirector] winSize]; 
            
        
            // 画面サイズ取得
            CGSize winSize =[[CCDirector sharedDirector] viewSize];
            
        


        <対応方法>

        • 画面サイズ取得メソッド名変更
          ・文字列への一括置換で対応可能。

        <所感>

        • cocos2dで画面サイズを取得する際に良く使う方法(メソッド)なので置換箇所は多いと思いますが一括置換で対応できますので、大きな影響は無いと思います。
        • 「winSize」と言うメソッド名が用途を示すには分かり辛いがための変更と推測しますが、ホント良く使うメソッドなんでマクロ定義でのサポートも検討して欲しかったですね。
          └画面サイズの取得:ccGetViewSizeとか、ccScreenSizeとか。。。


        ではまた〜

        cocos2d v3.1非互換:オーダー順変更メソッド「reorderChild:」無くなっている!?

        <非互換項目>

        • CCSprite等ノードオブジェクトの重なり順(どっちが前面に存在するか)を変更するメソッド(reorderChild:)が無くなっている。

        <対応方法>

        • 重なり順を変更したいノードオブジェクトのzOrderプロパティで設定する。

        // cocos2d v2での記述
        [_triangleShape.parent reorderChild:_triangleShape z:kOrderNormal];
        
        // cocos2d v3.1での記述
        _triangleShape.zOrder = kOrderNormal;
        


        <所感>

        • zOrderプロパティで直感的に分かり易くなったと思うので、良い改変だと思います。


        ではまた〜

        2014年7月11日金曜日

        cocos2d v3.1非互換:CCSpriteクラスも変えちゃうの(^^ゞ

        <非互換項目>

        1. 「spriteWithFile:」メソッド名変更( →「spriteWithImageNamed:」)
        2. 透明度プロパティ(opacity)が0〜255指定が0.0〜0.1実数指定に変更


            // 爆弾スプライト生成
            CCSprite *theBombSprite = [CCSprite spriteWithFile:@"Bomb.png"];
            
            // 爆弾透明度変更
            theBombSprite.opacity = 128;
            
        
            // 爆弾スプライト生成
            CCSprite *theBombSprite = [CCSprite spriteWithImageNamed:@"Bomb.png"];
            
            // 爆弾透明度変更
            theBombSprite.opacity = 0.5f;
            
        


        <対応方法>

        1. 「spriteWithFile:」メソッド名変更
          ・「spriteWithImageNamed:」文字列への一括置換で対応可能。
        2. 透明度プロパティ(opacity)変更対応
          ・指定方法が0〜255整数値指定から0.0〜1.0実数指定に変わっているので透明度プロパティ設定箇所を実数指定に修正。

        <所感>

        • 「spriteWithFile:」メソッド名変更はUIKitの「[UIImage imageNamed:@"xxx.png"];」のメソッド名命名に合わせたんでしょうか? だとすると、リソースファイルから読み込むメソッドが他にも存在すればメソッド名変更されている可能性がありますね。
        • 透明度プロパティ(opacity)変更については元々整数指定(0〜255)に違和感があったので実数指定(0.0〜1.0)に変更した事には賛成なのですが、Assertionチェック等が入っていないようで1.0より大きな値を代入してもエラーにならないので見落としてしまう危険性が気になりますね。


        ではまた〜

        cocos2d v3.1非互換:定数定義名が結構変わってる!?

        <非互換項目>

        • 「kCC〜〜〜」で始まる定数定義名が違う名前に変わっている。

        <対応方法>

        • 置き換わったと思われる定数名を探して置換する。
        • 先頭の「k」文字を消した命名規則になったと思いきや「kCC」で始まる定数も残っているようで改変の規則性は無いかも。
        • 定数名の中で特徴的な文字列で全ファイル対象に検索を掛けるとそれっぱい定数名定義が見つかるんで地道に調べては置換する。(^^ゞ 面倒くさ!

        <所感>

        • タイプ定義とかしてくれてたらコードアシストで候補が表示されると思うんですけど、単純に「#define」してたりしてるんでイチイチ調べるのが面倒です。(^_^;)


        ではまた〜

        cocos2d v3.1非互換:カラー指定引数がCCColorクラスに統一!?

        <非互換項目>

        • 全部かどうかは調査し尽くしていませんがメソッド呼び出し時の引数でカラー指定している箇所がマチマチ(ccColor4F,ccColor3Bとか)だったのが「CCColor」インスタンスに統一されている感じがします。

        <対応方法>

        • カラー指定の引数値を「CCColor型」インスタンス値に変更する。

        <所感>

        • 今までがマチマチで統一感がなく不便に感じた事はありましたからこれも良い改変と思います。


        ではまた〜

        cocos2d v3.1非互換:CCAction関連クラスが全部クラス名変更

        <非互換項目>

        • CCAction関連のクラス名がほとんど全て変更となっている。

        <対応方法>

        • 下記の対応に従ってクラス名を全置換する。
        No
        旧クラス名
        新クラス名
        1
        CCSequence
        CCActionSequence
        2
        CCRepeat
        CCActionRepeat
        3
        CCRepeatForever
        CCActionRepeatForever
        4
        CCSpawn
        CCActionSpawn
        5
        CCRotateTo
        CCActionRotateTo
        6
        CCRotateBy
        CCActionRotateBy
        7
        CCMoveTo
        CCActionMoveTo
        8
        CCMoveBy
        CCActionMoveBy
        9
        CCSkewTo
        CCActionSkewTo
        10
        CCSkewBy
        CCActionSkewBy
        11
        CCJumpTo
        CCActionJumpTo
        12
        CCJumpBy
        CCActionJumpBy
        13
        CCBezierTo
        CCActionBezierTo
        14
        CCBezierBy
        CCActionBezierBy
        15
        CCScaleTo
        CCActionScaleTo
        16
        CCScaleBy
        CCActionScaleBy
        17
        CCBlink
        CCActionBlink
        18
        CCFadeIn
        CCActionFadeIn
        19
        CCFadeOut
        CCActionFadeOut
        20
        CCFadeTo
        CCActionFadeTo
        21
        CCTintTo
        CCActionTintTo
        22
        CCTintBy
        CCActionTintBy
        23
        CCDelayTime
        CCActionDelay
        24
        CCReverseTime
        CCActionReverse
        25
        CCAnimate
        CCActionAnimate
        26
        etc…
        etc…

        <所感>

        • こうやって一覧で見ると元々のクラス名が雑然としている感じもして、CCAction系のクラスである事が一目で分かるって意味では改変後のクラス名の方が分り易い感はありますね。
        • Xcodeエディタでのコードアシストで「CCAction…」まで入力するとアクションクラスが並びますから選択し易いです。
        • 置換しないといけないのは手間ですが、この改変は「良し」としましょうw


        ではまた〜

        cocos2d v3.1非互換:CCSprite等のノード識別方法の変更

        <非互換項目>

        • CCSprite等のノード識別に使っていた「Tag」が「Name」に変わっている

        <対応方法>

        • getChildByTag:」,「removeChildByTag:」とかTag値で識別していた箇所はそれぞれ対応する「ByName」新メソッドへ全部置き換え。

          <改修例>

          1. addChildメソッド
            [_triangleShape addChild:theBombSprite z:1 tag:kTagMark];
                        ↓
            [_triangleShape addChild:theBombSprite z:1 name:kTagMark];

          2. getChildByTagメソッド
            [_triangleShape getChildByTag:kTagMark]
                        ↓
            [_triangleShape getChildByName:kTagMark recursively:NO]
              …「recursively:」は再帰的に探すって意味でしょうか!?

          3. removeChildByNameメソッド
            [_triangleShape removeChildByTag:kTagMark cleanup:YES];
                        ↓
            [_triangleShape removeChildByName:kTagMark cleanup:YES];


          <所感>

          • Tag指定は整数値だったのがName指定ではNSString文字列に変更となっていますので上記例では「kTagMark」は文字列定数として宣言しています。
          • この改変もSpriteBuilder採用による判断だとは推測できますし、確かに文字列での名前付けは自然で人間にも分り易いとは思いますがTag値による識別も残しても良かったんではないでしょうか。(Tagは使わなければ影響無いですし、既にTagを使っているプログラムの互換性も保てますので。。。)

          ではまた〜

          cocos2d v3.1非互換:「SimpleAudioEngine」クラスの置き換え

          <非互換項目>

          • 「SimpleAudioEngine」クラスが無くなっている

          <対応方法>

          • 「OALSimpleAudio」クラスへ置き換える
          • 「SimpleAudioEngine sharedEngine」文字列を「OALSimpleAudio sharedInstance」へ置き換えれば一気に改修可能かも。
          • playEffectメソッド以外にBGM再生とかしていればそれぞれ対応しているメソッドへ置き換える。

          <改修例>


          - (ALuint)playSound:(SoundIDType)inSoundType
          {
              // サウンド再生
              ALuint retSoundId = [[SimpleAudioEngine sharedEngine] playEffect:
                                            [_arraySounds objectAtIndex:inSoundType]];
              
              // 再生中サウンド識別子を返す
              return retSoundId;
          }

                    ↓

          - (id<ALSoundSource>)playSound:(SoundIDType)inSoundType
          {
              // サウンド再生
              id<ALSoundSource> retSoundId = [[OALSimpleAudio sharedInstance] playEffect:
                                                      [_arraySounds objectAtIndex:inSoundType]];
              
              // 再生中サウンド識別子を返す
              return retSoundId;
          }


          <所感>

          • ほとんどのケースでは文字列置換だけで対処可能そうですけど凝ったサウンド機能を利用していた場合は結構大変かも知れませんね。


          ではまた〜

          cocos2d最新バージョン v3.1非互換に驚愕!(その2)

          記事タイトルに「驚愕!」と煽りながら前回の記事ではARC対応程度の非互換だけでしたので、今回はまず現時点までに発見した「驚愕!」の非互換項目を一覧でどうぞ!

          <非互換項目>
          • 「SimpleAudioEngine」クラスが無くなっている
            └サウンド再生関連は別のクラスに置き換えとなります。
          • CCLayerクラスが無くなっている
            └「CCScene」と並んで基本的と思われた「CCLayer」クラスがありません。(^_^;)
          • CCMenuクラスが無くなっている
            └こちらも必ず利用する基本的なクラスですが無くなっています。
          • CCSprite等のノード識別に使っていた「Tag」が「Name」に変わっている。
            └「getChildByTag:」,「removeChildByTag:」とかTag値で識別していた箇所は全部修正

          まだ、移行作業を始めたばかりですが上記のような「何故それを変える!?」って言いたくなるような根底を揺るがすような非互換が多く一瞬自分の目を疑いたくなりました。(^^ゞ

          冷静になって好意的に考えるとこのバージョンから開発ツールのベースとなった(したい?)「SpriteBuilder」使用を前提に考えた改変のような気はします。

          「SpriteBuilder」がCCSceneをベースに生成するのでCCLayerは不要にしたとかCCMenuもメニューコントロールのグループ化と配置制御ならばCCLayoutに統合しようとか。。。

          また、Tag識別も整数値で識別するよりかは文字列で名前付けした方が分かり易いとの判断なのでしょうけど、イキナリ過ぎるような気はしますね。

          でもさすがに今回の改変は下位互換とか常に移行やメンテに重点を置いて考える日本人には理解し難いですね。(^^ゞ 欧米人の割り切り加減には驚くばかりです。。。(^_^;)

          と言うことで結論としてはcocos2d v2系列とv3系列は別物と捉えた方が良いと思いますので、既存v2で作成しているプロジェクトはそのままの方が良さそうです。

          新規作成で且つ「SpriteBuilder」の開発効率の恩恵を受けたい場合はv3.1の利用も検討できると思います。

          私は引き続きv2 → v3.1へのマイグレーション作業は続けていきたいと思いますので、新たに発見した非互換項目については随時当ブログにて公開させていただきます。


          ではまた〜

          2014年7月10日木曜日

          Swift:ViewController.swiftの中身

          前回の「AppDelegate.swift」に続いて、今回は「ViewController.swift」の中身を見ていきたいと思います。

          --------------------------------------------------------------------------
          //
          //  ViewController.swift
          //  HelloSwift
          //
          //  Created by  on 2014/07/01.
          //  Copyright (c) 2014 . All rights reserved.
          //

          import UIKit

          class ViewController: UIViewController {
                                      
              override func viewDidLoad() {
                  super.viewDidLoad()
                  // Do any additional setup after loading the view, typically from a nib.
              }

              override func didReceiveMemoryWarning() {
                  super.didReceiveMemoryWarning()
                  // Dispose of any resources that can be recreated.
              }


          }
          --------------------------------------------------------------------------
          えっ!、これで終わりって思う程の短さです。

          継承元の「UIViewControllerクラスの2つのメソッドをオーバーライドしています。

          ビューへ「Hello World!」を描画するなら「viewDidLoad()」メソッドへ記述することになりそうです。

          描画先オブジェクトとして「UILabel」をViewへ配置してOutlet定義した変数へ繋げれば指定した文字列を描画できそうな感じ。。。

          「Hello World!」と描画させるためのコードは以下の通りです。
          --------------------------------------------------------------------------
          //
          //  ViewController.swift
          //  HelloSwift
          //
          //  Created by  on 2014/07/01.
          //  Copyright (c) 2014 . All rights reserved.
          //

          import UIKit

          class ViewController: UIViewController {
              
              // Outlet変数宣言
              @IBOutlet var lblHello : UILabel
              
              // オーバーライドメソッド
              override func viewDidLoad() {
                  super.viewDidLoad()
                  // Do any additional setup after loading the view, typically from a nib.
                  
                  // Hello World!! 描画
                  lblHello.text = "Hello World!"
              }

              override func didReceiveMemoryWarning() {
                  super.didReceiveMemoryWarning()
                  // Dispose of any resources that can be recreated.
              }


          }
          --------------------------------------------------------------------------


          Outlet宣言でUILabelオブジェクト「lblHello」を宣言しておいて、Main.storyboardファイルにてビュー画面にUILabelオブジェクトを配置して「lblHello」アウトレットと接続します。

          あとはviewDidLoad()オーバーライドメソッド内で「Hello World!」文字列を設定すればiPhoneシミュレーター画面に「Hello World!」と描画されました。
          「Hello World!」と描画するだけの超簡単なプログラムでしたが如何だったでしょうか?
          私は思っていたよりかは違和感なくコーディングすることが出来ました。

          ベータ版のせいかコード記入時のコードアシストが利かず若干戸惑いましたが、ちゃんとアシストされればそんなに困ることなくコーディングできそうですね〜。

          あとはSwift言語独自の記述方法やらコーディングスタイルに慣れていこうと思います。

          ではまた〜