我可以使用某种容器节点而不是 SKSpriteNode 来表示敌人吗?

Can I use some kind of container node instead of a SKSpriteNode to represent enemies?

我的敌人有问题。我做了 5 个,每个都独立于另一个场景。但问题是 - 除了外观外,它们几乎相同。他们喜欢成群结队地产卵,因为他们为每个人提供了一种随机的耳朵机制。 我尝试使用 SKConstraint 在它们之间建立差距,但它对我不起作用。

所以我考虑了不同的方法:我想使用一些东西,比如一个空节点来代表敌人出现在场景中之前(它们就像飞扬的小鸟中的下部管道从右侧到左侧) .在它们出现在屏幕上之前,我希望我的游戏在其中的 5 个节点之间随机选择并执行正确的动画。因此,我的组出现问题将得到解决。

我该怎么做?

目前我使用他们的节点。如果有帮助,我会提供代码:

var robot = SKSpriteNode()
let robotAtlas = SKTextureAtlas(named: "robot")
var robotArray = [SKTexture]()

robotArray.append(robotAtlas.textureNamed("robot0"));
robotArray.append(robotAtlas.textureNamed("robot1"));

然后我将 physicBodies 应用于它们

robot = SKSpriteNode(texture: robotArray[0]);
robot.position = CGPointMake(CGRectGetMaxX(self.frame), CGRectGetMidY(self.frame) - 138)
self.robot.name = "robot"
self.addChild(robot)

我该怎么做,或者还有其他方法可以做到这一点?

现在,这是我的方案: 这是随机函数:

func random() -> UInt32 {
var range = UInt32(60)..<UInt32(200)
return range.startIndex + arc4random_uniform(range.endIndex - range.startIndex + 1)}

我有一个自定义的 class 外观:

class EnemyAppear {
var nowAppear = false
var waitToAppear = UInt32(0)
var currentInterval = UInt32(0)
init(nowAppear:Bool, waitToAppear:UInt32, currentInterval:UInt32) {
self.nowAppear = nowAppear
self.waitToAppear = waitToAppear
self.currentInterval = currentInterval  }


func shouldRun() -> Bool {
return self.appearInterval > self.waitToAppear  }

那我有一个追踪敌人的状态:

var enemyStatus:Dictionary<String,EnemyAppear> = [:]


enemyStatus["robot"] = EnemyAppear(nowAppear: false, waitToAppear: random(), currentInterval: UInt32(0))
enemyStatus["drone"] = EnemyAppear(nowAppear: false, waitToAppear: random(), currentInterval: UInt32(0))

在更新功能中我有移动它们的功能:

func enemyRun() {
    for(enemy, enemyAppear) in self.enemyStatus {
    var thisPet = self.childNodeWithName(enemy)!
        if enemyAppear.shouldRun() {
            enemyAppear.waitToAppear = random()
            enemyAppear.currentInterval = 0
            enemyAppear.nowAppear = true
        }

        if enemyAppear.nowAppear {
            if thisPet.position.x > petMaxX {
                thisPet.position.x -= CGFloat(self.groundSpeed)
            }else {
                thisPet.position.x = self.originalPetPositionX
                enemyAppear.nowAppear = false
                self.score++
                self.scoreText.text = String(self.score)
            }
        }
    }

我只需要设置敌人之间的距离。

我认为你把事情复杂化了,或者我仍然误解你:( 但这里有一些建议。如果你只需要生成随机敌人,你可以选择以下几种方法:

1.制作自定义机器人 class

你可以做一个class叫机器人,随机选择不同的纹理。要完成随机化纹理(来自纹理图集或纹理数组),您可以使用 arc4random() 方法。

使用示例(伪代码):

Robot.init(texture:someRandomTexture) //note that texture is a type of SKTexture, it's not a string

Robot class 在这种情况下将是 SKSpriteNode 的子class,您可以通过构造函数使用纹理对其进行初始化(如上面的示例),或者您可以移动所有纹理选择逻辑内部构造函数(init 方法)。由你决定。

用法示例:

Robot.init()

整个逻辑在调用SKSpriteNode的initWithTexture方法的init方法中调用

如果你真的需要你的机器人有骨架和皮肤并且你不能为每种类型的机器人使用单一纹理那么你可以制作 Robot class 这是 subclass SKNode(空容器)。

在那种情况下机器人class应该有两个变量,SKSpriteNode骨架和SKSpriteNode皮肤。在这种情况下,皮肤变量将被随机选择。骨架和皮肤节点应作为子节点添加到 self(本例中的 self 是 Robot class,即 SKNode)。 SKNode 没有视觉表示,但它有位置 属性,所以当你移动 SKNode 时,你也会移动它的子节点。

2。使用 SKSpriteNode

如果您决定不使用机器人 class,而只使用 SKSpriteNode,情况是一样的。我会为每种类型的敌人使用不同的纹理,但如果这无法管理,您可以为每个机器人使用多个 SKSpriteNode。

所以,你应该制作一个return敌人的方法,就是SKSpriteNode。在该方法中,您将创建带有骨架纹理的 SKSpriteNode,之后您将添加皮肤作为子节点,将皮肤的 zPosition 设置为高于骨架的 zPosition,创建物理体和 return 该节点。

一个有用的东西(如果你只需要改变精灵的颜色)是你可以很容易地 colorize nodes programatically (着色纹理)

编辑:

使用动作序列在随机持续时间后生成敌人的简单示例:

import SpriteKit

class GameScene: SKScene {

    var enemies: NSMutableArray = []
    var textures = [SKTexture]()

    let debugLabel = SKLabelNode(fontNamed: "Arial-BoldMT")

    override func didMoveToView(view: SKView) {

        /* Setup your scene here */

        debugLabel.fontColor = SKColor.purpleColor()
        debugLabel.fontSize = 20.0
        debugLabel.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
        self.addChild(debugLabel)


        let atlas = SKTextureAtlas(named: "enemies")

        //Fill the array with textures to use them later
        //Not needed IMO, but suitable to show you how to pick a random element from an array
        for var i = 1; i<=atlas.textureNames.count; i++ {

            textures.append(atlas.textureNamed( "enemy\(i)"))

        }


         debugLabel.text = "Enemies count : \(enemies.count), Nodes count : \(self.children.count)"

        spawnEnemiesWithDelay(3)

    }


    //This method is just for creating a sprite
    func createRandomEnemy() ->SKSpriteNode{

        let rand = Int(arc4random_uniform(UInt32(textures.count)))

        let enemy =  SKSpriteNode(texture: textures[rand])

        //setup here enemy physics body

        return enemy

    }

    //This method spawns enemies after random period of time. You can stop this by removing an action key
    func spawnEnemiesWithDelay(delay: NSTimeInterval){



        let delay = SKAction.waitForDuration(delay, withRange:3) //The duration may vary in either direction by up to half of the value of the durationRange parameter. Which means duration can vary either plus or minus 1.5 sec



        let block = SKAction.runBlock({

            let enemy = self.createRandomEnemy()

            enemy.position = CGPoint(x: self.frame.size.width+enemy.size.width/2, y:100)

            self.addChild(enemy)

            self.enemies.addObject(enemy) // Store reference to enemy if needed

            let move = SKAction.moveTo(CGPoint(x: -enemy.size.width/2, y: 100), duration: 5)

            let moveAndRemove = SKAction.sequence([move, SKAction.runBlock({
                enemy.removeFromParent()


                self.enemies.removeObjectIdenticalTo(enemy as AnyObject)

            })]) //remove enemy when offscreen



            enemy.runAction(moveAndRemove, withKey: "moving")

        })

        let sequence = SKAction.sequence([delay,block])

        self.runAction(SKAction.repeatActionForever( sequence), withKey: "spawning")

    }

    override func update(currentTime: CFTimeInterval) {
        /* Called before each frame is rendered */

       debugLabel.text = "Enemies count : \(enemies.count), Nodes count : \(self.children.count)"

    }
}

如果您的场景和视图初始化正确,您可以制作 enemies.atlas 文件夹,其中包含一些不同的纹理,然后复制并粘贴此代码进行尝试。希望这能有所帮助。