Skip to content

Instantly share code, notes, and snippets.

@robreuss
Last active June 18, 2018 11:48
Show Gist options
  • Save robreuss/842aefb95417e96ab110 to your computer and use it in GitHub Desktop.
Save robreuss/842aefb95417e96ab110 to your computer and use it in GitHub Desktop.
VirtualGameController implementation for Apple's SceneKit Vehicle Demo
/*
Copyright (C) 2014 Apple Inc. All Rights Reserved.
See LICENSE.txt for this sample’s licensing information
*/
@import GameController;
@import VirtualGameController;
#import <simd/simd.h>
#import <sys/utsname.h>
#import "AAPLGameViewController.h"
#import "AAPLGameView.h"
#import "AAPLOverlayScene.h"
#define MAX_SPEED 250
@implementation AAPLGameViewController {
//some node references for manipulation
SCNNode *_spotLightNode;
SCNNode *_cameraNode; //the node that owns the camera
SCNNode *_vehicleNode;
SCNPhysicsVehicle *_vehicle;
SCNParticleSystem *_reactor;
SCNNode*floor;
//accelerometer
CMMotionManager *_motionManager;
UIAccelerationValue _accelerometer[3];
CGFloat _orientation;
//reactor's particle birth rate
CGFloat _reactorDefaultBirthRate;
// steering factor
CGFloat _vehicleSteering;
}
- (NSString *)deviceName
{
static NSString *deviceName = nil;
if (deviceName == nil) {
struct utsname systemInfo;
uname(&systemInfo);
deviceName = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
}
return deviceName;
}
- (BOOL)isHighEndDevice
{
//return YES for iPhone 5s and iPad air, NO otherwise
if ([[self deviceName] hasPrefix:@"iPad4"]
|| [[self deviceName] hasPrefix:@"iPhone6"]) {
return YES;
}
return NO;
}
- (void)setupEnvironment:(SCNScene *)scene
{
// add an ambient light
SCNNode *ambientLight = [SCNNode node];
ambientLight.light = [SCNLight light];
ambientLight.light.type = SCNLightTypeAmbient;
ambientLight.light.color = [UIColor colorWithWhite:0.3 alpha:1.0];
[[scene rootNode] addChildNode:ambientLight];
//add a key light to the scene
SCNNode *lightNode = [SCNNode node];
lightNode.light = [SCNLight light];
lightNode.light.type = SCNLightTypeSpot;
if ([self isHighEndDevice])
lightNode.light.castsShadow = YES;
lightNode.light.color = [UIColor colorWithWhite:0.8 alpha:1.0];
lightNode.position = SCNVector3Make(0, 80, 30);
lightNode.rotation = SCNVector4Make(1,0,0,-M_PI/2.8);
lightNode.light.spotInnerAngle = 0;
lightNode.light.spotOuterAngle = 50;
lightNode.light.shadowColor = [SKColor blackColor];
lightNode.light.zFar = 500;
lightNode.light.zNear = 50;
[[scene rootNode] addChildNode:lightNode];
//keep an ivar for later manipulation
_spotLightNode = lightNode;
//floor
floor = [SCNNode node];
floor.geometry = [SCNFloor floor];
floor.geometry.firstMaterial.diffuse.contents = @"wood.png";
floor.geometry.firstMaterial.diffuse.contentsTransform = SCNMatrix4MakeScale(2, 2, 1); //scale the wood texture
floor.geometry.firstMaterial.locksAmbientWithDiffuse = YES;
if ([self isHighEndDevice])
((SCNFloor*)floor.geometry).reflectionFalloffEnd = 10;
SCNPhysicsBody *staticBody = [SCNPhysicsBody staticBody];
floor.physicsBody = staticBody;
[[scene rootNode] addChildNode:floor];
}
- (void)addTrainToScene:(SCNScene *)scene atPosition:(SCNVector3)pos
{
SCNScene *trainScene = [SCNScene sceneNamed:@"train_flat"];
//physicalize the train with simple boxes
[trainScene.rootNode.childNodes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
SCNNode *node = (SCNNode *)obj;
if (node.geometry != nil) {
node.position = SCNVector3Make(node.position.x + pos.x, node.position.y + pos.y, node.position.z + pos.z);
SCNVector3 min, max;
[node getBoundingBoxMin:&min max:&max];
SCNPhysicsBody *body = [SCNPhysicsBody dynamicBody];
SCNBox *boxShape = [SCNBox boxWithWidth:max.x - min.x height:max.y - min.y length:max.z - min.z chamferRadius:0.0];
body.physicsShape = [SCNPhysicsShape shapeWithGeometry:boxShape options:nil];
node.pivot = SCNMatrix4MakeTranslation(0, -min.y, 0);
node.physicsBody = body;
[[scene rootNode] addChildNode:node];
}
}];
//add smoke
SCNNode *smokeHandle = [scene.rootNode childNodeWithName:@"Smoke" recursively:YES];
[smokeHandle addParticleSystem:[SCNParticleSystem particleSystemNamed:@"smoke" inDirectory:nil]];
//add physics constraints between engine and wagons
SCNNode *engineCar = [scene.rootNode childNodeWithName:@"EngineCar" recursively:NO];
SCNNode *wagon1 = [scene.rootNode childNodeWithName:@"Wagon1" recursively:NO];
SCNNode *wagon2 = [scene.rootNode childNodeWithName:@"Wagon2" recursively:NO];
SCNVector3 min, max;
[engineCar getBoundingBoxMin:&min max:&max];
SCNVector3 wmin, wmax;
[wagon1 getBoundingBoxMin:&wmin max:&wmax];
// Tie EngineCar & Wagon1
SCNPhysicsBallSocketJoint *joint = [SCNPhysicsBallSocketJoint jointWithBodyA:engineCar.physicsBody anchorA:SCNVector3Make(max.x, min.y, 0)
bodyB:wagon1.physicsBody anchorB:SCNVector3Make(wmin.x, wmin.y, 0)];
[scene.physicsWorld addBehavior:joint];
// Wagon1 & Wagon2
joint = [SCNPhysicsBallSocketJoint jointWithBodyA:wagon1.physicsBody anchorA:SCNVector3Make(wmax.x + 0.1, wmin.y, 0)
bodyB:wagon2.physicsBody anchorB:SCNVector3Make(wmin.x - 0.1, wmin.y, 0)];
[scene.physicsWorld addBehavior:joint];
}
- (void)addWoodenBlockToScene:(SCNScene *)scene withImageNamed:(NSString *)imageName atPosition:(SCNVector3)position
{
//create a new node
SCNNode *block = [SCNNode node];
//place it
block.position = position;
//attach a box of 5x5x5
block.geometry = [SCNBox boxWithWidth:5 height:5 length:5 chamferRadius:0];
//use the specified images named as the texture
block.geometry.firstMaterial.diffuse.contents = imageName;
//turn on mipmapping
block.geometry.firstMaterial.diffuse.mipFilter = SCNFilterModeLinear;
//make it physically based
block.physicsBody = [SCNPhysicsBody dynamicBody];
//add to the scene
[[scene rootNode] addChildNode:block];
}
- (void)setupSceneElements:(SCNScene *)scene
{
// add a train
[self addTrainToScene:scene atPosition:SCNVector3Make(-5, 20, -40)];
// add wooden blocks
[self addWoodenBlockToScene:scene withImageNamed:@"WoodCubeA.jpg" atPosition:SCNVector3Make(-10, 15, 10)];
[self addWoodenBlockToScene:scene withImageNamed:@"WoodCubeB.jpg" atPosition:SCNVector3Make( -9, 10, 10)];
[self addWoodenBlockToScene:scene withImageNamed:@"WoodCubeC.jpg" atPosition:SCNVector3Make(20, 15, -11)];
[self addWoodenBlockToScene:scene withImageNamed:@"WoodCubeA.jpg" atPosition:SCNVector3Make(25, 5, -20)];
// add walls
SCNNode *wall = [SCNNode nodeWithGeometry:[SCNBox boxWithWidth:400 height:100 length:4 chamferRadius:0]];
wall.geometry.firstMaterial.diffuse.contents = @"wall.jpg";
wall.geometry.firstMaterial.diffuse.contentsTransform = SCNMatrix4Mult(SCNMatrix4MakeScale(24, 2, 1), SCNMatrix4MakeTranslation(0, 1, 0));
wall.geometry.firstMaterial.diffuse.wrapS = SCNWrapModeRepeat;
wall.geometry.firstMaterial.diffuse.wrapT = SCNWrapModeMirror;
wall.geometry.firstMaterial.doubleSided = NO;
wall.castsShadow = NO;
wall.geometry.firstMaterial.locksAmbientWithDiffuse = YES;
wall.position = SCNVector3Make(0, 50, -92);
wall.physicsBody = [SCNPhysicsBody staticBody];
[scene.rootNode addChildNode:wall];
wall = [wall clone];
wall.position = SCNVector3Make(-202, 50, 0);
wall.rotation = SCNVector4Make(0, 1, 0, M_PI_2);
[scene.rootNode addChildNode:wall];
wall = [wall clone];
wall.position = SCNVector3Make(202, 50, 0);
wall.rotation = SCNVector4Make(0, 1, 0, -M_PI_2);
[scene.rootNode addChildNode:wall];
SCNNode *backWall = [SCNNode nodeWithGeometry:[SCNPlane planeWithWidth:400 height:100]];
backWall.geometry.firstMaterial = wall.geometry.firstMaterial;
backWall.position = SCNVector3Make(0, 50, 200);
backWall.rotation = SCNVector4Make(0, 1, 0, M_PI);
backWall.castsShadow = NO;
backWall.physicsBody = [SCNPhysicsBody staticBody];
[scene.rootNode addChildNode:backWall];
// add ceil
SCNNode *ceilNode = [SCNNode nodeWithGeometry:[SCNPlane planeWithWidth:400 height:400]];
ceilNode.position = SCNVector3Make(0, 100, 0);
ceilNode.rotation = SCNVector4Make(1, 0, 0, M_PI_2);
ceilNode.geometry.firstMaterial.doubleSided = NO;
ceilNode.castsShadow = NO;
ceilNode.geometry.firstMaterial.locksAmbientWithDiffuse = YES;
[scene.rootNode addChildNode:ceilNode];
//add more block
for(int i=0;i<4; i++) {
[self addWoodenBlockToScene:scene withImageNamed:@"WoodCubeA.jpg" atPosition:SCNVector3Make(rand()%60 - 30, 20, rand()%40 - 20)];
[self addWoodenBlockToScene:scene withImageNamed:@"WoodCubeB.jpg" atPosition:SCNVector3Make(rand()%60 - 30, 20, rand()%40 - 20)];
[self addWoodenBlockToScene:scene withImageNamed:@"WoodCubeC.jpg" atPosition:SCNVector3Make(rand()%60 - 30, 20, rand()%40 - 20)];
}
// add cartoon book
SCNNode *block = [SCNNode node];
block.position = SCNVector3Make(20, 10, -16);
block.rotation = SCNVector4Make(0, 1, 0, -M_PI_4);
block.geometry = [SCNBox boxWithWidth:22 height:0.2 length:34 chamferRadius:0];
SCNMaterial *frontMat = [SCNMaterial material];
frontMat.locksAmbientWithDiffuse = YES;
frontMat.diffuse.contents = @"book_front.jpg";
frontMat.diffuse.mipFilter = SCNFilterModeLinear;
SCNMaterial *backMat = [SCNMaterial material];
backMat.locksAmbientWithDiffuse = YES;
backMat.diffuse.contents = @"book_back.jpg";
backMat.diffuse.mipFilter = SCNFilterModeLinear;
block.geometry.materials = @[frontMat, backMat];
block.physicsBody = [SCNPhysicsBody dynamicBody];
[[scene rootNode] addChildNode:block];
// add carpet
SCNNode *rug = [SCNNode node];
rug.position = SCNVector3Make(0, 0.01, 0);
rug.rotation = SCNVector4Make(1, 0, 0, M_PI_2);
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(-50, -30, 100, 50) cornerRadius:2.5];
path.flatness = 0.1;
rug.geometry = [SCNShape shapeWithPath:path extrusionDepth:0.05];
rug.geometry.firstMaterial.locksAmbientWithDiffuse = YES;
rug.geometry.firstMaterial.diffuse.contents = @"carpet.jpg";
[[scene rootNode] addChildNode:rug];
// add ball
SCNNode *ball = [SCNNode node];
ball.position = SCNVector3Make(-5, 5, -18);
ball.geometry = [SCNSphere sphereWithRadius:5];
ball.geometry.firstMaterial.locksAmbientWithDiffuse = YES;
ball.geometry.firstMaterial.diffuse.contents = @"ball.jpg";
ball.geometry.firstMaterial.diffuse.contentsTransform = SCNMatrix4MakeScale(2, 1, 1);
ball.geometry.firstMaterial.diffuse.wrapS = SCNWrapModeMirror;
ball.physicsBody = [SCNPhysicsBody dynamicBody];
ball.physicsBody.restitution = 0.9;
[[scene rootNode] addChildNode:ball];
}
- (SCNNode *)setupVehicle:(SCNScene *)scene
{
SCNScene *carScene = [SCNScene sceneNamed:@"rc_car"];
SCNNode *chassisNode = [carScene.rootNode childNodeWithName:@"rccarBody" recursively:NO];
// setup the chassis
chassisNode.position = SCNVector3Make(0, 10, 30);
chassisNode.rotation = SCNVector4Make(0, 1, 0, M_PI);
SCNPhysicsBody *body = [SCNPhysicsBody dynamicBody];
body.allowsResting = NO;
body.mass = 80;
body.restitution = 0.1;
body.friction = 0.5;
body.rollingFriction = 0;
chassisNode.physicsBody = body;
[scene.rootNode addChildNode:chassisNode];
SCNNode *pipeNode = [chassisNode childNodeWithName:@"pipe" recursively:YES];
_reactor = [SCNParticleSystem particleSystemNamed:@"reactor" inDirectory:nil];
_reactorDefaultBirthRate = _reactor.birthRate;
_reactor.birthRate = 0;
[pipeNode addParticleSystem:_reactor];
//add wheels
SCNNode *wheel0Node = [chassisNode childNodeWithName:@"wheelLocator_FL" recursively:YES];
SCNNode *wheel1Node = [chassisNode childNodeWithName:@"wheelLocator_FR" recursively:YES];
SCNNode *wheel2Node = [chassisNode childNodeWithName:@"wheelLocator_RL" recursively:YES];
SCNNode *wheel3Node = [chassisNode childNodeWithName:@"wheelLocator_RR" recursively:YES];
SCNPhysicsVehicleWheel *wheel0 = [SCNPhysicsVehicleWheel wheelWithNode:wheel0Node];
SCNPhysicsVehicleWheel *wheel1 = [SCNPhysicsVehicleWheel wheelWithNode:wheel1Node];
SCNPhysicsVehicleWheel *wheel2 = [SCNPhysicsVehicleWheel wheelWithNode:wheel2Node];
SCNPhysicsVehicleWheel *wheel3 = [SCNPhysicsVehicleWheel wheelWithNode:wheel3Node];
SCNVector3 min, max;
[wheel0Node getBoundingBoxMin:&min max:&max];
CGFloat wheelHalfWidth = 0.5 * (max.x - min.x);
wheel0.connectionPosition = SCNVector3FromFloat3(SCNVector3ToFloat3([wheel0Node convertPosition:SCNVector3Zero toNode:chassisNode]) + (vector_float3){wheelHalfWidth, 0.0, 0.0});
wheel1.connectionPosition = SCNVector3FromFloat3(SCNVector3ToFloat3([wheel1Node convertPosition:SCNVector3Zero toNode:chassisNode]) - (vector_float3){wheelHalfWidth, 0.0, 0.0});
wheel2.connectionPosition = SCNVector3FromFloat3(SCNVector3ToFloat3([wheel2Node convertPosition:SCNVector3Zero toNode:chassisNode]) + (vector_float3){wheelHalfWidth, 0.0, 0.0});
wheel3.connectionPosition = SCNVector3FromFloat3(SCNVector3ToFloat3([wheel3Node convertPosition:SCNVector3Zero toNode:chassisNode]) - (vector_float3){wheelHalfWidth, 0.0, 0.0});
// create the physics vehicle
SCNPhysicsVehicle *vehicle = [SCNPhysicsVehicle vehicleWithChassisBody:chassisNode.physicsBody wheels:@[wheel0, wheel1, wheel2, wheel3]];
[scene.physicsWorld addBehavior:vehicle];
_vehicle = vehicle;
return chassisNode;
}
- (SCNScene *)setupScene
{
// create a new scene
SCNScene *scene = [SCNScene scene];
//global environment
[self setupEnvironment:scene];
//add elements
[self setupSceneElements:scene];
//setup vehicle
_vehicleNode = [self setupVehicle:scene];
//create a main camera
_cameraNode = [[SCNNode alloc] init];
_cameraNode.camera = [SCNCamera camera];
_cameraNode.camera.zFar = 500;
_cameraNode.position = SCNVector3Make(0, 60, 50);
_cameraNode.rotation = SCNVector4Make(1, 0, 0, -M_PI_4*0.75);
[scene.rootNode addChildNode:_cameraNode];
//add a secondary camera to the car
SCNNode *frontCameraNode = [SCNNode node];
frontCameraNode.position = SCNVector3Make(0, 3.5, 2.5);
frontCameraNode.rotation = SCNVector4Make(0, 1, 0, M_PI);
frontCameraNode.camera = [SCNCamera camera];
frontCameraNode.camera.xFov = 75;
frontCameraNode.camera.zFar = 500;
[_vehicleNode addChildNode:frontCameraNode];
return scene;
}
- (void)setupAccelerometer
{
//event
_motionManager = [[CMMotionManager alloc] init];
AAPLGameViewController * __weak weakSelf = self;
if ([[GCController controllers] count] == 0 && [_motionManager isAccelerometerAvailable] == YES) {
[_motionManager setAccelerometerUpdateInterval:1/60.0];
[_motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
[weakSelf accelerometerDidChange:accelerometerData.acceleration];
}];
}
}
- (BOOL)prefersStatusBarHidden {
return YES;
}
// BEGIN VGC IMPLEMENTATION
// --------------------------
- (void) controllerDidConnect:(NSNotification *) aNotification {
VgcController * controller = (VgcController *)[aNotification object];
[controller.motion setValueChangedHandler:^(VgcMotion * motion) {
#define kFilteringFactor 0.5
_accelerometer[0] = motion.gravity.x;
_accelerometer[1] = motion.gravity.y;
_accelerometer[2] = motion.gravity.z;
if (_accelerometer[0] > 0) {
_orientation = _accelerometer[1]*1.3;
}
else {
_orientation = -_accelerometer[1]*1.3;
}
}];
// Just for fun, take an image sent from the Peripheral and swap it in as the floor
[controller.elements.sendImage setValueChangedHandler:^(VgcController * controller, Element * element) {
floor.geometry.firstMaterial.diffuse.contents = [UIImage imageWithData:element.valueAsNSData];
}];
}
// END VGC IMPLEMENTATION
// --------------------------
- (void)viewDidLoad
{
[super viewDidLoad];
[VgcManager startAs:AppRoleCentral appIdentifier:@"vgc"];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerDidConnect:) name:@"VgcControllerDidConnectNotification" object:nil];
[[UIApplication sharedApplication] setStatusBarHidden:YES];
SCNView *scnView = (SCNView *) self.view;
//set the background to back
scnView.backgroundColor = [SKColor blackColor];
//setup the scene
SCNScene *scene = [self setupScene];
//present it
scnView.scene = scene;
//tweak physics
scnView.scene.physicsWorld.speed = 4.0;
//setup overlays
scnView.overlaySKScene = [[AAPLOverlayScene alloc] initWithSize:scnView.bounds.size];
//setup accelerometer
[self setupAccelerometer];
//initial point of view
scnView.pointOfView = _cameraNode;
//plug game logic
scnView.delegate = self;
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)];
doubleTap.numberOfTapsRequired = 2;
doubleTap.numberOfTouchesRequired = 2;
scnView.gestureRecognizers = @[doubleTap];
[super viewDidLoad];
}
- (void) handleDoubleTap:(UITapGestureRecognizer *) gesture
{
SCNScene *scene = [self setupScene];
SCNView *scnView = (SCNView *) self.view;
//present it
scnView.scene = scene;
//tweak physics
scnView.scene.physicsWorld.speed = 4.0;
//initial point of view
scnView.pointOfView = _cameraNode;
((AAPLGameView*)scnView).touchCount = 0;
}
// game logic
- (void)renderer:(id<SCNSceneRenderer>)aRenderer didSimulatePhysicsAtTime:(NSTimeInterval)time
{
const float defaultEngineForce = 300.0;
const float defaultBrakingForce = 3.0;
const float steeringClamp = 0.6;
const float cameraDamping = 0.3;
AAPLGameView *scnView = (AAPLGameView*)self.view;
CGFloat engineForce = 0;
CGFloat brakingForce = 0;
NSArray* controllers = [VgcController controllers];
float orientation = _orientation;
// BEGIN VGC IMPLEMENTATION
// --------------------------
if (controllers && [controllers count] > 0) {
VgcController *controller = controllers[0];
static float orientationCum = 0;
#define INCR_ORIENTATION 0.03
#define DECR_ORIENTATION 0.8
// Lean device left/right to control steering
orientationCum = controller.motion.attitude.y;
orientation = orientationCum;
if (controller.motion.attitude.x < 0) { // Go forward by leaning device top downwards
engineForce = -(controller.motion.attitude.x * 400);
_reactor.birthRate = _reactorDefaultBirthRate;
}
else if (controller.motion.attitude.x > 0) { // Go backward by leaning device top upwards
engineForce = (controller.motion.attitude.x * -400);
_reactor.birthRate = 0;
}
}
// END VGC IMPLEMENTATION
// ------------------------
_vehicleSteering = -orientation;
if (orientation==0)
_vehicleSteering *= 0.9;
if (_vehicleSteering < -steeringClamp)
_vehicleSteering = -steeringClamp;
if (_vehicleSteering > steeringClamp)
_vehicleSteering = steeringClamp;
//update the vehicle steering and acceleration
[_vehicle setSteeringAngle:_vehicleSteering forWheelAtIndex:0];
[_vehicle setSteeringAngle:_vehicleSteering forWheelAtIndex:1];
[_vehicle applyEngineForce:engineForce forWheelAtIndex:2];
[_vehicle applyEngineForce:engineForce forWheelAtIndex:3];
[_vehicle applyBrakingForce:brakingForce forWheelAtIndex:2];
[_vehicle applyBrakingForce:brakingForce forWheelAtIndex:3];
//check if the car is upside down
[self reorientCarIfNeeded];
// make camera follow the car node
SCNNode *car = [_vehicleNode presentationNode];
SCNVector3 carPos = car.position;
vector_float3 targetPos = {carPos.x, 30., carPos.z + 25.};
vector_float3 cameraPos = SCNVector3ToFloat3(_cameraNode.position);
cameraPos = vector_mix(cameraPos, targetPos, (vector_float3)(cameraDamping));
_cameraNode.position = SCNVector3FromFloat3(cameraPos);
if (scnView.inCarView) {
//move spot light in front of the camera
SCNVector3 frontPosition = [scnView.pointOfView.presentationNode convertPosition:SCNVector3Make(0, 0, -30) toNode:nil];
_spotLightNode.position = SCNVector3Make(frontPosition.x, 80., frontPosition.z);
_spotLightNode.rotation = SCNVector4Make(1,0,0,-M_PI/2);
}
else {
//move spot light on top of the car
_spotLightNode.position = SCNVector3Make(carPos.x, 80., carPos.z + 30.);
_spotLightNode.rotation = SCNVector4Make(1,0,0,-M_PI/2.8);
}
//speed gauge
AAPLOverlayScene *overlayScene = (AAPLOverlayScene*)scnView.overlaySKScene;
overlayScene.speedNeedle.zRotation = -(_vehicle.speedInKilometersPerHour * M_PI / MAX_SPEED);
}
- (void)reorientCarIfNeeded
{
SCNNode *car = [_vehicleNode presentationNode];
SCNVector3 carPos = car.position;
// make sure the car isn't upside down, and fix it if it is
static int ticks = 0;
static int check = 0;
ticks++;
if (ticks == 30) {
SCNMatrix4 t = car.worldTransform;
if (t.m22 <= 0.1) {
check++;
if (check == 3) {
static int try = 0;
try++;
if (try == 3) {
try = 0;
//hard reset
_vehicleNode.rotation = SCNVector4Make(0, 0, 0, 0);
_vehicleNode.position = SCNVector3Make(carPos.x, carPos.y + 10, carPos.z);
[_vehicleNode.physicsBody resetTransform];
}
else {
//try to upturn with an random impulse
SCNVector3 pos = SCNVector3Make(-10*((rand()/(float)RAND_MAX)-0.5),0,-10*((rand()/(float)RAND_MAX)-0.5));
[_vehicleNode.physicsBody applyForce:SCNVector3Make(0, 300, 0) atPosition:pos impulse:YES];
}
check = 0;
}
}
else {
check = 0;
}
ticks=0;
}
}
- (void)accelerometerDidChange:(CMAcceleration)acceleration
{
}
- (void)viewWillDisappear:(BOOL)animated
{
[_motionManager stopAccelerometerUpdates];
_motionManager = nil;
}
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment