#はじめに
はじめまして。初投稿です。
趣味でプログラミングしてて、友人にどうせだったらQiitaとかGithubに公開すればいいのにと言われ、確かにその通りだと思ったのでこれから随時投稿していこうと思います。
よろしくお願いします。
#概要
Swiftで反射神経を鍛えるゲームを作りました。Swiftで初めてちゃんと最後まで作ったアプリなので、結構思い入れがあります。1から10まで小さい数から順番にタップしていくシンプルなゲームです。
プレイ画面はこんな感じ。↓
#開発環境
・ iOS 13.3.1
・ Xcode 11.3.1
#ソースコード
簡単にソースコードの説明をします。
全部載せるととても長くなってしまうので、スコアシーンなどは割愛します。
全てのコードはGithubに置いておきます。
##TitleScene
タイトル画面で表示されます。
背景に表示される数字の傾きや大きさが毎回ランダムに変わるというちょっとした遊び心(?)も入れてます。
import SpriteKit
import GameplayKit
var i = 1
class TitleScene: SKScene {
let Start = SKLabelNode(fontNamed: "Chalkboard SE")
override func didMove(to view: SKView) {
self.backgroundColor = .white
let QuickTap = SKLabelNode(fontNamed: "Chalkboard SE")
QuickTap.text = "Quick Tap!"
QuickTap.fontColor = .red
QuickTap.fontSize = 110
QuickTap.position = CGPoint(x: self.frame.midX, y:(self.frame.midY) + 150 )
self.addChild(QuickTap)
for i in 1...10 {
let num = SKLabelNode(fontNamed: "Chalkboard SE")
let angle:CGFloat = CGFloat(Int.random(in : 0...359))
num.text = "\(i)"
num.fontColor = .gray
num.fontSize = CGFloat(Int.random(in : 100...500))
num.position = CGPoint(x: Int.random(in: -100...600), y: Int.random(in: -200...800))
num.zRotation = angle
num.alpha = 0.2
self.addChild(num)
}
Start.text = "Start"
Start.fontColor = .black
Start.fontSize = 100
Start.position = CGPoint(x: self.frame.midX, y:(self.frame.midY) - 250 )
self.addChild(Start)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for obj in touches {
let touch = obj
let location = touch.location(in: self)
let node = self.atPoint(location)
if node == self.Start {
let secondScene = GameScene(size: self.size)
secondScene.scaleMode = SKSceneScaleMode.aspectFill
self.view?.presentScene(secondScene)
}
}
}
override func update(_ currentTime: CFTimeInterval){}
}
##GameScene
ゲームシーンって書いてますが、ただのカウントダウンが表示される場面です。
ここのカウントダウンと効果音を一緒に出すやり方はもっと効率のいい方法があると思います。無理やり効果音を加工しました。
import SpriteKit
import GameplayKit
class GameScene: SKScene {
override func didMove(to view: SKView) {
let countdownSound = SKAudioNode(fileNamed: "countdown.mp3")
self.backgroundColor = .white
let count = SKLabelNode(fontNamed: "Gill Sans")
count.fontColor = .systemRed
count.fontSize = 200
count.position = CGPoint(x : self.frame.midX, y : self.frame.midY)
self.addChild(count)
let inter = SKAction.wait(forDuration: 1.0)
let hidden = SKAction.run ({
count.isHidden = true
})
let three = SKAction.run ({
count.text = "3"
})
let two = SKAction.run ({
count.text = "2"
})
let one = SKAction.run ({
count.text = "1"
})
self.run(SKAction.sequence([three,inter,two,inter,one,inter,hidden]))
self.addChild(countdownSound)
_ = Timer.scheduledTimer(timeInterval: 3.0, target: self, selector: #selector(self.NextScene), userInfo: nil, repeats: false)
}
@objc func NextScene(){
let thirdScene = GamePlayScene(size: self.size)
thirdScene.scaleMode = SKSceneScaleMode.aspectFill
self.view?.presentScene(thirdScene)
}
func touchMoved(toPoint pos : CGPoint) {
}
func touchUp(atPoint pos : CGPoint) {
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
}
##GamePlayScene
実際に1から順に消していく画面です。
いらないコードを途中で消したり、必要なコードを途中で足したりしたので、かなり歪な書き方になってます、、、本当はもっと綺麗な書き方あると思います。。
数字の配置と大きさ、色はランダムになるようになってます。
import SpriteKit
import GameplayKit
import AVFoundation
var timeTotal: Double = 0
var timer1: Timer?
let StartSound = SKAudioNode(fileNamed: "pi.mp3")
class GamePlayScene: SKScene {
var timer: Timer?
var array1:Set = [100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600]
var array2:Set = [100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000]
var TrueInstanse: AVAudioPlayer! = nil
var FalseInstanse: AVAudioPlayer! = nil
@objc func handleTimer(_ timer: Timer) {
timeTotal += timer.timeInterval
print("timer fired. total : \(timeTotal)")
}
@objc func StopStart() {
let stopAction = SKAction.stop()
StartSound.run(stopAction)
}
override func didMove(to view: SKView) {
timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(handleTimer), userInfo: nil, repeats: true)
let TrueSoundPath = Bundle.main.path(forResource: "true", ofType: "mp3")!
let FalseSoundPath = Bundle.main.path(forResource: "false", ofType: "mp3")!
let TrueSound = URL(fileURLWithPath: TrueSoundPath)
let FalseSound = URL(fileURLWithPath: FalseSoundPath)
do {
TrueInstanse = try AVAudioPlayer(contentsOf: TrueSound, fileTypeHint: nil)
} catch {
print("TrueSound is error.")
}
do {
FalseInstanse = try AVAudioPlayer(contentsOf: FalseSound, fileTypeHint: nil)
} catch {
print("FalseSound is error.")
}
TrueInstanse.prepareToPlay()
FalseInstanse.prepareToPlay()
self.addChild(StartSound)
self.backgroundColor = .white
timer1 = Timer.scheduledTimer(timeInterval: 1.8, target: self, selector: #selector(self.StopStart), userInfo: nil, repeats: false)
for i in 0...9{
let randomSize = Int.random(in : 100...300)
let randomSizeDouble1 = array1.randomElement()
let randomSizeDouble2 = array2.randomElement()
array1.remove(randomSizeDouble1!)
array2.remove(randomSizeDouble2!)
let num = SKLabelNode(fontNamed: "Chalkboard SE")
num.position = CGPoint(x: randomSizeDouble1!, y: randomSizeDouble2!)
num.fontSize = CGFloat(randomSize)
num.text = "\(10 - i)"
switch(Int.random(in : 0...9)) {
case 0:
num.fontColor = .systemPink
case 1:
num.fontColor = .systemYellow
case 2:
num.fontColor = .systemGreen
case 3:
num.fontColor = .systemBlue
case 4:
num.fontColor = .systemGray
case 5:
num.fontColor = .systemTeal
case 6:
num.fontColor = .systemIndigo
case 7:
num.fontColor = .systemPurple
case 8:
num.fontColor = .systemRed
default:
num.fontColor = .systemOrange
}
self.addChild(num)
}
}
var TenArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 888]
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for obj in touches {
let touch = obj
let location = touch.location(in: self)
let node = self.atPoint(location)
if let label = node as? SKLabelNode {
if label.text == "\(TenArray.min()!)"{
TrueInstanse.currentTime = 0
TrueInstanse.play()
label.removeFromParent()
TenArray.removeFirst()
if TenArray[0] == 888 {
timer!.invalidate()
let scoreScene = ScoreScene(size: self.size)
scoreScene.scaleMode = SKSceneScaleMode.aspectFill
self.view?.presentScene(scoreScene)
}
} else if label.text != "\(TenArray.min()!)"{
FalseInstanse.currentTime = 0
FalseInstanse.play()
} else {
continue
}
}
}
}
func touchMoved(toPoint pos : CGPoint) {
}
func touchUp(atPoint pos : CGPoint) {
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
}
##その他
各シーンごとに同名のsksファイルを一緒に作りました。あと、main.storyboardには今回、何も手を加えてません。全部コードで書きました。
#最後に
ここまでご覧いただきありがとうございました。ちなみに このゲームの私の最高記録は1.8sです(自分でもなかなかすごいと思ってます)。私の中でアプリといえば真っ先に思いつくのがゲームなんですよね。実際、ゲーム作るのすごく楽しいですし。まあこれからはいろんなアプリを勉強しながら作っていきたいと思ってます。