2017-05-28 29 views
1

私は、オブジェクトが食品を追跡する必要があるゲームを作成しようとしています。現在、オブジェクトは指定された半径内にあるときにオブジェクトの速度を上げます。しかし、私はいつも同じスピードが必要です。一定の速度で移動するオブジェクトが必要です

これを修正する方法を教えてください。私は、私がposition.xとposition.yを設定するchase関数の下にSKActionを追加しようとしましたが、正しく動作させることはできません。

魚クラス:

class Fish:SKSpriteNode{ 
private let kMovingAroundKey = "movingAround" 
private let kFishSpeed:CGFloat = 4.5 
private var swimmingSpeed:CGFloat = 100.0 
private let sensorRadius:CGFloat = 100.0 
private weak var food:SKSpriteNode! = nil //the food node that this fish currently chase 

override init(texture: SKTexture?, color: UIColor, size: CGSize) { 
    super.init(texture: texture, color: color, size: size) 

    physicsBody = SKPhysicsBody(rectangleOf: size) 
    physicsBody?.affectedByGravity = false 
    physicsBody?.categoryBitMask = Collider.fish 
    physicsBody?.contactTestBitMask = Collider.food 
    physicsBody?.collisionBitMask = 0x0 //No collisions with fish, only contact detection 
    name = "fish" 

    let sensor = SKShapeNode(circleOfRadius: 100) 
    sensor.fillColor = .red 
    sensor.zPosition = -1 
    sensor.alpha = 0.1 
    addChild(sensor) 
} 

func getDistanceFromFood()->CGFloat? { 

    if let food = self.food { 

     return self.position.distance(point: food.position) 
    } 
    return nil 

} 

func lock(food:SKSpriteNode){ 

    //We are chasing a food node at the moment 
    if let currentDistanceFromFood = self.getDistanceFromFood() { 

     if (currentDistanceFromFood > self.position.distance(point: food.position)){ 
      //chase the closer food node 
      self.food = food 
      self.stopMovingAround() 
     }//else, continue chasing the last locked food node 

    //We are not chasing the food node at the moment 
    }else{ 
     //go and chase then 
     if food.position.distance(point: self.position) <= self.sensorRadius { 

      self.food = food 
      self.stopMovingAround() 
     } 
    } 
} 

//Helper method. Not used currently. You can use this method to prevent chasing another (say closer) food while already chasing one 
func isChasing(food:SKSpriteNode)->Bool{ 

    if self.food != nil { 

     if self.food == food { 
      return true 
     } 
    } 

    return false 
} 

func stopMovingAround(){ 

    if self.action(forKey: kMovingAroundKey) != nil{ 
     removeAction(forKey: kMovingAroundKey) 
    } 
} 


//MARK: Chasing the food 
//This method is called many times in a second 
func chase(within rect:CGRect){ 

    guard let food = self.food else { 

     if action(forKey: kMovingAroundKey) == nil { 
      self.moveAround(within: rect) 
     } 
     return 
    } 

    //Check if food is in the water 
    if rect.contains(food.frame.origin) { 

     //Take a detailed look in my Stackoverflow answer of how chasing works : https://stackoverflow.com/a/36235426 

     let dx = food.position.x - self.position.x 
     let dy = food.position.y - self.position.y 

     let angle = atan2(dy, dx) 

     let vx = cos(angle) * kFishSpeed 
     let vy = sin(angle) * kFishSpeed 

     position.x += vx 
     position.y += vy 

    } 
} 

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

func moveAround(within rect:CGRect){ 

    if scene != nil { 

     //Go randomly around the screen within view bounds 
     let point = rect.randomPoint() 

     //Formula: time = distance/speed 
     let duration = TimeInterval(point.distance(point: position)/self.swimmingSpeed) 
     let move = SKAction.move(to: point, duration: duration) 
     let block = SKAction.run { 
      [unowned self] in 

      self.moveAround(within: rect) 
     } 
     let loop = SKAction.sequence([move,block]) 

     run(loop, withKey: kMovingAroundKey) 
    } 
} 
} 

Gamesceneアップデート機能を見ることができます。おそらく

