テックキャンプで1ヶ月半、自作iPhoneオリジナルアプリ作った

テックキャンプに通いだしてからおよそ1ヶ月半iPhoneアプリ開発コースを受講していました。

レッスンは1~8までありますがレッスン5までの内容で1つ自作のオリジナルアプリを作ることができました。

と言ってもとても単純な赤ちゃん向けの「いないいないばぁ」アプリなので大したものじゃないんですが、うちには1歳半の子供が居るのでこれぐらいのゲームは興味深く遊んでくれるようです。もう少し先の知育ゲームはまだ無理っぽい。

あと自分のswiftの技術力的には習得した事を使ってもっと発展できると思うけど、この手のゲームは「グラフィック」「サウンド」が無いと話にならないし、自分にそっちのスキルやセンスは無いので。

今日はそれの備忘録とかソースコード全体とかを書いています。(Swiftは脱初心者ぐらいなので恥ずかしいけど)

テックキャンプを検討している方がいればiPhoneコースで途中まででこれぐらい作れるよ、というのをお見せしたいと思いました。

今回作ったアプリ

SwiftとXcodeで作ったPeek-a-booアプリ仕様とか

「いないいないばぁ」を英語にするとピーカブーというそうです。

iPhoneを立ち上げたらすぐに「いないいない状態」の動物のキャラクターが出てきて、画面をタップしたら「ばぁ状態」の動物の絵に切り替わる。

もう1回タップしたらランダムで絵が出てきて、タップしたらまた「ばぁ」になる。それだけのアプリです。

今回Xcodeというapple製の開発環境を使っていて、画面へのボタンや絵の配置が楽になる機能でStory Boardというのがあります。それを使って画像を配置しています。

またXcodeではソースコードでの編集もできるのですが今回は主にソースコードを手打ちするやり方で実装していきました。

用意した動物画像は9種類。この絵がかわいくて好きなんよ。

背景画像が1個。画像はココナラでデザイナーさんに依頼して作っていただきました。→まぁぺ様

また「かけ声」を出したいので音声ファイルを2個用意しました。これはココナラで声優の方に録音して提供いただいたものです。→みとみんと様

自作iPhoneアプリのソースコード解説

お見せするのもお恥ずかしいのですが、たったの100行。

import UIKit
import AVFoundation

class ViewController: UIViewController {
    var screenWidth: CGFloat!
    var screenHeight: CGFloat!
    
    @IBOutlet weak var bgImageView: UIImageView!
    @IBOutlet weak var imageView: UIImageView!
    @IBOutlet weak var btn: UIButton!
    
    let bgImg = UIImage(named: "bg1.jpg") //背景画像
    let animalNames: [String] = ["dog", "panda", "cat", "inko", "koara", "lion", "sima", "usa", "zou"] //キャラ画像名
    var animalName: String!

    let voiceURL1: URL = Bundle.main.url(forResource: "peekaboo-voice-1", withExtension: "mp3")!
    let voiceURL2: URL = Bundle.main.url(forResource: "peekaboo-voice-2", withExtension: "mp3")!
    var peekabooVoice1: AVAudioPlayer!
    var peekabooVoice2: AVAudioPlayer!
    
    var peekabooFlg = 0 //いないいない

    override func viewDidLoad() {
        super.viewDidLoad()

        self.peekabooVoice1 = try? AVAudioPlayer(contentsOf: voiceURL1)
        self.peekabooVoice2 = try? AVAudioPlayer(contentsOf: voiceURL2)
        
        screenWidth = self.view.frame.width
        screenHeight = self.view.frame.height
        
        setBgImage()
        setRandAnimal()
        setAnimalImage1()
        initImageView()
        setButton()
    
    }
    
