【问题标题】:SpriteKit collision error, not sure how to get a function to run when two sprite nodes hit each otherSpriteKit 碰撞错误,当两个精灵节点相互碰撞时,不确定如何让函数运行
【发布时间】:2022-10-04 22:12:34
【问题描述】:

我收到错误消息:无法将“SKSpriteNode.Type”类型的值转换为预期的参数类型“SKSpriteNode”

当精灵节点敌人和小球发生碰撞时,我试图让碰撞子弹()函数运行时遇到了麻烦。我愿意改变我的设置,但可能我一辈子都无法让这个功能正常工作。

导入 SpriteKit 导入 GameplayKit

类游戏场景:SKScene,SKPhysicsContactDelegate {

let mainballcategory:UInt32 = 0x1 << 0
let smallballcategory:UInt32 = 0x1 << 1
let enemycategory:UInt32 = 0x1 << 3
var Mainball = SKSpriteNode(imageNamed: "Ball")
var enemytimer = Timer()

override func didMove(to view: SKView) {
    self.physicsWorld.contactDelegate = self

    Mainball.size = CGSize(width: 100, height: 100)
    Mainball.position = CGPoint(x:frame.width / 80, y:frame.height / 80)
    Mainball.zPosition = 1.0
    Mainball.physicsBody = SKPhysicsBody(circleOfRadius: Mainball.size.width/2)
    Mainball.physicsBody?.categoryBitMask = mainballcategory
    Mainball.physicsBody?.collisionBitMask = enemycategory
    Mainball.physicsBody?.contactTestBitMask = enemycategory
    Mainball.name = "Mainball"
    Mainball.physicsBody?.affectedByGravity = false
    self.addChild(Mainball)
    Timer.scheduledTimer(withTimeInterval: 0.8, repeats: true) { timer in
        let randomNumber = Int.random(in: 1...20)
        print("Number: \(randomNumber)")
        if randomNumber > 10 {
            self.Enemies()
        }
    }
}
    
func didBegin(_ contact: SKPhysicsContact) {
    let collision:UInt32 = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
    if collision == smallballcategory | enemycategory {
       collisionBullet(enemy: SKSpriteNode, smallball: SKSpriteNode) 
    }  
}

func collisionBullet(enemy : SKSpriteNode, smallball : SKSpriteNode){
    enemy.physicsBody!.isDynamic = true
    enemy.physicsBody!.affectedByGravity = true
    enemy.physicsBody!.mass = 6.0
    smallball.physicsBody?.mass = 10.0
    enemy.removeAllActions()
    smallball.removeAllActions()
    enemy.removeFromParent()
}

func touchDown(atPoint pos : CGPoint) {
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    for t in touches { self.touchDown(atPoint: t.location(in: self))
        for _ in (touches ){
            }
    }
    let smallball = SKSpriteNode(imageNamed: "Ball")
    
    smallball.position = Mainball.position
    smallball.size = CGSize(width: 30, height: 30)
    smallball.physicsBody = SKPhysicsBody(circleOfRadius: smallball.size.width / 2)
    
    smallball.physicsBody!.categoryBitMask = smallballcategory
    smallball.physicsBody!.collisionBitMask = enemycategory
    smallball.physicsBody!.contactTestBitMask = enemycategory
    smallball.name = "smallball"
    smallball.physicsBody!.isDynamic = true
    smallball.physicsBody!.affectedByGravity = true
    self.addChild(smallball)
    
    for t in touches { self.touchDown(atPoint: t.location(in: self))
        for touch in (touches ){
            let spot = touch.location(in: self)

            var dx = CGFloat(spot.x - Mainball.position.x)
            var dy = CGFloat(spot.y - Mainball.position.y)
            let magnitude = sqrt(dx * dx + dy * dy)
            dx /= magnitude
            dy /= magnitude
            let vector = CGVector(dx: 35.0 * dx, dy: 35.0 * dy)
            
            smallball.physicsBody!.applyImpulse(vector)
        }
    }
}

func Enemies(){
    let enemy = SKSpriteNode(imageNamed: "Ball")
    enemy.size = CGSize(width: 25, height: 25)
    enemy.color = UIColor(red: 0.9, green: 0.1, blue: 0.1, alpha: 1.0)
    enemy.colorBlendFactor = 1.0

   //Physics
    enemy.physicsBody = SKPhysicsBody(circleOfRadius: enemy.size.width / 2)
    enemy.physicsBody!.categoryBitMask = enemycategory
    enemy.physicsBody!.contactTestBitMask = smallballcategory | mainballcategory
    
    enemy.physicsBody!.collisionBitMask = smallballcategory | mainballcategory
    enemy.physicsBody!.isDynamic = false
    enemy.name = "enemy"
    
    let RandomPosNmbr = arc4random() % 6
    
    switch RandomPosNmbr{
    case 0:
        enemy.position = CGPoint(x:self.view!.bounds.width, y:self.view!.bounds.height)
        self.addChild(enemy)
        break
    case 1:
        enemy.position = CGPoint(x:self.view!.bounds.width * -1, y:self.view!.bounds.height)
        self.addChild(enemy)
        break
    case 2:
        enemy.position = CGPoint(x:self.view!.bounds.width, y:self.view!.bounds.height * -1)
        self.addChild(enemy)
        break
    case 3:
        enemy.position = CGPoint(x:self.view!.bounds.width * -1, y:self.view!.bounds.height * -1)
        self.addChild(enemy)
        break
    case 4:
        enemy.position = CGPoint(x:self.view!.bounds.width / 10, y:self.view!.bounds.height * -1)
        self.addChild(enemy)
        break
    case 5:
        enemy.position = CGPoint(x:self.view!.bounds.width / 10, y:self.view!.bounds.height)
        self.addChild(enemy)
        break
    default:
        break
    }

    enemy.run(SKAction.move(to: Mainball.position, duration: 5))
}

override func update(_ currentTime: TimeInterval) { 
}

}

