如何在Spritekite Swift中正确设置碰撞?

时间:2018-07-31 23:10:29

标签: swift sprite-kit

我正在创建一个游戏,在该游戏中,球在顶部产生,然后掉落并反弹到地面上(此方法有效)。我现在正在进行碰撞,子弹击中球并弹起。如果您需要任何其他代码,我会将其发布。 (已编辑)

import Foundation
import SpriteKit

已移动到视图

struct PhysicsCategory {
    static let none: UInt32 = 0b0
    static let player: UInt32 = 0b1
    static let ball: UInt32 = 0b10
    static let bullet: UInt32 = 0b100
    static let ground: UInt32 = 0b1000
}

class GameScene: SKScene, SKPhysicsContactDelegate {


override func didMove(to view: SKView) {
    self.physicsWorld.contactDelegate = self
    let sceneBody = SKPhysicsBody(edgeLoopFrom: self.frame)
    sceneBody.friction = 0
    self.physicsBody = sceneBody
    player.position = CGPoint(x: self.size.width/2, y: self.size.height / 8)
    var timer = Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(spawnBullet), userInfo: nil, repeats: true)
    player.size = CGSize(width: 100, height: 100)
    player.physicsBody = SKPhysicsBody(circleOfRadius: player.size.width/2)
    player.physicsBody?.affectedByGravity = false
    player.physicsBody?.isDynamic = true

    ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.width/2)
    ball.physicsBody?.restitution = 1
    ball.physicsBody?.linearDamping = 0


    bullet.size = CGSize(width: 30, height: 30)
    bullet.zPosition = -5
    bullet.position = CGPoint(x: player.position.x, y: player.position.y)
    let action = SKAction.moveTo(y: self.size.height + 30, duration: 1.0)
    bullet.run(SKAction.repeatForever(action))
    bullet.physicsBody = SKPhysicsBody(circleOfRadius: bullet.size.width/2)
    bullet.name = "bullet"
    player.physicsBody?.categoryBitMask = PhysicsCategory.player
    player.physicsBody?.collisionBitMask = PhysicsCategory.none
    player.physicsBody?.contactTestBitMask = PhysicsCategory.ball

    bullet.physicsBody?.categoryBitMask = PhysicsCategory.bullet
    bullet.physicsBody?.collisionBitMask = PhysicsCategory.none
    bullet.physicsBody?.contactTestBitMask = PhysicsCategory.ball


    ball.physicsBody?.categoryBitMask = PhysicsCategory.ball
    ball.physicsBody?.contactTestBitMask = PhysicsCategory.bullet
    ball.physicsBody?.collisionBitMask = PhysicsCategory.ground

    ground.physicsBody?.categoryBitMask = PhysicsCategory.ground
    ground.physicsBody?.collisionBitMask = PhysicsCategory.ball
    ground.physicsBody?.contactTestBitMask = PhysicsCategory.none
    player.name = "player"
    addChild(player)
    ballSpawner(delay: 2.0)
    spawnGround()
}
//didBegin function
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

我认为这部分不正确 我的情况对吗?因为当我尝试写子弹和球时,它给我一个错误-“ Binary operator'|'不能应用于两个'SKSpriteNode'操作数”。因此只调用默认情况。

    switch contactMask {
  //This case never gets called, i can't see it in the console when i run it
    case PhysicsCategory.bullet | PhysicsCategory.ball:
        let bullet = contact.bodyA.categoryBitMask == 
PhysicsCategory.bullet ? contact.bodyA.node : contact.bodyB.node
        let ball = contact.bodyA.categoryBitMask == 
PhysicsCategory.ball ? contact.bodyA.node : contact.bodyB.node
        collisionBulletAndBall(ball: (ball)!, bullet: (bullet)!)
        print("bullet and ball have contacted.")
    case PhysicsCategory.bullet:
        print("bullet contact")
    case PhysicsCategory.ball & PhysicsCategory.bullet:
        print("collision ball with bullet")
    default:
        print("Some other contact occurred")
    }
}

