• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
㉖cocos2dを覚えよう!
 

㉖cocos2dを覚えよう!

on

  • 6,341 views

https://www.facebook.com/TonosamaLabo

https://www.facebook.com/TonosamaLabo

Statistics

Views

Total Views
6,341
Views on SlideShare
1,686
Embed Views
4,655

Actions

Likes
3
Downloads
0
Comments
0

1 Embed 4,655

http://tonosamart.com 4655

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    ㉖cocos2dを覚えよう! ㉖cocos2dを覚えよう! Presentation Transcript

    • cocos2d 2.0for iPhone 勉強会 cocos2dを覚えよう! 初級編④
    • 動作環境•  Mac OS X 10.8 Mountain Lion•  xcode 4.5.2•  cocos2d for iPhone 2.0 http://www.cocos2d-iphone.org/
    • はじめに•  cocos2dを覚えよう!初級編④•  当たり判定とかそういうやつ!
    • もくじ•  忍ベーダー•  敵の移動•  手裏剣•  当たり判定•  点数の増加とレベル•  改造してみよう!
    • 忍ベーダー•  次々と現れる侵略者(忍ベーダー)をたおしていこう!•  忍ベーダーが、ライフラインを超えるとゲームオーバー
    • ルール•  タイトル画面でボタンを押すとゲーム開始•  READY→STARTのあと、ゲーム開始•  忍ベーダーは、上から攻めてくる。大きさによって硬さ や得点が違う•  忍者は、ボタンで左右移動•  忍者が止まると上を向いて、手裏剣を自動で打つ•  ライフラインに忍ベーダーが来たらゲームオーバー•  GAMEOVERを表示して、タイトル画面に戻る
    • 4inch対応 •  今回は画面上部の見え る部分を変更すること で対応します •  スコアなどの文字は、 画面の高さをもとに表 示して、画面内に収ま るようにします。 •  忍ベーダーや手裏剣は、 4inchの座標で計算しま す。3.5inchでも得ない 画面外の部分でも処理 を行います。
    • がめんこうせいタイトルscene メインscene
    • タイトルscene•  フロントlayer –  スコア•  タイトルlayer –  タイトルロゴ –  スタートボタン –  床•  背景layer –  背景画像
    • メインscene•  フロントlayer –  スコア•  スティックlayer –  左右のボタン•  メインlayer –  READY? 、START! –  ゲームオーバー –  忍ベーダー、手裏剣 –  忍者 –  点線、床•  背景layer –  背景画像
    • 今回作るところ •  敵が出る •  忍者が手裏剣を投げる •  あたりはんてい
    • 音楽素材について①•  音楽素材については、PANICPUMPKIN様 のご好意により、使用させていただいてい ます。•  http://panicpumpkin.omiki.com/•  ゲームBGMに特化したサイトなのでおす すめ!(曲数も多いです)•  利用報告、 著作表記、リンクなどの明記 不要で商用利用可能の音楽素材を多数公 開されています。
    • 音楽素材について②•  有料でオリジナル曲を制作してもらえる 「PANSOUND」というサイトもあるので、 ぜひ利用してみてください!•  http://pansound.com/
    • 敵の移動•  上からせまってくる忍ベーダーを作ってみ よう!
    • 忍ベーダーの仕様 •  一定間隔で上から出現 •  いろんな大きさがある •  下に移動する
    • 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
    • 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
    • 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);
    • 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;}
    • かいせつ•  sprite.scaleで大きさを変更できる(通常 は1.0f)•  画面の端から自分の大きさを引いたりして、 表示位置の最小と最大を求める•  最小と最大の間をランダムで求めて、初期 表示の位置にする!
    • かいせつ2•  speed、life、scoreを大きさを元に設定 する!•  大きいほどゆっくりで、lifeを大きくする と、良い感じになる!
    • 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];}
    • かいせつ•  CCAnimation でフレームを指定してパラ パラアニメみたいなのをする!•  CCRepeatForever で繰り返せる!•  これで、忍ベーダーがアニメーションする ようになる!
    • MainLayer.h@property float invaderDelayCount;@property (nonatomic, retain) NSMutableArray *invaderArray;
    • 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]; }
    • MainLayer.m②// 敵の移動BOOL isGameOver = NO;for (Invader *invader in self.invaderArray) { BOOL isAttack = [invader tick:dt]; if(isAttack){ isGameOver = YES; break; }}
    • かいせつ•  self.invaderDelayCountが一定の値を超 えたら、忍ベーダーを1体追加する•  忍ベーダーは、配列に入れておく!•  忍ベーダーの移動処理は、配列の中をルー プして一体ずつ行う!
    • 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;}
    • かいせつ•  移動は、自分の座標をスピード*経過時間 分減らすことで行う!•  移動後、境界線まで来てるかどうかを チェックして返却する!
    • できた!•  てきだ!
    • 手裏剣•  手裏剣を投げてみよう•  INVADERみたいにクラスを作ってもいい けど、シンプルにspriteだけで作ってみよ う!
    • 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]];
    • 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];}
    • かいせつ•  self.smallShotArrayに手裏剣を入れて管 理する!•  CCRotateBy で1回転のアニメーション を作って4連続させることでくるくるまわ す!•  shotActionEndでアニメーションが終 わったら、手裏剣を配列から消す!画面 からも消す!
    • 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]; }
    • かいせつ•  忍者が上を向いてちょっとたったら手裏剣 発射!•  手裏剣を投げたら、self.waitCount = 0; にして待ち時間をリセットする!
    • できた!•  ゲームっぽくなってき た!
    • 当たり判定•  手裏剣と敵の当たり判定をつけてみよう
    • 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];                                                                              
    • 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];
    • かいせつ①•  今回は、手裏剣の中心が忍ベーダーの当た り判定に入っているかどうかで判定! CGRectContainsPointを使う。•  当たり判定については、見た目に自然にな るように判定方法を考えよう!•  手裏剣があたったら、忍ベーダーにダメー ジを与える!
    • かいせつ②•  忍ベーダーが消滅したら消滅処理!パー ティクルを表示する!•  ps.autoRemoveOnFinish = YES;を忘れ ずに!これをYESにすると、パーティクル 消滅後自動的に終了処理が行われる!•  ループ中の配列から値を消去するには、 removeObjectsInArrayを使おう!
    • かいせつ③•  今回は、後半たくさん敵が来るので、1個 の手裏剣で複数ダメージにしてみた!•  重なっている忍ベーダすべてにダメージを あたえる!(それがいやならbreakしよ う!)
    • 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;}
    • かいせつ•  ダメージを受けたら、画像を変えて少し後 ろの位置に表示する!
    • できた!•  ゲームっぽくなってき た!
    • 点数の増加とレベル•  点数の増加に合わせて、レベルが上がるよ うにしよう!
    • 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; }}
    • かいせつ•  スコアの増加を一箇所にまとめて、スコア 増加→レベルアップの処理をおこなう!•  レベルアップするたびに、忍ベーダーの最 大の大きさと、移動速度をあげて、出現間 隔を小さくする!
    • かんせい! •  まあまあいいかんじ!
    • 改造してみよう!•  アイテムを作ってみよう!•  バランスを調整しよう!
    • アイテムを作ってみよう!•  パワーアップするアイテムを作ってみよ う!•  連射速度や、手裏剣の飛距離を変更してみ よう!•  自分の移動速度を早くしよう!•  貫通手裏剣を作ってみよう!
    • バランスを調整しよう!•  敵の出現間隔を調整しよう!•  アイテムの出る感覚を調整しよう!•  敵の速度を調整しよう!
    • かんせい! •  アップストア申請中!
    • まとめ•  簡単なゲームが出来た!•  cocos2d 1.0.の資料だけど、参考に! –  http://tonosamart.com/blog/
    • とのさまラボ!•  勉強会に参加した人どうしのコミニュティがほしい! 勉強会の開催日時の告知がほしい! という意見をみなさまからいただいたので、 コミニュティを作成しました! ぜひ「いいね!」をお願いします!https://www.facebook.com/TonosamaLabo  
    • おわり主催(共同開催):株式会社 gooyahttp://www.gooya.co.jp/メドレー株式会社http://www.medley.co.jp/講師:西田 寛輔 (Tonosamart)http://www.facebook.com/tonosamart