0

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.

Nicholas L.
  • 293
  • 2
  • 3
  • 9

1 Answers1

1

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
lock
  • 2,861
  • 1
  • 13
  • 20
  • Thank you! This definitely helps. myScene is not accessible from handleSingleTap: though as myScene is declared in the viewDidLoad. Can I declare it somewhere else? Sorry, pretty new here. – Nicholas L. Mar 29 '16 at 02:54
  • Ah yes, sorry, I just assumed you had `myScene` declared as a instance variable already. Will update the above... my code snippet needed a bit of work anyway. – lock Mar 29 '16 at 03:14
  • Note: in the edited version we declare `myScene` as an instance variable in the class interface definition. Then in the `viewDidLoad` method we assign our scene to this variable making it accessible to all functions within the class (and also other classes). FWIW if I was just starting out I'd probably go straight to Swift. – lock Mar 29 '16 at 03:22
  • I've got it working now, thanks so much! I've learned swift and obj-c. Equally confused with both honestly. lol. – Nicholas L. Mar 29 '16 at 03:29