Метод делегата didBeginContact не запускается для обнаружения столкновений ARKit - PullRequest
0 голосов
/ 20 апреля 2020

Я не могу заставить метод didBeginContact сработать, я пытался некоторое время и не могу определить ошибку, могу использовать набор sh глаз:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.lastRender = nil;
    self.accelX = 0.0;
    self.accelY = 0.0;
    self.accelZ = 0.0;
    self.isLooping = TRUE;
    self.tripWire = TRUE;
    self.lastPaddleNode = [[SCNNode alloc] init];

    self.paddleNode = [[SCNNode alloc] init];
    SCNPlane* paddlePlane = [SCNPlane planeWithWidth:0.067056 height:0.138176];
    self.paddleNode.geometry = paddlePlane;
    self.paddleNode.geometry.firstMaterial.diffuse.contents = [UIColor colorWithRed:133.0/255.0f green:158.0/255.0f blue:122.0/255.0f alpha:0.8];
    self.paddleNode.simdTransform = matrix_identity_float4x4;
    self.paddleNode.name = @"paddle";

    SCNPhysicsBody* paddlePhys = [[SCNPhysicsBody alloc] init];
    paddlePhys.type = SCNPhysicsBodyTypeDynamic;
    paddlePhys.physicsShape = [SCNPhysicsShape shapeWithGeometry:paddlePlane options:nil];
    //paddlePhys.affectedByGravity = FALSE;
    paddlePhys.categoryBitMask = SCNPhysicsCollisionCategoryAll;
    paddlePhys.collisionBitMask = SCNPhysicsCollisionCategoryAll;
    paddlePhys.contactTestBitMask = SCNPhysicsCollisionCategoryAll;
    paddlePhys.usesDefaultMomentOfInertia = TRUE;
    self.paddleNode.physicsBody = paddlePhys;

    SCNNode* ball = [[SCNNode alloc] init];
    SCNPhysicsBody* phys = [[SCNPhysicsBody alloc] init];
    phys.type = SCNPhysicsBodyTypeDynamic;
    SCNSphere* sphere = [SCNSphere sphereWithRadius:0.067f];
    phys.physicsShape = [SCNPhysicsShape shapeWithGeometry:sphere options:nil];
    ball.geometry = sphere;
    ball.geometry.firstMaterial.diffuse.contents = [UIColor yellowColor];
    //phys.affectedByGravity = FALSE;
    phys.categoryBitMask = SCNPhysicsCollisionCategoryAll;
    phys.collisionBitMask = SCNPhysicsCollisionCategoryAll;
    phys.contactTestBitMask = SCNPhysicsCollisionCategoryAll;
    phys.usesDefaultMomentOfInertia = TRUE;
    phys.velocityFactor = SCNVector3Make(10.0, 10.0, 10.0);
    ball.physicsBody = phys;
    ball.physicsBody.continuousCollisionDetectionThreshold = 0.134f;
    ball.simdPosition = simd_make_float3(0.0, 0.27, -0.27);
    ball.name = @"ball";
    //phys.velocityFactor = SCNVector3Make(10, 10, 10);

    [self.sceneView setPreferredFramesPerSecond:60];

    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;

    // Set the view's delegate
    self.sceneView.delegate = self;

    // Show statistics such as fps and timing information
    self.sceneView.showsStatistics = YES;

    //phys.velocityFactor = SCNVector3Make(10, 10, 10);

    // Create a new scene
    SCNScene* scene = [[SCNScene alloc] init];
    scene.physicsWorld.contactDelegate = self;
    self.sceneView.scene = scene;

    [locationManager startUpdatingHeading];

    while(!(self.locationManager.heading.trueHeading <= 360 && self.locationManager.heading.trueHeading >= 359)) {

        NSLog(@"heading: %f", self.locationManager.heading.trueHeading);

        if (self.locationManager.heading.trueHeading <= 360 && self.locationManager.heading.trueHeading >= 359) {
            break;
        }
    }

    [self.sceneView.scene.rootNode addChildNode:self.paddleNode];
    [self.sceneView.scene.rootNode addChildNode:ball];

    [self startUpdates];
}

