我一直在用Swift开发一个简单的游戏,以增加对语言语法和概念的了解。我目前面临的问题是在游戏应用程序中未检测到触摸。该应用程序使用动作作为一种关键方法来启动游戏,但是不幸的是,当我点击屏幕时,SKSpriteNodes并没有从屏幕顶部生成(至少从视觉上看)。我进入了几种打印状态,以查看代码是否已达到某些方法,但看起来问题的原因在touch方法内,因为在touch方法上未执行打印行。有人可以帮助我确定我的错误以及如何防止此错误吗?
出于参考目的,我包括了该类:
import SpriteKit
import GameplayKit
class GameScene: SKScene {
private var counter: Int = 0
private var level: Int = 0
private var debug: SKLabelNode?
// Here we set initial values of counter and level. Debug label is created here as well.
override func didMove(to view: SKView) {
counter = 0
level = 1
backgroundColor = SKColor.gray
debug = SKLabelNode(fontNamed: "ArialMT")
debug?.fontColor = SKColor.purple
debug?.fontSize = 30.0
debug?.position = CGPoint(x: frame.midX, y: frame.midY)
debug?.text = "Counter : [ \(counter) ], Level [ \(level) ]"
if let aDebug = debug {
addChild(aDebug)
}
print(action(forKey: "counting") == nil)
}
//Method to start a timer. SKAction is used here to track a time passed and to maintain the current level
func startTimer() {
print("TIMER STARTED...")
weak var weakSelf: GameScene? = self
//make a weak reference to scene to avoid retain cycle
let block = SKAction.run({
weakSelf?.counter = (weakSelf?.counter ?? 0) + 1
//Maintaining level
if (weakSelf?.counter ?? 0) < 5 {
//level 1
weakSelf?.level = 1
} else if (weakSelf?.counter ?? 0) >= 5 && (weakSelf?.counter ?? 0) < 10 {
//level 2
weakSelf?.level = 2
} else {
//level 3
weakSelf?.level = 3
}
weakSelf?.debug?.text = "Counter : [ \(Int(weakSelf?.counter ?? 0)) ], Level [ \(Int(weakSelf?.level ?? 0)) ]"
})
run(SKAction.repeatForever(SKAction.sequence([SKAction.wait(forDuration: 1), block])), withKey: "counting")
}
//Method for stopping the timer and reset everything to the default state.
func stopTimer() {
print("TIMER STOPPED.")
if action(forKey: "counting") != nil {
removeAction(forKey: "counting")
}
counter = Int(0.0)
level = 1
debug?.text = "Counter : [ \(counter) ], Level [ \(level) ]"
}
//Get current speed based on time passed (based on counter variable)
func getCurrentSpeed() -> CGFloat {
if counter < 5 {
//level 1
return 1.0
} else if counter >= 5 && counter < 10 {
//level 2
return 2.0
} else {
//level 3
return 3.0
}
}
//Method which stops generating stones, called in touchesBegan
func stopGeneratingStones() {
print("STOPPED GENERATING STONES...")
if action(forKey: "spawning") != nil {
removeAction(forKey: "spawning")
}
}
func randomFloatBetween(_ smallNumber: CGFloat, and bigNumber: CGFloat) -> CGFloat {
let diff: CGFloat = bigNumber - smallNumber
//return (CGFloat(arc4random_uniform(UInt32(CGFloat(RAND_MAX) + 1 / CGFloat(RAND_MAX) * diff )))) + smallNumber
return CGFloat(arc4random() % (UInt32(RAND_MAX) + 1)) / CGFloat(RAND_MAX) * diff + smallNumber
}
//Method for generating stones, you run this method when you want to start spawning nodes (eg. didMoveToView or when some button is clicked)
func generateStones() {
print("GENERATING STONES...")
let delay = SKAction.wait(forDuration: 2, withRange: 0.5)
//randomizing delay time
weak var weakSelf: GameScene? = self
//make a weak reference to scene to avoid retain cycle
let block = SKAction.run({
let stone: SKSpriteNode? = weakSelf?.spawnStone(withSpeed: weakSelf?.getCurrentSpeed() ?? 0.0)
stone?.zPosition = 20
if let aStone = stone {
weakSelf?.addChild(aStone)
}
})
run(SKAction.repeatForever(SKAction.sequence([delay, block])), withKey: "spawning")
}
//Returns stone with moving action added. Inside, you set standard things, like size, texture, physics body, name and position of a stone
func spawnStone(withSpeed stoneSpeed: CGFloat) -> SKSpriteNode? {
print("SPAWNNING STONES...")
let stoneSize = CGSize(width: 30, height: 30) //size of shape.
//you can randomize size here
let stonePosition = CGPoint(x: randomFloatBetween(0.0, and: frame.size.width), y: frame.maxY) //initial position
//you can randomize position here
let stone = SKSpriteNode(color: SKColor.green, size: stoneSize) //setting size and color.
stone.name = "stone" //named shape so we can check collision.
//this helps if you want to enumerate all stones by name later on in your game
stone.position = stonePosition //set position.
let move = SKAction.moveBy(x: 0, y: -200, duration: 3.25)
//one way to change speed
move.speed = stoneSpeed
let moveAndRemove = SKAction.sequence([move, SKAction.removeFromParent()])
stone.run(moveAndRemove, withKey: "moving")
//access this key if you want to stop movement
return stone
}
func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
/* Called when a touch begins */
//just a simple way to start and stop a game
/**
TOUCH METHOD NOT WORKING.
*/
if action(forKey: "counting") == nil {
print("HERE")
startTimer()
generateStones()
} else {
print("OR HERE")
stopTimer()
stopGeneratingStones()
}
}
}
答案 0 :(得分:0)
经过一些调试,我已将问题解决为我自己的问题。我已经意识到touchesBegan方法不会使用覆盖超级方法,因此应用程序将其误认为是本地方法。要解决此问题,只需添加覆盖将解决问题。
更改此内容:
func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
/* Called when a touch begins */
//just a simple way to start and stop a game
/**
TOUCH METHOD NOT WORKING.
*/
if action(forKey: "counting") == nil {
print("HERE")
startTimer()
generateStones()
} else {
print("OR HERE")
stopTimer()
stopGeneratingStones()
}
}
对此:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
/* Called when a touch begins */
//just a simple way to start and stop a game
/**
TOUCH METHOD NOT WORKING.
*/
if action(forKey: "counting") == nil {
print("HERE")
startTimer()
generateStones()
} else {
print("OR HERE")
stopTimer()
stopGeneratingStones()
}
}