我正在尝试制作一个Wack-a-Mole游戏。我这样做的方法是让一个按钮随机出现,并在有人点击它后在屏幕周围消失。如果他们在重新出现后一秒钟内没有点击按钮,那么它将消失并找到一个新位置,然后重新出现并等待一秒钟并重复上述步骤。但是,每当我运行此代码时,它都不会这样做。只有当我摆脱'while'语句和'if else'语句时,它才会移动位置。为什么它不会循环,消失,重新出现等?
延迟是这样的:https://stackoverflow.com/a/24318861/5799228
@IBAction func moveButton(button: UIButton) {
while self.WaffleButton.hidden == true || false {
if self.WaffleButton.hidden == false {
self.WaffleButton.hidden = true
delay(3) {
// Find the button's width and height
let buttonWidth = button.frame.width
let buttonHeight = button.frame.height
// Find the width and height of the enclosing view
let viewWidth = button.superview!.bounds.width
let viewHeight = button.superview!.bounds.height
// Compute width and height of the area to contain the button's center
let xwidth = viewWidth - buttonWidth
let yheight = viewHeight - buttonHeight
// Generate a random x and y offset
let xoffset = CGFloat(arc4random_uniform(UInt32(xwidth)))
let yoffset = CGFloat(arc4random_uniform(UInt32(yheight)))
// Offset the button's center by the random offsets.
button.center.x = xoffset + buttonWidth / 2
button.center.y = yoffset + buttonHeight / 2
self.WaffleButton.hidden = false
self.delay(1) {
self.WaffleButton.hidden = true
}
}
} else { delay(3) {
// Find the button's width and height
let buttonWidth = button.frame.width
let buttonHeight = button.frame.height
// Find the width and height of the enclosing view
let viewWidth = button.superview!.bounds.width
let viewHeight = button.superview!.bounds.height
// Compute width and height of the area to contain the button's center
let xwidth = viewWidth - buttonWidth
let yheight = viewHeight - buttonHeight
// Generate a random x and y offset
let xoffset = CGFloat(arc4random_uniform(UInt32(xwidth)))
let yoffset = CGFloat(arc4random_uniform(UInt32(yheight)))
// Offset the button's center by the random offsets.
button.center.x = xoffset + buttonWidth / 2
button.center.y = yoffset + buttonHeight / 2
self.WaffleButton.hidden = false
self.delay(1) {
self.WaffleButton.hidden = true
}
}
}
}
}
答案 0 :(得分:1)
您正在以不应使用的方式使用while
。
这是您应该使用while
:
var someCondition = true
while someCondition {
// this will loop as fast as possible untill someConditionIsTrue is no longer true
// inside the while statement you will do stuff x number of times
// then when ready you set someCondition to false
someCondition = false // stop
}
这是您使用while
的方式:
let someConditionThatIsAlwaysTrue = true
while someConditionThatIsAlwaysTrue {
// condition is always true, so inifinite loop...
// this creates a function that is executed 3 seconds after the current looping pass of the while loop.
// while does not wait for it to be finished.
// while just keeps going.
// a fraction of a second later it will create another function that will execute 3 seconds later.
// so after 3 seconds an infite amount of functions will execute with a fraction of a second between them.
// except they won't, since the main thread is still busy with your infinite while loop.
delay(3) {
// stuff
}
}
如何正确地做到这一点:
请勿使用while
或repeat
来计划""延迟代码执行。
在较小的问题中解决问题:
问题1:创建循环
通过具有两个相互触发的函数来创建循环。
我会称他们为execute
和executeAgain
。
因此execute
触发executeAgain
和executeAgain
触发器execute
,然后重新开始 - >循环!
您还可以创建execute
函数,而不是直接调用executeAgain
和start
。这不是必需的,但它是为循环功能设置条件的好地方。 start
将调用execute
并开始循环。
要停止循环,您需要创建一个更改某些条件的stop
函数。
execute
和executeAgain
将检查此情况,并且只有在检查成功时才会继续循环。 stop
使此检查失败。
var mustLoop : Bool = false
func startLoop() {
mustLoop = true
execute()
}
func execute() {
if mustLoop {
executeAgain()
}
}
func executeAgain() {
if mustLoop {
execute()
}
}
func stop() {
mustLoop = false
}
问题2:延迟执行
如果在NSObject
的子类中需要延迟,最明显的选择是NSTimer
。大多数UI类(如UIButton
和UIViewController
)都是NSObject
的子类。
NSTimer
也可以设置为重复。这也会创建一个每x秒执行一次的循环。但是,由于你实际上有两个交替的动作,因此采用更详细的循环模式更有意义。
NSTimer
在x个时间后执行一个函数(作为Selector("nameOfFunction")
传递)。
var timer : NSTimer?
func planSomething() {
timer = NSTimer.scheduledTimerWithTimeInterval(3, target: self, selector: Selector("doSomething"), userInfo: nil, repeats: false)
}
func doSomething() {
// stuff
}
如果您需要延迟其他课程/结构(或者您不喜欢NSTimer
),您可以使用 matt {{3}的delay
功能}}
它将在x个时间后执行您在closure
中输入的任何内容。
func planSomething() {
delay(3) {
doSomething()
}
}
func doSomething() {
// stuff
}
结合两种解决方案:
通过使用上面的循环模式,您现在拥有不同的功能。而不是直接调用它们来保持循环。您插入所选的延迟方法并将下一个函数传递给它。
因此,NSTimer
会Selector
指向execute
或executeAgain
,delay
会将其置于closure
如何优雅地实施它:
我会继承UIButton
来实现所有这些。然后你可以保持你的UIViewController
更清洁。只需选择IB中的子类并照常连接IBOutlet。
此子类具有timer
属性,可替代您的延迟。
按钮操作wacked()
也在init
方法中设置。
从UIViewController
拨打按钮的start()
功能。这将启动timer
。
timer
会触发appear()
或disappear
。
wacked()
将停止计时器并隐藏按钮。
class WackingButton : UIButton {
var timer : NSTimer?
var hiddenTime : NSTimeInterval = 3
var popUpTime : NSTimeInterval = 1
override init(frame: CGRect) {
super.init(frame: frame)
self.addTarget(self, action: "wacked", forControlEvents: UIControlEvents.TouchUpInside)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.addTarget(self, action: "wacked", forControlEvents: UIControlEvents.TouchUpInside)
}
func start() {
timer = NSTimer.scheduledTimerWithTimeInterval(hiddenTime, target: self, selector: Selector("appear"), userInfo: nil, repeats: false)
}
func appear() {
self.center = randomPosition()
self.hidden = false
timer?.invalidate()
timer = NSTimer.scheduledTimerWithTimeInterval(popUpTime, target: self, selector: Selector("dissappear"), userInfo: nil, repeats: false)
}
func dissappear() {
self.hidden = true
timer?.invalidate()
timer = NSTimer.scheduledTimerWithTimeInterval(hiddenTime, target: self, selector: Selector("appear"), userInfo: nil, repeats: false)
}
func wacked() {
self.hidden = true
timer?.invalidate()
}
func randomPosition() -> CGPoint {
// Find the width and height of the enclosing view
let viewWidth = self.superview?.bounds.width ?? 0 // not really correct, but only fails when there is no superview and then it doesn't matter anyway. Won't crash...
let viewHeight = self.superview?.bounds.height ?? 0
// Compute width and height of the area to contain the button's center
let xwidth = viewWidth - frame.width
let yheight = viewHeight - frame.height
// Generate a random x and y offset
let xoffset = CGFloat(arc4random_uniform(UInt32(xwidth)))
let yoffset = CGFloat(arc4random_uniform(UInt32(yheight)))
// Offset the button's center by the random offsets.
let x = xoffset + frame.width / 2
let y = yoffset + frame.height / 2
return CGPoint(x: x, y: y)
}
}
您的UIViewController
:
class ViewController: UIViewController {
@IBOutlet weak var button1: WackingButton!
override func viewDidAppear(animated: Bool) {
button1.start()
}
}