Все, что я сейчас пытаюсь сделать, это написать метод делегата, который запускается, когда два узла в моей игре сталкиваются:

- (void)physicsWorld:(SCNPhysicsWorld *)world didBeginContact:(SCNPhysicsContact *)contact {
    NSLog(@"in didBeginContact");
    CollisionCategory contactMask =
        contact.nodeA.physicsBody.categoryBitMask | contact.nodeB.physicsBody.categoryBitMask;

    // first, sort out what kind of collision
    if (contactMask == (CollisionCategoryPaddle | CollisionCategoryBall)) {
        // next, sort out which body is the missile and which is the rocket
        // and do something about it
        if (contact.nodeA.physicsBody.categoryBitMask == CollisionCategoryPaddle) {
            NSLog(@"nodeA is paddle!");
            //[self hitRocket:contact.nodeB withMissile:contact.nodeA];
        } else {
            NSLog(@"nodeB is paddle!");
            //[self hitRocket:contact.nodeA withMissile:contact.nodeB];
        }
    }
}

Примечание Я знаю, что использую SCNPhysicsCollisionCategoryAll и затем проверка другого типа битовой маски в методе. Это не моя проблема, моя проблема до этого, я никогда не вижу этого оператора журнала, который является первой строкой в ​​моем didBeginContact методе делегата:

NSLog(@"in didBeginContact");

Почему мой метод не запускается? Я думаю, что я правильно установил делегата. Спасибо.

ОБНОВЛЕНИЕ Мой viewDidLoad теперь выглядит так, согласно предложению комментатора:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Create a new scene
    SCNScene* scene = [[SCNScene alloc] init];
    scene.physicsWorld.contactDelegate = self;
    self.sceneView.scene = scene;
    // Set the view's delegate
    self.sceneView.delegate = self;

    SCNPlane* paddlePlane = [SCNPlane planeWithWidth:0.067056 height:0.138176];
    self.paddleNode = [SCNNode nodeWithGeometry:paddlePlane];
    self.paddleNode.geometry.firstMaterial.diffuse.contents = [UIColor colorWithRed:133.0/255.0f green:158.0/255.0f blue:122.0/255.0f alpha:0.8];
    self.paddleNode.simdTransform = matrix_identity_float4x4;
    self.paddleNode.name = @"paddle";
    [self.sceneView.scene.rootNode addChildNode:self.paddleNode];

    SCNPhysicsBody* paddlePhys = [[SCNPhysicsBody alloc] init];
    paddlePhys.type = SCNPhysicsBodyTypeDynamic;
    paddlePhys.physicsShape = [SCNPhysicsShape shapeWithGeometry:self.paddleNode.geometry options:@{SCNPhysicsShapeTypeKey: SCNPhysicsShapeTypeBoundingBox}];
    //paddlePhys.affectedByGravity = FALSE;
    paddlePhys.categoryBitMask = SCNPhysicsCollisionCategoryAll;
    paddlePhys.collisionBitMask = SCNPhysicsCollisionCategoryAll;
    paddlePhys.contactTestBitMask = SCNPhysicsCollisionCategoryAll;
    //paddlePhys.usesDefaultMomentOfInertia = TRUE;
    self.paddleNode.physicsBody = paddlePhys;

    SCNNode* ball = [[SCNNode alloc] init];
    [self.sceneView.scene.rootNode addChildNode:ball];

    SCNPhysicsBody* phys = [[SCNPhysicsBody alloc] init];
    phys.type = SCNPhysicsBodyTypeDynamic;
    SCNSphere* sphere = [SCNSphere sphereWithRadius:0.067f];
    phys.physicsShape = [SCNPhysicsShape shapeWithGeometry:sphere options:@{SCNPhysicsShapeTypeKey: SCNPhysicsShapeTypeConvexHull}];
    ball.geometry = sphere;
    ball.geometry.firstMaterial.diffuse.contents = [UIColor yellowColor];
    //phys.affectedByGravity = FALSE;
    phys.categoryBitMask = SCNPhysicsCollisionCategoryAll;
    phys.collisionBitMask = SCNPhysicsCollisionCategoryAll;
    phys.contactTestBitMask = SCNPhysicsCollisionCategoryAll;
    phys.usesDefaultMomentOfInertia = TRUE;
    phys.velocityFactor = SCNVector3Make(10.0, 10.0, 10.0);
    ball.physicsBody = phys;
    ball.physicsBody.continuousCollisionDetectionThreshold = 0.134f;
    ball.simdPosition = simd_make_float3(0.0, 0.27, -0.27);
    ball.name = @"ball";

    //phys.velocityFactor = SCNVector3Make(10, 10, 10);

    // Show statistics such as fps and timing information
    self.sceneView.showsStatistics = YES;

    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;

    [locationManager startUpdatingHeading];

    while(!(self.locationManager.heading.trueHeading <= 360 && self.locationManager.heading.trueHeading >= 358)) {

        NSLog(@"heading: %f", self.locationManager.heading.trueHeading);

        if (self.locationManager.heading.trueHeading <= 360 && self.locationManager.heading.trueHeading >= 358) {
            break;
        }
    }

    [self.sceneView setPreferredFramesPerSecond:60];

    self.lastRender = nil;
    self.accelX = 0.0;
    self.accelY = 0.0;
    self.accelZ = 0.0;
    self.isLooping = TRUE;
    self.tripWire = TRUE;
    self.lastPaddleNode = [[SCNNode alloc] init];

    [self startUpdates];
}

