㉖cocos2dを覚えよう!

6,184 views
6,096 views

Published on

https://www.facebook.com/TonosamaLabo

Published in: Technology
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
6,184
On SlideShare
0
From Embeds
0
Number of Embeds
4,714
Actions
Shares
0
Downloads
0
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

㉖cocos2dを覚えよう!

  1. 1. cocos2d 2.0for iPhone 勉強会 cocos2dを覚えよう! 初級編④
  2. 2. 動作環境•  Mac OS X 10.8 Mountain Lion•  xcode 4.5.2•  cocos2d for iPhone 2.0 http://www.cocos2d-iphone.org/
  3. 3. はじめに•  cocos2dを覚えよう!初級編④•  当たり判定とかそういうやつ!
  4. 4. もくじ•  忍ベーダー•  敵の移動•  手裏剣•  当たり判定•  点数の増加とレベル•  改造してみよう!
  5. 5. 忍ベーダー•  次々と現れる侵略者(忍ベーダー)をたおしていこう!•  忍ベーダーが、ライフラインを超えるとゲームオーバー
  6. 6. ルール•  タイトル画面でボタンを押すとゲーム開始•  READY→STARTのあと、ゲーム開始•  忍ベーダーは、上から攻めてくる。大きさによって硬さ や得点が違う•  忍者は、ボタンで左右移動•  忍者が止まると上を向いて、手裏剣を自動で打つ•  ライフラインに忍ベーダーが来たらゲームオーバー•  GAMEOVERを表示して、タイトル画面に戻る
  7. 7. 4inch対応 •  今回は画面上部の見え る部分を変更すること で対応します •  スコアなどの文字は、 画面の高さをもとに表 示して、画面内に収ま るようにします。 •  忍ベーダーや手裏剣は、 4inchの座標で計算しま す。3.5inchでも得ない 画面外の部分でも処理 を行います。
  8. 8. がめんこうせいタイトルscene メインscene
  9. 9. タイトルscene•  フロントlayer –  スコア•  タイトルlayer –  タイトルロゴ –  スタートボタン –  床•  背景layer –  背景画像
  10. 10. メインscene•  フロントlayer –  スコア•  スティックlayer –  左右のボタン•  メインlayer –  READY? 、START! –  ゲームオーバー –  忍ベーダー、手裏剣 –  忍者 –  点線、床•  背景layer –  背景画像
  11. 11. 今回作るところ •  敵が出る •  忍者が手裏剣を投げる •  あたりはんてい
  12. 12. 音楽素材について①•  音楽素材については、PANICPUMPKIN様 のご好意により、使用させていただいてい ます。•  http://panicpumpkin.omiki.com/•  ゲームBGMに特化したサイトなのでおす すめ!(曲数も多いです)•  利用報告、 著作表記、リンクなどの明記 不要で商用利用可能の音楽素材を多数公 開されています。
  13. 13. 音楽素材について②•  有料でオリジナル曲を制作してもらえる 「PANSOUND」というサイトもあるので、 ぜひ利用してみてください!•  http://pansound.com/
  14. 14. 敵の移動•  上からせまってくる忍ベーダーを作ってみ よう!
  15. 15. 忍ベーダーの仕様 •  一定間隔で上から出現 •  いろんな大きさがある •  下に移動する
  16. 16. Invader.h@interface Invader : NSObject{}@property float score;@property float speed;@property float minX;@property float maxX;@property int life;@property (nonatomic, retain) CCSprite *sprite;@property (nonatomic, retain) MainLayer *mainLayer;-(BOOL)damage:(int)pow;-(BOOL)tick:(ccTime)dt;@end
  17. 17. Invader.h@interface Invader : NSObject{}@property float score;@property float speed;@property float minX;@property float maxX;@property int life;@property (nonatomic, retain) CCSprite *sprite;@property (nonatomic, retain) MainLayer *mainLayer;-(BOOL)damage:(int)pow;-(BOOL)tick:(ccTime)dt;@end
  18. 18. Invader.m①- (id)init{ if((self = [super init])){ self.sprite = [CCSprite spriteWithSpriteFrameName:@"vader.png"]; GameData *gameData = [GameData getInstance]; self.sprite.scale = (CCRANDOM_0_1() * (gameData.invaderScaleMax -gameData.invaderScaleMin)) + gameData.invaderScaleMin; self.minX = self.sprite.boundingBox.size.width / 2; self.maxX = 320 - (self.sprite.boundingBox.size.width / 2);
  19. 19. Invader.m② float ex = (CCRANDOM_0_1() * (self.maxX - self.minX)) + self.minX; float ey = 568 + (self.sprite.boundingBox.size.height / 2); self.sprite.position = ccp(ex, ey); self.speed = gameData.invaderSpeed / self.sprite.scale; self.life = (int)(self.sprite.scale * MIN_LIFE); self.score = self.life; [self animeStart]; } return self;}
  20. 20. かいせつ•  sprite.scaleで大きさを変更できる(通常 は1.0f)•  画面の端から自分の大きさを引いたりして、 表示位置の最小と最大を求める•  最小と最大の間をランダムで求めて、初期 表示の位置にする!
  21. 21. かいせつ2•  speed、life、scoreを大きさを元に設定 する!•  大きいほどゆっくりで、lifeを大きくする と、良い感じになる!
  22. 22. Invader.m③-(void)animeStart{ [self.sprite stopAllActions]; NSMutableArray *animFrames = [NSMutableArray array]; [animFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache]spriteFrameByName:@"vader.png"]]; [animFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache]spriteFrameByName:@"vader2.png"]]; CCAnimation *animation = [CCAnimationanimationWithSpriteFrames:animFrames delay:0.2f]; id repeatAnim = [CCRepeatForever actionWithAction:[CCAnimateactionWithAnimation:animation]]; [self.sprite runAction:repeatAnim];}
  23. 23. かいせつ•  CCAnimation でフレームを指定してパラ パラアニメみたいなのをする!•  CCRepeatForever で繰り返せる!•  これで、忍ベーダーがアニメーションする ようになる!
  24. 24. MainLayer.h@property float invaderDelayCount;@property (nonatomic, retain) NSMutableArray *invaderArray;
  25. 25. MainLayer.m① // 敵を出す self.invaderDelayCount += dt; if(gameData.invaderDelayMax <= self.invaderDelayCount){ self.invaderDelayCount = 0; Invader *invader = [[[Invader alloc] init] autorelease]; CCSpriteBatchNode *gameBatchNode = (CCSpriteBatchNode*)[self getChildByTag:OBJECT_GAME]; [gameBatchNode addChild:invader.spritez:SPRITE_GAME_ENEMY tag:SPRITE_GAME_ENEMY]; [self.invaderArray addObject:invader]; }
  26. 26. MainLayer.m②// 敵の移動BOOL isGameOver = NO;for (Invader *invader in self.invaderArray) { BOOL isAttack = [invader tick:dt]; if(isAttack){ isGameOver = YES; break; }}
  27. 27. かいせつ•  self.invaderDelayCountが一定の値を超 えたら、忍ベーダーを1体追加する•  忍ベーダーは、配列に入れておく!•  忍ベーダーの移動処理は、配列の中をルー プして一体ずつ行う!
  28. 28. invader.m-(BOOL)tick:(ccTime)dt{ float x = self.sprite.position.x; float y = self.sprite.position.y - (self.speed * dt); self.sprite.position = ccp(x, y); // 侵略判定 float dy = self.sprite.position.y -(self.sprite.boundingBox.size.height / 2); if(dy <= GAMEOVER_LINE){ return YES; } return NO;}
  29. 29. かいせつ•  移動は、自分の座標をスピード*経過時間 分減らすことで行う!•  移動後、境界線まで来てるかどうかを チェックして返却する!
  30. 30. できた!•  てきだ!
  31. 31. 手裏剣•  手裏剣を投げてみよう•  INVADERみたいにクラスを作ってもいい けど、シンプルにspriteだけで作ってみよ う!
  32. 32. MainLayer.m①-(void)shotAction:(CGPoint)startPos{ if([self.smallShotArray count] >= SHOT_MAX){ return; } CCSprite *sp = [CCSprite spriteWithSpriteFrameName:@"shot1.png"]; sp.position = ccp(startPos.x, startPos.y + 24.0f + 20.0f); CCSpriteBatchNode *gameBatchNode = (CCSpriteBatchNode*)[self getChildByTag:OBJECT_GAME]; [gameBatchNode addChild:sp z:SPRITE_GAME_SHOT]; NSMutableArray* actions = [NSMutableArray array]; [actions addObject:[CCSpawn actions: [CCMoveTo actionWithDuration:2.0f position:ccp(sp.position.x, 500)], [CCSequence actions: [CCRotateBy actionWithDuration:0.5f angle:360], [CCRotateBy actionWithDuration:0.5f angle:360], [CCRotateBy actionWithDuration:0.5f angle:360], [CCRotateBy actionWithDuration:0.5f angle:360], nil], nil]];
  33. 33. MainLayer.m② [actions addObject:[CCCallFuncN actionWithTarget:selfselector:@selector(shotActionEnd:)]]; id action; action = [CCSequence actionWithArray:actions]; [sp runAction:action]; [self.smallShotArray addObject:sp];}-(void)shotActionEnd:(id)node{ [self.smallShotArray removeObject:node]; [node removeFromParentAndCleanup:YES];}
  34. 34. かいせつ•  self.smallShotArrayに手裏剣を入れて管 理する!•  CCRotateBy で1回転のアニメーション を作って4連続させることでくるくるまわ す!•  shotActionEndでアニメーションが終 わったら、手裏剣を配列から消す!画面 からも消す!
  35. 35. Ninja.mself.waitCount += dt; if(self.way != NINJYA_WAY_UP && self.waitCount >=NINJA_UP_DELAY){ self.waitCount = 0; CCSpriteFrame *sf = [[CCSpriteFrameCachesharedSpriteFrameCache]spriteFrameByName:@"ninjya_u.png"]; [self.sprite setDisplayFrame:sf]; self.way = NINJYA_WAY_UP; } if(self.way == NINJYA_WAY_UP && self.waitCount >=SHOT_DELAY){ self.waitCount = 0; [self.mainScene.mainLayershotAction:self.sprite.position]; }
  36. 36. かいせつ•  忍者が上を向いてちょっとたったら手裏剣 発射!•  手裏剣を投げたら、self.waitCount = 0; にして待ち時間をリセットする!
  37. 37. できた!•  ゲームっぽくなってき た!
  38. 38. 当たり判定•  手裏剣と敵の当たり判定をつけてみよう
  39. 39. MainLayer.m① //  弾の処理 NSMutableArray  *delShotSpriteArray  =  [NSMutableArray  array];          NSMutableArray  *delInvaderArray  =  [NSMutableArray  array];          for(CCSprite  *shotSprite  in  self.smallShotArray){                  BOOL  isDelShot  =  NO;                  //  攻撃                for  (Invader  *invader  in  self.invaderArray)  {                          //  if(CGRectIntersectsRect(shotSprite.boundingBox,  invader.sprite.boundingBox)){                          if(CGRectContainsPoint(invader.sprite.boundingBox,  shotSprite.position)){                                  BOOL  isDel  =  [invader  damage:SHOT_SMALL_POW];                                  if(isDel){                                          CCParticleSystem  *  ps  =  [CCParticleSystemQuad  particleWithFile:@"fire.plist"];                                          ps.position  =  invader.sprite.position;                                          ps.scale  =  invader.sprite.scale  *  0.5f;                                          ps.autoRemoveOnFinish  =  YES;                                          [self  addChild:ps  z:SPRITE_GAME_PARTICLE];                                                                              
  40. 40. MainLayer.m②  [delInvaderArray  addObject:invader];                                          [invader.sprite  removeFromParentAndCleanup:YES];                                                                                    [[SimpleAudioEngine  sharedEngine]playEffect:@"xout.caf"];                                  }else{                                          [[SimpleAudioEngine  sharedEngine]playEffect:@"xhit.caf"];                                  }                                  isDelShot  =  YES;                          }                  }                  [self.invaderArray  removeObjectsInArray:delInvaderArray];                  [delInvaderArray  removeAllObjects];                    //  弾を削除                if(isDelShot){                          [delShotSpriteArray  addObject:shotSprite];                          [shotSprite  removeFromParentAndCleanup:YES];                  }          }          [self.smallShotArray  removeObjectsInArray:delShotSpriteArray];
  41. 41. かいせつ①•  今回は、手裏剣の中心が忍ベーダーの当た り判定に入っているかどうかで判定! CGRectContainsPointを使う。•  当たり判定については、見た目に自然にな るように判定方法を考えよう!•  手裏剣があたったら、忍ベーダーにダメー ジを与える!
  42. 42. かいせつ②•  忍ベーダーが消滅したら消滅処理!パー ティクルを表示する!•  ps.autoRemoveOnFinish = YES;を忘れ ずに!これをYESにすると、パーティクル 消滅後自動的に終了処理が行われる!•  ループ中の配列から値を消去するには、 removeObjectsInArrayを使おう!
  43. 43. かいせつ③•  今回は、後半たくさん敵が来るので、1個 の手裏剣で複数ダメージにしてみた!•  重なっている忍ベーダすべてにダメージを あたえる!(それがいやならbreakしよ う!)
  44. 44. Invader.m-(BOOL)damage:(int)pow{ self.life -= pow; self.sprite.position = ccp(self.sprite.position.x, self.sprite.position.y +32.0f); CCSpriteFrame *sf = [[CCSpriteFrameCachesharedSpriteFrameCache] spriteFrameByName:@"vader_hit.png"]; [self.sprite setDisplayFrame:sf]; if(self.life <= 0){ GameData *gameData = [GameData getInstance]; [gameData addScore:self.score]; return YES; } return NO;}
  45. 45. かいせつ•  ダメージを受けたら、画像を変えて少し後 ろの位置に表示する!
  46. 46. できた!•  ゲームっぽくなってき た!
  47. 47. 点数の増加とレベル•  点数の増加に合わせて、レベルが上がるよ うにしよう!
  48. 48. GameData.m-(void)resetScore{ self.score = 0; self.exp = 0; self.level = 1; self.invaderScaleMin = 1.0f; self.invaderScaleMax = 1.0f; self.invaderDelayMax = 2.0f; self.invaderSpeed = 90;}-(void)addScore:(int)point{ self.score += point; self.exp++; if(self.level < (self.exp / 10)){ self.level++; self.invaderScaleMax += 0.3f; self.invaderDelayMax -= 0.25f; self.invaderSpeed += 5; }}
  49. 49. かいせつ•  スコアの増加を一箇所にまとめて、スコア 増加→レベルアップの処理をおこなう!•  レベルアップするたびに、忍ベーダーの最 大の大きさと、移動速度をあげて、出現間 隔を小さくする!
  50. 50. かんせい! •  まあまあいいかんじ!
  51. 51. 改造してみよう!•  アイテムを作ってみよう!•  バランスを調整しよう!
  52. 52. アイテムを作ってみよう!•  パワーアップするアイテムを作ってみよ う!•  連射速度や、手裏剣の飛距離を変更してみ よう!•  自分の移動速度を早くしよう!•  貫通手裏剣を作ってみよう!
  53. 53. バランスを調整しよう!•  敵の出現間隔を調整しよう!•  アイテムの出る感覚を調整しよう!•  敵の速度を調整しよう!
  54. 54. かんせい! •  アップストア申請中!
  55. 55. まとめ•  簡単なゲームが出来た!•  cocos2d 1.0.の資料だけど、参考に! –  http://tonosamart.com/blog/
  56. 56. とのさまラボ!•  勉強会に参加した人どうしのコミニュティがほしい! 勉強会の開催日時の告知がほしい! という意見をみなさまからいただいたので、 コミニュティを作成しました! ぜひ「いいね!」をお願いします!https://www.facebook.com/TonosamaLabo  
  57. 57. おわり主催(共同開催):株式会社 gooyahttp://www.gooya.co.jp/メドレー株式会社http://www.medley.co.jp/講師:西田 寛輔 (Tonosamart)http://www.facebook.com/tonosamart

×