iPhone 缶打ち

空き缶っぽいのにボールを投げるiPhoneアプリのサンプルコードを描いてみます。

#import “ViewController.h”

@import SceneKit;

@interface ViewController () <SCNSceneRendererDelegate>

@property (nonatomic, weak) SCNView *sceneView;

@property (nonatomic, weak) SCNNode *selected;

@property (nonatomic, strong) NSValue *movePoint;

@end

@implementation ViewController

– (void)viewDidLoad {

    [super viewDidLoad];

    self.view.backgroundColor = [UIColor lightGrayColor];

    [self setupScene];

    [self createCan];

    [self createBall];

}

– (void)setupScene {

    float w = CGRectGetMaxX(self.view.bounds);

    SCNView *sv = [[SCNView alloc] initWithFrame:CGRectMake(0, 100, w, w)];

    sv.backgroundColor = [self color:0];

    sv.scene = [SCNScene scene];

    sv.delegate = self;

    [self.view addSubview:sv];

    

    self.sceneView = sv;

}

– (void)createCan {

    SCNBox *ground = [SCNBox boxWithWidth:40 height:1 length:40 chamferRadius:0];

    ground.firstMaterial.diffuse.contents = [self color:1];

    SCNNode *groundNode = [SCNNode nodeWithGeometry:ground];

    groundNode.physicsBody = [SCNPhysicsBody staticBody];

    [self.sceneView.scene.rootNode addChildNode:groundNode];

    

    SCNBox *rack = [SCNBox boxWithWidth:40 height:1 length:5 chamferRadius:0];

    rack.firstMaterial.diffuse.contents = [self color:1];

    SCNNode *rackNode = [SCNNode nodeWithGeometry:rack];

    rackNode.position = SCNVector3Make(0, 10, –15);

    rackNode.physicsBody = [SCNPhysicsBody staticBody];

    [self.sceneView.scene.rootNode addChildNode:rackNode];

    

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

        SCNCylinder *can = [SCNCylinder cylinderWithRadius:2 height:6];

        can.firstMaterial.diffuse.contents = [self color:i + 2];

        SCNNode *canNode = [SCNNode nodeWithGeometry:can];

        canNode.position = SCNVector3Make(-10 + 20 * i, 13.1, –15);

        canNode.physicsBody = [SCNPhysicsBody dynamicBody];

        [self.sceneView.scene.rootNode addChildNode:canNode];

    }

}

– (void)createBall {

    SCNSphere *ball = [SCNSphere sphereWithRadius:2];

    

    CALayer *tex = [CALayer layer];

    tex.frame = CGRectMake(0, 0, 100, 100);

    tex.backgroundColor = [self color:4].CGColor;

    CALayer *texSub = [CALayer layer];

    texSub.frame = CGRectMake(0, 50, 100, 50);

    texSub.backgroundColor = [self color:3].CGColor;

    [tex addSublayer:texSub];

    

    ball.firstMaterial.diffuse.contents = tex;//[self color:4];

    

    SCNNode *ballNode = [SCNNode nodeWithGeometry:ball];

    ballNode.name = @”ball”;

    ballNode.position = SCNVector3Make(0, 2, 19);

    ballNode.physicsBody = [SCNPhysicsBody dynamicBody];

    ballNode.physicsBody.allowsResting = NO;

    ballNode.physicsBody.friction = 0.8;

    [self.sceneView.scene.rootNode addChildNode:ballNode];

}

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

{

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

    SCNNode *hit = [[self.sceneView hitTest:p options:@{SCNHitTestSortResultsKey:@YES}].firstObject node];

    if ([hit.name isEqual:@”ball”]) {

        self.selected = hit;

    }

}

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

{

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

    if (!self.selected) return;

    

    if (p.y >  180) {

        SCNVector3 v = [self.sceneView unprojectPoint:SCNVector3Make(p.x, p.y, 0.1)];

        self.movePoint = [NSValue valueWithSCNVector3:SCNVector3Make(v.x * 10.0,self.selected.position.y, self.selected.position.z)];

    } else {

        [self.selected.physicsBody applyForce:SCNVector3Make(0, 30, –60) impulse:YES];

        self.selected = nil;

    }

}

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

{

    self.selected.physicsBody.angularVelocity = SCNVector4Zero;

    self.selected = nil;

    self.movePoint = nil;

}

– (void)renderer:(id<SCNSceneRenderer>)aRenderer updateAtTime:(NSTimeInterval)time

{

    SCNNode *ball = [self.sceneView.scene.rootNode childNodeWithName:@”ball” recursively:NO];

    if (self.movePoint) {

        float d = ball.presentationNode.position.x  [self.movePoint SCNVector3Value].x;

        if (d > 1) {

            [ball.physicsBody applyTorque:SCNVector4Make(0, 0, 1, 20) impulse:NO];

        } else if (d < –1) {

            [ball.physicsBody applyTorque:SCNVector4Make(0, 0, 1, –20) impulse:NO];

        } else {

            ball.physicsBody.angularVelocity = SCNVector4Zero;

        }

    }

    

    if (ball.presentationNode.position.z < 0) {

        ball.name = @””;

        [self createBall];

    }

}

#define ColorHex(rgb) [UIColor colorWithRed:((rgb & 0xFF0000) >> 16)/255.0 green:((rgb & 0xFF00) >> 8)/255.0 blue:(rgb & 0xFF)/255.0 alpha:1]

– (UIColor *)color:(int)i {

    switch (i) {

        case 0: return ColorHex(0xE3BBBC);

        case 1: return ColorHex(0x27415B);

        case 2: return ColorHex(0x7CBCB2);

        case 3: return ColorHex(0xE3E3E3);

        case 4: return ColorHex(0xD26F6C);

    }

    return nil;

}

@end