用 SpriteKit 抛出一个对象

Posted

技术标签:

【中文标题】用 SpriteKit 抛出一个对象【英文标题】:Throwing an object with SpriteKit 【发布时间】:2015-05-22 11:03:19 【问题描述】:

我目前有以下代码。即使代码构建成功,我似乎也无法让它工作。我正在努力做到这一点,因此当您轻弹对象时,它会以您开始和结束触摸的速度移动。

import SpriteKit
class GameScene: SKScene 
    var sprite: SKSpriteNode!
    var touchPoint: CGPoint = CGPoint()
    var touching: Bool = false
    override func didMoveToView(view: SKView) 
        self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
        sprite = SKSpriteNode(color: UIColor.redColor(), size: CGSize(width: 50, height: 50))
        sprite.physicsBody = SKPhysicsBody(rectangleOfSize: sprite.size)
        sprite.position = CGPoint(x: self.size.width/2.0, y: self.size.height/2.0)
        self.addChild(sprite)
    

    //for touch: AnyObject in touches 
    //let location = touch.locationInNode(self)
    //let touchedNode = self.nodeAtPoint(location)

     override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) 
        for touch: AnyObject in touches 

        let location = touch.locationInNode(self)
        if sprite.frame.contains(location) 
            touchPoint = location
            touching = true
        
    
    func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) 
        for touch: AnyObject in touches 
        let location = touch.locationInNode(self)
        touchPoint = location
    
    func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) 
        touching = false
    
    func update(currentTime: CFTimeInterval) 
        if touching 
            let dt:CGFloat = 1.0/60.0
            let distance = CGVector(dx: touchPoint.x-sprite.position.x, dy: touchPoint.y-sprite.position.y)
            let velocity = CGVector(dx: distance.dx/dt, dy: distance.dy/dt)
            sprite.physicsBody!.velocity = velocity
        
    

【问题讨论】:

不是 100% 确定这会有所帮助,但我认为您只想在完成轻弹后应用速度。因为您正在应用每个更新,所以您正在应用非常小的速度。您可能想尝试在 touchesMoved 中更改精灵的位置,然后根据距起点和终点的距离在 touches 结束时应用速度。您也可以根据电影的开始时间和电影的结束时间来确定它。如果你解释你得到的结果不是它的构建,也可能会有所帮助:) 在这里查看我的答案! ***.com/a/28259980/2158465 how to throw SKSpriteNode?的可能重复 【参考方案1】:

您不小心将touchesMovedtouchesEndedupdate 放在touchesBegan 中。除此之外,您的代码有效。存在问题的提示是,您不需要在 touchesMovedtouchesEndedupdate 前加上 override

以后,我会建议使用断点和打印语句来检查您期望执行的方法,实际上是在运行。这样做你会看到touchesMovedtouchesEndedupdate 的版本没有被调用。

不管怎样,这里已经纠正了它,现在它可以完美地工作了:

import SpriteKit
class GameScene: SKScene 
    var sprite: SKSpriteNode!
    var touchPoint: CGPoint = CGPoint()
    var touching: Bool = false
    override func didMoveToView(view: SKView) 
        self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
        sprite = SKSpriteNode(color: UIColor.redColor(), size: CGSize(width: 50, height: 50))
        sprite.physicsBody = SKPhysicsBody(rectangleOfSize: sprite.size)
        sprite.position = CGPoint(x: self.size.width/2.0, y: self.size.height/2.0)
        self.addChild(sprite)
    

    override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) 
        for touch: AnyObject in touches 

            let location = touch.locationInNode(self)
            if sprite.frame.contains(location) 
                touchPoint = location
                touching = true
            
        
    

    override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) 
        for touch: AnyObject in touches 
            let location = touch.locationInNode(self)
            touchPoint = location
        
    

    override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) 
        touching = false
    

    override func touchesCancelled(touches: Set<NSObject>!, withEvent event: UIEvent!) 
        touching = false
    

    override func update(currentTime: NSTimeInterval) 
        if touching 
            let dt:CGFloat = 1.0/60.0
            let distance = CGVector(dx: touchPoint.x-sprite.position.x, dy: touchPoint.y-sprite.position.y)
            let velocity = CGVector(dx: distance.dx/dt, dy: distance.dy/dt)
            sprite.physicsBody!.velocity = velocity
        
    