Я согласен с комментатором, что это, вероятно, проблема с как все здесь упорядочено, я просто не могу понять, что это такое ... helllppp, я droowwnnninng ...

ОБНОВЛЕНИЕ Я изменил свои побитовые маски следующим образом, я не сделал Я не использую пользовательский тип enum, потому что у меня есть только два объекта, поэтому я думаю, что могу просто использовать ...All и ...Default, но это не работает так. Я попробую пользовательский тип enum, когда пойму побитовую операцию И, если кто-нибудь сможет объяснить мне левую / правую часть и как выполнить операцию?

//Paddle
paddlePhys.categoryBitMask = SCNPhysicsCollisionCategoryDefault;
paddlePhys.collisionBitMask = SCNPhysicsCollisionCategoryAll;
paddlePhys.contactTestBitMask = SCNPhysicsCollisionCategoryAll;

...

//Ball
phys.categoryBitMask = SCNPhysicsCollisionCategoryAll;
phys.collisionBitMask = SCNPhysicsCollisionCategoryDefault;
phys.contactTestBitMask = SCNPhysicsCollisionCategoryDefault;

Должно ли это работать? У меня также теперь есть мой весло:

paddlePhys.type = SCNPhysicsBodyTypeKinematic;
paddlePhys.physicsShape = [SCNPhysicsShape shapeWithGeometry:self.paddleNode.geometry options:@{SCNPhysicsShapeTypeKey: SCNPhysicsShapeTypeBoundingBox}];

Мой мяч такой:

phys.type = SCNPhysicsBodyTypeDynamic;
phys.physicsShape = [SCNPhysicsShape shapeWithGeometry:sphere options:@{SCNPhysicsShapeTypeKey: SCNPhysicsShapeTypeConvexHull}];

Все вместе сейчас у меня есть:

