【问题标题】:Objects Position Not Matching Up (Spritekit)对象位置不匹配(Spritekit)
【发布时间】:2018-07-31 12:43:13
【问题描述】:

我正在构建一个 spritekit 游戏,并且刚刚开始该项目。我在屏幕上有一个从中心开始的圆圈,当我将手指从圆圈向外拖动时,它会显示一条连接到球的虚线/贝塞尔路径,这将帮助用户看到它瞄准球的位置。当用户抬起手指时,球会朝与瞄准线相反的方向射击。 (想想像足球明星或台球这样的游戏)。问题是,当一切都从中间开始时,这个动作第一次起作用:我拖动手指,球向相反的方向射击,然后停止。但是当我再次尝试时,瞄准线的位置说它与球相同(应该是),但随后它在屏幕上显示为距离球一英寸。我觉得这可能是物体后面的场景可能大小不同的问题?但我很困惑,因为我认为我只使用了一个场景。

GameViewController viewDidLoad:

override func viewDidLoad() {
    super.viewDidLoad()

    if let view = self.view as! SKView? {
        // Load the SKScene from 'GameScene.sks'
        if let scene = SKScene(fileNamed: "GameScene") {
            // Set the scale mode to scale to fit the window
            scene.scaleMode = .aspectFill
            scene.size = view.bounds.size
            //scene.anchorPoint = CGPoint(x: 0.0, y: 0.0)


            // Present the scene
            view.presentScene(scene)
        }

        view.ignoresSiblingOrder = true

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

GameScene 代码(怀疑你需要它,但无论如何):

import SpriteKit
import GameplayKit

class GameScene: SKScene {

    var ball = SKShapeNode(circleOfRadius: 35)
    var touchingBall = false
    var aimLine = SKShapeNode()

    var startAimPoint = CGPoint()
    var endAimPoint = CGPoint()

    let damping:CGFloat = 0.94

    override func didMove(to view: SKView) {

        ball.fillColor = SKColor.orange
        ball.name = "ball"

        let borderBody = SKPhysicsBody(edgeLoopFrom: self.frame)
        borderBody.friction = 0
        self.physicsBody = borderBody
        physicsWorld.gravity = CGVector(dx: 0.0, dy: 0.0)

        var physicsBody = SKPhysicsBody(circleOfRadius: 35)
        ball.physicsBody = physicsBody
        ball.physicsBody?.affectedByGravity = false
        ball.physicsBody?.friction = 10.0

        ball.position = CGPoint(x: frame.midX, y: frame.midY)

        self.addChild(ball)
    }


    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("TOUCHES BEGAN.")
        for touch in touches {
            print("TB: \(touchingBall)")
            let location = touch.location(in: self)
            let node : SKNode = self.atPoint(location)
            if node.name == "ball" {
                // touched inside node
                if ball.physicsBody!.angularVelocity <= 0.0{
                    touchingBall = true

                    startAimPoint = ball.position

                    print(touchingBall)
                }
            }
        }

    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("TOCUHES MOVED.")
        for touch in touches {
            let location = touch.location(in: self)
            if touchingBall{
                endAimPoint = location

                assignAimLine(start: startAimPoint, end: endAimPoint)
                print("Moving touched ball")

            }
        }

    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("Touches ended. \(touchingBall)")
        if touchingBall == true{

            ball.physicsBody!.applyImpulse(CGVector(dx: -(endAimPoint.x - startAimPoint.x) * 3, dy: -(endAimPoint.y - startAimPoint.y) * 3))

        }

        touchingBall = false
        aimLine.removeFromParent()
        print(touchingBall)

    }

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

        print("Touches cancelled. \(touchingBall)")
        if touchingBall == true{

            ball.physicsBody!.applyImpulse(CGVector(dx: -(endAimPoint.x - startAimPoint.x) * 3, dy: -(endAimPoint.y - startAimPoint.y) * 3))

        }

        touchingBall = false
        aimLine.removeFromParent()
        print(touchingBall)

    }


    override func update(_ currentTime: TimeInterval) {
        // Called before each frame is rendered

        print(ball.physicsBody!.velocity)
        let dx2 = ball.physicsBody!.velocity.dx * damping
        let dy2 = ball.physicsBody!.velocity.dy * damping
        ball.physicsBody!.velocity = CGVector(dx: dx2, dy: dy2)


    }
    func assignAimLine(start: CGPoint, end: CGPoint){

        aimLine.removeFromParent()

        var bezierPath = UIBezierPath()
        bezierPath.move(to: start)
        bezierPath.addLine(to: shortenedEnd(startPoint: start, endPoint: end))

        var pattern : [CGFloat] = [10.0, 10.0]
        let dashed = SKShapeNode(path: bezierPath.cgPath.copy(dashingWithPhase: 2, lengths: pattern))

        aimLine = dashed
        aimLine.position = ball.position

        aimLine.zPosition = 0

        self.addChild(aimLine)



    }
    func hypotenuse(bp: UIBezierPath) -> Double{
        var a2 = bp.cgPath.boundingBox.height * bp.cgPath.boundingBox.height
        var b2 = bp.cgPath.boundingBox.width * bp.cgPath.boundingBox.width
        return Double(sqrt(a2 + b2))
    }
    func hypotenuse(startP: CGPoint, endP: CGPoint) -> Double{
        var bezierPath = UIBezierPath()
        bezierPath.move(to: startP)
        bezierPath.addLine(to: endP)
        return hypotenuse(bp: bezierPath)
    }
    func shortenedEnd(startPoint: CGPoint, endPoint: CGPoint) -> CGPoint{

        var endTemp = endPoint
        //while hypotenuse(startP: startPoint, endP: endTemp) > 150{
                endTemp = CGPoint(x: endTemp.x / 1.01, y: endTemp.y / 1.01)
        //}
        return endTemp
    }
    func addTestPoint(loc: CGPoint, color: UIColor){
        var temp = SKShapeNode(circleOfRadius: 45)
        temp.fillColor = color
        temp.position = loc
        self.addChild(temp)

    }
}

