Swift 如何在玩家触发事件后添加延迟?

Swift 如何在玩家触发事件后添加延迟?,swift,sprite-kit,game-development,Swift,Sprite Kit,Game Development,如何在玩家触发跳跃后添加延迟,以便跳跃不会被频繁触发(或垃圾邮件) 一个简单的方法是使用一个布尔标志,当玩家触发跳转时该标志会改变,并在短时间延迟后自动重置 var canJump: Bool = True func jumpRight() { guard canJump == True else { return } self.canJump = False player.physicsBody?.velocity = CGVector(dx: 0,dy: 0)

如何在玩家触发跳跃后添加延迟,以便跳跃不会被频繁触发(或垃圾邮件)


一个简单的方法是使用一个布尔标志,当玩家触发跳转时该标志会改变,并在短时间延迟后自动重置

var canJump: Bool = True

func jumpRight() {
    guard canJump == True else { return }
    self.canJump = False
    player.physicsBody?.velocity = CGVector(dx: 0,dy: 0)
    player.physicsBody?.applyImpulse(CGVector (dx: 100, dy: 500))
    DispatchQueue.main.asyncAfter(deadline: .now()+0.2) {
        self.canJump = True
    }
}

有几种方法可以做到这一点,无论您在何处设置了跳转按钮,选择的目标(无论是右跳转还是左跳转)都需要添加一个检查,以监控何时按下跳转命令以及跳转命令何时完成

首先,我将在函数中添加一个完成处理程序

func jumpRight(arg: Bool, completion: (Bool) -> ()) {
    completion(arg) 
}
通过这样做,您可以确定函数何时完成。 下面是调用跳转按钮命令的地方。无论在何处定义了操作,都应将其称为

jumpRight(arg: true, completion: { (success) -> Void in
    print("Second line of code executed")
    if success { // this will be equal to whatever value is set in this method call
          print("true")
    } else {
         print("false")
    }
})

如果该个人已垃圾邮件跳转,则将从完成处理程序打印“false”。在函数定义的操作完成之前,可以防止用户再次跳转

我的解决办法是尝试这样的方法

var lastUpdateTime: TimeInterval = 0
var dt: TimeInterval = 0
let jumpHysterisisTimeLimit: TimeInterval = 0.2
var jumpHysterisisTimer: TimeInterval = 0
var jumpAGoGo: Bool = false

func updateGameLoopTimer(currentTime: TimeInterval) {
  if lastUpdateTime > 0 {
    dt = currentTime - lastUpdateTime
  } else {
    dt = 0
  }
  lastUpdateTime = currentTime
}

override func update(_ currentTime: TimeInterval) {
    updateGameLoopTimer(currentTime: currentTime)
    isJumpAGoGo()
}

func isJumpAGoGo() {
  if jumpAGoGo {
    jumpHysterisisTimer += dt
    if jumpHysterisisTimer >= jumpHysterisisTimeLimit {
      jumpHysterisisTimer = 0
      jumpAGoGo = false
    }
  }
}

func jumpRight() {
  if !jumpAGoGo {
    jumpAGoGo = true
    player.physicsBody?.velocity = CGVector(dx: 0,dy: 0)
    player.physicsBody?.applyImpulse(CGVector (dx: 100, dy: 500))
  }  
}

func jumpLeft() {
  if !jumpAGoGo {
    jumpAGoGo = true
    player.physicsBody?.velocity = CGVector(dx: 0,dy: 0)
    player.physicsBody?.applyImpulse(CGVector (dx: -100, dy: 500)) 
  }
}
然后,您可以根据需要使用JumpHististimit值进行调整。

1)我将确定地面是什么,并且只在地面上跳跃

func jumpRight() {
    if onGround == false {return}
    player.physicsBody?.velocity = CGVector(dx: 0,dy: 0)
    player.physicsBody?.applyImpulse(CGVector (dx: 100, dy: 500))  
}

func jumpLeft() {
    if onGround == false {return}
    player.physicsBody?.velocity = CGVector(dx: 0,dy: 0)
    player.physicsBody?.applyImpulse(CGVector (dx: -100, dy: 500))    
}
onGround可以是一个检查,如果一个物理身体存在于一个球员的脚下,或者它可能是一个特定的y区域,这是在你身上

我想检查一下尸体

rayStart
是您的“脚”所在的位置