【讨论】:

非常感谢!它现在可以工作了:) 快速的问题,我将如何制作它以便精灵在你轻弹它之前不会移动?所以你不能拖动它,所以它有一个原始位置? 我建议查看this 以获取有关获取手势识别器速度的信息(您可以使用与SKScene 中相同的方法)。然后你可以在touchesEnded 中给出精灵速度。另外,如果答案解决了您的问题,您会考虑将其标记为正确吗? :) 很高兴为您提供帮助 :) 祝您项目顺利!【参考方案2】:

ABakerSmith 为 Swift 4 更新的解决方案:

import SpriteKit
class GameScene: SKScene 
    var sprite: SKSpriteNode!
    var touchPoint: CGPoint = CGPoint()
    var touching: Bool = false
    override func didMove(to view: SKView) 
        self.physicsBody = SKPhysicsBody.init(edgeLoopFrom: self.frame)
        sprite = SKSpriteNode(color: .red, size: CGSize(width: 50, height: 50))
        sprite.physicsBody = SKPhysicsBody.init(rectangleOf: sprite.size)
        sprite.position = CGPoint(x: self.size.width/2.0, y: self.size.height/2.0)
        self.addChild(sprite)
    

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) 
        if let touch = touches.first?.location(in: self) 
            if sprite.frame.contains(touch) 
                touchPoint = touch
                touching = true
            
        
    

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) 
        for t in touches 
            let location = t.location(in: self)
            touchPoint = location
        
    

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

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

    override func update(_ currentTime: TimeInterval) 
        if touching 
            let dt:CGFloat = 1.0/60.0
            let distance = CGVector(dx: touchPoint.x-sprite.position.x, dy: touchPoint.y-sprite.position.y)
            let velocity = CGVector(dx: distance.dx/dt, dy: distance.dy/dt)
            sprite.physicsBody!.velocity = velocity
        
    

【讨论】:

【参考方案3】:

解决方案更新为不让触摸/拖动捕捉到精灵的中间。如果您正在拖动/投掷一个对象,您将希望该投掷来自用户触摸对象的位置,而不是捕捉到对象的中间。这会让它看起来更流畅

import SpriteKit
class GameScene: SKScene 
    var sprite: SKSpriteNode!
    var touchPoint: CGPoint = CGPoint()
    var touching: Bool = false
    var xDif = CGFloat()
    var yDif = CGFloat()

    override func didMove(to view: SKView) 
        self.physicsBody = SKPhysicsBody.init(edgeLoopFrom: self.frame)
        sprite = SKSpriteNode(color: .red, size: CGSize(width: 50, height: 50))
        sprite.physicsBody = SKPhysicsBody.init(rectangleOf: sprite.size)
        sprite.position = CGPoint(x: self.size.width/2.0, y: self.size.height/2.0)
        self.addChild(sprite)
    

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) 
        if let touch = touches.first?.location(in: self) 
            xDif = sprite.position.x - touch.x
            yDif = sprite.position.y - touch.y

            if sprite.frame.contains(touch) 
                touchPoint = touch
                touching = true
            
        
    

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) 
        for t in touches 
            let location = t.location(in: self)
            touchPoint = location
        
    

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

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

    override func update(_ currentTime: TimeInterval) 
        if touching 
            let dt:CGFloat = 1.0/60.0
            let distance = CGVector(dx: touchPoint.x-sprite.position.x + xDif, dy: touchPoint.y-sprite.position.y + yDif)
            let velocity = CGVector(dx: distance.dx/dt, dy: distance.dy/dt)
            sprite.physicsBody!.velocity = velocity
        
    

【讨论】:

以上是关于用 SpriteKit 抛出一个对象的主要内容,如果未能解决你的问题,请参考以下文章

FPS在SpriteKit中下降

SpriteKit给游戏弹跳角色添加一个高度标示器

SpriteKit - 创建随机对象并使用 deltatime 移动它们

SpriteKit 对同一类型的多个对象的碰撞检测

SpriteKit:对象在彼此之下

将父类对象分配给SpriteKit中的继承类对象