如何确定两个圆最准确的碰撞?

问题描述 投票:-2回答:1

我正在用代码创建一个新的游戏应用程序!我使用spriteKit创建了一些气泡。我为此使用了纹理。他们随机飞来飞去。当它们彼此相交时,它们必须碰撞并改变其路径。

[第一个问题:当然是圆形的气泡图像。但是在碰撞中,气泡彼此之间的接触不是圆,而是正方形。

第二个问题:他们互相紧贴,我认为这是第一个问题的问题!

如果您知道如何解决此问题,请帮助我,因为我找不到解决该问题的方法。我认为可以通过口罩解决此问题,但我不知道如何解决。非常感谢)

这是我的bubbleClass:

class SKButton: SKSpriteNode{

private var buttonTexture:SKTexture

override init(texture: SKTexture?, color: UIColor, size: CGSize) {
    self.buttonTexture = texture!

    super.init(texture:buttonTexture , color: .black, size: buttonTexture.size())

}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}}

这是ViewController:

class GameViewController: UIViewController {

@IBOutlet weak var mySKView: SKView!

override func viewDidLoad() {
    super.viewDidLoad()

    if let view = mySKView {
        let scene = GameScene(size: CGSize(width: 2048, height: 1536))
        scene.scaleMode = .aspectFill
        view.presentScene(scene)
        view.ignoresSiblingOrder = true

        view.showsFPS = true
        view.showsNodeCount = true
    }
}}

这是GameScene:

class GameScene: SKScene {
private var arrayBubbles = [SKButton?]()
private var arrayVelosity = [CGPoint]()
private var bubbleMovePointsPerSecX = [CGFloat]()
private var bubbleMovePointsPerSecY = [CGFloat]()

private var currentVelosity:CGPoint!

private var lastUpdateTime: TimeInterval = 0
private var dt: TimeInterval = 0
private let min = 0
private let max = 3

private let bubbleTexture = SKTexture(imageNamed: "bubble")
private let playableRect: CGRect!

lazy var background: SKSpriteNode = {
    let back = SKSpriteNode(imageNamed: "back")
    back.position = CGPoint(x: self.size.width/2, y: size.height/2)
    back.anchorPoint = CGPoint(x: 0.5, y: 0.5)
    back.zPosition = -1
    return back
}()

lazy var bubble1: SKButton = {
    var button = SKButton(texture: bubbleTexture, color: .clear, size: bubbleTexture.size())
    button.position = CGPoint(x: size.width/2, y: size.height - (size.height/3))
    button.setScale(0)
    button.zPosition = 1
    button.name = "bubble1"
    return button
}()

lazy var bubble2: SKButton = {
    var button = SKButton(texture: bubbleTexture, color: .clear, size: bubbleTexture.size())
    button.position = CGPoint(x: size.width/3, y: size.height/2)
    button.setScale(0)
    button.zPosition = 1
    button.name = "bubble2"
    return button
}()

lazy var bubble3: SKButton = {
    var button = SKButton(texture: bubbleTexture, color: .clear, size: bubbleTexture.size())
    button.position = CGPoint(x: size.width - (size.width/3), y: size.height/2)
    button.setScale(0)
    button.zPosition = 1
    button.name = "bubble3"
    return button
}()

override init(size: CGSize) {
    let playableHeight = size.width/(16.0/9.0)
    let playableMargin = (size.height - playableHeight)/2

    playableRect = CGRect(x: 0, y: playableMargin, width: size.width, height: playableHeight)
    super.init(size:size)
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}


override func didMove(to view: SKView) {
    addChilds()
    appendBubblesToArray()
    setRandomBubbleSpead()
    appendVelosityToArray()
    showApearBubble()

}
private func addChilds(){
    addChild(background)
    addChild(bubble1)
    addChild(bubble2)
    addChild(bubble3)
}

private func appendBubblesToArray(){
    arrayBubbles.append(bubble1)
    arrayBubbles.append(bubble2)
    arrayBubbles.append(bubble3)
}

private func setRandomBubbleSpead(){
    for _ in min..<arrayBubbles.count{
        let randomSpeadX = CGFloat.random(in: -200..<200)/CGFloat(Double.pi)
        bubbleMovePointsPerSecX.append(randomSpeadX)

        let randomSpeadY = CGFloat.random(in: -200..<200)/CGFloat(Double.pi)
        bubbleMovePointsPerSecY.append(randomSpeadY)
    }
}

private func appendVelosityToArray(){
    for index in min..<arrayBubbles.count{
        currentVelosity = CGPoint(x: bubbleMovePointsPerSecX[index], y: bubbleMovePointsPerSecY[index])
        arrayVelosity.append(currentVelosity)
    }
}

private func showApearBubble(){
    let apearBubble = SKAction.scale(to: 1, duration: 0.5)
    let action = [apearBubble]

    bubble1.run(SKAction.sequence(action))
    bubble2.run(SKAction.sequence(action))
    bubble3.run(SKAction.sequence(action))
}

override func didEvaluateActions() {
    checkColisions()
}

private func checkColisions(){
    enumerateChildNodes(withName: "//*") { [weak self] node, _ in
        guard let self = self else { return }

        switch node.name{
        case "bubble1":
            self.checkBubbleIntersection(self.bubble1)
            break
        case "bubble2":
            self.checkBubbleIntersection(self.bubble2)
            break
        case "bubble3":
            self.checkBubbleIntersection(self.bubble3)
            break
        default:
            return
        }
    }
}

private func hitBubble(_ index: Int){
    arrayVelosity[index].y = -arrayVelosity[index].y
    arrayVelosity[index].x = -arrayVelosity[index].x
}

private func checkBubbleIntersection(_ firstBubble: SKButton){
    for bubble in arrayBubbles {
        if firstBubble.name != bubble!.name{
            if firstBubble.frame.insetBy(dx: 80,dy: 80).intersects(bubble!.frame){
                guard let indexBubble = self.arrayBubbles.firstIndex(of: bubble) else { return }
                self.hitBubble(indexBubble)
            }
        }
    }
}

override func update(_ currentTime: TimeInterval) {

    if lastUpdateTime > 0{
        dt = currentTime - lastUpdateTime

    } else{
        dt = 0
    }
    lastUpdateTime = currentTime

    for bubble in arrayBubbles{
        if bubble != nil {
            guard let index = arrayBubbles.firstIndex(of: bubble) else { return }

            moveSprite(sprite: arrayBubbles[index]!, velosity: arrayVelosity[index])
            boundsCheckBubbles(sprite: arrayBubbles[index]!, index: index)
        }
    }
}

private func moveSprite(sprite: SKButton, velosity: CGPoint){
    let amountToMove = CGPoint(x: velosity.x * CGFloat(dt), y: velosity.y * CGFloat(dt))
    sprite.position = CGPoint(x: sprite.position.x + amountToMove.x,
                              y: sprite.position.y + amountToMove.y)

}

private func boundsCheckBubbles(sprite: SKButton, index: Int){
    let bottomLeft = CGPoint(x: 80, y: playableRect.minY)
    let topRight = CGPoint(x: size.width-80, y: playableRect.maxY)

    if sprite.position.x <= bottomLeft.x{
        sprite.position.x = bottomLeft.x
        arrayVelosity[index].x = -arrayVelosity[index].x
    }
    if sprite.position.x >= topRight.x{
        sprite.position.x = topRight.x
        arrayVelosity[index].x = -arrayVelosity[index].x
    }
    if sprite.position.y <= bottomLeft.y{
        sprite.position.y = bottomLeft.y
        arrayVelosity[index].y = -arrayVelosity[index].y
    }
    if sprite.position.y >= topRight.y{
        sprite.position.y = topRight.y
        arrayVelosity[index].y = -arrayVelosity[index].y
    }
}}
swift collision
1个回答
0
投票

