このページの本文へ

前へ 1 2 3 4 5 次へ

アップルの無償プログラミング学習ツール「Swiftプログラミング」でいっしょに遊ぼう 第5回

アップルの無償プログラミング学習ツール「Swift Playgrounds」アクションゲーム作り(仕上編)

2020年10月11日 09時00分更新

文● 柴田文彦 編集●飯島恵里子/ASCII

  • この記事をはてなブックマークに追加
  • 本文印刷

ステップ4:ゲームに手を加えて、よりおもしろく遊べるようにする

 もぐら叩きと言いながら、これまではバスケットボールの絵文字を動かして叩く、ボール叩きになっていました。キャラがボールだと盛り上がらないという面もあるかもしれませんが、それだけでなく、穴の中を上下するキャラが1種類だけというのは、ゲームとしての面白みに欠ける要因になるかもしれません。そこでここではキャラを2種類にして、一方を叩くと得点が加算され、もう片方では減点されるようにしてみます。絵柄として紛らわしいキャラを選べば、その紛らわしさによってゲームの難易度も高くなります。

 この例では、一般的なスマイリーの2種類の絵文字をキャラとして使ってみましょう。1つは、口が笑っているもの。もう1つは口がへの字で、困ったような顔をしているものです。目はほとんど変わらないので、口の部分が穴から出てくるまで区別がつきにくくなっています。もちろん前者を叩けば得点はプラス、後者ではマイナスとします。プログラムの改造手順は以下のようになります。

・穴を叩いたら減点するインベント処理はやめる
・もぐらのイベント処理に得点の加算と減算の2通りの処理を加える
・タイマーの中でランダムにもぐらのキャラを変更する処理を加える
・ここまでのプログラムを動かして動作を確認する

 プログラムの最初の方で、穴に見立てて7個配置しているオレンジ色の円ですが、これまではonTouchDown {}のイベント処理で、タップしたりクリックしたりすると、それまでに稼いだ得点から10点を減点していました。今回は、それをやめます。穴をタップしたときではなく、間違ったキャラをタップしたときに減点するようにするためです。

 それに対して、やはり最初の方で7個配置していた「もぐら」ですが、とりあえず最初は口が笑ったスマイリーで初期化します。ただし、onTouchDown {}のイベント処理内では、キャラの絵文字の種類によって、得点を10点増やすか、逆に10点減らすかを判断して実行しています。ここまででは、もぐらのキャラは笑ったスマイリーでしかあり得ないのですが、後でタイマー処理の中で、乱数を使ってキャラの絵文字を切り替えるのです。

 そのキャラの絵文字の切り替えは、タイマーによるループの中で、もぐらの絵文字を含むTextのy座標の値が0以下になった際に実行します。これまでは、もぐらTextの速度をランダムに設定していただけですが、それに続いてキャラの絵文字も設定するわけです。まず例によってarc4random_uniform()で乱数を発生させますが、そこでは10を指定して、0〜9のいずれかの整数を得ます。

 ここでは、それが3より大きかった場合には笑ったスマイリー、そうでなければ困った顔のスマイリーに設定しています。これで、笑ったスマイリーと困ったスマイリーが、だいたい6:4の割合で出てくることになります。この比率は好みで調整してください。

 これでゲームの改造は完了です。書き加えなければならない部分も案外少なく、思ったより簡単だったでしょう。最後に動かして動作を確認してください。

 最後に改造済のプログラム全体を示しておきます。前回と今回のゲーム作りを参考にして、ぜひオリジナルのゲーム制作に挑戦してみてください。

import Foundation
import PlaygroundSupport

Canvas.shared.color = #colorLiteral(red: 0.466666668653488, 
;green: 0.764705896377563, blue: 0.266666680574417, alpha: 1.0)

let locations = [
    [-8.0, 16.0], [8.0, 16.0],
    [-16.0, 0.0], [0.0, 0.0], [16.0, 0.0],
    [-8.0, -16.0], [8.0, -16.0]
]

var score = 0
var time = 30
var frames = 20
var status = "running"

let scoreDisp = Text(string: "残り\(time)秒 - 得点:\(score)", fontSize: 30.0, fontName: "Menlo-Bold", color: Color.white)
scoreDisp.center = Point(x: 0.0, y: 35.0)

var moles = [Text]()
var mVels = [Double]()

for i in 0 ..< locations.count {
    mVels.append(Double(0.0))
}

for loc in locations {
    let hole = Circle(radius: 4.0)
    hole.color = #colorLiteral(red: 0.960784316062927, 
;green: 0.705882370471954, blue: 0.200000002980232, alpha: 1.0)
    hole.center = Point(x: loc[0], y: loc[1] + 4.0)
}

for loc in locations {
    let mole = Text(string: "🙂")
    mole.fontSize = 50.0
    mole.center = Point(x: loc[0], y: loc[1])
    mole.onTouchDown {
        if mole.string == "🙂" {
            score += 10
        } else {
            score -= 10
        }
        scoreDisp.string = "残り\(time)秒 - 得点:\(score)"
        animate {
            mole.center.y = loc[1]
        }
    }
    moles.append(mole)
}
    
for loc in locations {
    let cover = Rectangle(width: 8.0, height: 8.0)
    cover.color = #colorLiteral(red: 0.466666668653488, 
;green: 0.764705896377563, blue: 0.266666680574417, alpha: 1.0)
    cover.center = Point(x: loc[0], y: loc[1])
}

let overDisp = Text(string: "Game Over")
overDisp.color = #colorLiteral(red: 0.572549045085907, 
;green: 0.0, blue: 0.23137255012989, alpha: 1.0)
overDisp.fontSize = 0.1
overDisp.dropShadow = Shadow()
var overCount = 20

let timer = Timer.scheduledTimer(withTimeInterval: 0.05, repeats: true, 
block: {_ in
    if status == "running" {
        var i = 0
        for mole in moles {
            var y = mole.center.y - locations[i][1]
            if y <= 0.0 {
                mVels[i] = Double(arc4random_uniform(40)) / 100.0 + 0.1
                if arc4random_uniform(10) 
>
 3 {
                    mole.string = "🙂"
                } else {
                    mole.string = "🙁"
                }
            } else if y >
 6.5 {
                mVels[i] *= -1.0
            }
            mole.center.y += mVels[i]
            i += 1
        }
        
        frames -= 1
        if frames == 0 {
            time -= 1
            if time == 0 {
                status = "gameover"
                
                for i in 0 ..< moles.count {
                    moles[i].center.y = locations[i][1]
                }
            }
            scoreDisp.string = "残り\(time)秒 - 得点:\(score)"
            frames = 20
        }
    } else if status == "gameover" {
        overDisp.fontSize += 3.0
        overCount -= 1
        if overCount == 0 {
            PlaygroundPage.current.finishExecution()
        }
    } })

 

前へ 1 2 3 4 5 次へ

カテゴリートップへ

この連載の記事

ASCII.jp RSS2.0 配信中