2013年1月29日火曜日

sprite sheetのmax sizeについて

sprite sheetをつくって、BatchNodeで複数画像を読み込ませるため、
max sizeを調べた。

iPhone3を視野に入れなければ、2048x2048,
iPad2/3,iPhone 4sからは4096x4096がOK,とのこと。

http://www.cocos2d-iphone.org/forum/topic/34989

基本を2048x2048にしておいて、
高解像度版も用意するべか、と。

2013年1月26日土曜日

CCArrayでのint格納はcontainsObjectが上手くいかないらしい

cocos2dのCCArrayでint型整数を代入して、containsObjectで検査しようとしたところ、うまくいかない。

ググって、

http://blog.iphoneidiot.com/2012/06/ccarray-containsobject-does-not-work.html
から辿って、
http://www.cocos2d-iphone.org/forum/topic/12760
に行くと、

NSNumberは、CCArrayでcontainObjectに合ってない、というような記述。

うーん。

ということで、containsObjectのため、NSMutableSetを使ってみて、便利だった。

とりあえず、順番の関係ない数字のみの格納には、NSMutableSetを使っていこうと思う。

CCArrayの再帰処理


再帰についてのメモ。
CCArrayのオブジェクト中にCCArrayが含まれる場合、どんどん下層arrayまで入り込んでいって、最終的に配列でないオブジェクトにたどり着くまで入り込んでいき、処理を実行する、というもの。
便利。
以下のコードは、Kobold2dの開発者さんによるもの。

Recursion is your friend.
-(void) recurseIntoArray:(CCArray*)array
{
    for (id item in array)
    {
        if ([item isKindOfClass:[CCArray class]])
        {
             [self recurseIntoArray:(CCArray*)item];
        }
        else
        {
             NSLog(@"item: %@", item);
        }
    }
}
Just start the iteration anywhere with the root array:
[self recurseIntoArray:rootArray];
Worth mentioning: CCARRAY_FOREACH is no longer necessary, at least in cocos2d 1.1 and 2.0 you can just use regular fast iteration with for. May also work in cocos2d 1.0.1, I think I used fast enumeration there as well.

2013年1月24日木曜日

cocos2d・Kobold2dは、jQueryに似ているな、と。

Objective-Cにおける、cocos2dとその拡張であるKobold2dは、
javascriptにけるjQueryに似ている、と感じることが多々あります。

javascriptのフレームワークは多々ありますが、
jQueryはかなりの人気であり、私も初めて知った頃は、そのシンプルさに感動したものでした。

Objective-Cは、書けるようになるとかなりの可能性を追求できますが、
最初の入り口がわかりにくいことと、
コードを書く量が多く、それが大変です。(Xcodeのコード補完は秀逸ですが)

そこで、書く量を非常に省力化してくれるcocos2dを知ったときは、感動しました。
感覚として、jQueryを連想しました。

また、Kobold2dも、cocos2dのいいところを、さらにシンプル化して提供しておられ、好感が持てます。

こうした素晴らしいフレームワークをMITなどのライセンスで提供しておられることに感謝です。


2013年1月23日水曜日

CCArrayにint型整数を突っ込み、整数として取得し直すメモ

CCArrayにintを突っ込むのは、以下のよう。


i have a CCArray
    CCArray *indexs;
then i add a integer into it
    int x = 0;
    [indexs addObject:[NSNumber numberWithInteger:x]];
then i want to get this integer from this CCArray
    id temp1 = [indexs objectAtIndex:0];
    int firstOne = (int) temp1;//これまちがい

で、ここからint型整数整数を取り出すのは、


int firstOne = [temp1 intValue];

出典は、

iPhone、iPadの画面サイズ。

iPhone、iPadの画面サイズについて、良くまとめられているページがあったので、メモ。

http://program.station.ez-net.jp/special/handbook/objective-c/iphone/ui/layout.asp

Retina対応も、していかなくては。

CCArrayのドキュメント、とsortについて。

コレクションを使うことがこれから多くあるので、配列やSetについて学び中。

CCArrayについて、まずCocos2dであれば学ぶべし、と思い、以下のドキュメントを参照。
http://www.learn-cocos2d.com/api-ref/1.0/cocos2d-iphone/html/interface_c_c_array.html

Kobold2dの作者さんが、2010年にCCArrayとNSArrayの速度比較をした記事があり、
http://www.learn-cocos2d.com/2010/09/array-performance-comparison-carray-ccarray-nsarray-nsmutablearray
CCArrayで、insertObject:AtIndex:0 and removeObjectAtIndex:0を使った際には、NSArrayより断然遅かった、という記事が気になった。

