Swift Spawing框架周围的随机节点

时间:2017-07-31 03:58:10

标签: ios swift sprite-kit

我想让一个节点在屏幕外面产生并在随机点移动到另一侧(框架的所有四边,随机选择哪一边)。

我是Swift的新手,我不明白我是如何实现这一点的,或者当该节点点击frame的另一侧添加点时发生冲突我的分数。

2 个答案:

答案 0 :(得分:2)

基本上,这是关于分而治之的!就像在你的商店问题中一样,你有很多步骤要做,所以要把事情分开/保持井井有条!

我为SKScene做了一个简单的扩展,根据大小和宽度得到一个随机的X和Y ......如果你愿意的话,你可以把它放在你的游戏中,但是我把很多这些都重复使用了#34;辅助"作为SKScene扩展函数在自己的文件中运行。

其次,我们有一个名为Side的枚举,用于:

  • 提供我们想要在哪一方执行操作的实际数据
  • 确定产生敌人需要哪些随机值并确定其目的地的逻辑

  • 生成随机副本

  • 生成另一面

最后我们的gamecene,只有一个功能spawnEnemy ...这很酷,因为它让你的GS整洁有序!当您尝试实现新功能/调试旧功能时,这总是很棒。

extension SKScene {

  /// Something that could be useful in many scenes / games:
  func getRandomWidthHeight() -> (width: CGFloat, height: CGFloat) {
    // A little confusing but we have to do two casts because
    // I misplaced my random function that uses Floats :)
    var randX = CGFloat(arc4random_uniform(UInt32(size.width)))
    var randY = CGFloat(arc4random_uniform(UInt32(size.height)))

    // We need to subtract where the anchorPoint lies to fit into
    // SK's coordinate system when anchorPoint == (0.5, 0.5).
    // In other words, if scene height is 1000 pixels, then 
    // the highest Y value is 500, and the lowest Y value is -500.
    // Because, 1000 * 0.5 (anchorpoint) is 500.
    randX -= size.width * anchorPoint.x
    randY -= size.height * anchorPoint.y

    return (randX, randY)
  }
}

enum Side {

  case left, right, top, bottom

  /// Used for finding enemy destination:
  var opposite: Side {
    switch self {
    case .top:    return .bottom
    case .right:  return .left
    case .bottom: return .top
    case .left:   return .right
    }
  }

  /// Used for spawning enemy, and for finding its destination:
  func getRandomPoint(inScene scene: GameScene) -> CGPoint {


    let (randX, randY) = scene.getRandomWidthHeight()
    /*
                         top: randX, maxY
                         ______
     left: minX, randY   |    |
                         |    |   right: maxX, randY
                         |____|
                     bottom: randX, minY
     */

    switch self {
    case .top:    return CGPoint(x: randX,             y: scene.frame.maxY)
    case .right:  return CGPoint(x: scene.frame.maxX,  y: randY           )
    case .bottom: return CGPoint(x: randX,             y: scene.frame.minY)
    case .left:   return CGPoint(x: scene.frame.minX,  y: randY)
    }
  }

  /// Simply create a random side to be used for spawning:
  static var random: Side {
    // 0 is top, 1 is right, 2 is bottom, 3 is left
    let rand = Int(arc4random_uniform(4))

    switch rand {
    case 0: return .top
    case 1: return .right
    case 2: return .bottom
    case 3: return .left
    default: fatalError()
    }
  }
}


class GameScene: SKScene {

  func spawnEnemy(speed: TimeInterval) {

    let sideToSpawnOn = Side.random
    let spawnPosition = sideToSpawnOn.getRandomPoint(inScene: self)
    let destination   = sideToSpawnOn.opposite.getRandomPoint(inScene: self)

    let enemy = SKSpriteNode(color: .blue, size: CGSize(width: 50, height: 50))
    enemy.position = spawnPosition

    // Shift outside frame:
    enemy.position.x += (spawnPosition.x > 0 ? enemy.size.width  : -enemy.size.width)
    enemy.position.y += (spawnPosition.y > 0 ? enemy.size.height : -enemy.size.height)

    enemy.run(.move(to: destination, duration: speed))
    addChild(enemy)
  }

  override func didMove(to view: SKView) {
    anchorPoint = CGPoint(x: 0.5, y: 0.5)
    let sequence = SKAction.sequence([.wait(forDuration: 2), .run( { self.spawnEnemy(speed: 2) } )])
    run(.repeatForever(sequence))
  }
}

我没有超过命中检测,因为这是一个单独的问题:)

答案 1 :(得分:1)

流动性方法的缺陷是你会发现更多的敌人在角落产生,然后在中心。要获得更加均匀的生成,您需要使用半径为场景宽度或高度/ 2 +精灵宽度或高度/ 2的圆(取决于场景的哪一侧最长)

现在,先决条件是一切都需要是anchorPoint(0.5,0.5),甚至是场景。这种方法适用于anchorPoint(0,0),但这需要额外的数学运算才能改变你的圈子(这不是必需的,如果你把锚点保持在0.5,0.5,你会发现你的生活更容易)

func randomPosition(spriteSize:CGSize) -> CGPoint
{

   let angle = (CGFloat(arc4random_uniform(360)) * CGFloat.pi) / 180.0
   let radius = (size.width >= size.height ? (size.width + spritSize.width) : (size.height + spriteSize.height)) / 2
   return CGPoint(cos(angle) * radius,sin(angle) * radius)
}

使用它:

let pos = randomPosition(mySprite.size)
mySprite.position = pos`

现在向相反的方向前进,你只需要翻转坐标的标志

let oppositePosition = CGPoint(x:-1 * pos.x,y: -1 * pos.y)

现在,当它击中屏幕的另一侧时得分很容易。不需要任何碰撞。

您想要做的是一系列行动

let move = SKAction.move(to:oppositePosition,duration:10)
let score = SKAction.run({score += 1})
let seq = SKAction.sequence([move,score])
sprite.run(seq, withKey:"moving")

这里发生的事情是精灵完成其移动动作后,它会增加分数。

现在我假设某些东西与对象发生碰撞,然后你没有得分,所以在你的didBeginContact中,删除sprite.removeAction(forKey:"moving")的移动动作