我自己能够解决这个问题。但是我找到了解决这个问题的另一种方法。我使用位掩码和碰撞!

class GameScene: SKScene, SKPhysicsContactDelegate {

private var arrayBubbles = [SKButton?]()

private var bubbleTexture = SKTexture(image: #imageLiteral(resourceName: "Oval"))
private let playableRect: CGRect!

let bubble1Category:UInt32 = 0x1 << 0;
let bubble2Category:UInt32 = 0x1 << 1;
let bubble3Category:UInt32 = 0x1 << 2;
let borderCategory:UInt32 = 0x1 << 10

var borderBody: SKPhysicsBody!

lazy var bubble1: SKButton = {
    var button = SKButton(texture: bubbleTexture, color: .clear, size: bubbleTexture.size())
    button.position = CGPoint(x: size.width/2, y: size.height - (size.height/3))
    button.zPosition = 1
    button.name = "bubble1"
    button.physicsBody = SKPhysicsBody(circleOfRadius: bubbleTexture.size().width/2)
    button.physicsBody?.categoryBitMask = bubble1Category
    button.physicsBody?.contactTestBitMask = bubble2Category | bubble3Category | borderCategory
    button.physicsBody!.collisionBitMask = bubble2Category | bubble3Category | borderCategory
    button.physicsBody?.affectedByGravity = false
    button.physicsBody?.linearDamping = 0.0
    button.physicsBody?.restitution = 0.0
    return button
}()

lazy var bubble2: SKButton = {
    var button = SKButton(texture: bubbleTexture, color: .clear, size: bubbleTexture.size())
    button.position = CGPoint(x: size.width/3, y: size.height/2)
    button.zPosition = 1
    button.name = "bubble2"
    button.physicsBody = SKPhysicsBody(circleOfRadius: bubbleTexture.size().width/2)
    button.physicsBody?.categoryBitMask = bubble2Category
    button.physicsBody?.contactTestBitMask = bubble1Category | bubble3Category | borderCategory
    button.physicsBody!.collisionBitMask = bubble1Category | bubble3Category | borderCategory
    button.physicsBody?.affectedByGravity = false
    button.physicsBody?.linearDamping = 0.0
    button.physicsBody?.restitution = 0.0
    return button
}()

lazy var bubble3: SKButton = {
    var button = SKButton(texture: bubbleTexture, color: .clear , size: bubbleTexture.size())
    button.position = CGPoint(x: size.width - (size.width/3), y: size.height/2)
    button.zPosition = 1
    button.name = "bubble3"
    button.physicsBody = SKPhysicsBody(circleOfRadius: bubbleTexture.size().width/2)
    button.physicsBody?.categoryBitMask = bubble3Category
    button.physicsBody?.contactTestBitMask = bubble1Category | bubble2Category | borderCategory
    button.physicsBody!.collisionBitMask = bubble1Category | bubble2Category | borderCategory
    button.physicsBody?.affectedByGravity = false
    button.physicsBody?.linearDamping = 0.0
    button.physicsBody?.restitution = 0.0
    return button
}()

override init(size: CGSize) {
    let playableHeight = size.width/(16.0/9.0)
    let playableMargin = (size.height - playableHeight)/2

    playableRect = CGRect(x: 0, y: playableMargin, width: size.width, height: playableHeight)
    super.init(size:size)
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

override func didMove(to view: SKView) {
    self.physicsWorld.contactDelegate = self
    physicsWorld.gravity = CGVector(dx: 0.0, dy: 0.0)

    // Set border property
    setBorderBody()

    addChilds()
    appendBubblesToArray()
    showApearBubble()

    setFirstBubbleVelosity()
}

func setFirstBubbleVelosity(){
    for bubble in arrayBubbles{
        bubble!.physicsBody?.velocity = calculateRandomBubbleVelosity()
    }
}

func setBorderBody(){
    borderBody = SKPhysicsBody(edgeLoopFrom: self.frame)
    borderBody.categoryBitMask = borderCategory
    borderBody.friction = 0.0
    self.physicsBody = borderBody
}

func didBegin(_ contact: SKPhysicsContact) {
    let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask

    switch contactMask {
    case bubble1Category | bubble2Category:
        bubble1.physicsBody?.velocity = calculateRandomBubbleVelosity()
    case bubble1Category | bubble3Category:
        bubble1.physicsBody?.velocity = calculateRandomBubbleVelosity()
    case bubble1Category | borderCategory:
        bubble1.physicsBody?.velocity = calculateRandomBubbleVelosity()

    case bubble2Category | bubble1Category:
        bubble2.physicsBody?.velocity = calculateRandomBubbleVelosity()
    case bubble2Category | bubble3Category:
        bubble2.physicsBody?.velocity = calculateRandomBubbleVelosity()
    case bubble2Category | borderCategory:
        bubble2.physicsBody?.velocity = calculateRandomBubbleVelosity()

    case bubble3Category | bubble1Category:
        bubble3.physicsBody?.velocity = calculateRandomBubbleVelosity()
    case bubble3Category | bubble2Category:
        bubble3.physicsBody?.velocity = calculateRandomBubbleVelosity()
    case bubble3Category | borderCategory:
        bubble3.physicsBody?.velocity = calculateRandomBubbleVelosity()
    default: print("Unknown contact detected")
    }
}

private func addChilds(){
    addChild(bubble1)
    addChild(bubble2)
    addChild(bubble3)
}

private func appendBubblesToArray(){
    arrayBubbles.append(bubble1)
    arrayBubbles.append(bubble2)
    arrayBubbles.append(bubble3)
}

private func calculateRandomBubbleVelosity() -> CGVector{
    let randomVelosityByX = CGFloat.random(in: -200..<200)
    let randomVelosityByY = CGFloat.random(in: -200..<200)
    let randomVelosity = CGVector(dx: randomVelosityByX * cos(100.0), dy: randomVelosityByY * sin(100.0))
    return randomVelosity
}

private func showApearBubble(){
    bubble1.setScale(1.5)
    bubble2.setScale(1.5)
    bubble3.setScale(1.5)
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first{
        enumerateChildNodes(withName: "bubble1") {  node, _ in

            let bubble = node as! SKButton
            if bubble.contains(touch.location(in: self)){

                //Some your logic

            }
        }
    }
}}
© www.soinside.com 2019 - 2024. All rights reserved.