iOS SpriteKit与屏幕边缘的碰撞无法正常工作

时间:2016-03-15 01:30:28

标签: ios swift cocoa-touch sprite-kit

我正在尝试在SKShapeNode实例与屏幕边缘之间创建碰撞,但由于某种原因,ShapeNode仍然超出了屏幕的限制。我已经实现了我认为应该处理碰撞的代码,但我是SpriteKit的新手,所以我不完全确定。以下是代码片段:

//
//  GameScene.swift
//  SpriteKitTest
//
//  Created by 580380 on 3/10/16.
//  Copyright (c) 2016 580380. All rights reserved.
//

import SpriteKit
import UIKit
import CoreMotion

class GameScene: SKScene {

    //MARK: - Global variables
    let motionManager = CMMotionManager()
    var circleNode = SKShapeNode()
    var destX : CGFloat = 0.0
    var destY : CGFloat = 0.0

    enum Collision :UInt32 {
        case ball = 1
        case wall = 2
    }
    //MARK: - Sprite kit functionality
    override func didMoveToView(view: SKView) {

        backgroundColor = UIColor.whiteColor()
        createCircleNode()
        moveCircleNode()
        self.addChild(circleNode)
    }

    //Setup and configuring the SKShapeNode object
    private func createCircleNode() {
        circleNode.path = UIBezierPath(arcCenter: CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame)), radius: 20, startAngle: 0, endAngle: CGFloat(2*M_PI), clockwise: true).CGPath
        circleNode.fillColor = UIColor.redColor()
        circleNode.strokeColor = UIColor.blueColor()
        circleNode.lineWidth = 1
    }

    private func moveCircleNode() {
        circleNode.physicsBody = SKPhysicsBody()
        circleNode.physicsBody?.dynamic = true
        circleNode.physicsBody?.affectedByGravity = false
        if motionManager.accelerometerAvailable {
            motionManager.accelerometerUpdateInterval = 0.1
            motionManager.startAccelerometerUpdatesToQueue(NSOperationQueue.mainQueue(), withHandler: { (data, error) -> Void in
                self.destX = self.circleNode.position.x + CGFloat(data!.acceleration.x*100)
                self.destY = self.circleNode.position.y + CGFloat(data!.acceleration.y*200)
            })
        }
        self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
        self.physicsBody!.dynamic = true
        self.physicsBody!.affectedByGravity = false
        self.physicsBody!.categoryBitMask = Collision.wall.rawValue
        self.physicsBody!.collisionBitMask = Collision.ball.rawValue
    }

    override func update(currentTime: NSTimeInterval) {
        let destXAction = SKAction.moveToX(destX, duration: 0.1)
        let destYAction = SKAction.moveToY(destY, duration: 0.1)
        self.circleNode.runAction(destXAction)
        self.circleNode.runAction(destYAction)
    }
}

知道我哪里可能出错了吗?

1 个答案:

答案 0 :(得分:1)

我将假设的主要问题是游戏场景实际上从未实际设定其大小。

GameViewController scene.size = skView.bounds.size下添加行let skView = self.view as! SKView

这将正确设置场景的大小,所以现在你的球应该与你的屏幕边缘碰撞....但是当你设置circleNode路径时,实现它的方式会使你的圈子偏移一半屏幕的大小。

如果您希望圈子显示在屏幕中间,则更好的解决方案是circleNode = SKShapeNode(circleOfRadius: 20)而不是circleNode.path = UIBezierPath(arcCenter: CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame)), radius: 20, startAngle: 0, endAngle: CGFloat(2*M_PI), clockwise: true).CGPath。然后使用circleNode.position = CGPointMake(frame.width/2, frame.height/2)将其设置在中心位置。

这应该可以解决整个问题,但是你可能会注意到,球可能会在屏幕边缘消失。要解决此问题,请将更新方法更改为此类

func clamp(value: CGFloat, min: CGFloat, max: CGFloat) -> CGFloat {
    if value > max {
        return max
    }
    if value < min {
        return min
    }
    return value
}


override func update(currentTime: NSTimeInterval) {
    let ballRadius: CGFloat = 10
    destX = clamp(destX, min: ballRadius, max: frame.width - ballRadius)
    destY = clamp(destY, min: ballRadius, max: frame.height - ballRadius)

    let destXAction = SKAction.moveToX(destX, duration: 0.1)
    let destYAction = SKAction.moveToY(destY, duration: 0.1)
    self.circleNode.runAction(destXAction)
    self.circleNode.runAction(destYAction)
}

这将使球不应该试图超出屏幕的范围。我还建议添加circleNode.physicsBody?.usesPreciseCollisionDetection = true,以便您的碰撞更准确。