我目前正在Make School上iOS游戏开发课程。本课程的第一步是。制作一个类似于飘扬的小鸟的游戏,并具有一些基本知识,例如程序生成和无限滚动等等。我不熟悉Swift,因此我还无法真正解释游戏的机制,但是我将链接下面的课程页面:
Make School - iOS Game Development - Obstacles
在本节中,本课程着重于从源障碍物以程序方式产生障碍物的过程。这是代码:
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var hero: SKSpriteNode!
var scrollLayer: SKNode!
var sinceTouch : CFTimeInterval = 0
var spawnTimer: CFTimeInterval = 0
let fixedDelta: CFTimeInterval = 1.0 / 60.0 /* 60 FPS */
let scrollSpeed: CGFloat = 100
var obstacleSource: SKNode!
var obstacleLayer: SKNode!
override func didMove(to view: SKView) {
/* Setup your scene here */
/* Recursive node search for 'hero' (child of referenced node) */
hero = (self.childNode(withName: "//hero") as! SKSpriteNode)
/* Set reference to scroll layer node */
scrollLayer = self.childNode(withName: "scrollLayer")
/* Set reference to obstacle layer node */
obstacleLayer = self.childNode(withName: "obstacleLayer")
/* allows the hero to animate when it's in the GameScene */
hero.isPaused = false
/* Set reference to obstacle Source node */
obstacleSource = self.childNode(withName: "obstacle")
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
/* Called when a touch begins */
/* Apply vertical impulse */
hero.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 300))
/* Apply subtle rotation */
hero.physicsBody?.applyAngularImpulse(1)
/* Reset touch timer */
sinceTouch = 0
}
override func update(_ currentTime: TimeInterval) {
/* Called before each frame is rendered */
/* Grab current velocity */
let velocityY = hero.physicsBody?.velocity.dy ?? 0
/* Check and cap vertical velocity */
if velocityY > 400 {
hero.physicsBody?.velocity.dy = 400
}
/* Apply falling rotation */
if sinceTouch > 0.2 {
let impulse = -20000 * fixedDelta
hero.physicsBody?.applyAngularImpulse(CGFloat(impulse))
}
/* Clamp rotation */
hero.zRotation.clamp(v1: CGFloat(-90).degreesToRadians(), CGFloat(30).degreesToRadians())
hero.physicsBody?.angularVelocity.clamp(v1: -1, 3)
/* Update last touch timer */
sinceTouch += fixedDelta
/* Process world scrolling */
scrollWorld()
/* Process obstacle scrolling*/
updateObstacles()
spawnTimer+=fixedDelta
}
func scrollWorld() {
/* Scroll World */
scrollLayer.position.x -= scrollSpeed * CGFloat(fixedDelta)
/* Loop through scroll layer nodes */
for ground in scrollLayer.children as! [SKSpriteNode] {
/* Get ground node position, convert node position to scene space */
let groundPosition = scrollLayer.convert(ground.position, to: self)
/* Check if ground sprite has left the scene */
if groundPosition.x <= -ground.size.width / 2 {
/* Reposition ground sprite to the second starting position */
let newPosition = CGPoint(x: (self.size.width / 2) + ground.size.width, y: groundPosition.y)
/* Convert new node position back to scroll layer space */
ground.position = self.convert(newPosition, to: scrollLayer)
}
}
}
func updateObstacles() {
/* Update Obstacles */
obstacleLayer.position.x -= scrollSpeed * CGFloat(fixedDelta)
/* Loop through obstacle layer nodes */
for obstacle in obstacleLayer.children as! [SKReferenceNode] {
/* Get obstacle node position, convert node position to scene space */
let obstaclePosition = obstacleLayer.convert(obstacle.position, to: self)
/* Check if obstacle has left the scene */
if obstaclePosition.x <= -26 {
// 26 is one half the width of an obstacle
/* Remove obstacle node from obstacle layer */
obstacle.removeFromParent()
}
}
/* Time to add a new obstacle? */
if spawnTimer >= 1.5 {
/* Create a new obstacle by copying the source obstacle */
let newObstacle = obstacleSource.copy() as! SKNode
obstacleLayer.addChild(newObstacle)
/* Generate new obstacle position, start just outside screen and with a random y value */
let randomPosition = CGPoint(x: 347, y: CGFloat.random(in: 234...382))
/* Convert new node position back to obstacle layer space */
newObstacle.position = self.convert(randomPosition, to: obstacleLayer)
// Reset spawn timer
spawnTimer = 0
}
}
}
当我在Xcode中运行此代码时,该问题显示在该行中let newObstacle = obstacleSource.copy() as! SKNode
我检查了几次代码,甚至从课程页面复制粘贴了代码,但仍然无法解决问题
检查零头
让newObstacle = barrierSource.copy()为! SKNode
->
if let newObstacle = obstacleSource.copy() as? SKNode {
//newObstacle is SKNode
}
此错误((线程1:致命错误:意外发现nil,同时隐式展开一个可选值)出于多种原因,当您尝试访问/解开一个nil值时,可能会发生。 >
在您的情况下,这是因为obstacleSource
变量为nil。
当您尝试通过obstacleSource.copy() as? SKNode
访问它时,它会使您的应用程序崩溃。
因为您像这样初始化了obstacleSource
变量:
obstacleSource = self.childNode(withName: "obstacle")
这意味着在您的场景中找不到名称为“ obstacle”的子节点,因此您只需检查
GameScene.sks
文件并确保正确命名您的节点(“ obstacle”)。
它将按预期工作。
现在让我们说,由于某种原因,您不确定节点obstacle
是否确实存在,那么在这种情况下,不必将节点声明为implicitly unwrapped optional
:
var obstacleSource: SKNode!
您应将其初始化为可选内容,例如:
确保您的变量实际上持有一个值:var obstacleSource: SKNode?
在这种情况下,因为它被声明为可选,所以您的应用不会崩溃,并且您可以通过使用可选绑定
if let obstacleSource = self.obstacleSource {
// Access your node here
} else {
// The node 'obstacle' could not be found
}