その後2年は経っているので、改善されていると思うが。。

CCArray,ドキュメントを見る限り、いろいろな機能が備えられており、便利そう。
(個人的には、randomObject ()が便利そう。よく使います。)

ありがたく使用させて頂きます。

:::::::::::::::::::::::::::::::
と思ったら、
http://www.cocos2d-iphone.org/forum/topic/10202
ここに、sortの機能がない、ということが書かれていた。。
確かに、無さそう。
さて、どうするか。sortも使いたいのだが。

と思ったら、開発者さんのgithubで、sortのfunctionが書かれたものが。
https://github.com/cocos2d/cocos2d-iphone/blob/master-v2/cocos2d/Support/CCArray.m

ソースを確認したら、すでに実装されていますね。CCArray.h,.mに。
良かった。

https://github.com/ricardoquesada
この方、ありがたい方だ。。拝んでおこう。。

OpenGL ESってなんだろう、と調べてみた。

OpenGL ESとはなんだろう、ということが気になって色々調べた。
「ES」は「Embedded System」、すなわち、組み込みシステム用の様子。iOSとか、Androidとか。

以下の文章が、OpenGL ESとCocos2dの関係について簡潔に紹介されていたので参考になりました。英語ですが。
http://stackoverflow.com/questions/10228508/why-are-opengl-es-and-cocos2d-faster-than-cocoa-touch-ios-frameworks-itself

基本、3Dのレンダリング用なので、Cocos2dのspriteは、実は3Dの立体オブジェクトを平面として二つの三角形を四角として描いており、上部からの視点で見ているからぺったりして見えるけど、回転やズームなども簡単にできる。そして、Core Graphicより早い、とのこと。

Cocos2dは、OpenGL ESを非常に使いやすくしてくれている、ということの様子。
よく「OpenGl ESのラッパーです」と言われているが自分にはよくわからなかったので、上の文章で、やっと少し具体的なイメージが掴めた。


2013年1月22日火曜日

古いcertificationを削除

Xcodeが起動する度に、古いcertificationが復活して困った。
以下、参考になりました。
http://www.smartphone-dev.com/blog/?p=214

organizerのサイドバーのteamsのところで、refresh。
先に古いcertificationを消してから。

これでうまくいきました。
よかった。

ccTypesの設定をメモ。

ccTypes.hというところに、
ccc3やccc4などの設定が書いてあり、勉強になったので、メモ。
http://www.cocos2d-iphone.org/api-ref/0.99.2/cc_types_8h_source.html

こうやって、便利な拡張をしていくんですね。為になる。

00020 #import <objc/objc.h>                           // BOOL
00021 #import <CoreGraphics/CGGeometry.h>     // CGPoint
00022 #import <OpenGLES/ES1/gl.h>                     // GLenum, GLubyte
00023 
00027 typedef struct _ccColor3B
00028 {
00029         GLubyte r;
00030         GLubyte g;
00031         GLubyte b;
00032 } ccColor3B;
00033 
00035 static inline ccColor3B
00036 ccc3(const GLubyte r, const GLubyte g, const GLubyte b)
00037 {
00038         ccColor3B c = {r, g, b};
00039         return c;
00040 }
00041 //ccColor3B predefined colors
00043 static const ccColor3B ccWHITE={255,255,255};
00045 static const ccColor3B ccYELLOW={255,255,0};
00047 static const ccColor3B ccBLUE={0,0,255};
00049 static const ccColor3B ccGREEN={0,255,0};
00051 static const ccColor3B ccRED={255,0,0};
00053 static const ccColor3B ccMAGENTA={255,0,255};
00055 static const ccColor3B ccBLACK={0,0,0};
00057 static const ccColor3B ccORANGE={255,127,0};
00059 static const ccColor3B ccGRAY={166,166,166};
00060 
00064 typedef struct _ccColor4B
00065 {
00066         unsigned char r;
00067         unsigned char g;
00068         unsigned char b;
00069         unsigned char a;
00070 } ccColor4B;
00072 static inline ccColor4B
00073 ccc4(const GLubyte r, const GLubyte g, const GLubyte b, const GLubyte o)
00074 {
00075         ccColor4B c = {r, g, b, o};
00076         return c;
00077 }

実機インストール、やっとうまくいった。

久しぶりに実機インストールを試みて、躓いた。

色々参考ページを拝見して、以下が自分には一番分かりやすく、ありがたかった。
http://kentaro-shimizu.com/lecture/iphone/step3.html

なんとかインストール成功。

Swipeのdirectionを画面方向毎に対応させるためのメモ

