Swiftで初めてiPhoneゲーム開発する人向チュートリアル(マルバツゲームを例にStep by Step解説)



マルバツゲームとは

二人でマルとバツを交互に書いて行って、先に三つ並べた方が勝ちっていう例のやつです。
f:id:knj4484:20140907132951p:plain

これの作り方を通して、「Swift分かんない」「iPhoneアプリ作ったことない」という人がiPhoneゲーム開発の第一歩を踏み出すことを目的としたチュートリアルです。

他のプログラミング言語の経験も全くない方でも一応出来ると思いますが、専門用語がちょっと難しいかもしれません ^^;
その辺は、まずは目をつぶって頂いて、とりあえず書いてある通りにやってみて下さい。



iPhoneアプリ開発環境であるXcodeの準備とSwiftのとっかかりとしては、こちらのチュートリアルをご覧下さい。

続編も公開中

新しいゲームプロジェクトの開始

プロジェクトの開始方法は2通りあるので、どちらかで

  • Welcome to Xcode画面でCreate a new Xcode projectを選択する

f:id:knj4484:20140907133023p:plain

  • もしくは、既に起動している場合は、メニューからFile > New > Project

f:id:knj4484:20140907133045p:plain

プロジェクトの作成

新しいプロジェクトの画面で

f:id:knj4484:20140907133208p:plain

  1. 左側のiOSの下のApplicationをクリック
  2. Gameをクリック
  3. Nextをクリック

Choose options for your project画面で

f:id:knj4484:20140907133343p:plain

  1. 以下の通り入力
    • Product Name: OXGame
    • Organization Name: x
      • 本来はちゃんと考えるべきだが、練習なので適当な文字列にしておく
    • Organization Identifier: x
      • 本来はちゃんと考えるべきだが、練習なので適当な文字列にしておく
    • Language: Swift
    • Game Technology: SpriteKit
    • Device: iPhone
  2. Nextをクリック

SpriteKitは、2Dゲームを作るためのフレームワーク(Apple純正)です。

Save画面

f:id:knj4484:20140907133517p:plain

  1. 好きなディレクトリを選択
  2. create Git repositoryにチェックを入れておきましょう
  3. Createをクリック

新しいプロジェクトの画面

f:id:knj4484:20140907133600p:plain

まっさらな状態ですが、アプリを動かしてみましょう

  • 左上の再生ボタンを押す
  • あるいは、⌘ + R (コマンドキーを押しながらRキーを押す)

シミューレーターが起動して、何らかのアプリが動きましたね

Xcodeに戻って、アプリを停止しましょう

  • 左上の停止ボタンを押す
  • あるいは、⌘+.(コマンドキーを押しながらピリオドキーを押す)

よけいなファイルを消す

  1. Project Navigatorを表示します
    • 再生ボタン下のフォルダアイコンをクリック
    • もしくは、⌘ + 1 (コマンドキーを押しながら1キー)を押す
  2. GameScene.sksを右クリック > delete
  3. 確認ダイアログ > Move to Trash

よけいなコードを消す

左側のProject NagivatorでGameScene.swiftをクリックして開く

  • didMoveToViewメソッドを削除
  • touchesBeganメソッドを削除

GameScene.swiftのコードはこうなるはずです

import SpriteKit

class GameScene: SKScene {
    override func update(currentTime: CFTimeInterval) {
        /* Called before each frame is rendered */
    }
}


GameViewController.swiftを開きます

  • class GameViewControllerの中の
    • viewDidLoadのsuper.viewDidLoad()以外を全部消す
    • shouldAutorotateを消す
    • supportedInterfaceOrientationsを消す
    • didReceiveMemoryWarningを消す

GameViewController.swiftのコードはこうなるはずです

import UIKit
import SpriteKit

class GameViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func prefersStatusBarHidden() -> Bool {
        return true
    }
}

背景画像をプロジェクトに追加する

  1. この画像を保存して下さいf:id:knj4484:20140907134616p:plain
    • 名前はbg.pngにすること
  2. 保存した場所をFinderで開いてProject NavigatorのSupporting Filesにドラッグ&ドロップする
  3. Choose options for adding these filesダイアログf:id:knj4484:20140907134006p:plain
  4. Copy items if necessaryにチェック
  5. finishをクリック