【问题讨论】:

  • 该消息是说您正在尝试将SKSpriteNode(一种类型)传递给collisionBullet。您希望自己传递节点。从contact.bodyA.nodecontact.bodyB.node 获取它们。

标签: swift sprite-kit collision


【解决方案1】:

您确定 didBegin() 已开始调用吗?尝试像这样编码didBegin

      func didBegin(_ contact: SKPhysicsContact) {
         print("didBeginContact entered for (String(describing: contact.bodyA.node!.name)) and (String(describing: contact.bodyB.node!.name))")
    
         let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
    
         switch contactMask {
         case smallBallCategory | enemyCategory:
            print("smallBall and enemy have contacted.")
            let smallBallNode = contact.bodyA.categoryBitMask == smallBallCategory ? contact.bodyA.node : contact.bodyB.node
            let enemyNode = contact.bodyA.categoryBitMask == enemyCategory ? contact.bodyA.node : contact.bodyB.node
            collisionBullet(enemy: enemyNode, smallball: smallBallNode)
         default:
            print("Some other contact occurred")
         }

如果调用 didBegin(),您将看到一条消息 - 没有消息,则说明您的接触测试配置不正确。

正如前面的评论所说,当您应该传递 2 个实际节点时,您将一个类型传递给 collisionBullet

另外,当您要删除它时,您是否需要将collisionBullet() 中的所有代码发送到敌人节点?你能不能在didBegin() 中有这样的代码:

         case smallBallCategory | enemyCategory:
            print("smallBall and enemy have contacted.")
            let smallBallNode = contact.bodyA.categoryBitMask == smallBallCategory ? contact.bodyA.node : contact.bodyB.node
            let enemyNode = contact.bodyA.categoryBitMask == enemyCategory ? contact.bodyA.node : contact.bodyB.node
            smallBallNode.physicsBody?.mass = 10.0
            smallBallNode.removeAllActions()
            enemyNode.removeFromParent()

您可能会发现这些很有帮助(很旧,但希望仍然相关):

我的碰撞和接触分步指南: https://stackoverflow.com/a/51041474/1430420

以及碰撞和接触测试位掩码指南: https://stackoverflow.com/a/40596890/1430420

操作位掩码以关闭和打开单独的碰撞和接触。 https://stackoverflow.com/a/46495864/1430420

带有接触、碰撞和接触的小示例项目 https://stackoverflow.com/a/43605825/1430420

编辑:

我并不是说我的方式是编写didBegin() 的最佳方式,但我发现这样做对我来说非常清楚,不同的case 语句非常清楚地突出了不同的冲突。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-04
    • 1970-01-01
    • 1970-01-01
    • 2011-08-21
    • 1970-01-01
    • 1970-01-01
    • 2013-10-07
    相关资源
    最近更新 更多