Ios &引用;暂停“;斯威夫特的比赛
我用Swift制作了一个游戏,里面有怪物出现。怪物的出现和消失都是基于计时器使用的,如下所示:Ios &引用;暂停“;斯威夫特的比赛,ios,swift,swift3,grand-central-dispatch,Ios,Swift,Swift3,Grand Central Dispatch,我用Swift制作了一个游戏,里面有怪物出现。怪物的出现和消失都是基于计时器使用的,如下所示: func RunAfterDelay(_ delay: TimeInterval, block: @escaping ()->()) { let time = DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC) DispatchQueue.main.as
func RunAfterDelay(_ delay: TimeInterval, block: @escaping ()->())
{
let time = DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
DispatchQueue.main.asyncAfter(deadline: time, execute: block)
}
addTimer(delay: 4, repeating: true)
{ [unowned self] in
self.spawnMonster()
}
然后我会这样称呼它(例如在2秒后产卵):
然后我做了类似的隐藏动作(x秒后,我将怪物击溃)
因此,我在屏幕顶部创建了一个设置图标,当你点击它时,一个巨大的矩形窗口会出现以更改游戏设置,但问题自然是怪物仍然会在背景中繁殖。如果我把球员挥舞到另一个屏幕上,我相信我将失去我所有的比赛状态,并且不能在没有开始的情况下回到比赛中(球员可能在比赛的中间)。
有没有办法告诉我在上面创建的所有游戏计时器,即
DispatchQueue.main.asyncAfter(deadline: time, execute: block)
当我这么说的时候停下来继续?我想用所有的定时器都可以(如果没有办法标记和暂停某些定时器的话)
谢谢 我已经解决了这个问题,希望在下面的结论中分享我的研究/编码时间。为了更简单地重申这个问题,我实际上想实现这一点(而不是简单地使用SpriteKit场景暂停,这非常简单):
let timerKey = UUID().uuidString
let myTimer: Timer = Timer.scheduledTimer(withTimeInterval: delay, repeats: false) {
_ in
block()
self.timers.removeValue(forKey: timerKey)
}
}
let timerKey = UUID().uuidString
let myTimer: Timer = Timer.scheduledTimer(withTimeInterval: delay, repeats: false) {
_ in
block()
self.timers.removeValue(forKey: timerKey)
}
}
注意:block()只是调用您在计时器中封装的任何块。例如,我做了一些很酷的事情,比如:
func RunAfterDelay(_ delay: TimeInterval, block: @escaping ()->())
{
let time = DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
DispatchQueue.main.asyncAfter(deadline: time, execute: block)
}
addTimer(delay: 4, repeating: true)
{ [unowned self] in
self.spawnMonster()
}
因此,addTimer将运行self.spawnmoster代码(作为block()),然后在完成后从字典中自动删除
后来我变得更复杂了,我做了一些事情,比如让计时器不断重复运行,而不是自动删除,但对于我来说,这只是很多非常具体的代码,可能会占用太多的时间:)
无论如何,我真的希望这能帮助一些人,并且愿意回答任何人提出的任何问题。我在这上面花了很多时间
谢谢 我将在这里为您展示一些东西,并为未来的读者展示更多东西,这样他们就可以通过复制粘贴这些代码来获得一个可行的示例。接下来是以下几件事: 1.使用
SKAction
2.暂停操作
3.暂停节点本身
4.正如我所说,还有几件事:)
请注意,所有这些都可以用不同的方式完成,甚至比这更简单(当涉及到暂停动作和节点时),但我将向您展示详细的方式,以便您可以选择最适合您的方式
初始设置
我们有一个英雄节点和一个敌人节点。敌人节点将在屏幕顶部每5秒产卵一次,并向下移动,向玩家下毒
正如我所说,我们将只使用SKActions
,不使用NSTimer
,甚至不使用update:
方法。纯粹的行动。因此,在这里,玩家将静止在屏幕底部(紫色方块),敌人(红色方块),如前所述,将向玩家移动并毒害他
让我们看一些代码。我们需要定义所有这些工作的常规内容,比如设置物理类别、初始化和定位节点。我们还将设置敌人产卵延迟(8秒)和中毒持续时间(3秒):
还有一个名为isGamePaused
的变量,稍后我会对其进行更多的评论,但正如您所想象的,它的目的是跟踪游戏是否暂停,以及当用户点击黄色的大方形按钮时,它的值是否会发生变化
辅助方法
我已经为节点创建创建了一些辅助方法。我有一种感觉,这不是你个人需要的,因为你看起来对编程有很好的理解,但我会为完整性和未来的读者做这件事。所以这里是设置节点名称或其p的地方
//Inside of a GameScene.swift
let hero = SKSpriteNode(color: .purple , size: CGSize(width: 50, height: 50))
let button = SKSpriteNode(color: .yellow, size: CGSize(width: 120, height:120))
var isGamePaused = false
let kPoisonDuration = 3.0
override func didMove(to view: SKView) {
super.didMove(to: view)
self.physicsWorld.contactDelegate = self
hero.position = CGPoint(x: frame.midX, y:-frame.size.height / 2.0 + hero.size.height)
hero.name = "hero"
hero.physicsBody = SKPhysicsBody(rectangleOf: hero.frame.size)
hero.physicsBody?.categoryBitMask = ColliderType.Hero.rawValue
hero.physicsBody?.collisionBitMask = 0
hero.physicsBody?.contactTestBitMask = ColliderType.Enemy.rawValue
hero.physicsBody?.isDynamic = false
button.position = CGPoint(x: frame.maxX - hero.size.width, y: -frame.size.height / 2.0 + hero.size.height)
button.name = "button"
addChild(button)
addChild(hero)
startSpawningEnemies()
}
func getEnemy()->SKSpriteNode{
let enemy = SKSpriteNode(color: .red , size: CGSize(width: 50, height: 50))
enemy.physicsBody = SKPhysicsBody(rectangleOf: enemy.frame.size)
enemy.physicsBody?.categoryBitMask = ColliderType.Enemy.rawValue
enemy.physicsBody?.collisionBitMask = 0
enemy.physicsBody?.contactTestBitMask = ColliderType.Hero.rawValue
enemy.physicsBody?.isDynamic = true
enemy.physicsBody?.affectedByGravity = false
enemy.name = "enemy"
return enemy
}
func spawnEnemy(atPoint spawnPoint:CGPoint){
let enemy = getEnemy()
enemy.position = spawnPoint
addChild(enemy)
//moving action
let move = SKAction.move(to: hero.position, duration: 5)
enemy.run(move, withKey: "moving")
}
func startSpawningEnemies(){
if action(forKey: "spawning") == nil {
let spawnPoint = CGPoint(x: frame.midX, y: frame.size.height / 2.0 - hero.size.height)
let wait = SKAction.wait(forDuration: 8)
let spawn = SKAction.run({[unowned self] in
self.spawnEnemy(atPoint: spawnPoint)
})
let sequence = SKAction.sequence([spawn,wait])
run(SKAction.repeatForever(sequence), withKey: "spawning")
}
}
func didBegin(_ contact: SKPhysicsContact) {
let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
switch contactMask {
case ColliderType.Hero.rawValue | ColliderType.Enemy.rawValue :
if let projectile = contact.bodyA.categoryBitMask == ColliderType.Enemy.rawValue ? contact.bodyA.node : contact.bodyB.node{
projectile.removeAllActions()
projectile.removeFromParent()
addPoisionEffect(atPoint: hero.position)
}
// Handle more cases here
default : break
//Some other contact has occurred
}
}
func addPoisionEffect(atPoint point:CGPoint){
if let poisonEmitter = SKEmitterNode(fileNamed: "poison"){
let wait = SKAction.wait(forDuration: kPoisonDuration)
let remove = SKAction.removeFromParent()
let sequence = SKAction.sequence([wait, remove])
poisonEmitter.run(sequence, withKey: "emitAndRemove")
poisonEmitter.name = "emitter"
poisonEmitter.position = point
poisonEmitter.zPosition = hero.zPosition + 1
addChild(poisonEmitter)
}
}
func togglePaused(){
let newSpeed:CGFloat = isGamePaused ? 1.0 : 0.0
isGamePaused = !isGamePaused
//pause spawning action
if let spawningAction = action(forKey: "spawning"){
spawningAction.speed = newSpeed
}
//pause moving enemy action
enumerateChildNodes(withName: "enemy") {
node, stop in
if let movingAction = node.action(forKey: "moving"){
movingAction.speed = newSpeed
}
}
//pause emitters by pausing the emitter node itself
enumerateChildNodes(withName: "emitter") {
node, stop in
node.isPaused = newSpeed > 0.0 ? false : true
}
}