ルパン三世風タイトルコールをSwiftUIで作る方法

Kotlinを調べるのにQiitaを見ていたら"【Android】ルパン三世風タイトルコールをなるべく簡単に作る"を発見しました。

この記事では、ViewModelを使った簡単なサンプルコードになっていて、SwiftUIにしたら参考になるのではないかと思いました。

今回作成するアプリの完成イメージ

文字を入力するテキストフィールドとStartボタンを配置し、Startボタンを押すとタイトルコールが表示されるアプリです。

画像1

ViewModelを作成する

今回は、ファイル名をLupinTitleViewModel.swiftとしました。

入力した文字を格納するための変数titleを用意し、startTitleCall()を呼び出すとタイトルコール中かどうか判定するフラグisTypingtrueに書き換えます。その後タイトルコール中に表示すべき変数typeWriteに文字列を逐次格納するようにしています。

音源は、"【Android】ルパン三世風タイトルコールをなるべく簡単に作る"と同じ魔王魂の銃03と点火04を利用しています。

import Foundation
import UIKit
import AVFoundation

class LupinTitleViewModel: NSObject, ObservableObject {
   @Published var title:String = ""
   @Published var typeWrite:String = ""
   @Published var isTyping:Bool = false
   
   //音楽:魔王魂 - 銃03
   private let titleSound = try! AVAudioPlayer(data: NSDataAsset(name: "se_maoudamashii_battle_gun03")!.data)
   //音楽:魔王魂 - 点火04
   private let typewriter = try! AVAudioPlayer(data: NSDataAsset(name: "se_maoudamashii_se_ignition04")!.data)
   
   func startTitleCall() {
       if title.count == 0 {
           return
       }
       
       titleSound.prepareToPlay()
       typewriter.prepareToPlay()
       
       DispatchQueue.global().async {
           DispatchQueue.main.sync {
               self.isTyping = true
           }
           
           for string in self.title {
               Thread.sleep(forTimeInterval: 0.15)
               self.titleSound.stop()
               self.titleSound.currentTime = 0.0
               self.titleSound.play()
               DispatchQueue.main.sync {
                   self.typeWrite = String(string)
               }
           }
           Thread.sleep(forTimeInterval: 0.15)
           self.titleSound.stop()
           self.typewriter.play()
           DispatchQueue.main.sync {
               self.typeWrite = self.title
           }
           Thread.sleep(forTimeInterval: 2)
           DispatchQueue.main.sync {
               self.isTyping = false
               self.typeWrite = ""
           }
       }
   }
}

ContentViewを作成する

今回は、タイトルコール中かどうかを判定して、デザインを変更するようにしています。本来は、TitileCallViewなど作るべきなのでしょうが今回は簡単なデザインなのでベタ書きします。

import SwiftUI

struct ContentView: View {
   @ObservedObject private var lupinTitleViewModel = LupinTitleViewModel()
   
   var body: some View {
       Group {
           if lupinTitleViewModel.isTyping {
               ZStack {
                   Color(.black)
                       .edgesIgnoringSafeArea(.all)
                   
                   VStack {
                       Spacer()
                       
                       Text(lupinTitleViewModel.typeWrite)
                           .font(.largeTitle)
                           .fontWeight(.heavy)
                           .foregroundColor(.white)
                       
                       Spacer()
                       
                       Text("音楽:魔王魂")
                           .foregroundColor(.white)
                   }
               }
           } else {
               VStack {
                   TextField("Title", text: $lupinTitleViewModel.title)
                       .textFieldStyle(RoundedBorderTextFieldStyle())
                       .padding()
                   Button(action: {
                       self.lupinTitleViewModel.startTitleCall()
                   }) {
                       Text("Start")
                           .padding()
                   }
               }
           }
       }
   }
}

struct ContentView_Previews: PreviewProvider {
   static var previews: some View {
       ContentView()
   }
}

これで終わりです。

最後に

SwiftUIを利用すると、画面デザインと処理する部分を分けるようにしなくてはならなくなります。従来のViewControllerにベタガキするようなことはできないので、整理できていいのかも知れません。

作成したサンプルコードはこちらのGithubに公開しています。

ありがとうございました。

この記事が気に入ったらサポートをしてみませんか?