【问题标题】:Spawn Balls random position out of the screen生成球在屏幕外的随机位置
【发布时间】:2016-01-18 01:22:20
【问题描述】:

我想从屏幕外部调出敌人(var enemis),无论是屏幕的顶部、底部、左侧还是右侧。而这些敌人在横穿屏幕时有一个随机的方向。目前,我的代码确实会在屏幕顶部、底部、左侧和右侧生成敌人,但只有一个方向,我想要一个随机方向

func CreationEnnemis(){

        let Enemis = SKSpriteNode(imageNamed: "Meteroites.png")
        let choixDeCote = arc4random() % 4 + 1

        switch choixDeCote {

            case 1 : //Haut
                let MinValue = self.size.width / 8
                let MaxValue = self.size.width - 200
                SpawnX = UInt32(MaxValue - MinValue)
                SpawnX = arc4random_uniform(SpawnX)
                SpawnY = UInt32(self.size.height)
             break

            case 2 ://Bas
                let MinValue = self.size.width / 8
                let MaxValue = self.size.width - 200
                SpawnX = UInt32(MaxValue - MinValue)
                SpawnX = arc4random_uniform(SpawnX)
                SpawnY = UInt32(self.size.height) - UInt32(self.size.height)
             break

            case 3 : //Gauche
                let MinValue = self.size.height / 8
                let MaxValue = self.size.height - 200
                SpawnX = 0
                SpawnY = UInt32(MaxValue - MinValue)
                SpawnY = arc4random_uniform(SpawnY)
             break

            case 4 ://Droite
                let MinValue = self.size.height / 8
                let MaxValue = self.size.height - 200
                SpawnX = UInt32(self.size.width)
                SpawnY = UInt32(MaxValue - MinValue)
                SpawnY = arc4random_uniform(SpawnY)
             break

            default :
             break
        }

        Enemis.position = CGPoint(x: CGFloat(SpawnX), y: CGFloat(SpawnY))
        Enemis.setScale(4)
        Enemis.physicsBody = SKPhysicsBody(rectangleOfSize: Enemis.size)
        Enemis.physicsBody?.affectedByGravity = false
        Enemis.physicsBody?.dynamic = true

        let action = SKAction.moveTo(CGPoint(x: -50,y: -10),duration: 2.5)
        let actionFini = SKAction.removeFromParent()
        Enemis.runAction(SKAction.sequence([action, actionFini]))
        Enemis.runAction(SKAction.repeatActionForever(action))

        self.addChild(Enemis)
    }