- (void)viewDidLoad {
    [super viewDidLoad];

    self.sceneView.delegate = self;

    // Show statistics such as fps and timing information
    self.sceneView.showsStatistics = YES;

    SCNScene* scene = [[SCNScene alloc] init];

    // Create a new scene
    SCNPlane* paddlePlane = [SCNPlane planeWithWidth:0.067056 height:0.138176];
    paddlePlane.firstMaterial.doubleSided = YES;
    self.paddleNode = [SCNNode nodeWithGeometry:paddlePlane];
    self.paddleNode.geometry.firstMaterial.diffuse.contents = [UIColor colorWithRed:133.0/255.0f green:158.0/255.0f blue:122.0/255.0f alpha:0.8];
    self.paddleNode.simdTransform = matrix_identity_float4x4;
    self.paddleNode.name = @"paddle";

    SCNPhysicsBody* paddlePhys = [[SCNPhysicsBody alloc] init];
    paddlePhys.type = SCNPhysicsBodyTypeKinematic;
    paddlePhys.physicsShape = [SCNPhysicsShape shapeWithGeometry:self.paddleNode.geometry options:@{SCNPhysicsShapeTypeKey: SCNPhysicsShapeTypeBoundingBox}];
    //paddlePhys.affectedByGravity = FALSE;
    paddlePhys.categoryBitMask = SCNPhysicsCollisionCategoryDefault;
    paddlePhys.collisionBitMask = SCNPhysicsCollisionCategoryAll;
    paddlePhys.contactTestBitMask = SCNPhysicsCollisionCategoryAll;
    //paddlePhys.usesDefaultMomentOfInertia = TRUE;
    self.paddleNode.physicsBody = paddlePhys;

    self.paddleNode.simdPivot = [self makeTranslationMatrix:0 ty: 0 tz:0.1];

    SCNNode* ball = [[SCNNode alloc] init];

    SCNPhysicsBody* phys = [[SCNPhysicsBody alloc] init];
    SCNSphere* sphere = [SCNSphere sphereWithRadius:0.067f];
    phys.type = SCNPhysicsBodyTypeDynamic;
    phys.physicsShape = [SCNPhysicsShape shapeWithGeometry:sphere options:@{SCNPhysicsShapeTypeKey: SCNPhysicsShapeTypeConvexHull}];
    ball.geometry = sphere;
    ball.geometry.firstMaterial.diffuse.contents = [UIColor yellowColor];
    //phys.affectedByGravity = FALSE;
    phys.categoryBitMask = SCNPhysicsCollisionCategoryAll;
    phys.collisionBitMask = SCNPhysicsCollisionCategoryDefault;
    phys.contactTestBitMask = SCNPhysicsCollisionCategoryDefault;
    phys.usesDefaultMomentOfInertia = TRUE;
    phys.velocityFactor = SCNVector3Make(10.0, 10.0, 10.0);
    ball.physicsBody = phys;
    ball.physicsBody.continuousCollisionDetectionThreshold = 0.134f;
    ball.simdPosition = simd_make_float3(0.0, 0.27, -0.27);
    ball.name = @"ball";

    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;

    [locationManager startUpdatingHeading];

    while(!(self.locationManager.heading.trueHeading <= 360 && self.locationManager.heading.trueHeading >= 358)) {

        NSLog(@"heading: %f", self.locationManager.heading.trueHeading);

        if (self.locationManager.heading.trueHeading <= 360 && self.locationManager.heading.trueHeading >= 358) {
            break;
        }
    }

    [self.sceneView setPreferredFramesPerSecond:60];

    self.lastRender = nil;
    self.accelX = 0.0;
    self.accelY = 0.0;
    self.accelZ = 0.0;
    self.isLooping = TRUE;
    self.tripWire = TRUE;
    self.lastPaddleNode = [[SCNNode alloc] init];

    [scene.rootNode addChildNode:ball];
    [scene.rootNode addChildNode:self.paddleNode];

    scene.physicsWorld.contactDelegate = self;
    self.sceneView.scene = scene;

    [self startUpdates];
}

I Мне также интересно, если проблема может быть в блоке для событий CMDeviceMotion, вот что:

