Как предотвратить выход SKShapeNode с позицией касания за круговую траекторию? - PullRequest
1 голос
/ 03 ноября 2019

Я использую приложение SpriteKit для iOS с Swift.

Я создал маленький SKShapeNode («шарик») и большой круговой путь («комната»), и я хочу, чтобы SKShapeNode оставался в пределахкруг.

Вот мой код:


import SpriteKit
import GameplayKit

class GameScene: SKScene {

    var isFingerOnBall = false

    var ball: SKShapeNode!
    var room: SKShapeNode!

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = touches.first
        let touchLocation = touch!.location(in: self)

        if let body = physicsWorld.body(at: touchLocation) {
            if body.node!.name == "ball" {
                isFingerOnBall = true
            }
        }
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = touches.first
        let touchLocation = touch!.location(in: self)

        if isFingerOnBall {
            ball.position = touchLocation
        }

    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        isFingerOnBall = false
    }

    override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {

    }

    override func didMove(to view: SKView) {

        self.physicsWorld.contactDelegate = self
        self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)
        self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)

        let radius:CGFloat = 60

        // BALL
        ball = SKShapeNode(circleOfRadius: radius)
        ball.name = "ball"
        ball.fillColor = .red
        ball.strokeColor = .clear
        ball.position = CGPoint(x: 0, y: 150)
        ball.physicsBody = SKPhysicsBody(circleOfRadius: radius)
        ball.physicsBody?.isDynamic = true
        scene?.addChild(ball)

        // ROOM
        room = SKShapeNode(circleOfRadius: radius * 5)
        room.name = "room"
        room.strokeColor = .white
        room.lineWidth = 10
        room.position = CGPoint(x: 0, y: 0)
        room.physicsBody = SKPhysicsBody(edgeLoopFrom: room.path!)
        room.physicsBody?.isDynamic = false
        scene?.addChild(room)

    }

}


Я ожидал, что комната SKPhysicsBody ограничит выход мяча за пределы дорожки, OK image

но когда мой палец вытаскивает мяч из круга (комнаты), он тоже гаснет. Нет хорошего изображения

Заранее спасибо.

1 Ответ

0 голосов
/ 03 ноября 2019

Есть несколько способов сделать это, хотя самый простой, который я могу придумать, - это заменить метод didMove (для просмотра: SKView) следующим:

    override func didMove(to view: SKView) {

    self.physicsWorld.contactDelegate = self
    self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)
    self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)

    // BALL
    let ball = SKShapeNode(circleOfRadius: 10)
    ball.fillColor = .yellow
    ball.strokeColor = .yellow
    ball.lineWidth = 5
    ball.physicsBody = SKPhysicsBody(circleOfRadius: 10)
    ball.physicsBody?.isDynamic = true
    ball.physicsBody?.affectedByGravity = true
    ball.physicsBody?.categoryBitMask = 1
    ball.physicsBody?.collisionBitMask = 2
    ball.physicsBody?.contactTestBitMask = 0
    addChild(ball)


    // ROOM
    let room = SKShapeNode(circleOfRadius: 200)
    room.fillColor = .clear
    room.strokeColor = .red
    room.lineWidth = 5
    room.physicsBody = SKPhysicsBody(edgeLoopFrom: room.path!)
    room.physicsBody?.isDynamic = false
    room.physicsBody?.affectedByGravity = false
    room.physicsBody?.categoryBitMask = 2
    room.physicsBody?.collisionBitMask = 0
    room.physicsBody?.contactTestBitMask = 0
    addChild(room)

}

В основном вам просто нужно установить PhysicsBodyКатегория BitBask и Collision Bit mask. Также не назначайте твердое физическое тело, обратите внимание на использование «edgeFromLoop» для создания физического тела комнат.

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    let touch = touches.first
    let touchLocation = touch!.location(in: self)

    if isFingerOnBall {
        let roomRadius: CGFloat = 200
        let hyp = sqrt(touchLocation.x * touchLocation.x + touchLocation.y * touchLocation.y)
        if abs(hyp) > roomRadius {
            ball.position = ball.position
        } else {
            ball.position = touchLocation
        }
    }

}

Здесь вы получаете гипотенузу новой точки касания и проверяете, что еебольше, чем радиус комнаты. Если это так, то положение мяча остается прежним, если нет, то обновите положение мяча, как обычно.

Надеюсь, это поможет и наслаждайся

...