【问题标题】:Moving SKSpriteNode to location of the touch将 SKSpriteNode 移动到触摸的位置
【发布时间】:2017-08-14 15:39:09
【问题描述】:

以上是我的游戏图片。自上而下的游戏。无论玩家触摸屏幕上的哪个位置,我都希望子弹在一段时间内到达那个位置。我还希望玩家能够在屏幕上拖动手指,同样的事情也会发生。这样玩家就不用每次想射击都去触摸屏幕了。

到目前为止,我已经尝试了一些不同的东西,但似乎没有任何效果。

首先,我不知道我是否应该为子弹设置一个单独的功能。但无论如何,这是我的子弹功能。

func spawnBullets() {
    let bullet = SKSpriteNode(imageNamed: "Bullet")
    bullet.name = "Bullet"
    bullet.zPosition = 4
    bullet.position = CGPoint(x: player.position.x + 19, y: 
    player.position.y)
    self.addChild(bullet)
}

在 didMove 函数中我还有一个用于子弹的“计时器”:

var timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, 
selector: Selector("spawnBullets"), userInfo: nil, repeats: true)

最后,这是我的 touchesBegan 函数:

override func touchesBegan(_ touches: Set<UITouch>, with event: 
UIEvent?) {        
    for  touch in touches {            
        let location = touch.location(in: self)            
        let moveToPoint = SKAction.move(to: location, duration: 0.5)
        let repeatAction = SKAction.repeatForever(moveToPoint)            
        bullet.run(moveToPoint)
    }

}

【问题讨论】:

  • 运行这段代码会发生什么?我自己没有运行过这段代码,也没有仔细分析过它,但它可以编译吗?我认为touchesBegan 中的bullet.run 将无法编译,因为您没有bullet 属性。我将创建一个 bulletTarget 属性,将其用作“moveTo”位置,然后创建并应用 SKAction 以在您的 spawnBullet 方法中移动斗牛。
  • 我没有收到任何错误,但子弹没有移动。我是应用程序开发的新手,bulletTarget 属性是什么意思?
  • 在 ``touchesBegan? You must define it somewhere (with a var bullet = ...). If it's defined outside of any method (so with global scope within the class), then its referred to as a 'property 中,您在哪里定义 bullet.run(moveToPoint) 中使用的 'bullet' 变量。但这个“子弹”几乎肯定不是你在spawnBullets 中添加到场景中的“子弹”,这就是它们不动的原因。稍后我会尝试根据您的代码发布答案。

标签: swift sprite-kit skaction touchesbegan


【解决方案1】:

你来了 - 一个简单的应用程序,其中包含可以在屏幕上拖动的飞船和向触摸位置发射的导弹。

如果你触摸船,你可以拖动它;在船外触摸,导弹会从飞船发射到触摸位置。

import SpriteKit

class GameScene: SKScene {

var ship = SKSpriteNode()
var shipIsTouched = false
var missileDestination = CGPoint()
let missileSpeed: CGFloat = 800 // Points per second)
let missileFireRate : TimeInterval = 0.2 // Seconds between each missile

override func didMove(to view: SKView) {
    missileDestination = CGPoint(x: 0, y: (self.size.height / 2))
    createPlayerShip()
    let fire = SKAction.sequence([SKAction.run(fireMissile), SKAction.wait(forDuration: missileFireRate)])
    run(SKAction.repeatForever(fire))
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        if ship.contains(touch.location(in: self)) {
            shipIsTouched = true
        } else {
            missileDestination = touch.location(in: self)
            ship.zRotation = direction(to: missileDestination, from: ship.position) - CGFloat(Double.pi/2)
        }
    }
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    if (shipIsTouched == true) {
        ship.position = (touches.first?.location(in: self))!
        ship.zRotation = direction(to: missileDestination, from: ship.position) - CGFloat(Double.pi/2)
    }
}

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

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

