【问题标题】:collision not detected between SKSpitekit nodesSKSpitekit 节点之间未检测到冲突
【发布时间】:2018-09-28 13:13:59
【问题描述】:

我正在建造一个迷宫,并为墙壁添加了一些 SKSpritekit 节点,并为玩家添加了一个点。但是,当点和墙壁发生碰撞时,不会检测到碰撞。我的代码如下:

import UIKit
import SpriteKit
import GameplayKit
import Foundation
import GameplayKit


class level1: SKScene, SKPhysicsContactDelegate {
    var entities = [GKEntity]()
    var graphs = [String : GKGraph]()
    var dot = SKSpriteNode()

override func sceneDidLoad () {
    buildMaze()
    addDot()

    func addDot() {
    let startNum = x * (y - 1)
    startCoord = coordArray[startNum]
    dot = SKSpriteNode(imageNamed: "redDot")
    dot.physicsBody?.isDynamic = true
    dot.size = CGSize(width: 20, height: 20)
    dot.position = startCoord
    dot.physicsBody = SKPhysicsBody(circleOfRadius: 10)
    dot.physicsBody?.mass = 0
    dot.physicsBody?.usesPreciseCollisionDetection = true
    self.addChild(dot)
}

 func buildMaze() {
    let difference =  coordArray[1].x - coordArray[0].x 
    let wallDistance = difference/2
    let thickness = CGFloat(3)
    let length = difference  - CGFloat(thickness)/2



    var count = 0
    for point in coordArray {

        let northWall = SKSpriteNode(color: SKColor.black, size : CGSize (width: length, height: thickness))
        northWall.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: length, height: thickness))
        northWall.physicsBody?.mass = 200000

        let southWall = SKSpriteNode(color: SKColor.black, size : CGSize (width: length, height: thickness))
        southWall.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: length, height: thickness))
        southWall.physicsBody?.mass = 200000

        let eastWall = SKSpriteNode(color: SKColor.black, size : CGSize (width: thickness, height: length ))
        eastWall.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: thickness, height: length))
        eastWall.physicsBody?.mass = 200000

        let westWall = SKSpriteNode(color: SKColor.black, size : CGSize (width: thickness, height: length ))
        westWall.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: thickness, height: length))
        westWall.physicsBody?.mass = 200000


        if !instructions[count].contains("N")  {
            //print("added north wall")
            northWall.position = CGPoint (x: point.x , y: point.y + wallDistance)
            if nodes(at: northWall.position) == [] {

                addChild(northWall)}
            else {print("north wall already there")}

        }
        if !instructions[count].contains("S")  {
            //print("added south wall")
            southWall.position = CGPoint (x: point.x , y: point.y - wallDistance)
            if nodes(at: southWall.position) == [] {

                addChild(southWall)}
            else {//print("southwall already there")

            }

        }
        if !instructions[count].contains("E")  {
            //print("added east wall")
            eastWall.position = CGPoint (x: point.x + wallDistance , y: point.y)
            if nodes(at: eastWall.position) == [] {

                addChild(eastWall)}
            else {//print("east already there")

            }

        }
        if !instructions[count].contains("W")  {
            //print("added west wall")
            westWall.position = CGPoint (x: point.x - wallDistance , y: point.y)
            if nodes(at: westWall.position) == [] {

                addChild(westWall)}
            else {//print("west wall already there")

            }

        }
        count = count + 1

    }
}


    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        for t in touches {
            let location = t.location(in: self)
            dot.position.x = location.x
            dot.position.y = location.y
        }
    }

func didBegin(_ contact: SKPhysicsContact) {
    print("contact!")


}

墙的外观和我想要的一样,点也在正确的位置。

我为它们中的每一个添加了 20000 的质量,这样当我移动点时,墙壁保持在原位。但是,当我用手指移动圆点时,它只是直接穿过迷宫的墙壁,而不是被它们阻止。

我在 didBegin 函数中添加了一个打印语句,以查看它是否至少检测到精灵之间的任何接触,但它没有。

这是为什么?

干杯!

【问题讨论】:

    标签: swift sprite-kit skspritenode skphysicsbody skphysicscontact


    【解决方案1】:

    首先在你的didMoveTo或sceneDidLoad中,你需要设置physicsContactDelegate:

    override func sceneDidLoad () {
        physicsWorld.contactDelegate = self
        buildMaze()
        addDot()
    }
    

    要设置接触/碰撞掩码,你必须这样做,因为它们是基于位运算的:

    假设您希望 dot

    之间发生碰撞
    struct PhysicsCategory {
        static let wall: UInt32 = 0x1 << 1
        static let dot: UInt32 = 0x1 << 2
    }
    

    如果你愿意,你可以把结构放在你的类之上

    然后,当你分配物理体时,你必须设置位掩码:

    对于点:

        dot.physicsBody?.categoryBitMask = PhysicsCategory.dot
        dot.physicsBody?.contactTestBitMask = PhysicsCategory.wall
        dot.physicsBody?.collisionBitMask = PhysicsCategory.wall 
    
        //Collision is different from contact, so if you want to avoid collision
        //dot.physicsBody?.collisionBitMask = PhysicsCategory.dot 
    

    碰撞与接触不同,查看apple documentation about it

    对于墙壁:

        northWall.physicsBody?.categoryBitMask = PhysicsCategory.wall
        northWall.physicsBody?.contactTestBitMask = PhysicsCategory.dot
        northWall.physicsBody?.collisionBitMask = PhysicsCategory.dot
    
        //Do the same for all walls
    

    如果您希望墙壁与多个物体接触或碰撞:

        northWall.physicsBody?.contactTestBitMask = PhysicsCategory.dot | PhysicsCategory.other
        northWall.physicsBody?.collisionBitMask = PhysicsCategory.dot | PhysicsCategory.other
    

    对于墙壁是有效的,所有考虑都按点计算

    【讨论】:

      【解决方案2】:

      当您直接设置精灵的位置时,碰撞和接触检测效果不佳。

      在您的代码中,以下行:

              dot.position.x = location.x
              dot.position.y = location.y
      

      直接设置dot 的位置,覆盖物理引擎想要对对象执行的任何操作。

      此外,您似乎没有设置任何必要的类别或碰撞/接触测试位掩码。

      您允许手动移动点,但使用与墙壁的接触检测,那么您可能需要查看屏幕上的触摸是否在墙内,如果是这种情况,则不要移动点。 (这意味着你根本没有使用物理)。

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

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

      【讨论】:

      • 您好,我现在已将其更改为使用从我的手指运动得出的矢量施加脉冲。我再次运行这个东西,现在精灵不再穿墙了,但是 didBegin 函数中的打印语句仍然没有打印出来,所以我仍然怀疑没有检测到碰撞。你知道为什么会这样吗?
      • @JustABeginner 默认情况下,一切(带有物理实体)与其他一切发生碰撞,但没有与其他任何东西接触。碰撞是两个物体相互反弹的地方。 SK 引擎会自行执行此操作,并且只有在您想让某些对象不发生碰撞时才会涉及您的代码。联系人是当两个对象接触时调用didBegin 的地方,如果您没有设置您想要的联系人,则不会有任何联系人。稍后我会发布一些有关设置的信息,但是您可以通过单击我的名字来查看我的答案。
      • 好的,我现在明白了。是的,如果您能发布有关如何设置联系人的信息,我将非常感激,我也会看看您的其他答案,谢谢!
      猜你喜欢
      • 2019-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多