iPhoneナインボール

ビリーヤードの定番、ナインボールを模したシンプルなiPhoneゲームのサンプルコードを書いてみます。


サンプルを動画で確認

サンプルコード

#import “ViewController.h”

#import <SpriteKit/SpriteKit.h>

@protocol BallDelegate <NSObject>

– (void)selectBall:(UIColor*)ballColor;

@end

@interface BallScene : SKScene

@property BOOL contentCreated;

@property SKNode *selected;

@property (strong, nonatomic) id<BallDelegate> balldelegate;

– (void)hitAtAngle:(float)angle impulse:(float)impulse;

@end

@implementation BallScene

– (void)didMoveToView:(SKView *)view

{

    if (!self.contentCreated) {

        [self createSceneContents];

        self.contentCreated = YES;

    }

}

– (void)createSceneContents

{

    self.backgroundColor = [UIColor greenColor];

    self.physicsWorld.gravity = CGVectorMake(0, 0);

    [self createWall];

    [self createPocket];

    [self createBall];

}

– (void)createWall

{

    CGRect wallRects[] = {

        CGRectMake(0, 0, 10, 320),

        CGRectMake(0, 0, 320, 10),

        CGRectMake(310, 0, 10, 320),

        CGRectMake(0, 310, 320, 10),

    };

    

    for (int i=0; i<4; i++) {

        SKSpriteNode *wall = [SKSpriteNode spriteNodeWithColor:[SKColor brownColor] size:wallRects[i].size];

        wall.position = CGPointMake(CGRectGetMidX(wallRects[i]), CGRectGetMidY(wallRects[i]));

        [self addChild:wall];

        wall.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:wall.size];

        wall.physicsBody.dynamic = NO;

    }

}

– (void)createBall

{

    CGPoint points[] = {

        CGPointMake(160, 160),

        

        CGPointMake(150, 180),

        CGPointMake(170, 180),

        

        CGPointMake(140, 200),

        CGPointMake(160, 200),

        CGPointMake(180, 200),

        

        CGPointMake(130, 220),

        CGPointMake(150, 220),

        CGPointMake(170, 220),

        CGPointMake(190, 220),

    };

    

    UIBezierPath *circle = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-10, –10, 20, 20)];

    for (int i=0; i<sizeof(points)/sizeof(CGPoint); i++) {

        SKShapeNode *ball = [SKShapeNode node];

        ball.name = @”ball”;

        ball.path = circle.CGPath;

        ball.fillColor = [SKColor colorWithHue:i/12.0 saturation:1 brightness:1 alpha:1];

        ball.position = points[i];

        [self addChild:ball];

        

        ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:10];

        ball.physicsBody.restitution = 0.8;

        ball.physicsBody.linearDamping = 0.3;

    }

}

– (void)createPocket

{

    CGPoint points[] = {

        CGPointMake(20, 20),

        CGPointMake(300, 20),

        CGPointMake(300, 300),

        CGPointMake(20, 300),

    };

    

    for (int i=0; i<4; i++) {

        UIBezierPath *circle = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-15, –15, 30, 30)];

        SKShapeNode *pocket = [SKShapeNode node];

        pocket.name = @”pocket”;

        pocket.lineWidth = 0;

        pocket.fillColor = [SKColor blackColor];

        pocket.path = circle.CGPath;

        pocket.position = points[i];

        [self addChild:pocket];

    }

}

– (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{

    CGPoint p = [[touches anyObject] locationInNode:self];

    [self enumerateChildNodesWithName:@”ball” usingBlock:^(SKNode *node, BOOL *stop) {

        if (CGRectContainsPoint(node.frame, p)) {

            self.selected = node;

            [self.balldelegate selectBall:[(SKShapeNode*)node fillColor]];

        }

    }];

}

– (void)hitAtAngle:(float)angle impulse:(float)impulse

{

    CGPoint p = CGPointMake(10 * cos(angle) + 10, 10 * sin(angle) + 10);

    CGVector v = CGVectorMake(impulse * cos(angle), impulse * sin(angle));

    [self.selected.physicsBody applyImpulse:v atPoint:p];

}

– (void)didSimulatePhysics

{

    [self enumerateChildNodesWithName:@”ball” usingBlock:^(SKNode *ball, BOOL *stop) {

        [self enumerateChildNodesWithName:@”pocket” usingBlock:^(SKNode *pocket, BOOL *stop) {

            if (CGRectContainsPoint(pocket.frame, ball.position)) {

                

                SKAction *small = [SKAction scaleTo:0 duration:0.5];

                SKAction *move = [SKAction moveTo:pocket.position duration:0.5];

                [ball runAction:[SKAction group:@[small, move]] completion:^{

                    [ball removeFromParent];

                }];

            }

        }];

    }];

}

@end

@interface ViewController () <BallDelegate>

@property (weak, nonatomic) UIView *ballGuide;

@property (weak, nonatomic) UIView *hitMark;

@property (weak, nonatomic) BallScene *ballScene;

@end

@implementation ViewController

– (void)viewDidLoad

{

    [super viewDidLoad];

    [self createBallScene];

    [self createConsole];

}

– (void)createBallScene

{

    SKView *spriteView = [[SKView alloc] initWithFrame:CGRectMake(0, 0, 320, 320)];

    [self.view addSubview:spriteView];

    

    BallScene *scene = [[BallScene alloc] initWithSize:spriteView.frame.size];

    [spriteView presentScene:scene];

    scene.balldelegate = self;

    

    self.ballScene = scene;

}

– (void)createConsole

{

    UIView *b = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];

    b.backgroundColor = [UIColor whiteColor];

    b.center = CGPointMake(160, CGRectGetMaxY(self.view.frame) – 160);

    b.layer.cornerRadius = 50;

    [self.view addSubview:b];

    self.ballGuide = b;

    

    

    UIView *m = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];

    m.backgroundColor = [UIColor redColor];

    m.layer.cornerRadius = 10;

    m.center = CGPointMake(50, 100);

    [b addSubview:m];

    self.hitMark = m;

    

    self.view.backgroundColor = [UIColor blackColor];

    UISlider *s = [[UISlider alloc] init];

    s.value = 0;

    s.maximumValue = 10;

    s.center = CGPointMake(160, CGRectGetMaxY(self.view.frame) – 50);

    [self.view addSubview:s];

    [s addTarget:self action:@selector(pushBall:) forControlEvents:UIControlEventTouchUpOutside | UIControlEventTouchUpInside];

}

– (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{

    CGPoint p = [[touches anyObject] locationInView:self.view];

    if (CGRectContainsPoint(self.ballGuide.frame, p)) {

        [self updateMarker:p];

    }

}

– (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

{

    CGPoint p = [[touches anyObject] locationInView:self.view];

    if (CGRectContainsPoint(self.ballGuide.frame, p)) {

        [self updateMarker:p];

    }

}

– (void)updateMarker:(CGPoint)p

{

    CGPoint local = [self.ballGuide convertPoint:p fromView:self.view];

    float angle = atan2f(local.x50, local.y50) – M_PI/2.0;

    CGPoint newP = CGPointMake(50 * cos(angle) + 50, –50 * sin(angle) + 50);

    self.hitMark.center = newP;

}

– (void)pushBall:(UISlider*)sender

{

    float angle = atan2f(self.hitMark.center.x50, self.hitMark.center.y50) + M_PI/2.0;

    [self.ballScene hitAtAngle:angle impulse:sender.value];

    sender.value = 0;

}

– (void)selectBall:(UIColor *)ballColor

{

    self.ballGuide.backgroundColor = ballColor;

}

– (void)didReceiveMemoryWarning

{

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

@end