我尝试打印场景的帧大小,它显示 400 x 700(我在 iPhone 6 Plus 上测试),它说 UIScreen 大小相同,所以我不知道是什么问题。总的来说,我只需要瞄准线在圆的中心,而不仅仅是我第一次尝试这个动作。谢谢。

【问题讨论】:

  • 很确定问题出在游戏视图控制器中,场景大小与屏幕大小不匹配
  • 屏幕尺寸不必与场景尺寸相匹配。场景有自己的小世界,理想的方法是让你的游戏保持 1 个静态大小,并让系统为你扩展。我建议删除 scene.size = view.size
  • @Knight0fDragon 好的,你能帮我弄清楚我已经坚持了几个小时的问题
  • 我猜这就是您创建 BezierPath 的方式
  • 不要移动到起点,你的起点应该是相对于你的球,并且应该始终是CGPoint.zero

标签: swift sprite-kit position frame skscene


【解决方案1】:

就像我在 cmets 中提到的那样,您的问题是如何布置路径。下面的代码使路径相对于球,而不是相对于场景的绝对路径。我还解决了每次创建新形状的问题。

import SpriteKit
import GameplayKit

class GameScene: SKScene {

    var ball = SKShapeNode(circleOfRadius: 35)
    var touchingBall = false
    var aimLine = SKShapeNode()

    var endAimPoint = CGPoint()


    override func didMove(to view: SKView) {

        ball.fillColor = SKColor.orange
        ball.name = "ball"

        let borderBody = SKPhysicsBody(edgeLoopFrom: self.frame)
        borderBody.friction = 0
        self.physicsBody = borderBody
        physicsWorld.gravity = CGVector(dx: 0.0, dy: 0.0)
        ball.position = CGPoint(x: frame.midX, y: frame.midY)

        let physicsBody = SKPhysicsBody(circleOfRadius: 35)
        physicsBody.affectedByGravity = false
        physicsBody.friction = 10.0
        physicsBody.linearDamping = 0.94
        ball.physicsBody = physicsBody

        self.addChild(ball)
    }


    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("TOUCHES BEGAN.")
        for touch in touches {
            print("TB: \(touchingBall)")
            let location = touch.location(in: self)
            let node : SKNode = self.atPoint(location)
            if node.name == "ball" {
                // touched inside node
                if ball.physicsBody!.angularVelocity <= 0.0{
                    touchingBall = true
                    aimLine.path = nil
                    self.addChild(aimLine)

                    print(touchingBall)
                }
            }
        }

    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("TOCUHES MOVED.")
        for touch in touches {
            let location = touch.location(in: self)
            if touchingBall{
                endAimPoint = self.convert(location, to: ball)
                assignAimLine(end: endAimPoint)
                print("Moving touched ball")

            }
        }

    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("Touches ended. \(touchingBall)")
        if touchingBall == true{
            ball.physicsBody!.applyImpulse(CGVector(dx: -(endAimPoint.x) * 3, dy: -(endAimPoint.y) * 3))
        }

        touchingBall = false

        aimLine.removeFromParent()
        print(touchingBall)

    }

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

        print("Touches cancelled. \(touchingBall)")
        if touchingBall == true{

            ball.physicsBody!.applyImpulse(CGVector(dx: -(endAimPoint.x) * 3, dy: -(endAimPoint.y) * 3))

        }

        touchingBall = false
        aimLine.removeFromParent()
        print(touchingBall)

    }


    override func update(_ currentTime: TimeInterval) {
        // Called before each frame is rendered

        print(ball.physicsBody!.velocity)
        //let dx2 = ball.physicsBody!.velocity.dx * damping
        //let dy2 = ball.physicsBody!.velocity.dy * damping
        //ball.physicsBody!.velocity = CGVector(dx: dx2, dy: dy2)


    }
    func assignAimLine(end: CGPoint){


        let bezierPath = UIBezierPath()
        bezierPath.move(to: CGPoint.zero)
        bezierPath.addLine(to: end)

        let pattern : [CGFloat] = [10.0, 10.0]


        aimLine.position = ball.position
        aimLine.path = bezierPath.cgPath.copy(dashingWithPhase: 2, lengths: pattern)
        aimLine.zPosition = 0



    }

    func addTestPoint(loc: CGPoint, color: UIColor){
        var temp = SKShapeNode(circleOfRadius: 45)
        temp.fillColor = color
        temp.position = loc
        self.addChild(temp)

    }
}

【讨论】:

  • 另外,如果我想确保 bezierpath 可以拖出不超过 80 的长度,我应该写什么? (我应该仍然可以调整方向,但是当我放手时,我应该能够将贝塞尔路径拖到尽可能远的地方以获得大量速度)
  • 只检查你的终点的距离,如果超过80,你需要使用atan2获取线的角度,然后使用cos(角度)* 80作为x和-sin(角度) * 80 为 y
  • 嗯,你不应该改变角度......也许是因为你的速度是从头到尾,而不是从头到尾。很高兴它有效
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-19
  • 2018-09-27
  • 2020-02-22
相关资源
最近更新 更多