干支がヘビだから、レトロなヘビゲームを作ってみる

(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 * blocksizeuserTap.x;

    float difY = head.y * blocksizeuserTap.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