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 | |
Add | |
Edit | |
Done | |
Cancel | |
Save | |
Undo | |
Redo | |
Compose | |
Reply | |
Action | |
Organize | |
Trash | |
Bookmarks | |
Search | |
Refresh | |
Stop | |
Camera | |
Play | |
Pause | |
Rewind | |
Fast Forward |
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
- popToSceneStackLevelは一度に数階層遡れるのかな?後でちゃんと調べる。
- この変更のコミットログはこれ↓
- Adds Director:popToSceneStackLevel: method · 59c5272 · cocos2d/cocos2d-iphone · GitHub
- ざっくり言うと指定した数だけループを回して[_scenesStack removeLastObject];を呼んでる
- TTFフォントがinfo.plistいじらなくても使えるように鳴ったみたい。
- この記事いらんくなった!→CCLabelTTFでカスタムフォントを使う - taoru's memo
- Layerのタッチプライオリティ操作でモーダルLayer作っていたのが、propertyで一発になった
- 中ではやっぱりregisterTouchDispatcherいじってるっぽい
- コミットログ↓ setterでsetTouchEnableを呼び出して、registerWithTouchDispatcher呼んでる
- Added touchSwallow property to CCLayer · 9f33b4b · cocos2d/cocos2d-iphone · GitHub
気になったのはこんなところ。
既にsuperviewを持っているviewを他のviewにaddSubviewした場合の振る舞い
あるUIViewがaddSubviewしたときに、すでにsuperviewを持っている(addSubviewされている)viewを貼り付けようとした場合の振る舞いを初めて知った。
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ファイルを用意する。
- Default Timelineで1秒間で一回転させるアニメーションを付ける
- Chain先をDefaultTImelineに指定して、無限ループさせる
そして、メインとなるSceneに先ほどのCCBを設置して再生すると、
グルグル回り続けるSpriteが表示される。
わーいこれは楽ちんだ!
これを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は全てコードで書きなおした。
すごく残念な気持ちになった。
なにかいい方法を知っている親切な方、教えてください。