連載
» 2016年05月17日 05時00分 UPDATE

iOS SDKとSwiftで始めるゲーム作成入門(6):FactoryMethodパターンでリファクタリングすると、ゲーム開発がどう便利になるのかをSwiftコードで学ぶ (1/4)

iPhoneゲームをSwift言語で作成してみたいという初心者向けにiOSのゲームフレームワークを使った作り方を一から解説する入門連載。今回は、GoFデザインパターンの1つであるFactoryMethodパターンを使って、Swiftのコードをリファクタリングする方法について。

[杉本裕樹,マネーフォワード]

 本連載「iOS SDKとSwiftで始めるゲーム作成入門」は、iPhone向けのゲーム開発の入門連載です。タワーディフェンスを題材に、「SpriteKit」というゲーム開発フレームワークの解説やゲームの開発手法について書いています。

 実装に入る前に本連載で作るアプリの完成形を確認しておきます。本連載では、下記6つのルールを満たすタワーディフェンスを作っていきます。

  1. プレーヤーは開始前に与えられた所持金を元に、敵を攻撃するユニットを設置する
  2. ゲームは「Wave(ウエーブ)」という単位で行われる。基本的には1つのWaveで登場する敵の種類は1種類のみとなっている。Waveが始まると敵は入口から登場し、目的地に向かって行進する。プレーヤーが設置したユニットは攻撃可能範囲に入ると自動的に攻撃を行う
  3. 1Waveの敵を全て全滅させるとWaveクリアとなる。プレーヤーは次のWaveが始まるまでにユニットの増強(新設・アップグレード・売却など)を行う
  4. 以上の2と3を繰り返して行う
  5. 敵が目的地に到達すると、自分が所持しているライフが減少する。全て失うとゲームオーバーとなる
  6. ライフを全て失う前に、最終Waveの敵を全て全滅させることができればクリアとなる

 前回の「ゲームのState管理を簡単にするiOS 9 GameplayKitのクラスとは」では自機が範囲内にいる敵に一定間隔おきに自動攻撃する処理を実装しました。それと同時にGoFデザインパターンの1つであるStateパターンを使って今後の仕様変更に強いアプリ制作の方法を学んできました。

 今回は、自機を3種類にして、さらにそれらを好きな位置におけるようにしていきます。そして前回に続いてGoFデザインパターンの1つであるFactoryMethodパターンについての知見を共有していければと思います。

 今回は、こちらの「zenkai.zip」のコードを基に実装を進めていきます。

自機をセットするSceneを作る

 まずは、自機を好きな位置に配置できる処理を実装します。

 それに先立って、「Scene」を、ゲームをメイン部分である「GameScene」と、自機をセットする「SetCharScene」に分割します。新しく「Button.swift」「SetCharScene.swift」ファイルを作成して以下のように記述してください。Buttonクラスはゲーム開始ボタンに使うクラスです。

import UIKit
import SpriteKit
 
class Button: SKSpriteNode {
    let afterTap: () -> ()
 
    init(text: String, rect: CGRect, afterTap: () -> ()) {
        self.afterTap = afterTap
        super.init(texture: nil, color: UIColor.clearColor(), size: rect.size)
        position = rect.origin
 
        let button = SKShapeNode(rect: CGRect(origin: CGPoint(), size: rect.size),
                                 cornerRadius: 4.0)
        button.fillColor = UIColor.darkGrayColor()
        button.strokeColor = UIColor.clearColor()
        addChild(button)
        let myLabel = SKLabelNode(fontNamed: "HiraginoSans-W6")
        myLabel.text = text
        myLabel.fontSize = 18
        myLabel.position = CGPoint(
            x:rect.width/2,
            y:rect.height/2-myLabel.frame.height/2+1)
        addChild(myLabel)
    }
 
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
import UIKit
import SpriteKit
 
class SetCharScene: SKScene {
    override func didMoveToView(view: SKView) {
        physicsWorld.gravity = CGVectorMake(0, 0)
        let fieldImageLength = view.frame.width / 10
        let field = FieldFactory().createField(view.frame.size, fieldImageLength: fieldImageLength)
        field.nodes.forEach {
            addChild($0)
        }
 
        let buttonRect = CGRect(x: CGRectGetMaxX(self.frame) - 115,
                                y: CGRectGetMaxY(self.frame) - 49,
                                width: 110, height: 34)
        let button = Button(text: "ゲーム開始", rect: buttonRect, afterTap: {
            let scene = GameScene(fileNamed: "GameScene")
            scene?.scaleMode = .ResizeFill
            view.presentScene(scene)
        })
        addChild(button)
    }
}

 次に、初期表示画面をGameSceneからSetCharSceneに変更します。GameViewControllerのviewDidLoadを下のように修正してください。今までGameSceneを呼び出していた箇所をSetCharSceneを呼ぶように変更しています。

class GameViewController: UIViewController {
 
    override func viewDidLoad() {
        super.viewDidLoad()
 
        let scene = SetCharScene()
        // Configure the view.
        let skView = self.view as! SKView
        skView.showsFPS = true
        skView.showsNodeCount = true
 
        /* Sprite Kit applies additional optimizations to improve rendering performance */
        skView.ignoresSiblingOrder = true
        /* Set the scale mode to scale to fit the window */
        scene.scaleMode = .ResizeFill
 
        skView.presentScene(scene)
    }
 
    // 省略
}

 これで実行すると、キャラクター選択画面が表示できているかと思います。

コラム「アニメーション付きのScene移動を行う」

 今回の画面遷移では「view.presentScene(scene)」を使いました。このメソッドは第2引数にアニメーションを設定できます。アニメーションはフェードイン/フェードアウトのような簡単なものから、ドアが閉まるようなアニメーションなど面白いものも多々あります。うまく使うと、より楽しいユーザー体験を提供できるのでぜひ試してください。

view.presentScene(scene, transition: SKTransition.doorsCloseHorizontalWithDuration(1.0))

       1|2|3|4 次のページへ

Copyright© 2017 ITmedia, Inc. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

RSSについて

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

メールマガジン登録

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