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

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

サンプルプログラム「はしごゲーム」の基礎【Xcode5】iOS7

f:id:tadakazu1972:20140113111718p:plain

「ロー○ランナー」っぽいゲーム作りたくなりませんか?80年代はこのタイプのゲームいっぱいありました。
以前、迷路ゲームの基礎を作ったので簡単だろうと思っていましたが、予想以上にてこずりました…;
結構、移動処理の順番にも気を使わないといけなかったです。なお、これでもまだときどきカベにめり込むことを確認しているのでご注意を。
プロジェクトを立ち上げる処理は前回の記事を参照してください。慣れれば毎度同じ手順なのでサッサとできるようになります。
画像ファイルは前回と違って、3つとも32pixelx32pixelで用意してください。
browntile.png, ladder.png, kumako01.png
なので、以下はキモとなる2つのファイルのみ掲載します。

LadderKumakoView.h

//
//  LadderKumakoView.h
//  LadderKumako
//
//  Created by 中道 忠和 on 2014/01/11.
//  Copyright (c) 2014年 中道 忠和. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface LadderKumakoView : UIView {
    int WIDTH;
    int HEIGHT;
    CGContextRef context;
    NSMutableArray* draw;
    
    CGPoint lastPoint;
    
    float px; // prayer x position
    float py; // prayer y position
    float vx;
    float vy;
    float ay;
    
    int MAP[15][10];
    float mx1,mx2,mx3,mx4,mx5,mx6,mx7,mx8;  // MAP x
    float my1,my2,my3,my4,my5,my6,my7,my8;  // MAP y
    
    int touch_direction; // 0:stop 1:up 2:right 3:down 4:left
}

@end

LadderKumakoView.m

//
//  LadderKumakoView.m
//  LadderKumako
//
//  Created by 中道 忠和 on 2014/01/11.
//  Copyright (c) 2014年 中道 忠和. All rights reserved.
//

#import "LadderKumakoView.h"

@implementation LadderKumakoView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
    }
    return self;
}

-(id)initWithCoder:(NSCoder*)coder {
    self=[super initWithCoder:coder];
    if (self) {
        CGRect bounds=[[UIScreen mainScreen] bounds];
        WIDTH = bounds.size.width;
        HEIGHT= bounds.size.height;
        // 画面の準備
        context=NULL;
        
        // キャラクターの絵を準備
        draw=[NSMutableArray array];                      //配列を設定
        
        [ draw addObject:[UIImage imageNamed:@"browntile.png"]];//0
        [ draw addObject:[UIImage imageNamed:@"ladder.png"]];   //1
        [ draw addObject:[UIImage imageNamed:@"kumako01.png"]]; //2
        
        // タイマーの準備
        [NSTimer scheduledTimerWithTimeInterval:0.01f target:self selector:@selector(onTick:) userInfo:nil repeats:YES];
        
        // くまちゃんの準備
        px=0.0f;   //最初のX座標
        py=0.0f; //最初のY座標
        vx=0.0f;   //最初のX座標の移動量
        vy=0.0f;  //最初のY座標の移動量
        ay=1.0f;
        
        // ステージ
        int map[15][10]={
            0,0,0,0,0,0,0,0,0,0,
            0,2,1,1,1,1,1,1,1,2,
            0,2,0,0,0,0,0,0,0,2,
            0,2,0,0,0,0,0,0,0,2,
            0,1,1,1,1,0,0,0,0,2,
            0,0,0,0,0,0,0,0,0,2,
            1,0,0,0,0,2,1,1,1,1,
            1,1,0,0,0,2,0,0,0,0,
            1,1,1,2,0,2,0,0,0,0,
            0,0,0,2,0,1,1,1,2,1,
            0,0,0,2,0,0,0,0,2,0,
            0,2,1,1,1,0,0,0,2,0,
            0,2,0,0,0,0,2,1,1,1,
            0,2,0,0,0,0,2,0,0,0,
            1,1,1,1,1,1,1,1,1,1
        };
        
        // グローバル変数に読み込ませる
        for (int j=0;j<15;j++) {
            for (int i=0;i<10;i++) {
                MAP[j][i]=map[j][i];
            }
        }
        
        // その他変数 初期設定
        touch_direction=0;
        
    }
    return self;
}