    @objc func changeImg(_ sender: UIButton) {
        print("ボタンが押されました")
        switch(peekabooFlg) {
        case 0: //いないいない画像が表示中にタップされた
            peekabooFlg = 1
            setAnimalImage2()//ばぁ画像を表示
            break
        case 1: //ばぁ画像が表示中にタップされた
            peekabooFlg = 0
            setRandAnimal() //次の画像をセット
            setAnimalImage1()
            break
        default:
            break
        }
    }
    func setRandAnimal()  {
        let idx = arc4random() % UInt32(animalNames.count)
        animalName = animalNames[Int(idx)]
        print("animalName : \(animalName!)")
    }
    func setAnimalImage1() {
        let img = UIImage(named: "\(animalName!)1.png")
        imageView.image = img
        peekabooVoice1.play()
    }
    func setAnimalImage2() {
        let img = UIImage(named: "\(animalName!)2.png")
        imageView.image = img
        peekabooVoice2.play()
    }
    func setButton() {
        //普通のボタンを生成
        let btn = UIButton(type: UIButtonType.system)
        //画面いっぱいの大きさにする
        btn.frame = CGRect(x:0, y:0, width:screenWidth, height:screenHeight)
        self.view.addSubview(btn)
        //ボタンをタップした際に反応するメソッドを用意
        btn.addTarget(self, action: #selector(self.changeImg(_:)), for: UIControlEvents.touchUpInside)
    }
    //背景画像をセット
    func setBgImage() {
        bgImageView.image = bgImg
        bgImageView.frame = CGRect(x:0, y:0, width: screenWidth, height: screenHeight)
        bgImageView.contentMode = UIViewContentMode.redraw
        bgImageView.center = self.view.center
        self.view.addSubview(bgImageView)
    }
    //スマホ画面サイズ取得と画像の縮尺設定とUIImageのせる
    func initImageView() {
        //画像サイズを取得
        let imgW: CGFloat = imageView.image!.size.width
        let imgH: CGFloat = imageView.image!.size.height
        
        print("screen w, h : \(screenWidth), \(screenHeight)     img w, h : \(imgW), \(imgH)")
        
        //スマホ高さが375で画像が600だと画像を414/600=0.69倍すればよい.スマホ横向きなので高さに合わせる
        let hScale = screenHeight / imgH
        //imgViewをとりあえず(0,0)座標から描画し、縦横は倍率で計算してセット、縦横比も保たれる
        imageView.frame = CGRect(x:0, y:0, width: imgW * hScale, height: imgH * hScale)
        //imgViewの中央を画面中央とする
        imageView.center = self.view.center
        self.view.addSubview(imageView)
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

一応これで動いていますけど自分の理解を深めるためにも解説。

まず画面系と音楽系を使うのでimportでUIKitとAVFoundationを指定しています。

ViewControllerクラスを実装していきます。これでスマホに表示させる画面を作っていっています。

@IBOutletで始まる3つの変数(bgImageView、imageView、btn)はそれぞれ背景画像、動物画像、画面へのタップイベントを発生させるボタンを定義しています。これはInterface Builderに配置した画像やボタンと対応していてOutlet接続しています。

13行目と14行目で動物名(実は画像のファイル名)を配列に入れています。動物ごとに「いないいない」画像と「ばぁ」画像の2枚あるので(dog1.pngとdog2.pngみたいに)ファイル名の後ろについてる数字だけ切り替えるような形で画像の差し替えをする予定。

15行目~19行目で用意したmp3ファイルをロードして音を出す準備をしています。

23行目viewDidLoadメソッドでスマホでアプリが立ち上がった後の処理(初期化のような)が書かれています。

setBgImageメソッドで背景画像をImageViewにセットしてaddして表示。

setRandAnimalメソッドで画像ファイル名をランダムで取得しています。

setAnimalImage1で上でランダムに取得した画像ファイル名に1をつけて「いないいない」画像を表示。かつ音声を再生します。

setAnimalImage2は同様に画像ファイル名に2をつけて「ばぁ」画像を表示。かつ音声を再生します。

initImageViewメソッドは画像の縦横サイズとスマホの縦横サイズから計算してうまく画面におさめるように画像を縮小したりしています。

setButtonメソッドはボタンの大きさを画面の大きさにフィットさせスマホ画面のどこがタップされても反応するようにしています。またタップされたときのイベントを定義しています。タップされたらchangeImgメソッドが動くようにしています。

changeImgメソッドでは現在の状態(peekaboo_flg)を見て、

・いないいない画像が表示中にタップされたらばあ画像を表示
・ばぁ画像が表示中にタップされたらsetRandAnimalメソッドで次の画像をセットして、いないいない画像を表示

ということをやっています。

ソースコードはこれだけです。この後自分のiPhoneにインストールして動かしてみようと思っています。Apple Storeに公開することはしませんが、もしやるなら年額1万円ぐらいの費用がかかるそうです。

人に受け入れられて流行るiPhoneアプリを開発できるようになれば商売とかも出来そうですね。