KKSwipeGestureDirectionが、実機のportraitモードやlandscapeモードで変わってしまうので、困っていたら、Kobold2dの開発者さんが、同様の悩みに答えていた。

http://stackoverflow.com/questions/8626534/uiswipegesturerecognizer-doesnt-seem-to-respect-current-uidevice-orientation-on

その下には、Kobold2dではなく、Cocos2dのコードも。

さて、後で時間を作って対応してみよう。

Kobold2dのfirstSceneの呼び出しが気になって調査


Kobold2dのLibraiesのkobold2dのkobold2d Startupの中のKKAppDelegate.mに、FirstSceneをrunするメソッドが書かれていた。
どうも、sceneをpushするだけのようで、layerも同時にallocしているわけではないようだ。

-(void) tryToRunFirstScene
{
// try to run first scene
if (director.isSceneStackEmpty){
Class firstSceneClass = NSClassFromString(config.firstSceneClassName);
if (firstSceneClass)
{
Class sceneClass = [CCScene class];
Class superClass = class_getSuperclass(firstSceneClass);
if (sceneClass == superClass)
{
id scene = [[[firstSceneClass alloc] init] autorelease];
#if KK_PLATFORM_IOS
[director pushScene:scene];
#elif KK_PLATFORM_MAC
[director runWithScene:scene];
#endif
}

2013年1月21日月曜日

accelerometerの数値取得の様子メモ。

iPhoneのaccelerometerの分かりやすいビデオがあったのでメモ。
http://www.switchonthecode.com/tutorials/iphone-tutorial-reading-the-accelerometer


x,y,zの三つの方向を、筐体の回転で取得するのが、こんなに簡単とは。

Kobold2dのKKTouchPhaseのメモ

Kobold2dのKKTouchPhaseのまとめメモです。

以下、Kobold2dのリファレンスから。
http://www.learn-cocos2d.com/api-ref/KoboldTouch/6.0/Kobold2D/html/_k_k_input_enums_8h.html

enum KKTouchPhase
A touch can have just began, it can be moving, or it can be ended this frame. The kKKTouchPhaseAny can be used if want to include all three phases in a touch test. The KKTouchPhase enum values are equal to those in the UITouchPhase enum (except for any and lifted), that means they can be used interchangeably.
Enumerator:
KKTouchPhaseBegan touch began this frame
KKTouchPhaseMoved touch has moved this frame
KKTouchPhaseStationary touch didn't move this frame(このフレームでは何もしなかった、というphase)
KKTouchPhaseEnded touch ended this frame
KKTouchPhaseCancelled touch was cancelled (ie incoming call, incoming SMS, etc) this frame (着信などでキャンセルがあったフレーム)
KKTouchPhaseAny used for certain tests to disregard the phase of the touch (どんなphaseでも)
KKTouchPhaseLifted a touch is "lifted" if it is no longer associated with a finger on the screen (すでに指が離れている)

CCRemoveFromParentActionって?


Kobold2dのuser-inputプロジェクトのコードで、以下が気になったので、調査。
id remove = [CCRemoveFromParentAction action];

[CCRemoveFromParentAction ation];って文字通りの意味だろうけど、どうやって使うのか、と。

で、Kobold2dのKobold2d Cocos2d Extensionsの中にクラスが定義されていました。

@implementation CCRemoveFromParentAction
-(void) startWithTarget:(id)target
{
[super startWithTarget:target];[target removeFromParentAndCleanup:YES];}
@end

superで親クラスがstartWithTargetというメソッドを実装している様子。

で、startWithTargetは、以下のCocos2dリファレンス(CCAction Class Reference)に定義が書かれていました。

http://www.cocos2d-iphone.org/api-ref/0.99.5/interface_c_c_action.html#a791b44f936b12d01e2aab5df8af41bfb


- (void) startWithTarget:(id) target
called before the action start. It will also set the target.

なるほど。
親クラスで、actionがスタートする前に呼び出され、CCActionのターゲットがsetされている、と。
で、removeFromParentAndCleanup:YESで、削除される、と。

まあ、文字通りの意味ですが、ちょっとすっきりしました。

CCの接頭辞ですが、どうもKobold2dのエクステンションのようですね。

CCMoveToとCCMoveBy

CCMoveToとCCMoveByの違いを理解するために、リファレンスを参照。
CCMoveByはCCMoveToを継承し、deltaPosition(フレームごとのポジション移動量?)が指定されている。

deltaはどうやら、frameの差分の様子。
参考1 (どこかの質疑応答)
参考2「Unity におけるフレームと Update」

00134 @interface CCMoveTo : CCIntervalAction <NSCopying>
00135 {
00136         CGPoint endPosition;
00137         CGPoint startPosition;
00138         CGPoint delta;
00139 }
00141 +(id) actionWithDuration:(ccTime)duration position:(CGPoint)position;
00143 -(id) initWithDuration:(ccTime)duration position:(CGPoint)position;
00144 @end
00145 
00150 @interface CCMoveBy : CCMoveTo <NSCopying>
00151 {
00152 }
00154 +(id) actionWithDuration: (ccTime)duration position:(CGPoint)deltaPosition;
00156 -(id) initWithDuration: (ccTime)duration position:(CGPoint)deltaPosition;
00157 @end

CCMoveToは、特定地点(絶対位置)への移動。一度移動したら、そこで終了。
CCMoveByは、現在地からの相対的移動。絶対位置の指定ではなく。どんどん移動できる。現在地から、次の地点へ、同量の距離を。

ということらしい。

どんどんSpriteを動かす場合には、CCMoveByが便利。

ccpSub、ccpLengthのメモ。

Cocos2dの「ccpSub」や「ccpLength」などの定義を知るために、リファレンスを見たので、メモ。
http://www.cocos2d-iphone.org/api-ref/0.99.0/_c_g_point_extension_8h.html

float kMoveDistance = fabsf(ccpLength(ccpSub(swipeEndPoint, input.gestureSwipeLocation))) * 4;
というKobold2dのuser-inputのプロジェクトソースを理解するため。

ccpSubの定義は、以下。

00085 ccpSub(const CGPoint v1, const CGPoint v2)
00086 {
00087         return ccp(v1.x - v2.x, v1.y - v2.y);
00088 }

ccpLengthの定義は、みつからず。。

たぶん、ccpSubが二つのCGPointのx,yの差分を取るので、ccpLenghでその線分の長さを計算するんですね。

で、fabsfで絶対値として取得、と。

なるほど。

2013年1月20日日曜日

Kobold2dのKKInput Touchesのドキュメントメモ

Kobold2dのKKInput Touchesについてのドキュメントを、メモ用にコピペします。
元記事はここ
Kobold2dの「My-User-Input-Project」のソースを読んでいて、ドキュメントを読む必要を感じ、ついでにメモ的な日本語も少々付加いたしました。
(KKInput gestureに関してのメモは、こちら。)

KKInput Touches

Enable Multi-Touch (マルチタッチをEnabledに)
To enable multiple touches, either set the config.lua setting EnableMultiTouch = YES or set themultipleTouchEnabled property: 
[KKInput sharedInput].multipleTouchEnabled = YES;
Simple Touch Began/Ended Tests (Touch開始、終了を簡単に取得。 anyTouchBeganThisFrame,anyTouchEndedThisFrame)
You can quickly test if any touch began or ended in the current frame with the following methods. This is a quick & easy way to, for example, create screens which the user can dismiss by touching the screen anywhere, or having the user "touch the screen to play again".
if ([KKInput sharedInput].anyTouchBeganThisFrame) { ... }
if ([KKInput sharedInput].anyTouchEndedThisFrame) { ... }
Touches Available (指がタッチ中か確認。touchesAvailable)
To test if touches are available, ie if any finger is touching the screen, use touchesAvailable:
if ([KKInput sharedInput].touchesAvailable) { ... }
Did you just touch my Node??? (あるNodeをタッチしたか確認。isAnyTouchOnNode: touchPhase:)
You can determine if a node is being touched (oh my) with the isAnyTouchOnNode:touchPhase:method. You pass in the node like a CCSprite, CCLabelTTF, or any other CCNode derived object to test if any touch with the given phase (began, ended, any, etc) was on that node.(beganやendedやanyなどのphaseも指定できて、あるNodeのタッチを確認。)
The isAnyTouchOnNode method correctly performs the test even if the node is rotated, scaled or both.(nodeが回転したり、拡大縮小していても、isAnyTouchOnNodeは正しく動作します。)
KKInput* input = [KKInput sharedInput];
if ([input isAnyTouchOnNode:someNode touchPhase:KKTouchPhaseBegan]) {...}
if ([input isAnyTouchOnNode:someNode touchPhase:KKTouchPhaseAny]) {...}
Instances of CCNode by definition have a zero contentSize, so you can not use this method to test for touches on CCNode, unless you have modified the contentSize property of the CCNode object.(CCNodeのインスタンスは、contentSizeはゼロに定義されている。だから、contentSizeプロパティを修正しないと、このメソッドはつかえない。isAnyTouchOnNode。isAnyTouchOnNode: touchPhase:)
CCScene or CCLayer by definition have a contentSize that equals that of the screen/window size. You can test if a touch was on a CCScene or CCLayer object, but it makes little sense because if there is a touch on the screen, it will naturally be on the CCScene or CCLayer object — unless you have modified the contentSize property.
Location of Touches (タッチの位置取得。locationOfAnyTouchInPhase:メソッド。)
You can get the location of any touch with locationOfAnyTouchInPhase:. You can use one of the standard phases (began, moved, stationary, ended, cancelled) or use the special Kobold2D phaseKKTouchPhaseAny to test for the location of any touch in any phase.(phaseKKTouchPhaseAnyは、Kobold2dの特別なもので、どんなphaseのどんなtouchでも位置を取得できるとのこと。)
When is this useful? Whenever you don't care which finger is at that location, or if multiple touches are disabled you can get the location of the one (any) finger on the screen.
KKInput* input = [KKInput sharedInput];
CGPoint pos = [input locationOfAnyTouchInPhase:KKTouchPhaseAny];
If no finger is currently touching the screen that is in the given phase, then CGPointZero is returned.(指がタッチしてなかったら、CGPointZeroが返される、と。)
Accessing all Touches (全てのtouchesにアクセス。)
The most powerful way to work with touches is to obtain the list of currently available touches via thetouches property, which is a CCArray* containing zero to five KKTouch* objects.(ゼロから5つのKKTouch*オブジェクトを格納したCCArray* touchesを使えるとのこと。)
KKTouch is a wrapper for UITouch that allows you to work with touches already converted to the Cocos2D view space(KKTouchはUITouchのラッパーで、Cocos2dのview spaceに既に転換されたタッチを使えるようにしたものです), and without having to use #ifdef if you also build for Mac(Mac用にビルドする際にも、#ifdefを使う必要がありません。). You can get the KKTouch* array and iterate over it like this:(KKTouch*配列を、以下のように取得して、繰り返すことが出来ます。)
CCArray* touches = [KKInput sharedInput].touches;//[KKInput sharedInput].touchesで取得し、CCArray *touchesに格納、と。
KKTouch* touch;
CCARRAY_FOREACH(touches, touch)//CCARRAY_FOREACHというメソッドがあるのですね。便利だ。
{
    // do something with touch here
    mySprite.position = touch.location;
}
The KKTouch location and previousLocation properties are already converted to Cocos2D view coordinates. You do not need to (and shouldn't) call CCDirector's convertGL method. 
(KKTouchのlocationとpreviousLocationプロパティは、すでにCocos2dのview座標に転換されているので、CCDirectorのconvertGLメソッドを使う必要がなく、使ってはいけません。)
Each KKTouch object corresponds to a particular finger on the screen. The same KKTouch object is used for the same finger starting when the touch "began" until the touch either "ended" or got "cancelled". ("ended"か"cancelled”になるまで、"began"によって開始されたtouchは、同じ指がタッチしている限り、KKTouchオブジェクトは維持されている、と。)
You can not rely on the array index for accessing a particular finger's KKTouch as other touches may end and get started(他のタッチが終わったり始まったりした場合は、配列中のインデックスで、特定のKKTouchにアクセスするのは信頼できません。). You can either store and later compare the touchID property to make sure you're using the same KKTouch as before, or simply keep a weak reference to the KKTouch object. In that case you have to check that it's phase property isn't KKTouchPhaseLifted, which indicates that the KKTouch object is no longer associated with a finger on the screen.(KKTouchPhaseLiftedは、すでに指が画面から離されていて、KKTouchオブジェクトが関連づけられていないというphase) You will also want to nil your reference when the touch phase is either KKTouchPhaseEnded or KKTouchPhaseLifted.
If you ever need access to the underlying UITouch* object, you can simply cast the touchID property:
// access the underlying UITouch object if needed
UITouch* uiTouch = (UITouch*)touch.touchID;
Do not retain or otherwise hold on to UITouch* objects, they may contain invalid data in the next frame. Access them only through the touches property on a "as needed" basis.
Removing a Touch (タッチを削除も出来る、と。)
As of Kobold2D v1.0.2 you can remove a touch to prevent other classes from handling the same touch. The finger associated with that KKTouch object will be ignored from then on.
CCArray* touches = [KKInput sharedInput].touches;
KKTouch* touch;
CCARRAY_FOREACH(touches, touch)
{
    // remove touch
    [[KKInput sharedInput] removeTouch:touch];
}
It is legal to remove touches while iterating over the touches array. The touch is first invalidated (KKTouchPhase is set to KKTouchPhaseLifted among other things) and later removed.