保持节点以恒定的速度跟随



我正在尝试制作一个小型迷你游戏,在屏幕上拖动一个球,每10秒就会在您中添加一个球。到目前为止,您可以在屏幕上拖动一个球,然后一个球跟随您,但是当另一个球被添加到球组中时。我认为这是因为球正在跟随我,具体取决于我的速度。因此,有某种方式可以让我不断地以一定速度跟随我,例如每秒10个像素,这应该防止球分组在一起。

我目前正在研究分数,因此您应该很快就能生存。如果您触摸其中一个球,就会死亡。

以下是我当前代码的代码和简短的GIF

!(https://gyazo.com/1d6a56527bfd0884e8a26cff730f4e03(

  import SpriteKit
  import GameplayKit
   struct physicsCatagory{
     static let me : UInt32 = 0x1 << 1
     static let enemy : UInt32 = 0x1 << 2
    }
  class GameScene: SKScene, SKPhysicsContactDelegate {

private func makeEnemyName() -> String {
    enemyCounter += 1
    return "enemy(enemyCounter)"
}
private func addEnemyToDict(enemy: SKSpriteNode, target: SKSpriteNode) {
    if let name = enemy.name { spriteDictionary[name] = (enemy, target) }
    else { print("enemy not found") }
}
private func removeEnemyFromDict(enemy: SKSpriteNode) {
    if let name = enemy.name { spriteDictionary[name] = nil }
    else { print("enemy not removed from dictionary!") }
}
private func moveFollowerToTarget(_ sprites: FollowerAndTarget) {
    let action = SKAction.move(to: sprites.target.position, duration: 1)
    sprites.follower.run(action)
}

private func allEnemiesMoveToTarget() {
    for sprites in spriteDictionary.values {
        moveFollowerToTarget(sprites)
    }
}
let enemySpeed: CGFloat = 300
var me = SKSpriteNode()
// Tuple to keep track of enemy objects:
typealias FollowerAndTarget = (follower: SKSpriteNode, target: SKSpriteNode)
// [followerName: (followerSprite, targetSprite):
var spriteDictionary: [String: FollowerAndTarget] = [:]
// Give each enemy a unique name for the dictionary:
var enemyCounter = 0
var died = Bool()


override func didMove(to view: SKView) {
    createScene()
}

func createEnemy () {
    if died == true{
    }
    else {
    let enemy = SKSpriteNode(imageNamed: "enemy1")
    enemy.name = makeEnemyName()
    addEnemyToDict(enemy: enemy, target: me)
    moveFollowerToTarget((follower: enemy, target: me))
    enemy.size = CGSize(width: 60, height: 60)
    enemy.position = CGPoint(x:667, y: 200)
    enemy.physicsBody?.restitution = 0.5
    enemy.physicsBody = SKPhysicsBody(circleOfRadius: 60)
    enemy.physicsBody?.affectedByGravity = false
    enemy.zPosition = 2
    enemy.physicsBody?.linearDamping = 0
    enemy.physicsBody?.isDynamic = true
    enemy.physicsBody?.categoryBitMask = physicsCatagory.enemy
    enemy.physicsBody?.collisionBitMask = physicsCatagory.me
    enemy.physicsBody?.contactTestBitMask = physicsCatagory.me
    addChild(enemy)
    }
}

func didBegin(_ contact: SKPhysicsContact) {
    let firstBody = contact.bodyA
    let secondBody = contact.bodyB
    if firstBody.categoryBitMask == physicsCatagory.me && secondBody.categoryBitMask == physicsCatagory.enemy || firstBody.categoryBitMask == physicsCatagory.enemy && secondBody.categoryBitMask == physicsCatagory.me {
        died = true
        restartScene()
    }
}
var lose: SKLabelNode!

func restartScene(){
    self.removeAllChildren()
    self.removeAllActions()
    died = false
    if let nextScene = GameScene(fileNamed: "menuScene"){
        nextScene.scaleMode = self.scaleMode
        let transition = SKTransition.fade(withDuration: 1)
        view?.presentScene(nextScene, transition: transition)
    }
}
func createScene(){
    me = self.childNode(withName: "me") as! SKSpriteNode
    me.physicsBody = SKPhysicsBody(circleOfRadius: 20)
    me.physicsBody?.affectedByGravity = false
    me.physicsBody?.categoryBitMask = physicsCatagory.me
    me.physicsBody?.collisionBitMask = physicsCatagory.enemy
    me.zPosition = 2
    self.physicsWorld.contactDelegate = self
    let border = SKPhysicsBody (edgeLoopFrom: self.frame)
    border.friction = 0
    self.physicsBody = border
    run(SKAction.repeatForever(SKAction.sequence([SKAction.run(createEnemy), SKAction.wait(forDuration: 4.0)])))
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    for touch in touches{
        let location = touch.location(in: self)
        me.run(SKAction.moveTo(x: location.x, duration: 0))
        me.run(SKAction.moveTo(y: location.y, duration: 0))
        allEnemiesMoveToTarget()
    }


}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    for touch in touches{
        let location = touch.location(in: self)
        me.run(SKAction.moveTo(x: location.x, duration: 0))
        me.run(SKAction.moveTo(y: location.y, duration: 0))
        allEnemiesMoveToTarget()
    }
}
override func update(_ currentTime: TimeInterval) {
    // Will iterate through dictonary and then call moveFollowerToTarget()
    // thus giving each enemy a new movement action to follow.
    allEnemiesMoveToTarget()
}

}

