快速生成框架周围的随机节点



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

我是Swift新手,我不明白当该节点击中frame的另一侧以增加分数时,我将如何实现这一目标或让碰撞工作。

基本上,这是关于分而治之!就像您的商店问题一样,您有很多步骤要做,因此将事情间隔开/保持井井有条是要走的路!

我为 SKScene 做了一个简单的扩展,根据大小和宽度获得随机的 X 和 Y......如果你愿意,你可以把它放在你的游戏场景中,但我把很多这些可重用的"助手"函数作为SKScene扩展放到它们自己的文件中。

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

  • 提供我们要在哪一端执行操作的实际数据
  • 用于确定生成敌人并确定其目的地所需的随机值的逻辑

  • 生成随机侧

  • 生成相反的一面

最后是我们的游戏场景,它只有一个功能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))
}
}

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

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

现在一个先决条件是一切都需要锚点(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")删除移动动作

最新更新