func createPlayerShip() {
    ship = SKSpriteNode(imageNamed: "Spaceship")
    ship.zRotation = CGFloat(-Double.pi/2.0)
    ship.scale(to: CGSize(width: 150, height: 150))
    ship.position = CGPoint(x: -size.width/2 + 200, y: 0)

    addChild(ship)
}


func fireMissile() {
    let missile = SKSpriteNode(color: .white, size: CGSize(width: 50, height: 10))
    missile.position = ship.position

    let missileFlightTime = travelTime(to: missileDestination, from: ship.position, atSpeed: missileSpeed)
    missile.zRotation = direction(to: missileDestination, from: missile.position)

    addChild(missile)

    let missileMove = SKAction.move(to: missileDestination,
                                    duration: TimeInterval(missileFlightTime))
    let missileRemove = SKAction.removeFromParent()
    missile.run(SKAction.sequence([missileMove, missileRemove]))
}

func travelTime(to target : CGPoint, from : CGPoint, atSpeed speed : CGFloat) -> TimeInterval {
    let distance = sqrt(pow(abs(target.x - from.x),2) +
        pow(abs(target.y - from.y),2))
    return TimeInterval(distance/speed)
}


func direction(to target : CGPoint, from: CGPoint) -> CGFloat {
    let x = target.x - from.x
    let y = target.y - from.y
    var angle = atan(y / x)
    if x < 0 {
        angle = angle + CGFloat.pi
    }
    return angle
}
}

有一些额外的技巧可以让导弹的速度保持一致(因为 moveTo 需要时间,而不是速度,所以如果目的地很近,导弹会缓慢移动,如果更远,它们会移动得更快)并且使导弹旋转以朝向目的地。

您可以为导弹创建一条弯曲的路径以跟随到目的地,这看起来很酷,但可能不适合您的应用。

编辑:

如果您希望飞船静止,导弹跟随您的手指,请将所有代码替换为 createPlayerShip (是的,我们丢失了 touchesEnded()update()

import SpriteKit

class GameScene: SKScene {

var ship = SKSpriteNode()
var missileDestination = CGPoint()
let missileSpeed: CGFloat = 800 // Points per second)
let missileFireRate : TimeInterval = 0.2 // Seconds between each missile

override func didMove(to view: SKView) {
    missileDestination = CGPoint(x: size.height/2, y: 0)
    createPlayerShip()
    let fire = SKAction.sequence([SKAction.run(fireMissile), SKAction.wait(forDuration: missileFireRate)])
    run(SKAction.repeatForever(fire))
}

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

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

【讨论】:

  • 哇,虽然我在这个游戏中不需要所有这些,但所有这些对我将来肯定很有价值!谢谢!我希望播放器是静态的,并且我从您的代码中更改了一些内容以使其成为静态。但是有一个问题,你如何使用 touchesMoved 让玩家每次想要改变子弹的方向时都不必触摸屏幕?而是只是在屏幕上“拖动”手指并将子弹移动到那个方向?
  • @Flinigan 我认为(因为您已经删除了使船可拖动的代码)您可以在 touchesMoved 中设置“missileDestination”而不是“ship.position”。
  • @Finegan 查看我对“跟随”您手指的静止船和导弹的编辑...任何不合理的地方,请询问。
  • 啊啊,我们走了!现在它完全按照我的意愿工作了!这肯定对其他人也有帮助! :) 一个旁注,你知道如何将导弹的起始位置与玩家的旋转同步,以使导弹看起来总是来自玩家的枪。我已将“missile.position = player.position”更改为“missile.position = CGPoint(x: player.position.x + 25, y: player.position.y))”,以使其更适合枪支,但是当玩家旋转时它看起来仍然很糟糕,看起来不像是从枪里出来的。
  • @Flinigan 一个简单的方法是让枪始终指向你的目标。一个更困难(但有趣)的方法是让导弹向前“射出”枪管,然后转向目标。你更喜欢哪个? ?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多