干支がヘビだから、レトロなヘビゲームを作ってみる
(XcodeのiOS6 Simulatorで試しています。)
ポイント
・ヘビとかはNSArrayでCGPointを保持
・タップした場所に進むようにする
サンプルコード
#import “ViewController.h”
#import <QuartzCore/QuartzCore.h>
// 蛇のボディサイズ
#define blocksize 20
@interface ViewController () {
float interval;
CGPoint userTap;
CADisplayLink *timer;
NSMutableArray *fruit;
NSArray *hebi;
}
@end
@implementation ViewController
– (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
// データの初期化
[self initHebi];
[self initFruit];
[self drawMap];
// ループスタート
[self start];
}
– (void)initHebi
{
NSValue *head = [NSValue valueWithCGPoint:CGPointMake(15, 15)];
NSValue *body1 = [NSValue valueWithCGPoint:CGPointMake(15, 16)];
NSValue *body2 = [NSValue valueWithCGPoint:CGPointMake(15, 17)];
NSValue *body3 = [NSValue valueWithCGPoint:CGPointMake(15, 18)];
NSValue *body4 = [NSValue valueWithCGPoint:CGPointMake(15, 19)];
NSValue *body5 = [NSValue valueWithCGPoint:CGPointMake(15, 20)];
hebi = [NSArray arrayWithObjects:head, body1, body2, body3, body4, body5, nil];
}
– (void)initFruit
{
NSValue *fruit1 = [NSValue valueWithCGPoint:CGPointMake(10, 10)];
NSValue *fruit2 = [NSValue valueWithCGPoint:CGPointMake(5, 5)];
NSValue *fruit3 = [NSValue valueWithCGPoint:CGPointMake(10, 5)];
fruit = [NSMutableArray arrayWithObjects:fruit1, fruit2, fruit3, nil];
}
– (void)drawMap
{
// レイヤーの初期化
int count = [self.view.layer.sublayers count];
for (int i=0; i<count ; i++) {
[[self.view.layer.sublayers lastObject] removeFromSuperlayer];
}
// 蛇の頭
NSValue *head = [hebi objectAtIndex:0];
CALayer *headLayer = [CALayer layer];
CGPoint point = [self convertToViewPoint:[head CGPointValue]];
headLayer.frame = CGRectMake(point.x, point.y, blocksize, blocksize);
headLayer.backgroundColor = [UIColor whiteColor].CGColor;
headLayer.borderColor = [UIColor blackColor].CGColor;
headLayer.borderWidth = 1.0;
// 蛇の目
CALayer *eyeR = [CALayer layer];
eyeR.frame = CGRectMake(blocksize * 0.2, blocksize * 0.4, blocksize * 0.2, blocksize * 0.2);
eyeR.backgroundColor = [UIColor blackColor].CGColor;
CALayer *eyeL = [CALayer layer];
eyeL.frame = CGRectMake(blocksize * 0.6, blocksize * 0.4, blocksize * 0.2, blocksize * 0.2);
eyeL.backgroundColor = [UIColor blackColor].CGColor;
[headLayer addSublayer:eyeR];
[headLayer addSublayer:eyeL];
[self.view.layer addSublayer:headLayer];
// 蛇の体を描画
for (int i=1; i<[hebi count]; i++) {
NSValue *body = [hebi objectAtIndex:i];
CALayer *layer = [CALayer layer];
CGPoint point = [self convertToViewPoint:[body CGPointValue]];
layer.frame = CGRectMake(point.x, point.y, blocksize, blocksize);
layer.backgroundColor = [UIColor whiteColor].CGColor;
layer.borderColor = [UIColor blackColor].CGColor;
layer.borderWidth = 1.0;
[self.view.layer addSublayer:layer];
}
// フルーツの描画
for (NSValue *val in fruit) {
CALayer *layer = [CALayer layer];
CGPoint point = [self convertToViewPoint:[val CGPointValue]];
layer.frame = CGRectMake(point.x, point.y, blocksize, blocksize);
layer.backgroundColor = [UIColor orangeColor].CGColor;
[self.view.layer addSublayer:layer];
}
// タッチしたポイント
CALayer *layer = [CALayer layer];
layer.frame = CGRectMake(userTap.x, userTap.y, blocksize * 0.5, blocksize * 0.5);
layer.backgroundColor = [UIColor colorWithRed:1.0 green:0.8 blue:0.8 alpha:1.0].CGColor;
layer.cornerRadius = 5.0;
[self.view.layer addSublayer:layer];
}
– (void)start
{
timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateDisp:)];
[timer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}
– (void)updateDisp:(CADisplayLink *)sender
{
interval += sender.duration;
if (interval > 0.5) {
interval = 0.0;
// 蛇の頭を動かす
[self nextHeadPoint];
// 頭が動いた先に何かあるかチェック
[self checkMap];
// Mapの再描画
[self drawMap];
}
}
– (void)nextHeadPoint
{
// タップした場所に向けて蛇を動かす。
CGPoint head = [[hebi objectAtIndex:0] CGPointValue];
float difX = head.x * blocksize – userTap.x;
float difY = head.y * blocksize – userTap.y;
if (abs(difX) > abs(difY)) {
head.x += (difX > 0) ? –1 : 1;
} else {
head.y += (difY > 0) ? –1 : 1;
}
NSMutableArray *newHebi = [[NSMutableArray alloc] initWithCapacity:[hebi count] + 1];
[newHebi addObject:[NSValue valueWithCGPoint:head]];
for (NSValue *body in hebi) {
[newHebi addObject:body];
}
hebi = [newHebi copy];
}
– (void)newFruit
{
int xMax = 15;
int yMax = 20;
CGPoint newPoint = CGPointMake(arc4random() % xMax, arc4random() % yMax);
BOOL safePoint = YES;
// へびの上にないか
for (NSValue *val in hebi) {
CGPoint p = [val CGPointValue];
if (CGPointEqualToPoint(newPoint, p)) {
safePoint = NO;
}
}
// 既にフルーツがないか
for (NSValue *val in fruit) {
CGPoint p = [val CGPointValue];
if (CGPointEqualToPoint(newPoint, p)) {
safePoint = NO;
}
}
if (safePoint) {
[fruit addObject:[NSValue valueWithCGPoint:newPoint]];
} else {
[self newFruit];
}
}
– (void)checkMap
{
CGPoint head = [[hebi objectAtIndex:0] CGPointValue];
// へび自身にぶつかっていたらゲームオーバー
for (int i=1; i<[hebi count]; i++) {
CGPoint body = [[hebi objectAtIndex:i] CGPointValue];
if (CGPointEqualToPoint(head, body)) {
[self gameover];
return;
}
}
// フルーツを食べたら、体を大きくする
BOOL eat = NO;
for (int i=0; i<[fruit count]; i++) {
CGPoint f = [[fruit objectAtIndex:i] CGPointValue];
if (CGPointEqualToPoint(head, f)) {
// 食べたやつを消化
[fruit removeObjectAtIndex:i];
// 蛇を大きくするためにフラグをYES
eat = YES;
}
}
if (!eat) {
// 食べてなかったら、配列の最後をけす
NSMutableArray *newHebi = [hebi mutableCopy];
[newHebi removeLastObject];
hebi = [newHebi copy];
} else {
// 食べたら新しいのを出す
[self newFruit];
}
}
– (void)gameover
{
[timer invalidate];
timer = nil;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@”game over” message:@”miss” delegate:self cancelButtonTitle:@”OK” otherButtonTitles:nil];
[alert show];
}
– (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// タップした場所を、蛇の向かう場所に設定
UITouch *touch = [touches anyObject];
userTap = [touch locationInView:self.view];
}
– (CGPoint)convertToViewPoint:(CGPoint)point
{
return CGPointMake(point.x * blocksize, point.y * blocksize);
}
– (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end