背景画像を表示するコードを書く

まずは、GameScene.swiftからです。

GameSceneクラスの中に以下の2つのinitを追加します。
(Swiftではinitがクラスのコンストラクタです)

 required init(coder aDecoder: NSCoder) {
     fatalError("NSCoder not supported")
 }
 override init(size: CGSize) {
     super.init(size: size)

     anchorPoint = CGPoint(x: 0, y: 0)

     let background = SKSpriteNode(imageNamed: "bg")
     background.position = CGPoint(x: 0, y: 0)
     background.anchorPoint = CGPoint(x: 0, y: 0)
     addChild(background)
 }


SpriteKitの座標はCGPointで表すことになっていて、原点(0, 0)は画面の左下隅です。
単純に静止画像を表示するために、SKSpriteNodeを使います。
画像の位置を設定して
シーンに(自分自身に)画像のオブジェクトをaddChildして表示されます。

続いて、GameViewController.swiftです。

GameViewControllerクラスに、scene変数を追加します。

 var scene: GameScene!

viewDidLoadの中身を追加して次のコードのようにします。

override func viewDidLoad() {
    super.viewDidLoad()

     let skView = view as SKView
     skView.multipleTouchEnabled = false

     scene = GameScene(size: skView.bounds.size)
     scene.scaleMode = .AspectFill
     skView.presentScene(scene)
}

上で記述したGameSceneクラスのinitを使って、GameSceneを生成します。
SpriteKitビューのpresentSceneにGameSceneを渡せば、シーンが表示されます。


⌘+Rで背景画像が表示されることを確認しましょう

タップに反応させる

f:id:knj4484:20140907135024p:plain

  1. Project NavigatorでMain.storyboardをクリックして開く
  2. 右下の検索ボックスにtapと入力
  3. Tap Gesture Recognizerが表示されるので、ドラッグ&ドロップする

f:id:knj4484:20140907141229p:plain

  1. タキシードに蝶ネクタイっぽいアイコンをクリックしてAssistan Editorを開く
  2. controlを押しながらTap Gesture Recognizerをドラッグして、コード中のGameViewControllerの中にドロップする
  3. 出てきたダイアログで下記の通り入力して、connectボタンを押す
    • Connection: Action
    • Name: didTap
    • UITapGestureRecognizer
  4. Assistant Editorを使い終わったら閉じておきます

うまく行くとdidTapのコードが生成されます

    @IBAction func didTap(sender: UITapGestureRecognizer) {
    }


f:id:knj4484:20140907135126p:plain

  1. Tap Gesture Recognizerを右クリックする
    • 出てきたダイアログで、
      • Outletsの下にあるdelegateの右の○をドラッグして、Game View Controllerにドロップ


今の操作でUITapGestureRecognizerとGameViewControllerにdelegateの関係を追加したので、
コードにもこれを反映します。

