くまちゃんのiOS/Androidゲームプログラミング

マイペースでゲームつくってます。

「縦シューティング」敵出現テーブルの追加【Xcode5, iOS7】

f:id:tadakazu1972:20140209170626p:plain
先週の状態からモロモロ追加し、縦シューティングのほぼ土台はできあがった感があります。
・複数の種類の敵が現れる、出現数も指定できる
・ボス登場、ショットが当たるとダメージエフェクト、大破する演出
・ボスの弾幕発射
あとは地上物を追加すれば、プログラム的にはほぼゼビ○スの基礎システムはできあがりじゃないでしょうかね。
その後は敵の種類と動きを増やす、グラフィック、サウンド、マップと「調整」のフェーズに入っていくので。

そして、ここまででソースはかなりの長さ&思いつくままコードを書いているのでだいぶ「読みづらく」なってきてしまい、以前と同様に全文掲載はかなり無理があるようになってきてしまいました。

ですので、今回のキモは「敵出現テーブル」の実装のみ抜粋で掲載します。部分だけではなんのこっちゃわからないかもしれませんが、エッセンスだけでも何かの足しになればと思います。
ポイントは、タイマー使って敵出現テーブル読みに行って、敵配列に出現する敵のデータをセットし、メインのループで描画と移動処理をする、ということです。イメージとしては敵を配置する空きスロット(配列)を最大100個用意しておいて、出撃する敵をその空きに順次送り込んでいく、というものなのですが…。うーん、伝わらないかな…;あと、このアルゴリズムでは配列をすべて使い切ったときに先頭に戻るのでもしその時にまだ画面に敵が存在すれば一気に消えてしまうという難点があります。まあ、配列を増やせばいいだけですが。

蛇足ですが、正直もうここまで来るとリアルで対面で会って解説でもしないとプログラム解説ってやってられない、と思う長さと複雑さになってきました。これまで何冊もの本を読んでも満足できなかったのですが「ああ、こりゃ無理があるわ」と思うようになってきましたね…。プログラムってコツを掴んだらあとはとんとん、と進むようになるのですが。「車輪の再発明」のムダは省きたいのが人情ですが、やはりプログラミングのスキルを一番成長させるのは自分で考えてコーディングすることなんですよね。月並みですが。

ヘッダファイル

    int ENEMYTABLE[5][2];
    int table_counter;
    int enemy_type;
    int enemy_number;
    int enemy_startslot;

インプリメントファイル

-(id)initWithCoder:(NSCoder*)coder {
// 略
// 敵テーブルの設定
        int enemytable[5][2]={
            1,10,
            2,10,
            1,20,
            2,20,
            2,50
        };
        for (int et=0;et<5;et++) {
            ENEMYTABLE[et][0]=enemytable[et][0];
            ENEMYTABLE[et][1]=enemytable[et][1];
        }
        table_counter=0;
        enemy_type=ENEMYTABLE[0][0];
        enemy_number=ENEMYTABLE[0][1];

 // タイマー(敵の出撃)の準備
        [NSTimer scheduledTimerWithTimeInterval:5.0f target:self selector:@selector(launchEnemy:) userInfo:nil repeats:YES];
}

//いっぱい省略

//タイマー(敵の出撃)
-(void)launchEnemy:(NSTimer*)timer {
    // 敵テーブルからデータの読み込み
    enemy_type=ENEMYTABLE[table_counter][0];
    enemy_number=ENEMYTABLE[table_counter][1];
    for (int i=enemy_startslot;i<enemy_startslot+enemy_number;i++) {
        [self setEnemy:i];
    }
    enemy_startslot=enemy_startslot+enemy_number;
    if (enemy_startslot>49) enemy_startslot=0;
    table_counter=table_counter+1;
    if (table_counter>4) table_counter=0;
}

// 敵の再設定
-(void)setEnemy:(int)i {
    if (enemy_type==1) {
        a[i].i=2;
        a[i].x=rand()%320;
        a[i].xtr=(-1*M_PI)/2;
        a[i].y=(-1)*rand()%64;
        a[i].ytr=(-1*M_PI)/2;
        a[i].dd=alien_speed;
        a[i].wx=WX;
        a[i].wy=WY;
        a[i].dr=M_PI*a[i].dd/180;
        a[i].l=a[i].x+4.0f;
        a[i].r=a[i].x+27.0f;
        a[i].t=a[i].y+4.0f;
        a[i].b=a[i].y+27.0f;
        a[i].visible=1;
    } else if (enemy_type==2) {
        a[i].i=3;
        a[i].x=rand()%320;
        a[i].xtr=2*M_PI;
        a[i].y=(-1)*rand()%64;
        a[i].ytr=2*M_PI;
        a[i].dd=alien_speed;
        a[i].wx=WX;
        a[i].wy=WY;
        a[i].dr=M_PI*a[i].dd/180;
        a[i].l=a[i].x+4.0f;
        a[i].r=a[i].x+27.0f;
        a[i].t=a[i].y+4.0f;
        a[i].b=a[i].y+27.0f;
        a[i].visible=1;
    }
}

https://itunes.apple.com/jp/app/kumachanjanpu2/id789138227?mt=8&uo=4&at=10l8JW&ct=hatenablog