taoru's memo

Objective-c,cocos2d,など開発についてのメモ(andoroidも少しだけ)

CCSpriteのanchorPointを変更した際の位置ズレを吸収する

CCSpriteはanchorPointをセットすると位置がズレる。
瞬間的に位置がズレてしまうので、ズレないように見せるためにpositionを補正する

CCSprite *sprite = [CCSprite spriteWithFile:@"hoge.png"];
sprite.anchorPoint = ccp(0.5f, 0.5f);

// 位置ズレ前のboundingBox
CGRect oldBoundingBox = sprite.boundingBox;

sprite.anchorPoint = ccp(1.0f, 0.5f);

// 位置ズレ後のboundingBox
CGRect newBoundingBox = sprite.boundingBox;

// anchorPoint変更で発生した差分
CGPoint diff = ccpSub(newBoundingBox.origin, oldBoundingBox.origin);

// 位置ズレ差分を引くことで見た目上同じ位置になるようにセット
sprite.position = ccpSub(sprite.position, diff);

UILabelでadjustsFontSizeToFitWidthが効かなくてハマった

UILabelのsubClassを作っていて、initializeをoverrideして案件で最適なLabelクラスを作っていた。

adjustsFontSizeToFitWidth = YESにセットしているのに、なぜかscaleしてくれない!
という問題が発生し、ハマってた。


UILabel.hの当該コメントを見て即解決した

以下コピペ

// these next 3 property allow the label to be autosized to fit a certain width by scaling the font size(s) by a scaling factor >= the minimum scaling factor
// and to specify how the text baseline moves when it needs to shrink the font. this only affects single line text (lineCount == 1)

@property(nonatomic) BOOL adjustsFontSizeToFitWidth;         // default is NO
@property(nonatomic) BOOL adjustsLetterSpacingToFitWidth NS_AVAILABLE_IOS(6_0); // default is NO, adjust letter spacing to make text fit. Note: setting this property to YES will cause the value of -[NSParagraphStyle tighteningFactorForTruncation] to be disgregarded.
@property(nonatomic) CGFloat minimumFontSize NS_DEPRECATED_IOS(2_0, 6_0); // NOTE: deprecated - use minimumScaleFactor. default is 0.0

つまり、lineCountが1じゃないと効果がない。

今回問題になった原因は、initializeで

self.numberOfLines = 0;
self.adjustsFontSizeToFitWidth = YES;
self.minimumFontSize = 4.0f;

って感じでnumberOfLinesに1以外をセットしていたから。

もし改行させたいことが多いならデフォルトで0でもいいかもしれないけど、
xibで指定したのが効かない!って問題になりそうだから、コードでは指定しない方がいいのかな。

NSCFStringエラーでハマった(凡ミス)

NSStringをpropertyにセットして、いざ使おうとすると何もエラーを吐かずにクラッシュして困った。
凡ミスだったのでメモを残しておく。

breakpointをセットして、クラッシュ該当箇所でログを吐いてみたら、
該当文字列のクラスがNSCFStringになっていた。

(lldb) po [self.hogeString class]
$0 = 0x042d68e4 __NSCFString

もう全然解決できなくて、ググってもいまいち原因が分からず困り果てた。

NSCFStringって何だよ!ということでそっちから調べたところ
ダイナミックObjective-Cの記事に説明があった!

ダイナミックObjective-C 32 抽象クラスとクラスクラスタ

これに加えて、クラスクラスタの面白いところは、サブクラスの存在が完全に隠されており、その選択がNSStringに任されていることである。実際、Cocoaプログラミングの初心者は、NSCFStringやNSPathStore2の存在にまったく気付かないだろう。非常にスマートな手法といえるだろう。

すいません、初心者でした。
後でちゃんと記事読んでみよう。


ーーーー

原因は、propertyの属性を (nonatomic, assign)にしていたという凡ミスでした。
(nonatomic, copy) に変更して解決。

NSStringクラスのpropertyで、NSCFStringにはそんなselector無いよってエラーが出たら疑ってみよう。

NavigationBarのBarButtonItemに使えるIdentifier一覧

StoryBoardを学んでいて、BarButtonItemを設置することがあったのだけれど
結構種類があって使っていないと忘れてしまいそう。

せっかく色々用意してあるのだから、適宜使っていきたい。
どんなのがあるのか覚えるためにも一覧にしてみた。

Identifier Image
Custom f:id:taorun:20130512153827p:plain
Add f:id:taorun:20130512153836p:plain
Edit f:id:taorun:20130512153841p:plain
Done f:id:taorun:20130512153842p:plain
Cancel f:id:taorun:20130512153844p:plain
Save f:id:taorun:20130512153846p:plain
Undo f:id:taorun:20130512153847p:plain
Redo f:id:taorun:20130512154526p:plain
Compose f:id:taorun:20130512153850p:plain
Reply f:id:taorun:20130512153851p:plain
Action f:id:taorun:20130512153853p:plain
Organize f:id:taorun:20130512153855p:plain
Trash f:id:taorun:20130512153856p:plain
Bookmarks f:id:taorun:20130512153857p:plain
Search f:id:taorun:20130512153859p:plain
Refresh f:id:taorun:20130512153901p:plain
Stop f:id:taorun:20130512153902p:plain
Camera f:id:taorun:20130512153903p:plain
Play f:id:taorun:20130512153905p:plain
Pause f:id:taorun:20130512153907p:plain
Rewind f:id:taorun:20130512153908p:plain
Fast Forward f:id:taorun:20130512153909p:plain