【问题讨论】:

    标签: swift sprite-kit swift2


    【解决方案1】:

    这只是一个示例,让您了解如何在随机位置生成敌人并沿随机方向移动它们。我没有广泛使用 Swift,这更像是向您展示您可以往哪个方向发展,以及如何解决问题。我留给你关心 Swift 2 语法 :D 另外,我目前使用的是过时的 Swift 版本,所以不确定什么对我有用,对你有用,但逻辑​​是一样的。

    在这里您将看到如何做:

    • 生成一个节点并将其移动到屏幕的另一侧
    • 将节点移动到屏幕另一侧的随机点
    • 随机生成持续时间
    • 沿屏幕边框之一创建一个随机点
    • 在两个数字之间创建一个随机数
    • 使用 SKAction 完成所有这些操作

    这里重要的一件事是如何在闭包中使用对 self 的强引用。因为我的 Swift 版本,正如我所说,对我有用的,可能对你不起作用,但逻辑​​是一样的。如果有兴趣,请在此处阅读有关强参考周期的更多信息:

    这是一个代码示例:

    import SpriteKit
    
    
    class GameScene:SKScene, SKPhysicsContactDelegate{
    
        override func didMoveToView(view: SKView) {
    
    
            self.physicsWorld.contactDelegate = self
    
    
            createEnemies()
    
        }
    
        deinit{
           print("deinit called")
        }
    
    
    
        func randomBetweenNumbers(firstNum: CGFloat, secondNum: CGFloat) -> CGFloat{
            return CGFloat(arc4random()) / CGFloat(UINT32_MAX) * abs(firstNum - secondNum) + min(firstNum, secondNum)
        }
         //Helper method for spawning a point along the screen borders. This will not work for diagonal lines.
        func randomPointBetween(start:CGPoint, end:CGPoint)->CGPoint{
    
            return CGPoint(x: randomBetweenNumbers(start.x, secondNum: end.x), y: randomBetweenNumbers(start.y, secondNum: end.y))
    
        }
    
    
        func createEnemies(){
    
            //Randomize spawning time.
            //This will create a node every 0.5 +/- 0.1 seconds, means between 0.4 and 0.6 sec
            let wait = SKAction .waitForDuration(0.5, withRange: 0.2)
    
    
            weak var  weakSelf = self //Use weakSelf to break a possible strong reference cycle
    
    
            let spawn = SKAction.runBlock({
    
                var random = arc4random() % 4 +  1
                var position = CGPoint()
                var moveTo = CGPoint()
                var offset:CGFloat = 40
    
                println(random)
    
                switch random {
    
                    //Top
                case 1:
                    position = weakSelf!.randomPointBetween(CGPoint(x: 0, y: weakSelf!.frame.height), end: CGPoint(x: weakSelf!.frame.width, y: weakSelf!.frame.height))
    
                    //Move to opposite side
                    moveTo = weakSelf!.randomPointBetween(CGPoint(x: 0, y: 0), end: CGPoint(x:weakSelf!.frame.width, y:0))
    
                    break
    
                    //Bottom
                case 2:
                    position = weakSelf!.randomPointBetween(CGPoint(x: 0, y: 0), end: CGPoint(x: weakSelf!.frame.width, y: 0))
    
                    //Move to opposite side
                      moveTo = weakSelf!.randomPointBetween(CGPoint(x: 0, y: weakSelf!.frame.height), end: CGPoint(x: weakSelf!.frame.width, y: weakSelf!.frame.height))
    
                    break
    
                    //Left
                case 3:
                    position = weakSelf!.randomPointBetween(CGPoint(x: 0, y: 0), end: CGPoint(x: 0, y: weakSelf!.frame.height))
    
                    //Move to opposite side
                    moveTo = weakSelf!.randomPointBetween(CGPoint(x: weakSelf!.frame.width, y: 0), end: CGPoint(x: weakSelf!.frame.width, y: weakSelf!.frame.height))
    
                    break
    
                    //Right
                case 4:
                    position = weakSelf!.randomPointBetween(CGPoint(x: weakSelf!.frame.width, y: 0), end: CGPoint(x: weakSelf!.frame.width, y: weakSelf!.frame.height))
    
                    //Move to opposite side
                     moveTo = weakSelf!.randomPointBetween(CGPoint(x: 0, y: 0), end: CGPoint(x: 0, y: weakSelf!.frame.height))
                    break
    
                default:
                    break
    
                }
    
                weakSelf!.spawnEnemyAtPosition(position, moveTo: moveTo)
    
            })
    
            let spawning = SKAction.sequence([wait,spawn])
    
            self.runAction(SKAction.repeatActionForever(spawning), withKey:"spawning")
    
    
        }
    
    
        func spawnEnemyAtPosition(position:CGPoint, moveTo:CGPoint){
    
            let enemy = SKSpriteNode(color: SKColor.brownColor(), size: CGSize(width: 40, height: 40))
    
    
            enemy.position = position
            enemy.physicsBody = SKPhysicsBody(rectangleOfSize: enemy.size)
            enemy.physicsBody?.affectedByGravity = false
            enemy.physicsBody?.dynamic = true
            enemy.physicsBody?.collisionBitMask = 0 // no collisions
            //Here you can randomize the value of duration parameter to change the speed of a node
            let move = SKAction.moveTo(moveTo,duration: 2.5)
            let remove = SKAction.removeFromParent()
            enemy.runAction(SKAction.sequence([move, remove]))
    
    
            self.addChild(enemy)
    
        }
    
    
        func didBeginContact(contact: SKPhysicsContact) {
    
    
        }
    
    
        /*
    
        Added for debugging purposes
    
        override func touchesBegan(touches: NSSet, withEvent event: UIEvent?) {
    
            //Just make a transition to the other scene, in order to check if deinit is called
            //You have to make a new scene ... I named it WelcomeScene
            var scene:WelcomeScene = WelcomeScene(fileNamed: "WelcomeScene.sks")
    
            scene.scaleMode = .AspectFill
    
            self.view?.presentScene(scene )
    
    
        }
        */
    
    }
    

    结果如下:

    重要部分位于createEnemies()方法中:

    //Top
    case 1:
        position = weakSelf!.randomPointBetween(CGPoint(x: 0, y: weakSelf!.frame.height), end: CGPoint(x: weakSelf!.frame.width, y: weakSelf!.frame.height))
    
        //Move to opposite side
        moveTo = weakSelf!.randomPointBetween(CGPoint(x: 0, y: 0), end: CGPoint(x:weakSelf!.frame.width, y:0))
    
        break
    

    您可以在此处定义生成位置,该位置可以是顶部边框上的任何点。或者更准确地说,在顶部边界上方一点点。节点在屏幕外生成。接下来,您创建(随机化)一个您想要移动节点的点,与生成位置相比,这是相反的一侧。因此,这可以是底部边界上的任何随机点。

    如果你想停止产卵,你会这样做:

    if(self.actionForKey("spawning") != nil){
        self.removeActionForKey("spawning")
    }
    

    关于您的物理体设置...请注意,我已将节点的 collisionBitMask 设置为 0。

    enemy.physicsBody?.collisionBitMask = 0 // no collisions
    

    在 SpriteKit 中通过动作移动节点时,您会将它们从物理模拟中拉出来,如果您希望看到逼真的物理模拟,您可能会得到意想不到的行为。因此,仅当您对碰撞(或其他类型的物理模拟)不感兴趣时​​才使用动作,而只是对接触检测感兴趣。如果您还需要碰撞,请使用物理引擎并通过施加脉冲或力来移动节点。

    希望这会有所帮助!

    【讨论】:

      【解决方案2】:

      非常感谢! 我制作了您的代码的不同版本,因为我在您回答之前找到了解决方案

      func CreationMeteorites(){
      
              let Meteorites = SKSpriteNode(imageNamed: "Meteroites.png")
              let choixDeCote = arc4random() % 4 + 1
      
              switch choixDeCote {
      
              case 1 : //Haut
                  let MinValue = self.size.width / 8
                  let MaxValue = self.size.width - 200
                  SpawnX = UInt32(MaxValue - MinValue)
                  SpawnX = arc4random_uniform(SpawnX)
                  SpawnY = UInt32(self.size.height)
                  directionX = Int(arc4random()) % Int(self.frame.size.width)
                  directionY = 0
                  action = SKAction.moveTo(CGPoint(x: CGFloat(directionX),y: CGFloat(directionY)),duration: 4)
                  break
      
              case 2 ://Bas
                  let MinValue = self.size.width / 8
                  let MaxValue = self.size.width - 200
                  SpawnX = UInt32(MaxValue - MinValue)
                  SpawnX = arc4random_uniform(SpawnX)
                  SpawnY = 0
                  directionX = Int(arc4random()) % Int(self.frame.size.width)
                  directionY = Int(self.frame.size.height)
                  action = SKAction.moveTo(CGPoint(x: CGFloat(directionX),y: CGFloat(directionY)),duration: 4)
                  break
      
              case 3 : //Gauche
                  let MinValue = self.size.height / 8
                  let MaxValue = self.size.height - 200
                  SpawnX = 0
                  SpawnY = UInt32(MaxValue - MinValue)
                  SpawnY = arc4random_uniform(SpawnY)
                  directionY = Int(arc4random()) % Int(self.frame.size.height)
                  directionX = Int(self.frame.size.width)
                  action = SKAction.moveTo(CGPoint(x: CGFloat(directionX),y: CGFloat(directionY)),duration: 3)
                  break
      
              case 4 ://Droite
                  let MinValue = self.size.height / 8
                  let MaxValue = self.size.height - 200
                  SpawnX = UInt32(self.size.width)
                  SpawnY = UInt32(MaxValue - MinValue)
                  SpawnY = arc4random_uniform(SpawnY)
                  directionY = Int(arc4random()) % Int(self.frame.size.height)
                  directionX = 0
                  action = SKAction.moveTo(CGPoint(x: CGFloat(directionX),y: CGFloat(directionY)),duration: 3)
                  break
      
              default :
                  break
              }
      
              //Positioner les météorites
      
              Meteorites.position = CGPoint(x: CGFloat(SpawnX), y: CGFloat(SpawnY))
              Meteorites.setScale(4)
              Meteorites.physicsBody = SKPhysicsBody(circleOfRadius: 30)
              Meteorites.physicsBody?.affectedByGravity = false
              Meteorites.physicsBody?.dynamic = true
              Meteorites.physicsBody?.categoryBitMask = PhysicsCategories.Meteorites
              Meteorites.physicsBody?.contactTestBitMask = PhysicsCategories.Meteorites
      
              let actionFini = SKAction.removeFromParent()
      
              Meteorites.runAction(SKAction.sequence([action, actionFini]))
              Meteorites.runAction(SKAction.repeatActionForever(action))
      
              self.addChild(Meteorites)
          }
      

      关于碰撞,你知道有一个很好解释的教程吗,因为我不明白如何产生碰撞。

      【讨论】:

      【解决方案3】:

      对于任何有兴趣在 GameScene 中的目标 C 中执行此操作的人:

      -(void) randomSpawnPosition{
          NSUInteger randPos = arc4random_uniform(4);
          CGPoint spawnPosition;
          CGFloat randFloatX = arc4random_uniform(self.frame.size.width + 10);
          CGFloat randFloatY = arc4random_uniform(self.frame.size.height + 10);
      
          switch (randPos) {
                  //top
              case 1:
                  spawnPosition = CGPointMake(randFloatX, self.frame.size.height+10);
                  break;
                  //bottom
              case 2:
                  spawnPosition = CGPointMake(randFloatX, 0-10);
                  break;
                  //left
              case 3:
                  spawnPosition = CGPointMake(0 - 10, randFloatY);
                  break;
                  //right
              case 4:
                  spawnPosition = CGPointMake(self.frame.size.width + 10, randFloatY);
                  break;
          }
          [self addEnemy:spawnPosition];
      }
      

      【讨论】:

      • 确定 nsuinteger randPos 是案例 1 - 4 的随机数,CGFloat randFloatX 和 randFloatY 根据屏幕大小生成一个随机数,其中 x 是屏幕宽度,y是高度,然后在该值上加 10,因此它会延伸到屏幕的角落,应该可能会增加更多的 tbh。然后例如屏幕顶部的情况,随机 x 坐标插入 randFloatX 和 self.frame.size.height 是屏幕的最大高度 + 10 这是我的精灵节点的大小
      猜你喜欢
      • 2014-04-07
      • 2015-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-14
      • 1970-01-01
      相关资源
      最近更新 更多