在本节中,我们将了解生命系统。游戏中生命系统的实现为玩家提供了多次在死亡或重置游戏之前清除等级的机会。有很多方法可以代表这个系统。您可以申请生活酒吧,或者像塞尔达的游戏一样,拥有心形。
下载生命系统
要学习本教程,您将需要Xcode 9,您可以下载最终项目,以帮助您与自己的进度进行比较。
心形容器和心形
这个系统的布局基本上是你场景中一个不可见的矩形容器,我们将在其中插入心形。在Score分区下方,让我们声明心形容器和心形的变量。
// Hearts
var heartsArray = [SKSpriteNode]()
let heartContainer = SKSpriteNode()
heartsArray的括号表示我们正在创建一个空数组。
设置心形容器
在didMove方法中,创建一个新的部门并将其命名为:Hearts。设置位置,zPosition并将心形容器添加到cameraNode。
// Hearts
heartContainer.position = CGPoint(x: -300, y: 140)
heartContainer.zPosition = 5
cameraNode?.addChild(heartContainer)
设置心形
容器已设置好。我们需要一个将心形放在容器中的功能。在Action Mark中,添加一个新函数并将其命名为:fillHearts。为心形声明一个变量并设置其位置。然后,将心形添加到心形容器中。
func fillHearts(count: Int) {
for index in 1...count {
let heart = SKSpriteNode(imageNamed: "heart")
let xPosition = heart.size.width * CGFloat(index - 1)
heart.position = CGPoint(x: xPosition, y: 0)
heartsArray.append(heart)
heartContainer.addChild(heart)
}
}
在didMove方法中,将心形容器添加到相机后,调用fillHearts函数并将计数值设置为3。运行模拟器,您将在屏幕的左上角看到三个美丽的心。
心形约束
让失去三颗心的玩家死亡。首先,在布尔分区中声明一个新的布尔值,并将其命名为:isHit。将其值设置为false。与接触陷阱的玩家类似,玩家一次会失去一个以上的心形,我们需要将接触限制为一个。
var isHit = false
失去了一颗心
在Action Mark中,添加一个新函数并将其命名为:loseHeart。如果玩家被击中,我们将删除数组中的最后一个元素。两秒钟后,玩家不再被击中。
func loseHeart() {
if isHit == true {
let lastElementIndex = heartsArray.count - 1
if heartsArray.indices.contains(lastElementIndex - 1) {
let lastHeart = heartsArray[lastElementIndex]
lastHeart.removeFromParent()
heartsArray.remove(at: lastElementIndex)
Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { (timer) in
self.isHit = false
}
}
}
}
杀戮碰撞
我们需要更新玩家和杀戮对象之间的碰撞,因为我们实现了生命系统。在碰撞标记中,删除玩家与杀戮之间的碰撞内容,因为我们不希望玩家立即死亡。然后,插入loseHeart函数并将isHit设置为true。
if collision.matches(.player, .killing) {
loseHeart()
isHit = true
}
运行模拟器,将玩家移动到陷阱,您将看到玩家一次失去多个心形,最小上限为1。
无敌
在大多数游戏中,受伤后,玩家有两秒钟不能再被击中。我们称之为无敌状态。有很多方法可以实现无敌状态,但是到目前为止我发现的最简单的方法是改变玩家的类别掩码。在lostHeart函数之后的Action Mark中,添加一个新函数并命名为:invincible。将玩家的类别掩码设置为0.然后,将计时器设置为两秒的时间间隔,并将玩家的类别掩码设置为2。
func invincible() {
player?.physicsBody?.categoryBitMask = 0
Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { (timer) in
self.player?.physicsBody?.categoryBitMask = 2
}
}
在loseHeart函数内部,调用无敌函数。运行模拟器!当玩家触摸陷阱时,您将看到一次只有一颗心会消失。
垂死
在失去所有三颗心之后让我们让玩家死去。在无敌功能之后,添加一个新功能并命名为:dying。在其中,设置我们之前删除的死亡动作。然后,删除玩家上的所有操作并将fillHeart函数添加到3。
func dying() {
let dieAction = SKAction.move(to: CGPoint(x: -300, y: 0), duration: 0.1)
player?.run(dieAction)
self.removeAllActions()
fillHearts(count: 3)
}
让玩家死亡
在loseHeart功能中,如果我们不能再移除心形,玩家将会死亡。所以,在heartsArray的if语句之后,放一个else并调用垂死的函数。该loseHeart功能应该是这样的:
func loseHeart() {
if isHit == true {
let lastElementIndex = heartsArray.count - 1
if heartsArray.indices.contains(lastElementIndex - 1) {
let lastHeart = heartsArray[lastElementIndex]
lastHeart.removeFromParent()
heartsArray.remove(at: lastElementIndex)
Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { (timer) in
self.isHit = false
}
}
else {
dying()
}
invincible()
}
}
运行模拟器,所有功能都运行正常!
无敌状态
唯一的问题是我们需要一个信号来告诉我们玩家仍处于无敌状态。在玩游戏时很难计算两秒钟的无敌状态。许多游戏在玩家身上使用闪烁的视觉效果来告诉我们玩家是无敌的,就像马里奥一样。在playerStateMachine中,在Stunned State内,声明一个新变量,将其命名为isStunned并将值设置为false。声明isValidNextState方法。如果玩家已经无敌了,他就不能再无敌。然后,添加一个switch语句,如果玩家处于空闲状态,则将该值返回true。否则,返回false。
var isStunned : Bool = false
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
if isStunned { return false }
switch stateClass {
case is IdleState.Type: return true
default: return false
}
}
闪烁效果
有许多方法可以在游戏中应用闪烁效果,最常用的方法是更改相关对象的alpha。在isValidNextState方法之后,创建闪烁操作并重复操作5次。
let action = SKAction.repeat(.sequence([
.fadeAlpha(to: 0.5, duration: 0.01),
.wait(forDuration: 0.25),
.fadeAlpha(to: 1.0, duration: 0.01),
.wait(forDuration: 0.25),
]), count: 5)
didEnter方法
在Stunned ****State中,调用didEnter方法。将isStunned设置为true并在玩家上应用闪烁。放一个计时器并将isStunned设置为false。这样,玩家就不能连续多次被击晕。
override func didEnter(from previousState: GKState?) {
isStunned = true
playerNode.run(action)
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false) { (timer) in
self.isStunned = false
self.stateMachine?.enter(IdleState.self)
}
}
修复JumpingState
在JumpingState中,允许玩家在被击晕时跳跃。在isValidNextState内,将值返回true。
if stateClass is StunnedState.Type { return true }
让玩家闪烁
在玩家和碰撞之间的碰撞匹配中,添加StunnedState。碰撞匹配应如下所示。
if collision.matches(.player, .killing) {
loseHeart()
isHit = true
playerStateMachine.enter(StunnedState.self)
}
运行模拟器,整个生命系统现在应该正常工作!
结论
在本节中,我们学习了生命系统的工作原理。我们在游戏中实现了心形,以及如何让玩家立于不败之地。这是一个非常重要的部分,我希望你到目前为止真的很喜欢这个课程。
网友评论