ドラクエ的RPGの基礎 マップの描画&当たり判定【Xcode5, iOS7】
以前にもエントリしましたが、以下の対応をしました。
・Xcode5, iOS7対応
・画面スクロール対応(画面端から2キャラ分先へ移動しようとすると上下左右スクロールする)
・当たり判定(海や山は移動できない)
これでいくらでもやる気になれば広大な世界を創造できますね。
ダンジョンや塔、城などはマップの配列をもう1次元追加すればよいだけですし。
DragonHackerView.h
// // DragonHackerView.h // DragonHacker // // Created by 中道 忠和 on 2014/02/22. // Copyright (c) 2014年 中道 忠和. All rights reserved. // #import <UIKit/UIKit.h> @interface DragonHackerView : UIView { int WIDTH; int HEIGHT; CGContextRef context; NSMutableArray* draw; CGPoint lastPoint; int MAP[20][20]; float mapx; float mapy; struct mapcollision { float l; float r; float t; float b; }; struct mapcollision m; int touch_direction; // 0:stop 1:up 2:right 3:down 4:left struct mycharacter { float x; float y; float vx; float vy; float wx; //world x float wy; float l; float r; float t; float b; }; struct mycharacter p; int gs; } @end
DragonHackerView.m
// // DragonHackerView.m // DragonHacker // // Created by 中道 忠和 on 2014/02/22. // Copyright (c) 2014年 中道 忠和. All rights reserved. // #import "DragonHackerView.h" @implementation DragonHackerView - (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:@"banner.png"]]; //0 [ draw addObject:[UIImage imageNamed:@"kumako01.png"]];//1 [ draw addObject:[UIImage imageNamed:@"sea.png"]]; //2 [ draw addObject:[UIImage imageNamed:@"mountain.png"]];//3 [ draw addObject:[UIImage imageNamed:@"green.png"]]; //4 [ draw addObject:[UIImage imageNamed:@"earth.png"]]; //5 //マイキャラの準備 p.x=160.0f; //最初のX座標 p.y=240.0f; //最初のY座標 p.vx=0.0f; //最初のX座標の移動量 p.vy=0.0f; //最初のY座標の移動量 p.wx=160.0f; p.wy=240.0f; p.l=p.x; //当たり判定の設定 p.r=p.x+31.0f; p.t=p.y; p.b=p.y+31.0f; // マップの準備 [self setMap]; // その他変数 初期設定 touch_direction=0; gs=1; // 画面再描画タイマーの準備 [NSTimer scheduledTimerWithTimeInterval:0.01f target:self selector:@selector(onTick:) userInfo:nil repeats:YES]; } return self; } - (void)drawRect:(CGRect)rect { // 画面の準備(まあ、呪文のようなものです。アブダカダブラ。) 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)); //通常ゲーム処理**************************************************************************************** if (gs==1) { //マップの描画 [self drawMap]; //マイキャラの描画 [self drawMycharacter]; //データ表示************************************************************************************************** // iPhone5以降の時は、画面の下にバナーを出す if ([[UIScreen mainScreen] bounds].size.height == 568){ //[[draw objectAtIndex:0] drawAtPoint:(CGPointMake(0,481))]; //バナーを描画 } } else if (gs==2) { } } //マップ設定 -(void)setMap { int map[20][20]={ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,2,2,2,3,2,2,2,2,0,0,2,2,1,1,1,1,1,1,0, 0,2,2,2,3,2,2,2,2,0,0,2,1,1,1,2,2,1,0,0, 0,2,2,2,3,3,2,2,2,2,0,2,1,3,3,2,2,1,0,0, 0,2,2,2,2,3,3,2,2,2,0,2,1,1,3,3,3,1,0,0, 0,0,2,2,2,2,3,2,2,2,0,2,1,1,3,3,3,1,1,0, 0,0,2,2,2,2,3,2,2,2,0,2,1,2,3,3,3,1,1,0, 0,0,2,2,2,2,3,1,1,1,0,2,1,2,3,3,3,1,1,0, 0,2,2,2,2,2,3,1,1,1,0,2,2,2,2,3,3,3,1,0, 0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,0, 0,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,0, 0,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,0, 0,0,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,0, 0,0,0,0,0,0,0,0,2,2,2,2,3,3,3,3,1,1,1,0, 0,0,1,1,1,1,1,0,2,2,3,3,3,3,3,3,3,0,0,0, 0,1,1,1,1,1,1,0,2,2,3,3,3,3,3,3,3,0,0,0, 0,1,2,2,2,2,2,1,0,2,3,3,3,3,3,3,3,0,0,0, 0,1,2,1,1,1,2,2,2,2,2,3,3,3,3,3,3,1,0,0, 0,1,2,0,0,1,1,1,0,0,0,0,3,2,1,1,1,1,1,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; for (int j=0;j<20;j++) { for (int i=0;i<20;i++) MAP[j][i]=map[j][i]; } mapx=0.0f; mapy=0.0f; m.l=p.x; m.r=p.x+31.0f; m.t=p.t; m.b=p.b; } //マップ描画 -(void)drawMap { for (int j=0;j<20;j++) { for (int i=0;i<20;i++) { int mapid=MAP[j][i]; if (mapid==0) [[draw objectAtIndex:2] drawAtPoint:(CGPointMake(i*32+mapx,j*32+mapy))]; if (mapid==1) [[draw objectAtIndex:3] drawAtPoint:(CGPointMake(i*32+mapx,j*32+mapy))]; if (mapid==2) [[draw objectAtIndex:4] drawAtPoint:(CGPointMake(i*32+mapx,j*32+mapy))]; if (mapid==3) [[draw objectAtIndex:5] drawAtPoint:(CGPointMake(i*32+mapx,j*32+mapy))]; } } } //マイキャラ処理 -(void)drawMycharacter { //マイキャラ描画 [[draw objectAtIndex:1] drawAtPoint:(CGPointMake(p.x,p.y))]; //マイキャラ移動処理 //タッチ操作の方向に応じて移動量を代入しておく //if (touch_direction==0) { p.vx= 0.0f; p.vy=0.0f; } if (touch_direction==1) { p.vy=-1.0; p.vx=0.0f; } if (touch_direction==2) { p.vx= 1.0f; p.vy=0.0f; } if (touch_direction==3) { p.vy= 1.0f; p.vx=0.0f; } if (touch_direction==4) { p.vx=-1.0f; p.vy=0.0f;} //まず当たり判定を移動させる(ワールド座標を使用することに留意) p.l=p.wx+p.vx; p.r=p.wx+31.0f+p.vx; p.t=p.wy+p.vy; p.b=p.wy+31.0f+p.vy; //当たり判定用マップ座標を計算 m.l=p.l/32.0f; if (m.l<0) m.l=0; //配列添字オーバー防止 m.r=p.r/32.0f; if (m.r>19) m.r=19; m.t=p.t/32.0f; if (m.t<0) m.t=0; m.b=p.b/32.0f; if (m.b>19) m.b=19; //カベ判定 if (MAP[(int)m.t][(int)m.l]<2 || MAP[(int)m.t][(int)m.r]<2 || MAP[(int)m.b][(int)m.l]<2 || MAP[(int)m.b][(int)m.r]<2) { //カベがあるので移動量をリセット p.l=p.wx-p.vx; p.r=p.wx+31.0f-p.vx; p.t=p.wy-p.vy; p.b=p.wy+31.0f-p.vy; p.vx=0.0f; p.vy=0.0f; } //マップスクロール処理 p.x=p.x+p.vx; if (p.x<64.0f) { p.x=64.0f; mapx++; if (mapx>64.0f) mapx=64.0f; } if (p.x>224.0f) { p.x=224.0f; mapx--; if (mapx<-384.0f) mapx=-384.0f; } p.y=p.y+p.vy; if (p.y<64.0f) { p.y=64.0f; mapy++; if (mapy>64.0f) mapy=64.0f; } if (p.y>384.0f) { p.y=384.0f; mapy--; if (mapy<-224.0f) mapy=-224.0f; } //ワールド座標処理 p.wx=p.wx+p.vx; if (p.wx<0.0f) p.wx=0.0f; if (p.wx>640.0f) p.wx=640.0f; p.wy=p.wy+p.vy; if (p.wy<0.0f) p.wy=0.0f; if (p.wy>640.0f) p.wy=640.0f; } // 画面再描画 -(void)onTick:(NSTimer*)timer { [self setNeedsDisplay]; } // タッチ操作 -(void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event { // タッチした座標を取得 CGPoint point=[[touches anyObject] locationInView:self.superview]; // タッチ操作量はX方向とY方向のどちらが多いか絶対値で比較する(lastPointとpの座標を取得する構造がゆえに) float temp_vx, temp_vy; temp_vx=abs(lastPoint.x-point.x); temp_vy=abs(lastPoint.y-point.y); if (temp_vx > temp_vy) { if (lastPoint.x-point.x<0) { touch_direction=2; } else { touch_direction=4; } } else { if (lastPoint.y-point.y<0) { touch_direction=3; } else { touch_direction=1; } } // さっき取得したタッチの座標をラストポイントに書き換えておく。 lastPoint = point; } -(void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { touch_direction=0; } -(void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event { } @end
https://itunes.apple.com/jp/app/kumachanjanpu2/id789138227?mt=8&uo=4&at=10l8JW&ct=hatenablog