- (void)startUpdates {
    //dispatch_queue_t myQueue = dispatch_queue_create("com.eamon.corona_pong", DISPATCH_QUEUE_SERIAL);
    // Determine the update interval.
    NSTimeInterval updateInterval = 1.0/60.0;
    // Create a CMMotionManager object.
    CMMotionManager *mManager = [(AppDelegate *)[[UIApplication sharedApplication] delegate] sharedManager];
    if ([mManager isDeviceMotionAvailable] == YES) {
        [mManager setDeviceMotionUpdateInterval:updateInterval];
        // do something appropriate here
        if ([CMMotionManager availableAttitudeReferenceFrames] & CMAttitudeReferenceFrameXTrueNorthZVertical) {

            [mManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXArbitraryCorrectedZVertical toQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion * _Nullable motion, NSError * _Nullable error) {
                //[self handleMotionWrapper:motion];
                [SCNTransaction begin];
                [SCNTransaction setAnimationDuration:0];
                //simd_float4x4 rotateY = [self makeYRotationMatrix:270.0];
                //simd_float4x4 rotate = [self makeXRotationMatrix:270.0];

                simd_float4x4 cameraTrans = self.sceneView.session.currentFrame.camera.transform;

                simd_float4x4 temp = simd_mul(cameraTrans, [self makeYRotationMatrix:270.0]);

                //simd_float4x4 rotated = simd_mul(temp, [self makeYRotationMatrix:135]);

                simd_float4x4 transMatrixMotion = [self makeTranslationMatrix:self.lastPaddleNode.simdPosition.x ty:self.lastPaddleNode.simdPosition.y - 0.1 tz:self.lastPaddleNode.simdPosition.z];

                self.paddleNode.simdPosition = simd_make_float3(simd_mul(simd_make_float4(temp.columns[3][0], temp.columns[3][1], temp.columns[3][2], 1.0), transMatrixMotion));

                self.paddleNode.simdTransform = temp;
                [SCNTransaction commit];

                self.lastPaddleNode = self.paddleNode;
                self.tripWire = FALSE;
            }];
        }
    }
}

Я все еще работаю над кодом движения, но я думаю, что столкновение должно работать, хотя У меня пока нет ориентации весла, как я хочу (мне просто нужно повернуть его на 90 градусов вокруг оси y, но это раздражает, но не должно иметь значения для обнаружения столкновений, верно?)

Кроме того, что касается SCNPlane, я также сделал свой SCNPlane (весло) двухсторонним с атрибутом doubleSided атрибута firstMaterial, но это не помогло, возможно, мне нужно использовать мелкий SCNBox? Я пробовал это раньше, но, возможно, некоторые из внесенных мною изменений будут означать, что это сработает, если я сделаю весло и SCNBox вместо двухстороннего SCNPlane?

СПАСИБО!

ОБНОВЛЕНИЕ Я думал, что поделюсь своей последней попыткой, не работает, но я думаю, что это может быть ближе, может быть легче определить проблему:

typedef NS_OPTIONS(NSUInteger, CollisionCategory)
{
    CollisionCategoryPaddle = 1 << 0,
    CollisionCategoryBall = 1 << 1,
};