您去这里:

import SpriteKit
import GameplayKit
struct physicsCatagory{
  static let me    : UInt32 = 0x1 << 1
  static let enemy : UInt32 = 0x1 << 2
  static let coin  : UInt32 = 0x1 << 3
}
class GameScene: SKScene, SKPhysicsContactDelegate {
  var lose: SKLabelNode!
  var me = SKSpriteNode()
  // Tuple to keep track of enemy objects:
  typealias FollowerAndTarget = (follower: SKSpriteNode, target: SKSpriteNode)
  // [followerName: (followerSprite, targetSprite):
  var spriteDictionary: [String: FollowerAndTarget] = [:]
  // Give each enemy a unique name for the dictionary:
  var enemyCounter = 0
  let enemySpeed: CGFloat = 3
  var died = Bool()
  var timer = SKLabelNode()
  var timerValue: Int = 0 {
    didSet {
      timer.text = "(timerValue)"
    }
  }
  private func makeEnemyName() -> String {
    enemyCounter += 1
    return "enemy(enemyCounter)"
  }
  private func addEnemyToDict(enemy: SKSpriteNode, target: SKSpriteNode) {
    if let name = enemy.name { spriteDictionary[name] = (enemy, target) }
    else { print("enemy not found") }
  }
  private func removeEnemyFromDict(enemy: SKSpriteNode) {
    if let name = enemy.name { spriteDictionary[name] = nil }
    else { print("enemy not removed from dictionary!") }
  }
  // dont change anything outside of this, this is what makes the enemy follow you, so i have to have the enemy follow me at a constant speed
  private func moveFollowerToTarget(_ sprites: FollowerAndTarget) {
    let location = me.position
    // Aim
    let dx = location.x - sprites.follower.position.x
    let dy = location.y - sprites.follower.position.y
    let angle = atan2(dy, dx)
    sprites.follower.zRotation = angle
    // Seek
    let vx = cos(angle) * enemySpeed
    let vy = sin(angle) * enemySpeed
    sprites.follower.position.x += vx
    sprites.follower.position.y += vy
  }

