iPhone輪投げ3D

3Dの輪投げ、iPhoneアプリのサンプルコードを描いてみます。

#import “ViewController.h”

@import SceneKit;

@interface ViewController ()

@property (nonatomic, weak) SCNScene *scenen;

@property (nonatomic, weak) UIView *direction;

@property (nonatomic, weak) UIView *power;

@end

@implementation ViewController

– (void)viewDidLoad {

    [super viewDidLoad];

    self.view.backgroundColor = [UIColor colorWithHue:0.6 saturation:0.05 brightness:1 alpha:1];

    

    [self setupScene];

    [self createPole];

    [self createCamera];

    

    [self createUI];

}

– (void)setupScene {

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

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

    sceneView.backgroundColor = [UIColor colorWithHue:0.15 saturation:0.8 brightness:1 alpha:1];

    sceneView.scene = [SCNScene scene];

    [self.view addSubview:sceneView];

    

    self.scenen = sceneView.scene;

}

– (void)createPole {

    SCNBox *box = [SCNBox boxWithWidth:20 height:1 length:20 chamferRadius:0];

    box.firstMaterial.diffuse.contents = [UIColor colorWithHue:0.25 saturation:0.6 brightness:0.6 alpha:1];

    SCNNode *boxNode = [SCNNode nodeWithGeometry:box];

    [self.scenen.rootNode addChildNode:boxNode];

    boxNode.physicsBody = [SCNPhysicsBody staticBody];

    boxNode.physicsBody.friction = 1.0;

    

    SCNCylinder *pole = [SCNCylinder cylinderWithRadius:1 height:5];

    pole.firstMaterial.diffuse.contents = [UIColor colorWithHue:0.4 saturation:0.6 brightness:0.8 alpha:1];

    SCNNode *poleNode = [SCNNode nodeWithGeometry:pole];

    poleNode.position = SCNVector3Make(0, 3, 0);

    [self.scenen.rootNode addChildNode:poleNode];

    poleNode.physicsBody = [SCNPhysicsBody staticBody];

}

– (void)createCamera {

    SCNNode *camera = [SCNNode node];

    camera.camera = [SCNCamera camera];

    camera.position = SCNVector3Make(0, 10, 40);

    [self.scenen.rootNode addChildNode:camera];

}

– (void)createUI {

    

    UIView *direction = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 80, 80)];

    direction.layer.cornerRadius = 40;

    direction.backgroundColor = [UIColor colorWithHue:0.4 saturation:0.7 brightness:1 alpha:1];

    direction.center = CGPointMake(CGRectGetMaxX(self.view.bounds)/4.0, CGRectGetMaxX(self.view.bounds) + 80);

    [self.view addSubview:direction];

    UIBezierPath *path = [UIBezierPath bezierPath];

    [path moveToPoint:CGPointMake(-30, –10)];

    [path addLineToPoint:CGPointMake(0, –30)];

    [path addLineToPoint:CGPointMake(30, –10)];

    [path closePath];

    [path appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(-5, –10, 10, 50)]];

    CAShapeLayer *arrow = [CAShapeLayer layer];

    arrow.path = path.CGPath;

    arrow.fillColor = [UIColor whiteColor].CGColor;

    arrow.position = CGPointMake(40, 40);

    [direction.layer addSublayer:arrow];

    self.direction = direction;

    

    

    UIView *power = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 30, 120)];

    power.center = CGPointMake(CGRectGetMaxX(self.view.bounds) * 3.0 / 4.0, CGRectGetMaxX(self.view.bounds) + 80);

    [self.view addSubview:power];

    CAGradientLayer *gradient = [CAGradientLayer layer];

    gradient.frame = power.bounds;

    gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor redColor] CGColor], (id)[[UIColor greenColor] CGColor], nil];

    [power.layer insertSublayer:gradient atIndex:0];

    self.power = power;

}

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

{

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

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

        self.direction.transform = CGAffineTransformRotate(self.direction.transform, M_PI/10.0);

    } else if (CGRectContainsPoint(self.power.frame, p)) {

        float level = (120 – [[touches anyObject] locationInView:self.power].y) * 0.2;

        float angle = [[self.direction.layer valueForKeyPath:@”transform.rotation.z”] floatValue] – M_PI/2.0;

        

        SCNTorus *ring = [SCNTorus torusWithRingRadius:4 pipeRadius:0.3];

        ring.firstMaterial.diffuse.contents = [UIColor redColor];

        SCNNode *ringNode = [SCNNode nodeWithGeometry:ring];

        ringNode.position = SCNVector3Make(0, 0, 30);

        [self.scenen.rootNode addChildNode:ringNode];

        ringNode.physicsBody = [SCNPhysicsBody dynamicBody];

        

        NSMutableArray *arr = [NSMutableArray array];

        NSMutableArray *transforms = [NSMutableArray array];

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

            SCNBox *boxRing = [SCNBox boxWithWidth:2 height:0.6 length:0.6 chamferRadius:0];

            [arr addObject:[SCNPhysicsShape shapeWithGeometry:boxRing options:@{SCNPhysicsShapeTypeKey : SCNPhysicsShapeTypeBoundingBox, SCNPhysicsShapeKeepAsCompoundKey : @YES}]];

            

            float angle = i * M_PI / 5.0;

            [transforms addObject:[NSValue valueWithSCNMatrix4:SCNMatrix4MakeTranslation(4.0 * cos(angle), 0, 4.0 * sin(angle))]];

            

        }

        ringNode.physicsBody.physicsShape = [SCNPhysicsShape shapeWithShapes:arr transforms:transforms];

        

        float x = cos(angle) * level;

        float z = sin(angle) * level;

        [ringNode.physicsBody applyForce:SCNVector3Make(x, 15, z) impulse:YES];

    }

}

@end