如何在不同 class - swift 的循环中生成 SKnode

how to spawn a SKnode on a loop that is in a different class - swift

我正在创建一个射击游戏,我正在尝试创建一个射击方法,但我当前的方法在单击时一次只能产生一颗子弹。我将我的项目符号定义为 SKnode 子类,并在 gameScene.swift 中的 touches begin 方法中调用它。方法如下

class Bullet1: SKNode {

var Bullet1:SKSpriteNode = SKSpriteNode()
var Bullet1Animaton:SKAction?

required init(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

override init () {

    super.init()
}
func createBullet1s (){
    let wait:SKAction = SKAction.waitForDuration( CFTimeInterval(0.25))
    let block:SKAction = SKAction.runBlock(createBullet1)
    let seq2:SKAction = SKAction.sequence( [block, wait])
    SKAction.repeatActionForever(seq2)
    self.runAction(seq2, withKey:"droneAction")

}
func createBullet1() {

    Bullet1 = SKSpriteNode(imageNamed: "bullet.png")
    Bullet1.xScale = 0.5
    Bullet1.yScale = 0.5
    Bullet1.physicsBody = SKPhysicsBody(rectangleOfSize: Bullet1.size)
    Bullet1.physicsBody?.categoryBitMask = PhysicsCategory.bullet1
    Bullet1.physicsBody?.contactTestBitMask = PhysicsCategory.enemy1 
    Bullet1.physicsBody?.affectedByGravity = false
    Bullet1.physicsBody?.dynamic = true
    self.addChild(Bullet1)
    self.name = "Bullet1"
}

}
class GameScene: SKScene, SKPhysicsContactDelegate {

override func touchesBegan(touches: Set<UITouch>, withEvent  
event:UIEvent?) {

override func touchesBegan(touches: Set<UITouch>, withEvent 
event:UIEvent?) {
    for touch in touches {

    let location = touch.locationInNode(self)
    let node = nodeAtPoint(location)

        if (CGRectContainsPoint(joystick.frame, location)) {
            stickActive = true
            fireWeapon = true
        }else{
            stickActive = false
        }

if stickActive == true && fireWeapon == true{  if fireWeapon == false 
{}

let bulletAction = SKAction.runBlock({
let v = CGVector(dx: location.x - self.joystickBase.position.x, dy: 
location.y - self.joystickBase.position.y)
let angle = atan2(v.dy, v.dx) //where angle is defined "in radians"
let deg = angle * CGFloat(180 / M_PI)
print(deg + 180) // prints degree in debugging
self.hero.zRotation = angle - 1.57079633 //rotates with angle of joy 
stic

let bullet1:Bullet1 = Bullet1()
bullet1.createBullet1()

bullet1.position = CGPoint (x: self.hero.position.x , y: 
self.hero.position.y) // Bullet spawn @ anchor point
let xDist:CGFloat = sin(angle - 1.5709633) * 35 //bullet spawn location
let yDist:CGFloat = cos(angle - 1.5709633) * 35 //bullet spawn location

bullet1.position = CGPointMake( self.hero.position.x - xDist, 
self.hero.position.y + yDist) //spawning bullet @ defined location

let xDistMove:CGFloat = sin(angle - 1.5709633) * 700 //Bullet max x 
distance
let yDistMove:CGFloat = cos(angle - 1.5709633) * 700 //Bullet max y 
distance

let bulletMovementY = SKAction.moveToY(self.hero.position.y + 
yDistMove, duration: 1) //Bullet y speed
let bulletMovementX = SKAction.moveToX(self.hero.position.x - 
xDistMove, duration: 1) //Bullet x speed

bullet1.runAction(bulletMovementY)
bullet1.runAction(bulletMovementX)

self.addChild(bullet1)
})
let wait = SKAction.waitForDuration(0.25)
let completeSequence = SKAction.sequence([bulletAction, wait])
let repeatShootingActionForever =
SKAction.repeatActionForever(completeSequence)
self.runAction(repeatShootingActionForever, withKey: "BulletAction")
        }

override func touchesMoved(touches: Set<UITouch>, withEvent event: 
UIEvent?) {

for touch in touches {
let location = touch.locationInNode(self
if (stickActive == true) {

let v = CGVector(dx: location.x - joystickBase.position.x, dy: 
location.y - joystickBase.position.y)
let angle = atan2(v.dy, v.dx) //where angle is defined "in radians"
let deg = angle * CGFloat(180 / M_PI)
let length: CGFloat = joystickBase.frame.size.height / 2                   
print(deg + 180) // prints degree in debugging

joystick.position = location

hero.zRotation = angle - 1.57079633 //rotates with angle of joy stick

if (CGRectContainsPoint(joystickBase.frame, location)) {
}

override func touchesMoved(touches: Set<UITouch>, withEvent event: 
UIEvent?) {

    for touch in touches {

    let location = touch.locationInNode(self)

if stickActive == true && fireWeapon == true{  if fireWeapon == false 
{}

let v = CGVector(dx: location.x - joystickBase.position.x, dy: 
location.y - joystickBase.position.y)
let angle = atan2(v.dy, v.dx) //where angle is defined "in radians"
let deg = angle * CGFloat(180 / M_PI)//converts radains to degrees and 
generates a degree when touchesmove == true
let length: CGFloat = joystickBase.frame.size.height / 2 //sets maximum 
distance for joystick ball
print(deg + 180) // prints degree in debugging

joystick.position = location

self.hero.zRotation = angle - 1.57079633 //rotates with   
angle of joy stick
let xDist:CGFloat = sin(angle - 1.5709633) * 35 //bullet spawn location
let yDist:CGFloat = cos(angle - 1.5709633) * 35 //bullet spawn location

bullet1.position = CGPointMake( self.hero.position.x - xDist, 
self.hero.position.y + yDist) //spawning bullet @ defined location

let xDistMove:CGFloat = sin(angle - 1.5709633) * 700 //Bullet max x     
distance
let yDistMove:CGFloat = cos(angle - 1.5709633) * 700 //Bullet max y 
distance

let bulletMovementY = SKAction.moveToY(self.hero.position.y +   
yDistMove, duration: 1) //Bullet y speed
let bulletMovemenX = SKAction.moveToX(self.hero.position.x - xDistMove, 
duration: 1) //Bullet x speed

            bullet1.runAction(bulletMovementY)
            bullet1.runAction(bulletMovemenX)
}}

如您所见,我需要在 touches begin 中调用我的 bullet 方法,因为 bullet 产卵位置与操纵杆协调。当前方法在单击时仅产生 1 颗子弹,而不是像我在 createBullet1s 方法中尝试的那样在按住操纵杆时每 0.25 秒创建一颗新子弹。如果有人可以帮助我,我将不胜感激!谢谢

如果必须为每个项目符号重新计算值,那么我猜这样的方法是可行的(在每个节点名称前添加 self.):

if stickActive == true && fireWeapon == true{  if fireWeapon == false      
{}
let shootingAction = SKAction.runBlock({
    let v = CGVector(dx: location.x - joystickBase.position.x, dy: 
    location.y - joystickBase.position.y)
    let angle = atan2(v.dy, v.dx) //where angle is defined "in radians"
    let deg = angle * CGFloat(180 / M_PI)//converts radains to degrees and  
        generates a degree when touchesmove == true 
        print(deg + 180) 
        let bullet1:Bullet1 = Bullet1()
        self.bullet1.createBullet1s()

        self.bullet1.position = CGPoint (x: self.hero.position.x , y: self.hero.position.y) 
        let xDist:CGFloat = sin(angle - 1.5709633) * 35 
        let yDist:CGFloat = cos(angle - 1.5709633) * 35 
        self.bullet1.position = CGPointMake(self.hero.position.x - xDist,self.hero.position.y + yDist) 

        let xDistMove:CGFloat = sin(angle - 1.5709633) * 700 
        let yDistMove:CGFloat = cos(angle - 1.5709633) * 700 

        let bulletMovementY = SKAction.moveToY(self.hero.position.y + yDistMove, 
        duration: 1) 
        let bulletMovemenX = SKAction.moveToX(self.hero.position.x - xDistMove,   
        duration: 1) 
        let wait:SKAction = SKAction.waitForDuration(CFTimeInterval(0.25))

        self.addChild(self.bullet1)

        let groupMovement = SKAction.group([bulletMovementY,bulletMovementX])
        let removeNode = SKAction.removeFromParent()
        let sequenceMovementWithWait = SKAction.sequence([wait,groupMovement,removeNode])
        self.hero.runAction(sequenceMovementWithWait)
        self.hero.zRotation = angle - 1.57079633 
    })

let repeatShootingActionForever = SKAction.repeatActionForever(shootingAction)
self.runAction(repeatShootingActionForever, withKey: "BulletAction"))

如果每个项目符号的值都可以保持相同,也许这样就足够了:

        let bulletAction = SKAction.runBlock({
        self.addChild(self.bullet1)
        let groupAction = SKAction([bulletMovementY,bulletMovementX])
        let removeNode = SKAction.removeFromParent()
        let finalSequenceWithWait = SKAction.sequence([wait,groupAction,removeNode])
        self.bullet1.runAction(finalSequenceWithWait)
        })
        let repeatBulletActionForever = SKAction.repeatActionForever(bulletAction)
        self.runAction(repeatBulletActionForever, withKey: "BulletAction")

对于这两种方式,我会在 TouchesEnded 中说:

self.removeActionForKey("BulletAction")

编辑:

好的 .. 您有一个 SKNode 子 class,您可以在其中将项目符号 (SpriteNode) 添加到 SKNode。顺便说一句 - 这很复杂,因为你给 SpriteNodes 和 SKNode 取了相同的名字。但是,项目符号 (SpriteNodes) 被添加到 SKNode 并且 SKNode 被添加到 GameScene 中。现在我们 "spawn" 和 "remove" 游戏场景中的这个 SKNode,但我们只将 SpriteNode 添加到 SKNode,我们不会在那里删除它们。

您是否希望在 GameScene 中同时显示多颗子弹?如果您一次只需要 1 个子弹可见(但重复),我会说这可能有助于像我们在 GameScene 中那样从您的 SKNode 中删除子弹(SpriteNode)。

想象一下:

- GameScene creates a SKNode. (your class Bullet1)
- SKNode creates Child SpriteNode
- GameScene removes the SKNode.
- GameScene creates another SKNode. (again your class Bullet1)
- SKNode wants to create Child SpriteNode
-> Error: SpriteNode already exists.

因此我们需要编辑您的 class。

//class Bullet1
func createBullet1() {
if Bullet1.parent == nil{
    Bullet1 = SKSpriteNode(imageNamed: "bullet.png")
    Bullet1.xScale = 0.5
    Bullet1.yScale = 0.5
    Bullet1.physicsBody = SKPhysicsBody(rectangleOfSize: Bullet1.size)
    Bullet1.physicsBody?.categoryBitMask = PhysicsCategory.bullet1
    Bullet1.physicsBody?.contactTestBitMask = PhysicsCategory.enemy1 
    Bullet1.physicsBody?.affectedByGravity = false
    Bullet1.physicsBody?.dynamic = true
    self.addChild(Bullet1)
    self.name = "Bullet1"
    }
else{
    Bullet1.removeFromParent()
}
}

哦,我们需要等待 0.25 秒才能添加新的 SKNode 以便动画完成。在您的 GameScene 中编辑此部分:

let repeatShootingActionForever = SKAction.repeatActionForever(shootingAction)
self.runAction(repeatShootingActionForever, withKey: "BulletAction"))

对此:

let wait = SKAction.waitForDuration(0.25)
let runShootingAction = SKAction.runBlock(shootingAction)
let completeSequence = SKAction.sequence([wait,runShootingAction])
let repeatShootingActionForever = SKAction.repeatActionForever(completeSequence)
self.runAction(repeatShootingActionForever, withKey: "BulletAction"))

我打赌有更好的解决方案,我也不是 Swift 方面的专家。你必须测试一下..抱歉。

另一个编辑: 你没有告诉项目符号应该有哪个 zRotation。

试试这个(你有 bulletAction = SKAction.runBlock):

let bulletAction = SKAction.runBlock({
let v = CGVector(dx: location.x - self.joystickBase.position.x, dy: location.y - self.joystickBase.position.y)
let angle = atan2(v.dy, v.dx) //where angle is defined "in radians"
let deg = angle * CGFloat(180 / M_PI)//converts radains to degrees and generates a degree when touchesmove == true
print(deg + 180) // prints degree in debugging
let bullet1:Bullet1 = Bullet1()

bullet1.position = CGPoint (x: self.hero.position.x , y: self.hero.position.y) // Bullet spawn @ anchor point
bullet1.zRotation = angle - 1.57079633 //rotates with angle of joy stick
let xDist:CGFloat = sin(angle - 1.5709633) * 35 //bullet spawn location
let yDist:CGFloat = cos(angle - 1.5709633) * 35 //bullet spawn location

bullet1.position = CGPointMake( self.hero.position.x - xDist, self.hero.position.y + yDist) //spawning bullet @ defined location

bullet1.createBullet1()    

let xDistMove:CGFloat = sin(angle - 1.5709633) * 700 //Bullet max x distance
let yDistMove:CGFloat = cos(angle - 1.5709633) * 700 //Bullet max y distance

let bulletMovementY = SKAction.moveToY(self.hero.position.y+yDistMove, duration: 1) //Bullet y speed
let bulletMovemenX = SKAction.moveToX(self.hero.position.x -xDistMove, duration: 1) //Bullet x speed
let wait:SKAction = SKAction.waitForDuration( CFTimeInterval(0.25))
// let bulletFire = SKAction.sequence([wait,bulletMovemenX, bulletMovementY])
self.addChild(bullet1)

bullet1.runAction(wait)
bullet1.runAction(bulletMovementY)
bullet1.runAction(bulletMovemenX)

self.hero.zRotation = angle - 1.57079633 //rotates with angle of joy stick
})

上次编辑: 我在您的更新方法中看不到 bullet1.zRotation,所以我猜您只希望英雄更改 zRotation。

但是,如果 zRotation 仅在 touchesBegan 中发生变化而不在 touchesMoved 中发生变化,我会说您应该将 angle 设置为可以在两种方法中更改的全局变量。也许这有帮助,因为英雄根据 angle 的值获得他的 zRotation(我认为)。

  1. 使 angle 成为全局变量并添加一个变量来告诉您触摸是否移动:

    class GameScene: SKScene, SKPhysicsContactDelegate{
        var angle = CGFloat() // It should be a CGFloat, right?
        var touchesMovedOn = false
    
  2. touchesBegan编辑这部分:

    let bulletAction = SKAction.runBlock({
    let v = CGVector(dx: location.x - self.joystickBase.position.x, dy: location.y - self.joystickBase.position.y)
    let angle = atan2(v.dy, v.dx) //where angle is defined "in radians"
    let deg = angle * CGFloat(180 / M_PI)
    print(deg + 180) // prints degree in debugging
    self.hero.zRotation = angle - 1.57079633 //rotates with angle of joystic
    

对此:

    let bulletAction = SKAction.runBlock({
    let v = CGVector(dx: location.x - self.joystickBase.position.x, dy: location.y - self.joystickBase.position.y)
    if touchesMovedOn == false{
        angle = atan2(v.dy, v.dx) //where angle is defined "in radians"
    }
    let deg = angle * CGFloat(180 / M_PI)
    print(deg + 180) // prints degree in debugging
    self.hero.zRotation = angle - 1.57079633 //rotates with angle of joystic
  1. touchesMoved编辑这部分:

    let v = CGVector(dx: location.x - joystickBase.position.x, dy: location.y - joystickBase.position.y)
    let angle = atan2(v.dy, v.dx) //where angle is defined "in radians"
    let deg = angle * CGFloat(180 / M_PI)//converts radains to degrees and generates a degree when touchesmove == true
    let length: CGFloat = joystickBase.frame.size.height / 2 //sets Maximum distance for joystick ball
    print(deg + 180) // prints degree in Debugging to this:
    

对此:

    touchesMovedOn = true
    let v = CGVector(dx: location.x - joystickBase.position.x, dy: location.y - joystickBase.position.y)
    angle = atan2(v.dy, v.dx) //where angle is defined "in radians"
    let deg = angle * CGFloat(180 / M_PI)//converts radains to degrees and generates a degree when touchesmove == true
    let length: CGFloat = joystickBase.frame.size.height / 2 //sets Maximum distance for joystick ball
    print(deg + 180) // prints degree in Debugging to this:
  1. touchesEnded

    中添加这一行
    touchesMovedOn = false
    

如果这没有帮助,我真的需要这个项目,因为我必须自己测试问题所在。所以我希望它现在有效。好运 !正如我所说,我确信有更好的解决方案,所以将来你应该注意使代码更好。 ;-)