- (void)viewDidLoad {
    [super viewDidLoad];

    self.sceneView.delegate = self;

    // Show statistics such as fps and timing information
    self.sceneView.showsStatistics = YES;

    SCNScene* scene = [[SCNScene alloc] init];
    self.sceneView.scene = scene;
    self.sceneView.scene.physicsWorld.contactDelegate = self;
    // Create a new scene
    SCNBox* paddlePlane = [SCNBox boxWithWidth:0.067056 height:0.138176 length:0.01 chamferRadius:0.0];
    paddlePlane.firstMaterial.doubleSided = YES;
    self.paddleNode = [SCNNode nodeWithGeometry:paddlePlane];
    self.paddleNode.geometry.firstMaterial.diffuse.contents = [UIColor colorWithRed:133.0/255.0f green:158.0/255.0f blue:122.0/255.0f alpha:0.8];
    self.paddleNode.simdTransform = matrix_identity_float4x4;
    self.paddleNode.name = @"paddle";

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

    SCNPhysicsBody* paddlePhys = [[SCNPhysicsBody alloc] init];
    paddlePhys.type = SCNPhysicsBodyTypeKinematic;
    paddlePhys.physicsShape = [SCNPhysicsShape shapeWithGeometry:self.paddleNode.geometry options:nil];
    //paddlePhys.affectedByGravity = FALSE;
    paddlePhys.categoryBitMask = CollisionCategoryPaddle;
    paddlePhys.collisionBitMask = CollisionCategoryBall;
    paddlePhys.contactTestBitMask = CollisionCategoryBall;
    //paddlePhys.usesDefaultMomentOfInertia = TRUE;
    self.paddleNode.physicsBody = paddlePhys;

    SCNPhysicsBody* phys = [[SCNPhysicsBody alloc] init];
    SCNSphere* sphere = [SCNSphere sphereWithRadius:0.067f];
    self.ballNode = [[SCNNode alloc] init];
    self.ballNode.name = @"ball";
    self.ballNode.geometry = sphere;
    self.ballNode.geometry.firstMaterial.diffuse.contents = [UIColor yellowColor];
    //self.ballNode.physicsBody.continuousCollisionDetectionThreshold = (CGFloat)0.134f;
    self.ballNode.simdPosition = simd_make_float3(0.0, 0.27, -0.27);

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

    phys.type = SCNPhysicsBodyTypeDynamic;
    phys.physicsShape = [SCNPhysicsShape shapeWithGeometry:self.ballNode.geometry options:nil];
    phys.categoryBitMask = CollisionCategoryBall;
    phys.collisionBitMask = CollisionCategoryPaddle;
    phys.contactTestBitMask = CollisionCategoryPaddle;
    //phys.usesDefaultMomentOfInertia = TRUE;
    //phys.velocityFactor = SCNVector3Make(10.0, 10.0, 10.0);
    self.ballNode.physicsBody = phys;

    //phys.affectedByGravity = FALSE

    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;

    [locationManager startUpdatingHeading];

    while(!(self.locationManager.heading.trueHeading <= 360 && self.locationManager.heading.trueHeading >= 358)) {

        NSLog(@"heading: %f", self.locationManager.heading.trueHeading);

        if (self.locationManager.heading.trueHeading <= 360 && self.locationManager.heading.trueHeading >= 358) {
            break;
        }
    }

    [self.sceneView setPreferredFramesPerSecond:60];

    self.lastRender = nil;
    self.accelX = 0.0;
    self.accelY = 0.0;
    self.accelZ = 0.0;
    self.isLooping = TRUE;
    self.tripWire = TRUE;
    self.lastPaddleNode = [[SCNNode alloc] init];

    [self startUpdates];
}

Я пытался тоже так, хотя я не уверен, правильно ли я это использую:

phys.physicsShape = [SCNPhysicsShape shapeWithGeometry:self.ballNode.geometry options:@{SCNHitTestOptionCategoryBitMask:[NSNumber numberWithUnsignedInt:CollisionCategoryBall], SCNPhysicsTestCollisionBitMaskKey:[NSNumber numberWithUnsignedInt:CollisionCategoryPaddle]}];

1 Ответ

0 голосов
/ 25 апреля 2020

1.) Добавьте scene к sceneView

2.) Объявите узлы, которые вы будете использовать для объектов, которые вы также будете давать физике.

3.) Внесите необходимые изменения в созданные объекты (цвет и т. Д. c.).

- ШАГ 4 ВНИМАНИЯ ОЧЕНЬ ВАЖЕН -

4. ) Только после указанных выше шагов (1, 2 и 3) вы добавляете physicsBody подробности к объекту! (он же node.physicsBody.xxx)

Добавьте узлы на сцену.

На мой взгляд, способ, которым SceneKit обрабатывает эту часть вещей, нелеп и требует пересмотра. Слишком много часов, проведенных в ситуации, когда SCNNode, который еще даже не был добавлен в сцену, вызывает проблемы из-за порядка, в котором вы создаете его атрибуты: (

...