- (void)drawRect:(CGRect)rect
{
    // Drawing code
    // 画面の準備(まあ、呪文のようなものです。アブダカダブラ。)
    if (context!=NULL) {
        CGContextRelease(context);
        context=NULL;
    }
    context=UIGraphicsGetCurrentContext();
    CGContextRetain(context);
    
    // 画面を真っ黒に塗って、全部消す。(それからあとで背景とキャラクターを高速で描くから、アニメーションに見える)
    CGContextSetRGBFillColor(context,0,0,0,1);
    CGContextSetRGBStrokeColor(context,0,0,0,1);
    CGContextFillRect(context,CGRectMake(0,0,WIDTH,HEIGHT));
    
    // iPhone5以降の時は、画面の下にバナーを出すようにする。(もともとiphone4Sの画面サイズでつくってたから、すきまができてしまう)
    if ([[UIScreen mainScreen] bounds].size.height == 568){
        //[[p_bmp objectAtIndex:5] drawAtPoint:(CGPointMake(0,455))];    //バナーを描画
    }
    
    // ステージの描画
    for (int j=0;j<15; j++) {
        for (int i=0; i<10; i++) {
            int mapid=MAP[j][i];
            if (mapid==1) [[draw objectAtIndex:0] drawAtPoint:(CGPointMake(i*32.0f,j*32.0f))];
            if (mapid==2) [[draw objectAtIndex:1] drawAtPoint:(CGPointMake(i*32.0f,j*32.0f))];
        }
    }
    
    // TEXT
    NSString* s1=[NSString stringWithFormat:@"px=%f, py=%f", px,py];
    NSString* s2=[NSString stringWithFormat:@"mx5=%f, my5=%f", mx5,my5];
    NSString* s4=[NSString stringWithFormat:@"mx6=%f, my6=%f", mx6,my6];
    NSString* s3=[NSString stringWithFormat:@"MAP[Y][X]=%d", MAP[(int)my5][(int)mx5]];
    [[UIColor whiteColor] set];
    UIFont* font = [UIFont boldSystemFontOfSize:14];
    [s1 drawAtPoint:CGPointMake(0,480) withFont:font];
    [s2 drawAtPoint:CGPointMake(0,500) withFont:font];
    [s4 drawAtPoint:CGPointMake(0,520) withFont:font];
    [s3 drawAtPoint:CGPointMake(0,540) withFont:font];
    
    // くまちゃんの描画
    [[draw objectAtIndex:2] drawAtPoint:(CGPointMake(px,py))];
    
    // くまちゃん移動処理
    if (touch_direction==0) vx= 0.0f; vy=0.0f;
    
    //移動するも何も、まずそもそも足下に地面はあるんか
    mx7 =(px+4.0f)/32.0f;  //左下x座標+4pixel:くまちゃんのグラフィックにあわせて少し幅を狭める
    my7 =(py+32.0f)/32.0f; //左下y座標+1:足下をみるために+1pixel
    mx8 =(px+27.0f)/32.0f; //右下x座標
    my8 =(py+32.0f)/32.0f; //右下y座標+4
    //左下+1と右下+1ともに何かあるんだったら重力加速度を0にして、左右移動の処理へ
    if (MAP[(int)my7][(int)mx7]!=0 || MAP[(int)my8][(int)mx8]!=0) {
        vy=0.0f; ay=0.0f;
        //右
        if (touch_direction==2) {
            //カベはあるか
            mx1 =(px+32.0f)/32.0f;
            my1 =(py+0.0f)/32.0f;
            mx2 =(px+32.0f)/32.0f;
            my2 =(py+31.0f)/32.0f;
            if (MAP[(int)my1][(int)mx1]==1 || MAP[(int)my2][(int)mx2]==1) {
                vx=0.0f;
            } else {
                vx=1.0f;
            }
        }
        //左
        if (touch_direction==4) {
            //左に移動する際にカベはあるか
            mx3 =(px-1.0f)/32.0f;
            my3 =(py+4.0f)/32.0f;
            mx4 =(px-1.0f)/32.0f;
            my4 =(py+27.0f)/32.0f;
            if (MAP[(int)my3][(int)mx3]==1 || MAP[(int)my4][(int)mx4]==1) {
                vx=0.0f;
            } else {
                vx=-1.0f;
            }
        }
    } else { //足下が空間だから左右移動させないよ
        vx=0.0f;
    }
    
    px=px+vx;
    if (px>288) px=288;
    if (px<0)   px=0;
    
    //上
    if (touch_direction==1) {
        //はしごはあるか
        mx5 =(px+16.0f)/32.0f;
        my5 =(py+0.0f)/32.0f;
        mx6 =(px+16.0f)/32.0f;
        my6 =(py+31.0f)/32.0f; //この座標がミソ
        if (MAP[(int)my5][(int)mx5]==2 || MAP[(int)my6][(int)mx6]==2) {
            vy=-1.0f; vx=0.0f;
        } else {
            vy=0.0f;
        }
    }

    //下
    if (touch_direction==3) {
        //はしごはあるか
        mx7 =(px+8.0f)/32.0f;
        my7 =(py+0.0f)/32.0f;
        mx8 =(px+23.0f)/32.0f;
        my8 =(py+32.0f)/32.0f;
        if (MAP[(int)my7][(int)mx7]==2 || MAP[(int)my8][(int)mx8]==2) {
            vy=1.0f; vx=0.0f;
            //でも足下がカベの場合はストップ!
            if (MAP[(int)my8][(int)mx8]==1) vy=0.0f;
        } else {
            vy=0.0f;
        }
    }
   
    py=py+vy+ay;
    
    //あらためて移動量セット
    ay=1.0f;
    
}

// タイマー
-(void)onTick:(NSTimer*)timer {
    [self setNeedsDisplay];
}

// タッチパネル操作
-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
    lastPoint = [[touches anyObject] locationInView:self.superview];
}

-(void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
    // タッチした座標を取得
    CGPoint p=[[touches anyObject] locationInView:self.superview];
    
    // タッチ操作量はX方向とY方向のどちらが多いか絶対値で比較する(lastPointとpの座標を取得する構造がゆえに)
    float temp_vx, temp_vy;
    temp_vx=abs(lastPoint.x-p.x);
    temp_vy=abs(lastPoint.y-p.y);
    
    if (temp_vx > temp_vy) {
        if (lastPoint.x-p.x<0) {
            touch_direction=2;
        } else {
            touch_direction=4;
        }
    } else {
        if (lastPoint.y-p.y<0) {
            touch_direction=3;
        } else {
            touch_direction=1;
        }
    }
    
    // さっき取得したタッチの座標をラストポイントに書き換えておく。
    lastPoint = p;
}

-(void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
    //touch_direction=0;
}

-(void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
    [self touchesEnded:touches withEvent:event];
}

@end

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