  private func allEnemiesMoveToTarget() {
    for sprites in spriteDictionary.values {
      moveFollowerToTarget(sprites)
    }
  }
  private func keepEnemiesSeparated() {
    for sprites in spriteDictionary.values {
      let iterator = sprites.follower
      iterator.constraints = []
      // get every other follower:
      var otherFollowers: [SKSpriteNode] = []
      for sprites in spriteDictionary.values {
        if sprites.follower == iterator { continue }
        else { otherFollowers.append(sprites.follower) }
      }
      // Assign constrain
      for follower in otherFollowers {
        let distanceBetween = CGFloat(60)
        let constraint = SKConstraint.distance(SKRange(lowerLimit: distanceBetween), to: follower)
        iterator.constraints!.append(constraint)
      }
    }
  }
  func createEnemy () {
    if died { return }
    let enemy = SKSpriteNode(color: .green, size: CGSize(width: 60, height: 60))
    enemy.size = CGSize(width: 60, height: 60)
    enemy.zPosition = 2
    enemy.position.y -= size.height / 2
    enemy.physicsBody = {
      let pb = SKPhysicsBody(circleOfRadius: 30)
      pb.restitution = 0.5
      pb.affectedByGravity = false
      pb.linearDamping = 0
      pb.isDynamic = true
      pb.categoryBitMask    = physicsCatagory.enemy
      pb.collisionBitMask   = physicsCatagory.me
      pb.contactTestBitMask = physicsCatagory.me
      return pb
    }()
    enemy.name = makeEnemyName()
    addEnemyToDict(enemy: enemy, target: me)
    moveFollowerToTarget((follower: enemy, target: me))
    keepEnemiesSeparated()
    addChild(enemy)
  }
  func createCoin () {
    let coin = SKSpriteNode(color: .yellow, size: CGSize(width: 20, height: 20))
    let height = self.view!.frame.height
    let width = self.view!.frame.width
    let randomPosition = CGPoint( x:CGFloat( arc4random_uniform( UInt32( floor( width  ) ) ) ),
                                  y:CGFloat( arc4random_uniform( UInt32( floor( height ) ) ) )
    )
    coin.position = randomPosition
    addChild(coin)
  }
  func restartScene(){
    self.removeAllChildren()
    self.removeAllActions()
    died = false
    let nextScene = GameScene(size: self.size)
    nextScene.scaleMode = self.scaleMode
    let transition = SKTransition.fade(withDuration: 1)
    view?.presentScene(nextScene, transition: transition)
  }
  func createScene(){
    me = SKSpriteNode(color: .blue, size: CGSize(width: 60, height: 60))
    me.physicsBody = SKPhysicsBody(circleOfRadius: 30)
    me.physicsBody?.affectedByGravity = false
    me.physicsBody?.categoryBitMask = physicsCatagory.me
    me.physicsBody?.collisionBitMask = physicsCatagory.enemy
    me.zPosition = 2
    timer = SKLabelNode(fontNamed: "Chalkduster")
    timer.text = "(timerValue)"
    addChild(me)
    addChild(timer)
    let wait = SKAction.wait(forDuration: 1)
    let block = SKAction.run({
      [unowned self] in
      if self.timerValue >= 0{
        self.timerValue += 1
      }else{
        self.removeAction(forKey: "countdown")
      }
    })
    let sequence = SKAction.sequence([wait,block])
    run(SKAction.repeatForever(sequence), withKey: "countdown")
    self.physicsWorld.contactDelegate = self
    let border = SKPhysicsBody (edgeLoopFrom: self.frame)
    border.friction = 0
    self.physicsBody = border
    run(SKAction.repeatForever(SKAction.sequence([SKAction.run(createEnemy), SKAction.wait(forDuration: 2.0)])))
    run(SKAction.repeatForever(SKAction.sequence([SKAction.run(createCoin), SKAction.wait(forDuration: TimeInterval(arc4random_uniform(11) + 5))])))
  }

  override func didMove(to view: SKView) {
    scene?.anchorPoint = CGPoint(x: 0.5, y: 0.5)
    createScene()
  }
  func didBegin(_ contact: SKPhysicsContact) {
    let firstBody = contact.bodyA
    let secondBody = contact.bodyB
    if firstBody.categoryBitMask == physicsCatagory.me    && secondBody.categoryBitMask == physicsCatagory.enemy
    || firstBody.categoryBitMask == physicsCatagory.enemy && secondBody.categoryBitMask == physicsCatagory.me {
      died = true
      restartScene()
    }
  }
  override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    for touch in touches{
      let location = touch.location(in: self)
      me.run(SKAction.moveTo(x: location.x, duration: 0))
      me.run(SKAction.moveTo(y: location.y, duration: 0))
      allEnemiesMoveToTarget()
    }
  }
  override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    for touch in touches{
      let location = touch.location(in: self)
      me.run(SKAction.moveTo(x: location.x, duration: 0))
      me.run(SKAction.moveTo(y: location.y, duration: 0))
      allEnemiesMoveToTarget()
    }
  }
  override func update(_ currentTime: TimeInterval) {
    // Will iterate through dictonary and then call moveFollowerToTarget()
    // thus giving each enemy a new movement action to follow.
    allEnemiesMoveToTarget()
  }
}

最新更新