cocos2d-iphonev2.1-rc2アップデートメモ

ブログまとめるの結構労力がいるので、適当にメモするくらいしておく

4th coordinated release: cocos2d-iphone v2.1-rc2 and much more

rc2の変更点はgithubのchangelogで見られる。

cocos2d-iphone/CHANGELOG at develop-v2 · cocos2d/cocos2d-iphone · GitHub

version 2.1-rc2 - 01-May-2013
. [NEW] Director: Added popToSceneStackLevel method
. [NEW] LabelTTF: Can load .ttf in runtime without adding them in the info.plist file for iOS
. [NEW] Scheduler: Added 'setPaused' / 'isPaused' property
. [FIX] DrawingPrimitives: DrawSolidCircle calls lazy_init()
. [FIX] Layer: "swallow" is now a property. Can be changed in runtime.
. [FIX] MenuItem: target is not retained when using setTarget:selector: (issue #1482)
. [FIX] ParticleSystem: renders particles OK on device (issue #1462)
. [FIX] Progress Actions: "updateProgress" is called after setting the type
. [FIX] TileMaps: tile's offset property is used
. [3RD] JS Bindings: Updated to v0.7
. [3RD] SpiderMonkey: Updated to v20.0

気になったのはこんなところ。

既にsuperviewを持っているviewを他のviewにaddSubviewした場合の振る舞い

あるUIViewがaddSubviewしたときに、すでにsuperviewを持っている(addSubviewされている)viewを貼り付けようとした場合の振る舞いを初めて知った。

UIView Class Referenceによると

UIView Class Reference

Discussion
This method retains view and sets its next responder to the receiver, which is its new superview.

Views can have only one superview. If view already has a superview and that view is not the receiver, this method removes the previous superview before making the receiver its new superview.

つまり、既にaddされているviewがもう一度他のviewにaddされそうになったとき、
親をすげ替えてくれる。


これを知らなくて、今まではわざわざremoveFromSuperviewしてから張り替えてた…
cocos2dではaddChildを連続で呼び出すとクラッシュするので、UIViewでもそうなんだろうなと勝手に思ってた。


以前もUIViewの振る舞いを知らずに同じような記事書いてる。
InsertSubviewしたときはaddSubviewはいらない - taoru's memo

ClassReference分かりやすいし一度全部読んでみようかな…

CocosBuilderのTimelineとCCActionが共存できなくてハマった

最近はCocosBuilderを使ったりして遊んでおります。

raywenderlichさんとこにもCocosBuilderTutorialがあるのですが、

日本語訳してくれた方がいるのでなんとかbuildまでこぎつけました。
CocosBuilder入門

CocosBuilderとXcodeがあればもうbuildできるとばかり思っていましたが、
buildまで到達するためにはccbiファイルを読み込むためのCCBReaderが必要で、
それはCocosBuilderには同梱されていないという罠。

なぜですかね。

CocosBuilderExampleをダウンロードして、そこからcopyしました。

ここでしばらく詰まりました。
「CCBReaderのバージョンがccbiを書きだしたCocosBuilderと違う」、といったerrorが出てbuildできませんでした。
CocosBuilder v3 alpha を使っていましたが、CCBReaderは v2.1用だったようです。

versionを合わせたらbuildできました。

Timeline Chainを設定していると、コードでCCActionをセットしても動かない

これには相当頭を悩まされている。

TimelineChain機能で無限ループさせるアニメーションを作ったときに、コードでCCMoveなどを指定してもかき消されてしまう。

例えば、以下のようなTimeline LoopアニメーションをつけたCCBファイルを用意する。

f:id:taorun:20130309031905p:plain

  • Default Timelineで1秒間で一回転させるアニメーションを付ける
  • Chain先をDefaultTImelineに指定して、無限ループさせる


そして、メインとなるSceneに先ほどのCCBを設置して再生すると、
グルグル回り続けるSpriteが表示される。

f:id:taorun:20130309032617p:plain

わーいこれは楽ちんだ!

これをCCMove等で動かせれば、CCBで基本動作を設定して
コードではユーザー操作で気軽に動かしたりできるぞ!


そう思っていた時期が私にもありました。

Timelineがループするたびに、全てのCCActionがもみ消される

最初はなんで自分で定義したCCMoveが動かないのか全然わからなかった。
コードを追っていくことで、CCBAnimationManagerというものにたどり着いた。

CCBReaderで読み込まれたオブジェクトはCCBAnimationManagerを保持している。
オブジェクトのuserObjectにアクセスすればコードで操作することも出来る。

参考:http://cbbandtqb.seesaa.net/article/300014623.html



CCBAnimationManagerが、Timelineで定義したアニメーションを実行してくれている。
その実行メソッドがこれ

- (void) runAnimationsForSequenceId:(int)seqId tweenDuration:(float) tweenDuration;

Timelineに割り当てられたSequenceIdを指定して、そのタイムラインを実行するもの。
こいつが犯人だった。

真っ先に [rootNode stopAllActions]; を呼んでいる。

なんてことしてくれるの…



とりあえずコードでアニメーションをつけたいNodeにはCocosBuilderでループアニメーションは付けず、
CCAnimationや基本となるActinoは全てコードで書きなおした。


すごく残念な気持ちになった。
なにかいい方法を知っている親切な方、教えてください。

QLOOKアクセス解析