GameViewController.swiftを開きます。
GameViewControllerクラスにUIGestureRecognizerDelegateプロトコルを追加して次のようにします。

 class GameViewController: UIViewController, UIGestureRecognizerDelegate {

画面をタップするとdidTapの中身が実行されることになるので、ひとまずタップ位置の座標を出力することにしておきます。

 @IBAction func didTap(sender: UITapGestureRecognizer) {
        let location = sender.locationInView(view)
        println("tapped at \(location.x), \(location.y)")
 }


⌘+Rでアプリを起動してみましょう。

シミュレーターのどこかをタップしてみると、
コンソールにタップ位置が出力されます。

コンソールが表示されていない場合は、メニューのView > Debug Area > Activate Consoleで表示してから、タップしてみて下さい

タップされた升目に○×を画像を配置する

まずは、背景画像をプロジェクトに取り込んだのと同じ要領で、次の2つのマルとバツの画像をSupporting Filesフォルダに取り込みます。
f:id:knj4484:20140907141620p:plainf:id:knj4484:20140907141640p:plain
ファイル名として、
○画像は、o.png
×画像は、x.png
にします
GameScene.swiftを開きます。

下の説明の通り、最終的にGameScene.swiftのコードがこうなるようにしましょう。

import SpriteKit

class GameScene: SKScene {
    var turn_o = true

    required init(coder aDecoder: NSCoder!) {
        fatalError("NSCoder not supported")
    }

    override init(size: CGSize) {
        super.init(size: size)
        
        anchorPoint = CGPoint(x: 0, y: 0)
        
        let background = SKSpriteNode(imageNamed: "bg")
        background.position = CGPoint(x: 0, y: 0)
        background.anchorPoint = CGPoint(x: 0, y: 0)
        addChild(background)
    }
    
    override func update(currentTime: CFTimeInterval) {
        /* Called before each frame is rendered */
    }
    
    func transform(w: CGFloat) -> CGFloat {
        switch w {
        case let w where 0 < w && w < 80:
            return 0
        case let w where 80 < w && w < 160:
            return 80
        case let w where 160 < w && w < 240:
            return 160
        default:
            return -80
        }
    }

    func mark(location: CGPoint) {
        let imageName = turn_o ? "o" : "x"
        let sign = SKSpriteNode(imageNamed: imageName)
        sign.position = CGPoint(x: transform(location.x), y: 160 - transform(location.y - 320))
        sign.anchorPoint = CGPoint(x: 0, y: 0)
        addChild(sign)
        
        turn_o = !turn_o
    }
}
  • 「マルの番かバツの番か」を管理する変数turn_oをGemeSceneクラスに追加します。
    • turn_oがtrueなら○の番、falseなら×の番を表していることにします
  • タップされた場所から、画像を配置する正確な位置を計算する補助のtransformメソッドを、GameSceneクラスに追加します
  • ○×記号の画像を升目に配置して表示するmarkメソッドをGameSceneクラスに追加します


GameViewController.swiftを開きます。

import UIKit
import SpriteKit

class GameViewController: UIViewController {
    var scene: GameScene!

    override func viewDidLoad() {
        super.viewDidLoad()
        let skView = view as SKView
        skView.multipleTouchEnabled = false
        
        scene = GameScene(size: skView.bounds.size)
        scene.scaleMode = .AspectFill
        skView.presentScene(scene)
    }

    override func prefersStatusBarHidden() -> Bool {
        return true
    }
    
    @IBAction func didTap(sender: UITapGestureRecognizer) {
        let location = sender.locationInView(view)
        println("tapped at \(location.x), \(location.y)")
        scene.mark(location)
    }
    
}
  • 上で定義したmarkメソッドを呼び出すように、didTapメソッドの最後の一行を追加しましょう

完成です

おめでとうございます!

では、⌘+Rでゲームを起動して遊んでみましょう!

プログラムの構成に関する注意点

このプログラムでは、説明を簡単にするために、
ゲームの進行とルールに関わること(turn_oによるどちらの番かの管理)を、GameSceneの中で行っていますが、
本来はそういったことを管理するクラスを作ってその中でまとめた方がよいです。

おまけ

背景色を変える

GameSceneのbackgroundColorプロパティを設定すると、背景色が変更できます。
このコードを(例えば、GameSceneクラスのinitの中に)追加してみましょう。

backgroundColor = SKColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)

もっとSpriteKit/iOSアプリ開発を勉強する


おすすめツール

http://meyasuba.comeyasuba.co

おわりに

お疲れ様でした!
皆様が面白いゲームを開発して、楽しい人生をおくるきっかけ作りにこの記事が役立てば、これに勝る喜びはありません。
私も面白いゲームを作ろうと思って、色々本を読んでみて、アイデアがわき上がってきました。


スポンサーリンク


あとがき

Swiftでテトリス作る英語記事読みましたけど、長過ぎで疲れましたよ、ほんとに・・・。
最近は、仕事のストレスも結構溜まるので、ストレスを和らげるためにお酒を良く飲むようになりました。
カンパリを買って、自分でソーダで割って飲んでます。

ほろ苦い甘さと炭酸の刺激が疲れた体に気持ちいいです。
Dr.Pepperが好きな方はカンパリソーダもきっと好きになると思います。是非試してみて下さい!