ゲームのState管理を簡単にするiOS 9 GameplayKitのクラスとはiOS SDKとSwiftで始めるゲーム作成入門(5)(2/4 ページ)

» 2016年03月24日 05時00分 公開
[杉本裕樹マネーフォワード]

敵は1回の攻撃で倒せないようにする

 前項でキャラクターの動きがタワーディフェンスに近づいてきました。次は敵が何回も攻撃しないと倒せないようにします。

 敵にlifeプロパティーを持たせるためにEnemyクラスを作成します。「File」→「New」→「File」からEnemyクラスを作成してください。親クラスにはSKSpriteNodeを指定します。

 Enemyクラスを作成したら下のようにlifeプロパティーを付けてください。lifeはひとまず3に設定します。

  1. import UIKit
  2. import SpriteKit
  3. class Enemy: SKSpriteNode {
  4. var life = 3
  5. }

 次にEnemyList.swiftでSKSpriteNodeを指定している部分をEnemyに置き換えます。

  1. class EnemyList {
  2. private var enemies = [Enemy]()
  3. func enemiesCloseToPoint(point: CGPoint, distance: Double) -> [Enemy] {
  4. // 略...
  5. }
  6. func appendEnemy(enemy: Enemy) {
  7. enemies.append(enemy)
  8. }
  9. // 略...
  10. }

 同時にGameScene.swiftの敵の初期化処理も書き換えます。今まで「SKSpriteNode(imageNamed: "Enemy")」としていたところを「Enemy(imageNamed: "Enemy")」に置き換えます。

  1. class GameScene: SKScene, SKPhysicsContactDelegate {
  2. // 略...
  3. func createEnemy() {
  4. // 略...
  5. let enemy = Enemy(imageNamed: "Enemy")
  6. // 略...
  7. }
  8. // 略...
  9. }

 最後にGameScene.swiftのupdateメソッドも修正します。今は自機が敵を攻撃した瞬間に敵が消滅しているので、それを敵ライフが0になったら敵が消えるように変えます。

  1. class GameScene: SKScene, SKPhysicsContactDelegate {
  2. // 略...
  3. override func update(currentTime: NSTimeInterval) {
  4. enemyList.enemiesCloseToPoint(char.frame.origin, distance: 50).forEach {
  5. $0.life -= 1
  6. if $0.life <= 0 {
  7. $0.physicsBody?.node?.removeFromParent()
  8. $0.physicsBody?.node?.removeAllActions()
  9. if enemyList.isAllEnemyRemoved() {
  10. state = .GameClear
  11. let myLabel = SKLabelNode(fontNamed: "HiraginoSans-W6")
  12. myLabel.text = "ゲームクリア"
  13. myLabel.fontSize = 45
  14. myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame) - 20)
  15. addChild(myLabel)
  16. }
  17. }
  18. }
  19. }
  20. // 略...
  21. }

自機は一定の間隔を空けて攻撃させる

 前項の修正で敵のlifeを設定してきました。敵は3回まで攻撃に耐えれるようになったのですが、今は自機がupdateメソッドが呼ばれるたびに攻撃するので、一瞬で敵が倒されてしまいます。そこで自機が一定の間隔を空けて攻撃するよう修正してゲーム性を高めようと思います。

 具体的な方法として、自機に攻撃可能状態・待機状態の2種類の状態を作ります。そして1度攻撃したら待機状態になり、一定期間が過ぎたら攻撃可能状態に戻るようにします。

 自機に現在の状態を持たせるために、自機を表すCharクラスを作成します。Enemyを作ったときと同様にChar.swiftを作成して下のように置き換えます。

  1. import UIKit
  2. import SpriteKit
  3. class Char: SKSpriteNode {
  4. enum State {
  5. case Attack
  6. case Wait
  7. }
  8. var state: State = .Attack
  9. }

 GameScene.swiftの中のcharの初期化処理も少し修正します。

  1. class GameScene: SKScene, SKPhysicsContactDelegate {
  2. // 略...
  3. // let char = SKSpriteNode(imageNamed: "Char")
  4. let char = Char(imageNamed: "Char")
  5. // 略...
  6. }

 次に攻撃可能状態と待機状態を切り替える処理を実装します。GameScene.swiftのupdateを以下のように書き換えてください。

  1. class GameScene: SKScene, SKPhysicsContactDelegate {
  2. // 略...
  3. override func update(currentTime: NSTimeInterval) {
  4. // stateが.Attackのときだけ攻撃する
  5. if char.state == .Attack {
  6. enemyList.enemiesCloseToPoint(char.frame.origin, distance: 50).forEach {
  7. $0.life -= 1
  8. if $0.life <= 0 {
  9. $0.physicsBody?.node?.removeFromParent()
  10. $0.physicsBody?.node?.removeAllActions()
  11. if enemyList.isAllEnemyRemoved() {
  12. state = .GameClear
  13. let myLabel = SKLabelNode(fontNamed: "HiraginoSans-W6")
  14. myLabel.text = "ゲームクリア"
  15. myLabel.fontSize = 45
  16. myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame) - 20)
  17. addChild(myLabel)
  18. }
  19. }
  20. // 敵に攻撃したらstateを.Waitにする
  21. char.state = .Wait
  22. // 0.2秒経過したらstateを.Attackに戻す
  23. performSelector("changeCharStateToAttack", withObject: nil, afterDelay: 0.2)
  24. }
  25. }
  26. }
  27. func changeCharStateToAttack() {
  28. char.state = .Attack
  29. }
  30. // 略...
  31. }

 以上で一定間隔ごとに攻撃する処理の実装が終わりました。次ページではStateパターンを使って今実装したコードに拡張性を持たせていきます。

Copyright © ITmedia, Inc. All Rights Reserved.

スポンサーからのお知らせPR

Smart & Social 記事ランキング

本日月間

注目のテーマ

4AI by @IT - AIを作り、動かし、守り、生かす
Microsoft & Windows最前線2025
AI for エンジニアリング
ローコード/ノーコード セントラル by @IT - ITエンジニアがビジネスの中心で活躍する組織へ
Cloud Native Central by @IT - スケーラブルな能力を組織に
システム開発ノウハウ 【発注ナビ】PR
あなたにおすすめの記事PR

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。