2) 如果你需要添加一个“充电”,我会使用SKActions

func jumpRight() {
    if onGround == false || player.action(forKey:"jump") {return}
    player.physicsBody?.velocity = CGVector(dx: 0,dy: 0)
    player.physicsBody?.applyImpulse(CGVector (dx: 100, dy: 500))  
    player.run(SKAction.wait(forDuration:1), withKey:"jump")
}

func jumpLeft() {
    if onGround == false || player.action(forKey:"jump") {return}
    player.physicsBody?.velocity = CGVector(dx: 0,dy: 0)
    player.physicsBody?.applyImpulse(CGVector (dx: -100, dy: 500))    
    player.run(SKAction.wait(forDuration:1), withKey:"jump")
}
3) 为了安全起见,还包括y的速度为零(或某个不表示跳跃的阈值)

因为某个特定的人在使用Sprite Kit时遇到了困难,我将发布一个非常具体的问题的确切答案,因为他们无法推断。我不建议只在跳跃时这样做,因为它允许双跳或跌倒时跳跃

if !player.action(forKey:"jump”){
    player.run(SKAction.wait(forDuration:1), withKey:"jump")
    // insert your jump function calls here
}
您可以将此技术用于任何类型或充电


您甚至可以更进一步,用
customActionWithDuration
sequence
\
group
替换
wait
,以创建与充电时间同步的动画。

我建议在帧更新时执行检查,管理bool,并在60帧后或任何您想要的情况下,更改布尔状态,让用户能够像回答中提到的那样再次推送它。这没问题,但实际上是游戏循环中的调度队列?发生ApplicationIDBecMeactive(application:UIApplication)时会发生什么。调度队列很好吗handled@hoboBob这不是在游戏循环中触发的,而是通过用户交互(即,当用户让精灵跳跃时)触发的。它在游戏循环中。你从游戏循环中调用它来对游戏循环中的某些东西进行操作。时间对比赛的实际比赛没有影响。传播延迟。它将在哪里结束!此外,DispatchQueue和ApplicationIdentinterBackground(application:UIApplication)永远不会很好地结合在一起。@hoboBob True。如果应用程序进入后台,是否会取消调度队列?我没有想到我必须承认。我想当它再次出现在前台时,可能会让游戏处于一种不确定的状态。除了hoboBob所说的之外,还有其他问题。如果你决定暂停游戏怎么办?那批快件仍将开火。您应该避免使用SpriteKit之外的任何计时机制。您还应该节省使用更新循环中的currentTime,因为这将从
SKView的CADisplayLink.targetTimestamp
中退出,这意味着您最终将不得不在发生延迟此操作的系统事件时处理同步增量时间。在一些独立游戏中,利用这一点实际上是作弊的好方法;这段对话已经结束。
func jumpRight() {
    if onGround == false || player.action(forKey:"jump") {return}
    player.physicsBody?.velocity = CGVector(dx: 0,dy: 0)
    player.physicsBody?.applyImpulse(CGVector (dx: 100, dy: 500))  
    player.run(SKAction.wait(forDuration:1), withKey:"jump")
}

func jumpLeft() {
    if onGround == false || player.action(forKey:"jump") {return}
    player.physicsBody?.velocity = CGVector(dx: 0,dy: 0)
    player.physicsBody?.applyImpulse(CGVector (dx: -100, dy: 500))    
    player.run(SKAction.wait(forDuration:1), withKey:"jump")
}
func jumpRight() {
    if onGround == false || player.action(forKey:"jump") || player.physicsBody?.velocity.dy != 0 {return}
    player.physicsBody?.velocity = CGVector(dx: 0,dy: 0)
    player.physicsBody?.applyImpulse(CGVector (dx: 100, dy: 500))  
    player.run(SKAction.wait(forDuration:1), withKey:"jump")
}

func jumpLeft() {
    if onGround == false || player.action(forKey:"jump") || player.physicsBody?.velocity.dy != 0 {return}
    player.physicsBody?.velocity = CGVector(dx: 0,dy: 0)
    player.physicsBody?.applyImpulse(CGVector (dx: -100, dy: 500))    
    player.run(SKAction.wait(forDuration:1), withKey:"jump")
}
if !player.action(forKey:"jump”){
    player.run(SKAction.wait(forDuration:1), withKey:"jump")
    // insert your jump function calls here
}