didBeginContact 传递给 PKPhyicsObject

didBeginContact passed PKPhyicsObject

我有一个扩展 SKPhysicsContact

的辅助方法
extension SKPhysicsContact {

    /// - returns: `[SKPhysicsBody]` containing all the bodies that match `mask`
    func bodiesMatchingCategory(mask: UInt32) -> [SKPhysicsBody] {
        let bodies = [bodyA, bodyB]
        return bodies.filter { ([=10=].categoryBitMask & mask) != 0 }
    }
}

in didBeginContact() 我在传入的 contact.

上调用此方法
func didBeginContact(contact: SKPhysicsContact) {
    let ballMask: UInt32 = 0x1 << 2
    let ball = contact.bodiesMatchingCategory(ballMask)
...

我有时会收到此错误消息(如五分之一),这会导致应用程序崩溃:

-[PKPhysicsContact bodiesMatchingCategory:]: unrecognized selector sent to instance 0x165f2350

我查找了 PKPhysicsContact,它是私有框架 (link) 的一部分。 SKPhysicsContact 看起来只是一个空的 class 定义,它只公开了 PKPhysicsContact.

的某些属性

我觉得这是 SpriteKit 团队的 Objective-C 破解,它破坏了 Swift 的强类型。

帮忙?

如何确保我总是 SKPhysicsContact 回来?


我添加了一个检查以测试 SKPhysicsContact

let test = contact as Any
print("Test is: \(test)")
guard test is SKPhysicsContact else {
    return
}

正确捕捉到类型不匹配。

事实上,从不 returns SKPhysicsContact!!?


我已经在 Objective-C 中尝试这样做(根据回复者的建议),我得到了相同的结果。

我在Apple Dev Forums上进行了讨论,可能会给以后的求解答者一些帮助。

这里是Objective-C代码供参考:

@interface SKPhysicsContact (MatchingBodies)

- (NSArray *)bodiesMatchingCategory:(UInt32)category;

@end

@implementation SKPhysicsContact (MatchingBodies)

- (NSArray *)bodiesMatchingCategory:(UInt32)category {
    NSArray *bodies = @[self.bodyA, self.bodyB];

    NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(SKPhysicsBody *body, NSDictionary *bindings) {
        return (body.categoryBitMask & category) != 0;
    }];
    NSArray *matching = [bodies filteredArrayUsingPredicate:predicate];
    return matching;
}

@end

呼叫这里:

-(void)didBeginContact:(SKPhysicsContact *)contact
{
    static const uint32_t MarbleContact = 0x1 <<1;  // 2
    static const uint32_t GoalContact = 0x1 <<2;    // 4

    SKPhysicsBody *ball = [contact bodiesMatchingCategory:MarbleContact].firstObject;
    NSLog(@"Ball: %@", ball);
    ...

Returns 这次崩溃:

-[PKPhysicsContact bodiesMatchingCategory:]: unrecognized selector sent to instance 0x17dad9e0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[PKPhysicsContact bodiesMatchingCategory:]: unrecognized selector sent to instance 0x17dad9e0'

为 Apple 添加了错误报告,#23332190

我用这个简单的代码得到了同样的错误:

extension SKPhysicsContact {
    func bodiesMatchingCategory(mask: UInt32) -> [SKPhysicsBody] {
        let bodies = [bodyA, bodyB]
        return bodies.filter { ([=10=].categoryBitMask & mask) != 0 }
    }
}

let contact = SKPhysicsContact()
let body = contact.bodiesMatchingCategory(0)

问题是,contact 的类型是 PKPhysicsContact(如您所见),即使您明确告诉它是 SKPhysicsContact,并且扩展名是在 SKPhysicsContact 上。您必须能够对 PKPhysicsContact 进行扩展才能使其工作。根据这个逻辑,我们可以说目前没有实例方法可以在 SKPhysicsContact 扩展中工作。我会说这是 SpriteKit 的错误,您应该 提交雷达 。 Class 方法仍然有效,因为您在 class 本身上调用它们。

同时,您应该能够将该方法移动到您的场景或其他对象中并在那里成功调用它。


郑重声明,这不是 Swift 特有的问题。如果您在 SKPhysicsContact 的 Objective-C 类别中使用相同的方法,您将遇到同样的崩溃。