iPhone曲芸飛行

アクロバットのインサイドループっぽく動くiPhoneアプリのサンプルコードを描いてみます。

#import “ViewController.h”

@import SceneKit;

@interface ViewController () <SCNSceneRendererDelegate>

@property (nonatomic, weak) SCNView *sceneView;

@property (nonatomic) BOOL turn;

@end

@implementation ViewController

– (void)viewDidLoad {

    [super viewDidLoad];

    [self setupScene];

    [self createCamera];

}

– (void)setupScene {

    SCNView *sv = [[SCNView alloc] initWithFrame:self.view.bounds];

    sv.scene = [SCNScene scene];

    sv.backgroundColor = [UIColor colorWithHue:0.5 saturation:0.2 brightness:1 alpha:1];

    sv.allowsCameraControl = YES;

    sv.autoenablesDefaultLighting = YES;

    

    sv.scene.physicsWorld.gravity = SCNVector3Make(0, 0, 0);

    sv.delegate = self;

    

    [self.view addSubview:sv];

    

    self.sceneView = sv;

}

– (void)createPlane {

    SCNNode *plane = [SCNNode node];

    plane.position = SCNVector3Make(-10, –5, 0);

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

    

    SCNBox *body = [SCNBox boxWithWidth:2 height:0.2 length:0.2 chamferRadius:0];

    body.firstMaterial.diffuse.contents = [UIColor whiteColor];

    SCNNode *bodyNode = [SCNNode nodeWithGeometry:body];

    [plane addChildNode:bodyNode];

    

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

        SCNBox *wing = [SCNBox boxWithWidth:0.5 height:0.04 length:1 chamferRadius:0];

        wing.firstMaterial.diffuse.contents = [UIColor blueColor];

        SCNNode *wingNode =[SCNNode nodeWithGeometry:wing];

        wingNode.position = SCNVector3Make(0.2, –0.04, i==0 ? 0.5 : –0.5);

        wingNode.rotation = SCNVector4Make(0, 1, 0, i==0 ? –0.3 : 0.3);

        [plane addChildNode:wingNode];

    }

    

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

        SCNBox *tail = [SCNBox boxWithWidth:0.2 height:0.4 length:0.02 chamferRadius:0];

        tail.firstMaterial.diffuse.contents = [UIColor blueColor];

        SCNNode *tailNode =[SCNNode nodeWithGeometry:tail];

        tailNode.pivot = SCNMatrix4MakeTranslation(0, –0.2, 0);

        tailNode.pivot = SCNMatrix4Rotate(tailNode.pivot, –0.4, 0, 0, 1);

        tailNode.position = SCNVector3Make(-0.9, 0.01, 0);

        switch (i) {

            case 0:

                tailNode.rotation = SCNVector4Make(1, 0, 0, M_PI * 0.5);

                break;

            case 1:

                tailNode.rotation = SCNVector4Make(1, 0, 0, –M_PI * 0.5);

                break;

            default:

                break;

        }

        [plane addChildNode:tailNode];

    }

    

    plane.name = @”plane”;

    plane.physicsBody = [SCNPhysicsBody dynamicBody];

    plane.physicsBody.damping = 0.9;

    plane.physicsBody.angularDamping = 0.9;

    plane.physicsBody.angularVelocityFactor = SCNVector3Make(0, 0, 1);

    

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        [plane removeFromParentNode];

    });

}

– (void)createCamera {

    SCNNode *camera = [SCNNode node];

    camera.camera = [SCNCamera camera];

    camera.position = SCNVector3Make(0, 0, 15);

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

}

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

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

    if (!plane) {

        [self createPlane];

        return;

    }

    self.turn = YES;

}

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

    self.turn = NO;

}

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

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

    

    SCNVector3 o = plane.presentationNode.position;

    

    if (self.turn) {

        SCNVector3 vy = [plane.presentationNode convertPosition:SCNVector3Make(5, 5, 0) toNode:self.sceneView.scene.rootNode];

        vy = SCNVector3Make(vy.x – o.x, vy.y – o.y, 0);

        SCNVector3 atPosition = [plane.presentationNode convertPosition:SCNVector3Make(0.35, 0, 0) toNode:self.sceneView.scene.rootNode];

        atPosition = SCNVector3Make(atPosition.x – o.x, atPosition.y – o.y, 0);

        [plane.physicsBody applyForce:SCNVector3Make(vy.x, vy.y, 0) atPosition:atPosition impulse:NO];

    }

    

    SCNVector3 vx = [plane.presentationNode convertPosition:SCNVector3Make(10, 0, 0) toNode:self.sceneView.scene.rootNode];

    vx = SCNVector3Make(vx.x – o.x, vx.y – o.y, 0);

    [plane.physicsBody applyForce:vx impulse:NO];

}

@end