func gameOver() {
    print("game over")
}

func collisionBulletAndBall(ball: SKNode, bullet: SKNode) {

    ball.removeFromParent()
    bullet.removeFromParent()
    print("collision")
}
 @objc func spawnBullet() {
    var bullet = SKSpriteNode(imageNamed: "bullet")
    bullet.size = CGSize(width: 30, height: 30)
    bullet.zPosition = -5
    bullet.position = CGPoint(x: player.position.x, y: player.position.y)
    let action = SKAction.moveTo(y: self.size.height + 30, duration: 1.0)
    bullet.run(SKAction.repeatForever(action))
    bullet.name = "bullet"
    self.addChild(bullet)
    bullets.append(bullet)
}
 func spawnScoreBall() {
    var ballSize = CGSize(width: 30, height: 30)
    //Random Size
    let randomSize = arc4random() % 3
    switch randomSize {
    case 1:
        ballSize.width *= 1.2
        ballSize.height *= 1.2
    case 2:
        ballSize.width *= 1.5
        ballSize.height *= 1.5
    default:
        break
    }
    var ball = SKSpriteNode(imageNamed: "ball")
    ball.size = ballSize
    let y = size.height-ballSize.height/2
    //Random x
    var randomX = CGFloat(arc4random() % UInt32(size.width - ballSize.width))
    randomX -= size.width/2-ballSize.width*4
    ball.position = CGPoint(x: randomX, y: y)
    //Moving logic
    //        let moveDownAction = SKAction.moveBy(x: 0, y: -size.height + ball.size.height, duration: 2.0)
    //        let destroyAction = SKAction.removeFromParent()
    //        let sequenceAction = SKAction.sequence([moveDownAction, destroyAction])
    //        ball.run(sequenceAction)
    //Rotation
    var rotateAction = SKAction.rotate(byAngle: 1, duration: 1)
    let randomRotation = arc4random() % 2
    if randomRotation == 1 {
        rotateAction = SKAction.rotate(byAngle: -1, duration: 1)
    }
    let repeatForeverAction = SKAction.repeatForever(rotateAction)
    ball.run(repeatForeverAction)
    ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.width/2)
    ball.physicsBody?.affectedByGravity = true
    ball.physicsBody?.restitution = 1
    ball.physicsBody?.linearDamping = 0
    ball.zPosition = 3
    blocks.append(ball)
    self.addChild(ball)
}

产生地面行动

func spawnGround() {
    ground = SKSpriteNode(color: UIColor.white, size: CGSize(width: self.frame.size.width, height: 50))
    ground.position = CGPoint(x: self.size.width/2, y: 0)
 }

1 个答案:

答案 0 :(得分:2)

playerbullet似乎没有物理物体(没有player.physicsBody = SKPhysicsBody ...和bullet.physicsBody = SKPhysicsBody ...

分配物理物体的属性后,

将球的物理物体分配为 way

ball.physicsBody?.categoryBitMask = PhysicsCategory.ball
    ball.physicsBody?.contactTestBitMask = PhysicsCategory.bullet | PhysicsCategory.ground | PhysicsCategory.player
    ball.physicsBody?.collisionBitMask = PhysicsCategory.bullet | PhysicsCategory.ground | PhysicsCategory.player

然后再

ball.physicsBody = SKPhysicsBody ...

所以所有这些ball.physicsBody分配都没有做,因为physicsBody?是'nil'

编辑:您的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 PhysicsCategory.bullet | PhysicsCategory.ball:
      let bullet = contact.bodyA.categoryBitMask == bullet ? contact.bodyA.node : contact.bodyB.node
      let ball = contact.bodyA.categoryBitMask == ball ? contact.bodyA.node : contact.bodyB.node
      ball.removeFromParent()
      bullet.removeFromParent()
      print("bullet and ball have contacted.")
   default:
      print("Some other contact occurred")
 }

在删除球时,我删除了球物理实体的isDynamicaffectedByGravity属性的设置。