Nicholas L.
Nicholas L.

Reputation: 293

Anti-gravity physics in SceneKit

I am trying to make a simple app where if you tap the screen a box is switched from floating to affected by gravity. I can't seem to find a way to make the box float in the air though.

This code here takes care of half the problem:

    boxNode.physicsBody = [SCNPhysicsBody dynamicBody];

This causes the box to drop out of the air and hit a floor I created. Is there anything in SCNPhysicsBody that would do the opposite of this? Say, perhaps, cause objects to float or just sail off toward a ceiling?

Also, I've written this code:

- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer {

    if (myBool == false) {
        myBool = true;
        NSLog(@"true");
    } else {
        myBool = false;
        NSLog(@"false");
    }


}
- (void)viewDidLoad
{
    [super viewDidLoad];

// touch recognizer
    UITapGestureRecognizer *screenTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
    [self.view addGestureRecognizer:screenTap];

    // create box
    SCNBox *myBox = [SCNBox boxWithWidth:1.0 height:1.0 length:1.0 chamferRadius:0.1];
    SCNNode *boxNode = [SCNNode nodeWithGeometry:myBox];
    boxNode.position = SCNVector3Make(0.0, 0.0, 4.0);
    [myScene.rootNode addChildNode:boxNode];



    while (myBool == true) {

    boxNode.physicsBody = [SCNPhysicsBody dynamicBody];

    }


}

I'm not sure why the while loop doesn't work though. I was thinking it would detect that myBool has been changed and alter the physics of the boxNode, but it doesn't.

Upvotes: 0

Views: 961

Answers (1)

lock
lock

Reputation: 2897

The viewDidLoad method is only called once when the view is loaded. If your app is initialised with myBool = false, then the while loop will never be run. However in this case if myBool was true the while loop would never stop executing, preventing the view from loading, and therefore preventing the user from tapping the view to trigger your gesture recogniser.

I haven't tested the below, but it should at least give you a starting point. The scene is created in the viewDidLoad as per your code, importantly the scene's physicsWorld has its gravity set to zero (this is -9.8 by default). Later on when the user taps the view we reset the gravity to its default value, this should cause the box to fall.

The header file GameViewController.h

#import <UIKit/UIKit.h>
#import <SceneKit/SceneKit.h>

@interface GameViewController : UIViewController {
    SCNScene *myScene;
}

@end

and GameViewController.m

#import "GameViewController.h"

@implementation GameViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // create a new scene
    myScene = [SCNScene scene];

    // create box
    SCNBox *myBox = [SCNBox boxWithWidth:1.0 height:1.0 length:1.0 chamferRadius:0.1];
    SCNNode *boxNode = [SCNNode nodeWithGeometry:myBox];
    boxNode.position = SCNVector3Make(0.0, 0.0, 4.0);
    [myScene.rootNode addChildNode:boxNode];

    boxNode.physicsBody = [SCNPhysicsBody dynamicBody];

    //'disable' scene gravity
    myScene.physicsWorld.gravity = SCNVector3Make(0, 0, 0);

    SCNView *scnView = (SCNView *)self.view;
    scnView.scene = myScene;
    scnView.allowsCameraControl = YES;
    scnView.autoenablesDefaultLighting = YES;
    scnView.backgroundColor = [UIColor blackColor];

    // add a tap gesture recognizer
    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
    NSMutableArray *gestureRecognizers = [NSMutableArray array];
    [gestureRecognizers addObject:tapGesture];
    [gestureRecognizers addObjectsFromArray:scnView.gestureRecognizers];
    scnView.gestureRecognizers = gestureRecognizers;
}

- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer {
    myScene.physicsWorld.gravity = SCNVector3Make(0, -9.8, 0);
}

@end

Upvotes: 1

Related Questions