コンピューター基礎Ⅲ
UIKit でプログラム No.1「じゃんけんアプリ」 ○このセクションの目的 ・iPhone の画面サイズ、アイコンサイズについて、 実サイズ(pt)と @2x・@3x(px)の扱いを理解する ・Xcode7 で、UIBuilder を使ったプログラミングを理解する ・UI 部品の配置・プロパティ設定を理解する・Xcode7 で、UI 部品(UIButton)からプログラムを実行 する方法と、UI 部品(UIButton、UILabel)に表示する 方法を理解する ・ランダムを作る方法(arc4random_uniform())を理解する ・時間を待つ方法(NSTimer の使い方の一つ)を理解する ・BGM を鳴らす方法(import 文と AVAPlayer)を理解する ○仕様 ・画面サイズは、iPhone5S(640×1136px、320×568pt)縦 置きのみとする ・画面遷移のない一画面だけのプログラム ・部品の配置は、コンストレイントをかけずに置くだけ ・入力は 3 種類の Button、出力は Button 一つと Label1つ ・無限に繰り返す(BGM も)
○コーディング
・「Main.storyboad」に UIButton4つ(100x100pt)と UILabel(200x25pt)1つを配置する ・Label に最初のメッセージを表示(「じゃんけん ...」)
・Button に画像を表示させる(「待っている」と自分の「ぐー・ちょき・ぱー」) ・「Assistant Editor」で「ViewController.swift」を表示させる
・PC の手の画像を入れ替えられるように、画像入りの定数を作る
・「let imgSTONE = UIImage(named: ”stone.png”」を、「ちょき・ぱー・待ち」分もやる ・勝敗をメッセージラベルに出力できるように、呼び出しようの変数を作る
・「option」キーを押しながら、Label を「ViewController.swift」の「override func viewDidLoard(){}」の前に D&D
・表れたダイアログで「Conection」を「Outlet」、「Name」を「labResult」にし、「Connect」 ボタンをクリックする
・「@IBOutlet weak var labResult: UILabel!」ができる
・PC の手をボタンの画像に出力できるように、呼び出しようの変数を作る
・「option」キーを押しながら、Label を「ViewController.swift」の「override func viewDidLoard(){}」の前に D&D
・表れたダイアログで「Conection」を「Outlet」、「Name」を「PC_HAND」にし、「Connect」 ボタンをクリックする
・「@IBOutlet weak var PC_HAND: UIButton!」ができる
・「ぐー」の Button から、func doJunken() 呼び出させる(同様に「ちょき・ぱー」も作る) ・「ぐー」Button から、「option」キーを押しながら「ViewController.swift」の「override func viewDidLoard(){}」の閉じ括弧の後ろに D&D
・表れたダイアログで「Conection」を「Action」、「Name」に「pushButtonStone」、「Type」を 「Button」、「Event」を「Touch Up Inside」にし、「Connect」ボタンをクリックする
・「@IBAction func pushButtonStone(){}」ができる
・doJunken(”いし”) とじゃんけん判定の関数(doJunken())を呼び出す ・「func doJunken(){}」を作る
・仮引数を「my_hand: String」
・PC の手を乱数で作る(0: ぐー、1: ちょき、2: ぱー) ・PC の手の画像を入れ替える
・例えば「いし」の場合、「PC_HAND.setBackgroundImage(IMGStone, forState: .Normal」 ・if 文を使って、my_hand と PC の手から勝敗を分け、ラベルに出力する
・たとえば「引き分け」なら、「labResult.text = “ひきわけ”」 ・次のじゃんけんまで、時間を待つ
・Timer を使って、3 秒待つ(画面を初期状態に戻す関数 func refresh() を呼び出す) ・func refresh(){} を書く 100pt 25pt 200pt 100pt ○プログラムの流れ 初期画面状態 ・PC の手が「待ち」 ・メッセージラベルが 「じゃんけん ...」 ・func viewDidLoad(){} で BGM を鳴らす 「ぐー・ちょき・ぱー」 ボタンをタッチ タッチされた Button ごとに
@IBAction func pushBtnStone(){} @IBAction func pushBtnTyoki(){} @IBAction func pushBtnPaper(){} のどれかを実行 (myHand に手を設定 ) func doJanken(myHand){} で ・PC の手を作る ・勝敗を判定する ・PC の手とメッセージを表示 ○手順 0. 背景画像とアイコンを用意する ・ファイル形式は PNG ・背景画像は @2x(アプリの座標系では 320×568、 実際のサイズは 640×1136px)で作る ・アプリのアイコンを最低限の3つ作る ・60x60 サイズ: 120x120px で ファイル名「[email protected]」 ・40x40 サイズ: spotlight 用、80x80px で ファイル名「[email protected]」 ・29x29 サイズ: 設定用、58x58px で ファイル名「[email protected]」 ・「じゃんけんの画像」を @2x で作る (200x200px で、「ぐー・ちょき・ぱー」3つと 「待っている画像」一つ) 1.Xcode 起動(詳細は、別プリント参照) ・新規プロジェクトの作成
・[iOS」の「Single View Application」 ・プロジェクトの設定変更 ・「Device Orientation」を「portrait」のみ ・ビューサイズを「iPhone-4inch」にする ・「Images.xcassets」でアイコンを設定(@2x)する ・プロジェクトに画像を D&D し、「グループ」に まとめる ・「Images.xcassets」にプロジェクトから D&D する
コンピューター基礎Ⅲ
UIKit でプログラム No.2「エセ占いアプリ」 ○このセクションの目的 ・UIPickView の使い方を理解する ・イベントメッセージの delegate を理解する ・プロトコルとメソッド(関数)の実装につ いて理解する ・配列の利用を理解する ・セグェによる画面遷移を理解する ・CSV ファイルの読み込みを理解する ・UserDefault を使って、データーを保存・再利 用する方法を理解する ・今日の日付を知る方法を理解する ○仕様 ・画面サイズは、iPhone5S(640×1136px、 320×568pt)縦置きのみとする ・画面は二つ。セグエを使って行き来する ・入力は UIPickerView と Button、出力は UITextView、UILabel、UIImageView ○コーディング(可能な限り例文集からコピペし、必要なところを書き換える) ・一画面目 ・UI を配置する ・UIPickerView 部分を作る ・class ViewController にプロトコル宣言を書く class ViewController:UIVewController の後ろ「{」までに 「, UIPickerViewDelegate, UIPicker ViewDataSource」・誕生月と誕生日を入れる変数を作る(配列添え字は「0」からだが、わかりやすく「1」) var monthNum: Int = 1
var dateNum: Int = 1
・PickerView へ出力できるように Outlet を作る
通常の手順で、「@IBOutlet weak var datePicker: UIPickerView!」
・プロトコルのメソッドを実装する(アプリごとにオリジナリティが必要なのは、ドラムの 文字配列データーと func pickerView のうち要素番号を取り出して利用するメソッドだけ) ・PickerView に表示する文字を配列で用意する。[ ドラムの数 ][ 各要素 ] の不ぞろいの長 さの 2 次元配列。クラス内全体から見える(スコープ)場所に書く。
let date = [
[”Jan”, ”Feb”, ”Mar”, ...”Dec”], [”1”,”2”, “3”, ...”31”] ]
・PickerView の列数(ドラムの数)を返すメソッドを実装
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> { return date.count
}
・PickerView の列の要素数(各ドラムの書かれている文字列数)を返すメソッドを実装 func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
let compo date[component] return compo.count } ○手順 0. リソースの準備 ・星座アイコンを用意する ・ファイル形式は PNG ・200x200px で、12 星座分 ・占い結果データーの準備 ・CSV で ・項目は、4 種類、各 23 要素 1.Xcode 起動(詳細は、別プリント参照) ・新規プロジェクトの作成、リソースの読み 込み ・一画面目(誕生日入力)を作る ・UI を設定 ・今日の日付を調べる ・前回の占いを使うか、新しい占いを行 うか判定 ・12 星座分の占い結果を UserDefault に 保存 ・誕生日入力から、占い結果文作成 ・AppDelegate に受け渡しデータを保存 ・二画面目への遷移ボタン ・二画面目(占い結果表示)を作る ・UI を設定 ・AppDelegate からデーターを読み込む ・星座マーク、占い文を表示 ・一画面目への遷移ボタン ○プログラムの流れ ・AppDelegate からデーターを 読み込む ・誕生星座マーク、誕生星座名 を表示 ・占い文を表示 ・前の画面に移るボタン ・初期画面状態 ・PickView のドラム表示 ・CSV を読み込む ・前回の DefaultUser を読み込む ・今日の日付を求める ・12 星座の今日の占いを作る 「占う」ボタンをタッチ ・誕生星座を求める ・占い文をつくる ・AppDelegate にデーターを 書き込む ・次の画面に移るボタン 一画面目 PickView から誕生日を作る 二画面目 ○占いデータ プログラム内でのデーター構造(配列の意味) ・CSV:テキストファイル 4 行でできている。 ・各行が占いの内容の種類(吉凶、ラッキーカラー、ラッキーアイテム、ラッキーフード) ・各行に「,」で区切った 23 の要素がある(例えば吉凶なら、「大吉,吉,小吉 ...」) ・CSV 読み込み関数では、行ごとに読み込んだ後、行を「,」で分割した 1 次元の配列ができる ・CSV 読み込み関数からの出力を、1 要素を「,」で分割し、messageDB[[]]:4 行 23 列の 2 次元配列 (添え字は、[ 行 ][ 列 ])に納める。 つまり [[String]] = [ [ 大吉,吉, , , , ... 大凶 ], [ 赤,青, , , , .... 紫 ], [ 鉛筆,マスク, , , , .... メガネ ], [ 卵焼き,カレーライス, , , , .... 親子丼 ] ] となっている。 ・占い結果は、12 行 4 列の2次元配列に 0-22 の数字を入れる。つまり [[Int]] = [ [5,8,0,20], [12,4,10,2], : : [1,9,7,5] ] 各行に誕生星座ごとの占い結果を配列 messageDB から探すために、messageDB の行順に列番号が 並んでいる(つまり一列目が”1”なら占いは”吉”、2 行目が”0”なら”赤”... という使い方)。 200pt 200pt セグェ 100pt 300pt 400pt 100pt
・PickerView の列の幅を決めるメソッドを実装
func PickerView(pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat { if component == 0 { // 左から一つ目のドラムの場合 return 100 // ここの数字は自分で決める } else { // 今回の場合、左から二つ目のドラム return 50 // ここの数字は自分で決める } } ・PickerView の特定のドラムの指定の位置の要素を返すメソッドを実装
func pickerView(pickerView: UIPickerView, titleForRow: Int, forComponent component: Int) -> String? {
let item = date[component][row] return item
}
・PickerView の各ドラムの表示中の要素の番号を取り出すメソッドを実装(返値はない) func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int){
let ROW1 = pickerView.selectedRowInComponent(0) // ドラム0から let ROW2 = pickerView.selectedRowInComponent(1)
monthNum = ROW1 + 1 // 配列の添え字は0からなので、1からに直す dateNum = ROW2 + 1
}
・override func viewDidLoad() から pickerView を使えるようにする。メソッドに以下を追加 datePicker.delegate = self
datePicker.dataSource = self
・pickerView の動作を確認してみる。ラベルとボタンを流用する(後で元に戻す。削除の手 順があるので適当に消さない)。
・ラベルから Outlet(@IBOutlet weak var test: UILabel!)を作る ・ボタンから Action を作る
・ボタンの Action に以下のコードを書く
test.text = monthNum + “月”+ dateNum + “日”
・pickerView のドラムを適当に設定し、ボタンをクリックしてみる。
☆Outlet や Action の消去には、手順がある(コードを消すだけではダメ) ・コードを消す
・Outlet や Action を設定した UI を選択し、インスペクターエリアで、下図右端の「 」 アイコン(Show The Conections Inspector)をクリックする
・「Sent Events」「Referrencing Outlets」でリンクされている項目を選択し削除する
・占い部分(12 行 4 列の2次元配列にランダムな整数値を入れる)をつくる ・占いに使う定数と占い結果を入れる配列を用意
let numKIKKYOU: Int = Int(23) //CSV の要素数は見出し込みで 4 個あるが、 let numLUCKY_COLOR: Int = Int(23) //「0」は使わないので全部で 23 個
let numLUCKY_ITEM: Int = Int(23) let numLUCKY_FOOD: Int = Int(23)
// 星座ごとの占い結果を格納する配列(下のは省略してあるが、12 行作る) var arrayFortune: [[Int]] = [
[0, 0, 0, 0], [0, 0, 0, 0], : [0, 0, 0, 0] ] ・占いメソッドを書く func makeUranai(){ //「0」を使わないので、「+1」している for var i: Int in 0 ..< 12 {
arrayFortune[i][0] = Int(arc4random_uniform(numKIKKYOU)) + 1 arrayFortune[i][1] = Int(arc4random_uniform(numLUCKY_COLOR)) + 1 arrayFortune[i][2] = Int(arc4random_uniform(numLUCKY_ITEM)) + 1 arrayFortune[i][3] = Int(arc4random_uniform(numLUCKY_FOOD)) + 1 } } ・CSV ファイルを読み込んで、占い分の配列に格納する ・行読み込み関数 loadCSV() をコピペ(CSV の行を要素とする一次元配列ができる) ・CSV の行を分解して二次元配列にし、特定の星座の占い番号に相当する占い結果を取り出す メソッドを書く
func makeUranaibun(seiza: Int) -> [String] { var messageDB: [[]] = [[String]]()
let csvRecord: [String] = loadCSV(”uranai”) for var i: Int in 0 ..< csvRecord.endIndex {
messageDB.append(csvRecord[i].componentsSeparatedByString(”,”)) } return [messageDB[0][arrayFortune[seiza][0]], messageDB[1][arrayFortune[seiza][1]], messageDB[2][arrayFortune[seiza][2]], messageDB[3][arrayFortune[seiza][3]] ] } ・func viewDidLoad() に占いを行う部分を作る ・日ごとに同じ占い結果しか出ないように、日付を調べて前回の起動と異なる日付のときだけ 新しい占いを行う。占い結果は NSUserDefaults に書き込んでおく
let NOW = NSDate() // 今の日付時間を手に入れる
let DEFAULT = NSUserDefaults.standardUserDefaults() // 前回の記録を取り出す // 前回の占い結果があれば、中身を取り出して調べる
if let BEFOR_DATE = DEFAULT.stringForKey(”URANAI_DATE”) { arrayFortune = DEFAULT.objectForKey(”Fortune”) as! [[Int]]
if TODAY != BEFOR_DATE { // 日付が今日でなければ新しく占い、結果を保存 makeTellSeed() // 占う
DEFAULT.setObject(todayString, forKey: “URANAI_DATE”) // 占い日付保存 DEFAULT.setObject(arrayFortune, forKey: “Fortune”) // 占い結果保存 }
}
else { // 初めての起動で前回の記録がないので新しく占い、結果を保存 makeTellSeed()
DEFAULT.setObject(todayString, forKey: “URANAI_DATE”) DEFAULT.setObject(arrayFortune, forKey: “Fortune”) } ・日付から誕生星座名を求めるクラスを別ファイル「astrogicalSign.swift」に作っておく ・メニュー「File」の「New」から「iOS」の「Souce」で「Swift」を選択し、「Next」ボタンを クリックする。ダイアログで、「Save as」を「astrogicalSign.swift」とする ・「月の星座区切りの日付を入れた配列」と「誕生星座名の配列」をつくる。誕生星座を調べた い日付の「月の数字ー1」で「月の星座区切りの日付を入れた配列」の中身の日付を呼び出す。 月番号と月の名を一致させたいので、配列の要素番号は月の名から「-1」したもの(つまり 1 月なら0、2 月なら1)呼び出した日付より調べたい誕生日の日付が前なら、「誕生星座名の 配列」の「調べたい月の数字ー1」の中身が誕生星座。12 月の後半の星座は例外として「誕生 星座名の配列」の始めの星座名にする。
let SIGN_DATE: [Int] = [21, 20, 21, ...23, 23]
let SIGN_NAME: [String] = [”山羊座”, “水瓶座”, ...”射手座”]
let SIGN_NAME_E: [String] = [”Capricon”, “Aquarius”, ...”Sagittarius”]
var signJ = String() var signE = String() var signNum = Int()
init(monthNum: Int, dateNum: Int){
if dateNum < SIGN_DATE[monthNum - 1]{ // 区切りより前なら、要素番号が星座名 signJ = SIGN_NAME{monthNum - 1]
signE = SIGN_NAME_E{monthNum - 1] signNum = monthNum - 1
}
else { // 区切りより後なら、要素番号+1が星座名 if monthNum < SIGN_DATE.count {
signJ = SIGN_NAME{monthNum] signE = SIGN_NAME_E{monthNum] signNum = monthNum } else { // ただし 12 月で区切りより後は、配列の頭の星座 signJ = SIGN_NAME{0] signE = SIGN_NAME_E{0] signNum = 0 } } } ・二画面目をつくる ・main.storyboad を表示させる
・ライブラリから ViewController を InterfaceBuilder の開いている部分に D&D する
・新しい viewController 用のソースファイル(ViewController2.swift)を作る(前述と同じ) ・ファイルの中身をすべて消し、ViewController.swift の中身の基本部分をコピーする ・クラス名は、viewController2 にする ・作った ViewController に ViewController2.swift ファイルを割り当てる ・作った ViewController の上部の ViewController アイコン( )をクリック ・インスペクタペインの Identity Inspector( )を選択 ・「Custom Class」の「Class」を「ViewController2」にする ・画面遷移(セグェの場合) ・セグェの配置 ・次の画面を呼び出すきっかけに使いたいボタンから次に表示させる View へ、「option」キー を押しながら D&D ・表れたダイアログで、画面遷移の演出(下から出てくるとか、ページが回転するとか)を選 ぶ ・コードを書く ・画面遷移後にデーターがなくならないように、AppDelegate.swift に変数の入れものを作る var seiza_name: String?
var seiza_num: Int?
var fortune_message: String?
・セグェ実行直前に実行するメソッドを書く(ViewController.swift に) ☆セグェを呼び出すボタンに Action を設定してコードを書くときには注意! 実行順が特殊!!「画面遷移が起きた後にボタン内のコードが実行される」 画面遷移前に実行したいことは、必ず override func prepareForSegue()に書く 誕生星座の検索と占いデーターの AppDelegate 保存など
override func prepareForSegue(segue: UIStoryboardSegue, sender:AnyObject?) { let SIGN: astrologicalSign = astrologicalSign(monthNum: monthNum,
dateNum: dateNum) let APPDELEGATE: AppDelegate
= UIApplication.sharedApplication(),delegate as! AppDelegate APPDELEGATE.seiza_name = SIGN.signJ // 星座名を保存
APPDELEGATE.seiza_num = SIGN.signNum // 星座画像の呼び出しに使う番号保存 // 誕生星座の占いを取り出して配列に入れる
let arrayMessage:[String] = makeUranaiMessageArray(SIGN.sigNum) // 星座名や占いの配列要素を使って占い結果の文章を作るって、保存 APPDELEGATE.fortune_message = “\(SIGH.signJ)のあなたの今日の運勢は、 「\(arrayMessage[0])」。\n そんなあなたのラッキーカラーは、「\(arrayMessage[1])」。\n ラッキーアイテムは、「\(arrayMessage[2])」。\n ラッキーフードは、「\(arrayMessage[3])」。\n” } この上の「\」は全て 1byte 文字で打つ(この文章を作っている PC ではバックスラッシュ を入力できないので、便宜的に全角になっている)
コンピューター基礎Ⅲ
Spritekit でプログラム No.1「おはじきアプリ」 ○このセクションの目的 ・Spritekit の使い方を理解する ・SKSNode、SKSprite などを理解する ・Animation を理解する ・物理エンジンの意味と使い方を理解する ・PhysicalBody と衝突判定を理解する ○ゲームのルール ・一度に一枚のコインに一度運動量を与えて移動させる ・同じマークのコイン同士を衝突させる(つまり最大二 回コインを移動させられる) ・二種類とも衝突させ終わったらゲームウイン ・動かしたコインが、間違ったコインや壁に当たるとゲ ームロスト ・動かしたコインが、何にも衝突せず停止してしまった らゲームロスト ・手駒として一枚のコインを板上に自由に置いて、コイ ンの反射に使える ○SpriteKit でのプログラミング ・画面作成にライブラリからの D&D は使わない(使えないわけではないが ...) ・シーンファイル(たとえば、はじめに用意されている GameScene.swift)内に、ゲームの コードを書く・起動時には、GameViewController.swift 内の func viewDidLoad() が、上の GameScene.swift 内の GameScene class からシーンのオブジェクト(インスタンス○○)を作り、view(SKView) に表示する(.presetScene(○○))。シーンを入れ替えれば多画面のゲームができる。
・ゲームが始まると、GameScene.swift 中の func didMoveToView() が最初に実行される。 ○仕様 ・画面サイズは、iPhone5S(640×1136px、320×568pt)縦置きのみとする ・一画面で完結 ・プログラムからの指示は画面上に出す ・メッセージ表示中は、タッチでゲーム開始 ・入力は画面タッチ(タッチ、ドラッグ、リリース) ・コインをドラッグしリリースするとコインが運動量を与えられて動く ・コインをドラッグする量で、コインの初速度を決める ・コイン移動中は、タッチで操作できなくする ・効果音を衝突イベント、失敗イベントで鳴らす ・机の外へ出た(壁に当たった)場合は、コインが落ちていく Animation をする ○物理エンジン(シミュレーション) ・運動方程式を自動処理する
・重力(gravity)、速度(velocity)、角速度(回転許可:allowsRotation)、質量(mass や density)、摩擦(減衰率 friction と .linearDamping と angularDamping)、反発力(restitution) ・衝突処理の簡素化(3種の BitMask)
・衝突境界の衝突精度設定(usesPreciseCollisionDetection と、texture から PhysicsBody を 作る精度「.filteringModey を .Linear と .Nearest」)
☆3 種類のビットマスク
・「.categoryBitMask」:physicsBody の種類分け(敵、味方、障害物 etc.)
・「.collisionBitMask」:特定の physicsBody が衝突する相手を categoryBitMask で指定する 「敵と障害物には衝突するが、味方や背景には衝突しない」など ・「.contactTestBitMask」:衝突が起きたときに、衝突判定処理するプログラムを呼ぶ衝突を 指定する(ぶつかって反射するだけの physicsBody は指定しない) ・ビットパターンは、構造体(struct)や列挙型(enum)を使って、分かりやすい言葉と対応 づけて使いやすくしておく ・BitMask は、型が Uint32 と二進数で 32 桁あるので、各ビットのどこを使うかで 32 種類に グループ分けが可能 ・どこのビットが ON(1)になっているか分かりやすいように、ビットシフト演算子で 00...00 なら「0」、 00...01 なら「(1 << 0)」、 00...10 なら「(1 << 1)」と書く 構造体の場合、 struct COLLIDER_TYPE {
static let NON: UInt32 = 0 // どのグループでもない static let COIN_MINE: UInt32 = (1 << 0) // 置きコイン
static let COIN_A: UInt32 = (1 << 1) // コイン A の 2 枚 static let COIN_B: UInt32 = (1 << 2) // コイン B の 2 枚 static let SIDE_WALL: UInt32 = (1 << 3) // 壁(画面の端) }
コイン A1 が、「同族 A のコイン」と「B グループのコイン」と「壁」に衝突したときに自分で 作った特別な処理(音を鳴らすとか、得点を数えるとか)をしたいときは、
spCoinA1.categoryBitMask = COLLIDER_TYPE.COIN_A
spCoinA1.contactTestBitMask = COLLIDER_TYPE.COIN_A | COLLIDER_TYPE.COIN_B | | COLLIDER_TYPE.SIDE_WALL | COLLIDER_TYPE.COIN_MINE 上の二行だけで「.collisionBitMask」を指定していないので、コイン A1 は全ての物体と ○プログラムの流れ ・初期画面状態 ・机表示 ・机の上に4枚コインをまく ・ルール説明文を表示 ・物理量の設定 タッチか? ・説明文を消去する ・画面タッチでコインを動かせる ようにする コインをタッチか? 反射用コインを 配置 ドラッグ中の 新しい座標 を覚える リリースか? ・コインにインパクトを与える ・画面をタッチできなくする ※ ※ YES NO YES YES NO 二種類ともか? 正しい衝突か? YES NO ゲームロスト YES ゲームウイン NO 再ゲーム 60pt
○手順 0. リソースの準備 ・コイン画像 3 種類を用意する ・ファイル形式は PNG ・200x200px ・机画像 ・ファイル形式は PNG ・机の外周は、コインの半分ぐらいの幅を黒く塗る ・効果音 ・コインの衝突音 ・コインが落ちていく音 ・ゲームロストの BGM 1.Xcode 起動 ・新規プロジェクトの作成(spritekit のひな形、swift で。詳細は、別プリント) ・「iOS」の「Application」から「Game」
・Language を「swift」、Game Technology を「SpriteKit」にする ・プロジェクトへのリソースの読み込み
・プロジェクトに D&D した後、グループにまとめる(右クリックから「New Group fron Selection)。 ・イメージリソースを Assets.xcassets に設定 (@2x) ・ひな形を掃除する(詳細は、別プリント) 2. コードを書く ・クラス宣言に,プロトコルを追加「 ,SKPhysicsContactDelegate」 ・物理シミュレーションする範囲(physicsBody)を作る。大抵 View の範囲で設定するはず なので
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame) ・物理シミュレーションの条件(world)を設定する
・全体(World)の設定
・重力を設定する(落下する場合は落下方向のベクトルを0以外にする。重力なしは0) self.physicsWorld.gravity = CGVector(dx: 0.0, dy: 0.0)
・衝突処理プログラムの受け手(contactDelegate)を設定する(大抵、設定したクラス で処理するので self に) self.physicsWorld.contactDelegate = self ・衝突ビットマスクと運動量・重力に対する反応を設定 ・カテゴリー self.physicsBody?.categoryBitMask = ○○○ // 壁のカテゴリーに設定 ・運動量に対する反応 dynamic self.physicsBody?.dynamic = false // 壁にしたいので衝突しても動かない // 重力で下に落ちない(今回は gravity が dy:0.0 なので意味がない) ・画面上に個別のオブジェクトを作成配置 ・SKSpriteNode オブジェクトをつくる。画像ファイルから作る場合
let spCoinA1 = SKSpriteNode(imgedNamed: “a”) // 画像ファイルが”a.png”の時 ・物理シミュレーションする対象(physicsBody)を作る(注意:anchorPoint を変更しない!) ・サイズ指定で枠を作る場合。例えば半径がオブジェクトサイズと同じ円なら、
spCoinA1.physicsBody = SKPhysicsBody(circleOfRadius: spCoinA1.frame.width / 2) ・画像ファイルの絵が描いてある部分(png ファイルの透明でない部分。一筆書きできる 単純な輪郭のものに限る)を使う場合、
let texCoinA = SKTexture(imgedNamed: “a”) //SKTexture を作る spCoinA1.physicsBody = SKPhysicsBody(texture: texCoinA)
・衝突後の運動を自動処理したいので、 spCoinA1.physicsBody?.dynamic = true spCoinA1.physicsBody?.mass = ○○ // 減衰や衝突を調整するために質量を与える spCoinA1.physicsBody?.LinearDamping = ○○ spCoinA1.physicsBody?.angularDamping = ○○ ・衝突処理のグループ分けをする spCoinA1.physicsBody?categoryBitMask = ●● //spCoinA1 の属するカテゴリー (spCoinA1.physicsBody?collisionBitMask 指定しないとき全ての物体と衝突する) // 衝突したときに自前の処理をするつもりの相手を、藍の categoryBitMask の論理和 で示す(下の場合相手は、自分の同族●●を含めて三種類にぶつかった時の処理を 自前でプログラムするということ) spCoinA1.physicsBody?contactTestBitMask = ●● | △△ | □■ ・画面に表示する ・座標を指定する
spCoinA1.position = CGPoint(x:○○, y:○○) // 小数。原点が左下・Y 軸は上が正 ・重なり順を指定する(数字が大きいほど上側に重なる。指定しないと addChild() した順) spCoinA1.zPosition = 5 ・親オブジェクト(大抵 View)に addChild() すると実際に表示される self.addChild(spCoinA1) // 自明なときは、「self.」なしで良い ・touch 入力処理を書く ・タッチを始めたときにすることは、
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?){} に ・タッチ場所を順に調べる定型文を使う(めんどくさいので、今回は複数の指で触っている ことは考えない) ・ゲーム進行中は(flag で区別する) ・どのコインを触ったかを if 文で判定し、コインだった場合その座標を覚えさせる。 コインでなければ手駒のコインをそこに置く ・ゲーム中断中は何もしない ・ドラッグ中にすることは、
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?){} に ・元の位置からのずれを計算し、コインを動かす時の力の目安として SKLabel で表示する ・ドラッグ中のコイン像を描く
・リリース時にすることは、
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?){} に ・元の位置からのずれを計算し、コインに .aspplyImpulse(CGVector 型の値 ) を与える ・ドラッグ中に表示した力の値 SKLabel とコインの像を見えなくする
・画面外の座標に移動させる ・衝突処理を書く
func didBeginContact(contact: SKPhysicsContact){} に衝突時の処理を書く ・正しいコイン同士なら、 ・衝突音を鳴らす ・ゲームのポイントを数え、終了に達していたら終了処理を呼ぶ ・壁や間違ったコインに衝突したり、コインが何にも当たらず止まったら、 ・コインの場合衝突音を鳴らす ・壁の場合、落下音を鳴らし、落下アニメーションを行う ・上記の終了を待って、ゲーム失敗画面を呼ぶ
コンピューター基礎Ⅲ
Spritekit でプログラム No.2「ふんころがしアプリ」 ○このセクションの目的 ・モーションセンサーの使い 方を理解する ・シミュレーターで代用でき る方法を理解する ・画面スクロールの方法を理解 する ・パーティクルを使ってみる ○ゲームのルール ・フンをころがしてゲートに たどり着いたらゲームクリア ・道の縁にフンが触れたら、 ゲームロスト ○仕様 ・画面サイズは、iPhone5S(1136×640px、568×320pt)横置きのみとする ・一画面で完結(ゲームオーバー・クリア画面は、擬似的に Sprite で作る) ・プログラムからの指示は画面上に出す ・メッセージ表示中は、操作を止める ・入力は iPhone の傾き(重力の成分を使う) ・道の外へ出た(谷底に当たった)場合は、コインが落ちていく Animation をする ・ゲートに当たったら、ゲームクリアパーティクルを表示 ○モーションセンサー(加速度センサー) ・iPhone などに内蔵されている加速度センサーなので、シミュレーターでは動かない ・デモソフトとコードを見て、モーションセンサーのどのゲッター(あるいはメンバ変数と 考えても良い)を使うか決める。今回は「.gravity」の「.x」「.y」を使う。 ・使用手順 1. モーションセンサーのライブラリ(foundation)を指定する import CoreMotion 2. モーションマネージャーオブジェクトを作る let M_MANAGER = CMMotionManager() 3. 測定を開始する・測定頻度を指定する
M_MANAGER.deviceMotionUpdateInterval = 0.05
・ハンドラー(モーションセンサーの値を処理する関数、ここでは○○())を指定する (無名関数を使った指定なので特殊な書き方になっている)
let HANDLER: CMDeviceMotionHandler = {
(motionData: CMDeviceMotion?, error: NSError?) -> Void in self.○○(motionData, error: error) } ・測定を開始する M_MANAGER.startDeviceMotionUpdatesToQueue( NSOperationQueue.mainQueue(),withHandler: HANDLER) ・ハンドラで指定した関数で測定地を読み込む ・測定を一時停止する M_MANAGER.stopAccelerometerUpdates() ○プログラムの流れ ・初期画面状態 ・道を準備・表示 ・フンコロガシ準備・表示 ・物理シミュレーション用意 ・メッセージ表示 ・タイマーでゲーム開始 ・モーションセンサーを 起動し、ハンドラに任す 衝突か? YES NO ゴールか? YES NO ゲームロスト処理 物理エンジンの衝突処理 フンコロガシを 左右に移動 X ・インターバルごとに値を送り出す Y 道路を スクロール モーションセンサーハンドラ処理 425pt(850px) 275pt(550px) 250pt − − + + gravity の値変化 x Y
○手順 0. リソースの準備 ・効果音 ・ゲームの BGM ・ゲームクリアの SE ・ゲームロストの SE ・フン画像(@2x) ・ファイル形式は PNG ・500x500px(250x250pt) ・フンコロガシ画像 ・ファイル形式は PNG ・400x300px(200x150pt) ・フンコロガシ墜落画像 ・ファイル形式は PNG ・960x540px(480x270pt) ・道画像 ・ファイル形式は PNG ・図のように 2 種類、6 枚で道1つになる ・道表面画像(一つのレベルで @2x の 850x3200px を2枚、衝突判定しない) ・谷底画像(実際には黒い壁画像。一つのレベルで道画像に合わせた @2x の 425x3200px を 左右の壁分を各二枚計4枚。衝突判定に使うので、physicsBody を作る) ・プログラムでは、空の SpriteNode(道レイヤ)に addChild しておき、スクロールは道レイヤ に対して操作する(道レイヤのみ anchorPoint を左下角にしておくとプログラムが分かりや すい) 1.Xcode 起動 ・新規プロジェクトの作成(spritekit のひな形、swift で。詳細は、別プリント) ・「iOS」の「Application」から「Game」
・Language を「swift」、Game Technology を「SpriteKit」にする ・プロジェクトへのリソースの読み込み
・プロジェクトに D&D した後、グループにまとめる(右クリックから「New Group fron Selection)。 ・イメージリソースを Assets.xcassets に設定 (@2x) ・ひな形を掃除する(詳細は、別プリント) 2. コードを書く ・タイマーで道をスクロールさせるプログラムを作る(実機用では、モーションセンサーで スクロールさせる) ・フンが斜めに重力で浮いていくプログラムを作る(実機用では、モーションセンサーで左右 にスクロールさせる) ・谷に当たったらゲームオーバーになるように作る ・失敗したフンコロガシの画像を回転アニメーションさせる ・ゲームオーバー画面を作る ・勝敗メッセージ文を表示 ・ゲーム再開ボタンを作る 谷画像左1 谷画像右2 谷画像右 1 谷画像左2 道画像1 道画像 2 道レイヤ View