override func update(_ currentTime: TimeInterval) { 

    self.enumerateChildNodes(withName: "fish") { 
     [unowned self] node, stop in 

     if let fish = node as? Fish { 

      self.enumerateChildNodes(withName: "food") { 
       node, stop in 

       fish.lock(food: node as! SKSpriteNode) 
      } 

      fish.chase(within: self.water.frame) 
     } 
    } 
} 
+0

@Whirlwindここをクリックしてください:) – Grumme

+0

答えをチェックして、私はちょうどそれをテストし、良い結果を得ました。 – Whirlwind

答えて

2

このような何か(GameScene):

var prev : TimeInterval! 

    //MARK: Chasing the food 
    override func update(_ currentTime: TimeInterval) { 

     defer { prev = currentTime } 
     guard prev != nil else { return } 

     let dt = currentTime - prev 

     print("delta time \(dt)") 

     self.enumerateChildNodes(withName: "fish") { 
      [unowned self] node, stop in 

      if let fish = node as? Fish { 

       self.enumerateChildNodes(withName: "food") { 
        node, stop in 

        fish.lock(food: node as! SKSpriteNode) 
       } 

       fish.chase(within: self.water.frame, delta:CGFloat(dt)) 
      } 
     } 
    } 

変数prevがGameSceneの財産です。

そしてFishクラスのchase()方法変更:

//MARK: Chasing the food 
    func chase(within rect:CGRect, delta:CGFloat){ 

     guard let food = self.food else { 

      if action(forKey: kMovingAroundKey) == nil { 
       self.moveAround(within: rect) 
      } 
      return 
     } 

     //Check if food is in the water 
     if rect.contains(food.frame.origin) { 

      //Take a detailed look in my Stackoverflow answer of how chasing works : https://stackoverflow.com/a/36235426 

      //check for collision 

      if self.frame.contains(food.frame.origin) { 
       food.removeFromParent() 
      }else { 
       let dx = food.position.x - self.position.x 
       let dy = food.position.y - self.position.y 

       let angle = atan2(dy, dx) 



       let vx = cos(angle) * self.swimmingSpeed * delta 
       let vy = sin(angle) * self.swimmingSpeed * delta 

       print("vx \(vx), vy (\(vy)") 



       position.x += vx 
       position.y += vy 

       //time = distance/speed 
      } 
     } 
    } 

を私はdelta timeパラメータが追加されました。デルタタイムとは何ですか?私はその記事からLearnCocos2dを引用します:

デルタ時間は、単純に前回と 現在のフレームとの間の時間差です。

ノードの一定速度を維持することはなぜ重要ですか?さて、我々はFish.swimmingSpeed変数を使って魚の速度を決定します(kFishSpeedを忘れて、今は目的がありません)。

は今SKActionの場合には、期間パラメータは、直接期間は、時間に適用されるため、魚の速度を決定し、time = distance/speedので、私たちは現在、このような時の計算:

let duration = TimeInterval(point.distance(point: position)/self.swimmingSpeed) 

は今それを言うことができます期間は1になります。つまり、魚は毎秒100ポイント移動します。さて、update()メソッドとアクションの違いは、1秒間に60回実行されることです。私たちの方法chase()は理想的には毎秒60回と呼ばれているので、現在の速度はFish.swimmingSpeed/60でなければなりません。

これはデルタ時間が来るところです。フレームが1/60秒(0.016667)でレンダリングされず、レンダリングに時間がかかります(0.02,0.03秒など) 、それを使って動きを調整します。デルタ時間を使用しない通常の行動と比較して、IMOを欺くのは、ゲームがずっと遅れていると(例えば、そのヒーローテレポート)、瞬間にコントロールを失うためですが、その部分は話題にはなりません:)作品/あなたのためによく見えます。

だから我々は(距離を計算するために)実行します。

let vx = cos(angle) * self.swimmingSpeed * delta 
let vy = sin(angle) * self.swimmingSpeed * delta 

、それはあなたに一定の速度を与えるだろう。

詳細については詳しく説明していきますが、ここに遅れています。機能していると考えられているので、ここでやります。ハッピーコーディング!

+0

デルタタイムを使いたくない場合は、deltaを乗算するのではなく、 'swimmingSpeed'を60(またはあなたの好みのフレームレート)で除算するだけです。 – Whirlwind

関連する問題