iPhone台風の目

運動会の競技、台風の目みたいなiPhoneアプリのサンプルコードを描いてみます。

#import “ViewController.h”

@import SceneKit;

@interface ViewController () <SCNSceneRendererDelegate>

@property (nonatomic, weak) SCNView *sceneView;

@property (nonatomic) int status;

@end

@implementation ViewController

– (void)viewDidLoad {

    [super viewDidLoad];

    [self setupScene];

    [self createRunnerBar];

    [self createCone];

    [self createCamera];

}

– (void)setupScene {

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

    sv.backgroundColor = [UIColor brownColor];

    sv.scene = [SCNScene scene];

    sv.autoenablesDefaultLighting = YES;

    sv.delegate = self;

    [self.view addSubview:sv];

    

    self.sceneView = sv;

}

– (void)createRunnerBar {

    SCNNode *runBar = [SCNNode node];

    runBar.name = @”run bar”;

    

    SCNCylinder *bar = [SCNCylinder cylinderWithRadius:0.3 height:8];

    bar.firstMaterial.diffuse.contents = [UIColor colorWithHue:0 saturation:1 brightness:0.8 alpha:1];

    SCNNode *barNode = [SCNNode nodeWithGeometry:bar];

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

    [runBar addChildNode:barNode];

    

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

        SCNNode *runner = [SCNNode node];

        runner.position = SCNVector3Make(-1.2, –0.3, 2 * i – 3);

        [runBar addChildNode:runner];

        

        SCNSphere *head = [SCNSphere sphereWithRadius:0.6];

        head.firstMaterial.diffuse.contents = [UIColor darkGrayColor];

        SCNNode *headNode = [SCNNode nodeWithGeometry:head];

        headNode.position = SCNVector3Make(0, 1, 0);

        [runner addChildNode:headNode];

        

        SCNBox *body = [SCNBox boxWithWidth:0.5 height:1 length:0.5 chamferRadius:0.25];

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

        SCNNode *bodyNode = [SCNNode nodeWithGeometry:body];

        [runner addChildNode:bodyNode];

        

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

            SCNBox *foot = [SCNBox boxWithWidth:0.4 height:1 length:0.4 chamferRadius:0.2];

            foot.firstMaterial.diffuse.contents = [UIColor darkGrayColor];

            SCNNode *footNode = [SCNNode nodeWithGeometry:foot];

            footNode.pivot = SCNMatrix4MakeTranslation(0, 0.5, 0);

            footNode.position = SCNVector3Make(0, –0.4, i==0 ? 0.25 : –0.25);

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

            [runner addChildNode:footNode];

            

            SCNBox *arm = [SCNBox boxWithWidth:1 height:0.3 length:0.3 chamferRadius:0.1];

            arm.firstMaterial.diffuse.contents = [UIColor darkGrayColor];

            SCNNode *armNode = [SCNNode nodeWithGeometry:arm];

            armNode.position = SCNVector3Make(0.5, 0.3, i==0 ? 0.4 : –0.4);

            [runner addChildNode:armNode];

        }

    }

    

    runBar.physicsBody = [SCNPhysicsBody dynamicBody];

    runBar.physicsBody.velocityFactor = SCNVector3Make(1, 0, 1);

    runBar.physicsBody.angularDamping = 0.6;

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

}

– (void)createCone {

    SCNCone *corn = [SCNCone coneWithTopRadius:0.2 bottomRadius:1 height:2];

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

    SCNNode *cornNode = [SCNNode nodeWithGeometry:corn];

    cornNode.position = SCNVector3Make(10, 0, –4);

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

}

– (void)createCamera {

    SCNNode *camera = [SCNNode node];

    camera.camera = [SCNCamera camera];

    camera.position = SCNVector3Make(10, 10, 20);

    camera.rotation = SCNVector4Make(1, 0, 0, –0.4);

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

}

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

{

    if (self.status == 0) {

        self.status = 2;

    } else {

        self.status = 1;

    }

    self.sceneView.playing = YES;

}

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

{

    self.status = 2;

}

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

{

    if (self.status == 0) {

        return;

    }

    

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

    if (self.status == 1) {

        [runbar.physicsBody applyForce:SCNVector3Make(-0.02, 0, 0) atPosition:SCNVector3Make(0, 0, –5) impulse:YES];

    } else {

        SCNVector3 v = [runbar.presentationNode convertPosition:SCNVector3Make(3, 0, 0) toNode:self.sceneView.scene.rootNode];

        runbar.physicsBody.velocity = SCNVector3Sub(v, runbar.presentationNode.position);

    }

}

static inline SCNVector3 SCNVector3Sub(SCNVector3 a, SCNVector3 b)

{

    return SCNVector3Make(a.x – b.x, a.y – b.y, a.z – b.z);

}

@end