リブートキャンプ by Swift 目次

 

 まずは前々回のサンプルの

 

   message.backgroundColor = UIColor.orange

 
から。
 messageのbackgroundColorプロパティには背景色を設定します。
 なので、そこに指定しているのは「色」ってことになるわけですが、プログラムでは、こいつを色情報を持つオブジェクトとして扱います。
 それがUIColor。
 

UIColor

 

 色情報とは何か?

 赤色なのか、青色なのか、暗めか、明るめか、鮮やかか、渋めか、表現は色々ですが、ハードウェアに依存した表現となるとRGB値ということになります。

 RGB値ってなんだというと

 

親切本より


 まず、色は目から受け取った光に対する、網膜を構成する3種類の細胞の生理学的反応です。そして、光はさまざまな波長の電磁波の集まりであり、3つの細胞はそれぞれに反応する電磁波の波長が異なります。 

 
 

 600nm前後の波長に反応する細胞は、脳に赤色を、550nm前後の波長は緑色、460nm前後は青色のイメージを作り出させます。 

 
 

 これら3つの波長の電磁波の比率が、人間の感じる色を決定するわけです。

したがって赤、緑、青、この3つの色を混ぜ合わせる事で、人間が感じる色はすべて(厳密にいえば、 レーザー光などで正確に表現できないものもある)再現できるということになります。

 液晶画面も虫眼鏡などで拡大すると、ひとつひとつの点がRGBの発光体で構成されている事が わかります。 

 


 

 強弱を0.0 〜 1.0の範囲で表すとして、赤 :Red、緑 :Green、青 :Blue、すべて 1.0 なら真っ白になり、 すべて 0.0 なら真っ黒になります。赤だけ 1.0 で他が 0.0 なら真っ赤です。 

 

 このようにして色を指定する方法が RGB 値による色の表現で RGB 表色系といいます。 Wiki:色空間より

 

 

 というように、液晶画面を虫眼鏡で見ると赤 :Red、緑 :Green、青 :Blueの3色のタイルのセットがずらずらと並んでるわけですよ。「スクールカーストとかヒエラルキとか」で話した液晶の画素ってのがこれです。

 

 ダイレクトに色を表現するなら、このRGB値ってことになって、UIColorオブジェクトを作るときは次のように、RGB値をそれぞれ0.0〜1.0の範囲で指定することになってます。

 

  UIColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 0.5)

 

 ちなみに最後のalphaはアルファ値といって、色の不透明度の表現となります。

 色付きのガラスの後ろの透け具合を想像してもらったらいいでしょう。0.0で無色透明で後ろが透け放題、1.0で完全に不透明になって後ろの色は透けなくなる。

 この指定だと半透明の赤色ってことになりますね。

 その他に、最初から用意されている馴染みの色もいくつかあって、red、blue、gray、whiteといった名前で、UIColorクラスオブジェクトのプロパティとして用意されていたりもします。

 

クラスオブジェクト

 

 UIColorクラスオブジェクトってのは、クラスごとに1つだけ、アプリケーション起動時に自動的に用意されるオブジェクトです。

 クラス定義では、プログラム中で個別に作成するオブジェクトと、このクラスオブジェクトの2種類を定義できるようになっていて、プロパティやメソッドの定義の前にclassキーワードをつけるとクラスオブジェクト側の定義ってことになります。

 

↓UIColorクラスの定義

class UIColor  … {

  ↓クラスオブジェクト側のプロパティ定義

    class var orange: …

 

  ↓個別に作るオブジェクト側のプロパティ定義

    var cgColor: …

}

 

 個別に作るオブジェクトごとじゃなく、クラスごとに用意したい特性は、こうやってクラスオブジェクト側に定義するのがSwift流です。というかObjective-C、というか、その源流であるSmalltalkからそうなんですが…

 ま、それは置いといて、クラス名を書くことでUIColorクラスオブジェクトを指定したことになるので、いつも通り、そこから . (ドット)で繋げればプロパティを指定できます。

 つまり

 

   UIColor.orange

 

てのは、UIColorクラスオブジェクトのorangeプロパティの指定であり、このプロパティには橙色の色情報を持つUIColorオブジェクトが設定されてます。

 これが

 

   message.backgroundColor = UIColor.orange

 

で、messageのbackgroundColorプロパティに設定されることになるんで、messageの背景は橙色になるんですな。

 

 

 

 

 で、いよいよ前回のサンプルの話。

 のっけにViewControllerに2つのプロパティ、imageViewとmessageを用意してるのは、viewDidLoadで作ったUIImageViewとUILabelオブジェクトを別のメソッドでも使うためです。

class ViewController: UIViewController {
    
    var imageView:UIImageView!      //  人物用
    var message:UILabel!            //  セリフ・説明用

 プロパティ名の後ろに : (コロン)とクラス名を書いているのは、このプロパティが、どの型用に使われるかを教えるため。

 これまでのように

 

   let imageView = UIImageView(frame:…

 

 とか

 

   let message = UILabel(frame:…

 

ていうように、宣言時に = で、記憶するべき内容を指定するのなら、わざわざ型を指定する必要はないんですが、今回の場合、記憶するべきオブジェクト(の識別子ね。参照と言います。何の話かわからん人は「こんにちはデベロッパの世界」を読みましょう)が設定されるのはViewControllerが作られた後のviewDidLoadメソッド呼び出し時なんで、それより前に用意されるプロパティには、型が決められないんですよ。

 なので、コロンを挟んでの型の明示が必要になります。でもって、この変数宣言で値を設定しないのはミスじゃなくて故意だよってのをXcodeに知らせるために、型名の後ろに!をつけるってのがルールです。

 

 

 で、その後に続く

    let script = [
        "雨の日はだるい…\n今日は学校休んじゃおっかな〜",
        "誰だ"
    ]

てのは文字列配列の用意。

 こいつは [ ] (ブラケットペア)で囲んだ中に、複数の文字列を , (カンマ)で区切って並べることで作ります。

 

 

 こうすると、それぞれの文字列は配列の要素として格納され、配列の0番目の要素、1番目の要素というように、0から始まる続き番号(インディックス)で指定できるようになるんですよ。

 プログラム中でのインディックスの指定方法は、配列名の後ろに [ ] で囲んだ数値という書き方で次のように書きます。

 

 

 この [ ] で囲んだ数値は添え字と呼ばれ、これには整数型の変数・定数や計算式の結果も指定できるんですよ。

 

  let str = ["a", "b", "c"]  

  ↑ こんな感じで行を変えずに文字列を並べてもいい

    1行に1文字列としたりするのは、読みやすさを考えてのこと

  var a = 0

  print(str[a])   ← 0番目の文字列 a が出力される

  a += 1

  print(str[a])   ← 1番目の文字列 b が出力される

  a += 1

  print(str[a])   ← 2番目の文字列 c が出力される

  print(str[a - 2])  ← 0番目の文字列 a が出力される

 

 これが、今回のサンプルの肝なわけで、場面の進行に合わせて表示する文字列を変えるのに使ってます。

 それが、新しく追加しているtapメソッドでやってること。

    func tap() {
        if scriptIndex < script.count {
            message.text = script[scriptIndex]
            scriptIndex += 1
            if scriptIndex == script.count {
                UIView.animate(withDuration: 2, animations: { 
                    self.imageView.alpha = 1
                })
            }
        }
    }

 このメソッドはviewDidLoadメソッドで、画面をタップされるたびに呼び出されるように設定してて、配列scriptの要素数よりscriptIndexの値が小さい時だけ処理を実行するようにしています。それが最初のif文。

 

        if scriptIndex < script.count { … }

 

 配列scriptの要素数はcountプロパティで調べることができるので、scriptIndexがこれより小さいかどうかで比較して真偽を決定してる。

 scriptIndexとscript.countの間の記号 < は数学の記号と同じ意味で、右側より小さいという意味になります。もしその通りなら真となってif文の { } 内の処理が実行されるわけですな。

 ちなみに左側が右側以下の ≦ なら <= と書きます。右側より大きいは > 、右側以上は >= です。

 

 実行されたらscriptIndexで指定される要素が新しい文字列としてmessage.textに設定され、scriptIndexの値は1つ増やされます。

 

            message.text = script[scriptIndex]

            scriptIndex += 1

 

 でもって、scriptIndexが要素数と一致したなら、scriptIndexが示すインディックスは、配列の最後の要素を超えているってことになり(インディックスは0から始まるので、配列の最後の要素のインディックスは要素数-1)最後の場面に到着したことがわかる。

 そこでimageViewをジワリと現れるアニメーション(フェードイン)で表示させるようにしてるのが、最後のif文

 

            if scriptIndex == script.count {

                UIView.animate(withDuration: 2, animations: { 

                    self.imageView.alpha = 1

                })

            }

 

てやつです。

 画面をタップされるとtapメソッドが呼ばれるようにするのはどうするか?imageViewをフェードインさせるアニメーションを実行させてるUIView.animate(withDuration:…てのは何なのか?

 

 待て次回!

 

AD

全方位に投げつけろ!

 昔、うんこ投げるゴリラいたな。

 いや、そうじゃない。

 

 前回の実装は運動方程式に基づいて動かしてるので、当然、上に投げると重力で落ちてくるようになってます。

 

 ただ、カメラポジションとか立方体の大きさなんかも、初期高度を示す変数altitudeに依存させちゃってるので、altitudeを0mとかにすると画面が変になります。なので、元々のaltitudeは画面最大高度ということにし、新しく高度用変数positionを追加することにしました。で、このpositionを逐次更新することにしdisplacementは廃止します。

	var altitude = 828;		//	初期高度画面最大高度 m
	var startDate;			//	開始時刻
	var lastDate;			//	最後の移動処理の時刻
	var velocity = 0;		//	初速度 m/s
	var displacement = 0;		//	変位 m
	var position = 0;		//	高度 m

 それと、空気抵抗も落ちるの前提だったので、これを進行方向に逆らう形に直す。

	function sign(value) {
		return (value < 0) ? -1 : 1;
	}

	function updateTime(deltasec) {		
		・・・
		var spv2 = s / 2 * p * velocity * velocity * sign(velocity);
		・・・
		velocity += (-9.8 + (-a * Lnv - b * spv2) / m) * deltasec;
		・・・
	}

 こうしないと、投げ上げる時に空気抵抗で上方向に加速しちゃうことになるんでな。

 新しく追加したsignメソッドは、引数で受け取ったvalueの値が正なら1、負なら-1を返すというもの。その中でやってる

		return (value < 0) ? -1 : 1;

 は三項演算子( ? : )を使ったもので、条件によって値を変えたい時に使うもんです。

 

    条件 ? 条件が真の時の値 : 条件が偽の時の値

 

 結果、以下のように書いたことと同じ意味になります。

	if (value < 0) {
		return -1;
	} else {
		return 1;
	}

 後は、displacementの削除、positionの追加に合わせた細かな調整なので、説明は省略。重要なのはupdateTime関数の計算の変更で、こうすることで速度が上向きなら下向きに、下向きなら上向きに空気抵抗が働くことになる。

 これで準備OKなんで、例えば20m/sの初速度を与えれば…

 

    var velocity = 20;                    //    初速度 m/s

 ↓こうなる

 

http://www.tetera.jp/xcc/ameba/free-throw.html

 

 なかなかいい動きします。

 で、ここまできたら、せっかくの3次元表示なんで、縦横斜め、八方になげられるようにしたいですよね。私はしたいです。

 

 全然関係無いけど、よく言われる四方八方の8や、八極拳の8は3次元空間のx,y,z3軸、左右、上下、前後の組み合わせの8だから、平面上で8方向想像してた人、間違いだからそれ。一極集中(ビッグクランチ)の太極拳と、全方位膨張(ビッグバン)の八極拳です。小学校の頃、二極拳〜七極拳とかもあるのかと、そんな風に考えていた時期が俺にもありました。

 
 なので高度を扱うだけの上下方向のみだった速度や加速度、位置を3次元に拡張します。

 スカラ:scalarからベクタ:vectorへ。

 スカラってのは、これまで使ってきた単独の量のことね。

 

  5とか、2とか

 

 ベクタってのは、複数のスカラで構成される量。

 例えば、x軸、y軸、2つの座標値をペアにした2次元ベクトルってのを習ったと思いますが、あれがベクタです。

 1つの点の位置を表現するのに2つのスカラ値(x、y)を使っていたでしょ。

 

  (5, 2)とか

 

 

 ベクトルもベクタも、英語のvectorをどう読むかであって、全く同じだけど、日本では、ベクトルは「向き」ってイメージが強いっすね。

 

 でも複素数をベクタで表現(実数部, 虚数部)したりもするんで、一概に「向き」って言っちゃうのはどうかと思われ。スカラ、ベクタ混在で構成するベクタとかもあるし。そもそもスカラ値のプラスマイナスからして数直線上の向きって言えなくもないし…

 ちなみに複素数の複素平面(ガウス平面というのじゃよ)を見て、あれ、これ2次元表現するのにちょうどよくね?って極座標使ってeのなんちゃらってやってsin、cosの式を簡潔に書いたりするとか、3次元でも使える複素数あるんじゃねとか言ってハミルトンが4元数とか言い出す話はまた今度。

 

 まあどっちでもいい。

 

 で、Three.jsにも3次元ベクタがオブジェクトとして定義されてるんで、こいつを使って、先のプログラムを書き直しました。

	var velocity = new THREE.Vector3( 0.7, 20, 0);	//	初速度 m/s
	var position = new THREE.Vector3( 0, 1.7, 0 );	//	初期位置 m

 THREE.Vector3はx,y,zプロパティを持つオブジェクトです。

 プロパティ?オブジェクト?って人は「走れJavaScriptちゃん!」から出直してこい!

 ま、それはいいとして、上のように書くと、velocityは(x、y、z)要素の順に(0.7, 10, 0)が設定されたTHREE.Vector3オブジェクトを示すようになり、positionは( 0, 1.7, 0 )が設定されたTHREE.Vector3オブジェクトを示すようになります。

 で、このpositionのx、y、z値をsphereのpositionにcopyメソッドを使って設定しています。実はTHREE.Meshの持つpositionプロパティもTHREE.Vector3なのでこんなことができる。「超高校級のMikuMikuDance」で話した「positionはカメラオブジェクトのプロパティで、3次元空間でのカメラ座標を示す。この3D座標を表現するプロパティ自身もオブジェクト」もTHREE.Vector3。

	function arrengeObjects() {
		・・・
		sphere.position.copy(position);

 それと床に立方体を使うのはやめて平面(THREE.PlaneGeometry)にしました。ここら辺は自分で調べてみてください。

 updateTimeメソッドもTHREE.Vector3に合わせて変更してるけど、x、y、zそれぞれの要素に対して運動方程式で計算してるだけで違いはないです。

 加速度のy成分だけ重力加速度が追加されるわけやね。

		var F = new THREE.Vector3();
		F.x = - nR * velocity.x 
			- D * (velocity.x * velocity.x) * sign(velocity.x);
		F.y = - nR * velocity.y 
			- D * (velocity.y * velocity.y) * sign(velocity.y); 
		F.z = - nR * velocity.z 
			- D * (velocity.z * velocity.z) * sign(velocity.z); 

		var acc = F.divideScalar(m);
		acc.y += -9.8;

 それと人間を投げあげるのは豪快すぎるので、バレーボール投げあげることにします。

 

  半径:10cm

  質量:200g

 

としました。それに合わせ、粘性抵抗

 

 

については、バレーボールにしたことだし素直にナビエストークの式使って

 

    F = 6πrηv

 

とします。結局人間用のαがわからんかったからね。

 

 THREE.Vector3のaddメソッドは、引数で渡したTHREE.Vector3のx,y,z値を加算するというものです。

 例えば、a、b、二つのTHREE.Vector3オブジェクトがあれば

 

        a.add(b)

 

でaのx,y,zは、それぞれbのx,y,zが加算された状態になります。

 

   a.x += b.x;

   a.y += b.y;

   a.z += b.z;

 

 こんな感じ。「+=」は左辺の変数(またはプロパティ)に右辺の値を加算という意味ね。

 multiplyScalarの場合は、引数で渡した値がx,y,z値にかけられます。

 

        a.multiplyScalar(2)

 

なら

 

        a.x *= 2;

        a.y *= 2;

        a.z *= 2;

 

とやったことと同じです。「*=」は「+=」の掛け算版です。

 でもってdivideScalarはその割り算版。

 cloneメソッドは複製で

 

    b = a.clone();

 

でbは、aのx,y,z値を持つ、新しいTHREE.Vector3オブジェクトを示すことになります。

 

 詳細はupdateTimeメソッド見てもらうとして、これでようやく斜め発射もできるようになる。

 で、ここまできたら床で跳ね返らせたいわけですよ。

 なので、床に当たると速度ベクタを運動エネルギー保存則使って変換します。

 

   v' = v - 2(v・n)n

 

   v':衝突後の速度ベクタ

   v:衝突時の速度ベクタ

   n:床の法線ベクタ

   

 v・nってのは内積です。

 THREE.Vector3にはdotメソッドとして用意されてます。便利。

 完全弾性衝突なんで、エネルギー減らず、減るのは空気中の移動による抵抗だけってことで、ボールはしつこく跳ね続けます。

 

 ↓それが、これだ!

http://www.tetera.jp/xcc/ameba/free-throw-3d.html

 

    ↓jsdo.it版

http://jsdo.it/reborn_xcc/ULWR

 

 完全弾性衝突とか内積とか、法線ベクタとか、詳細は次回!

AD

リブートキャンプ by Swift 目次

 

 例えば、前回のサンプルにしても、説明されてないプロパティや、クラスが出てくるわけですが…

 

   ↓こんな感じで

   message.backgroundColor = UIColor.orange

 

 そういうときにどうするかって話です。

 

 基本、単語をコピペしてググればいいです。

 まあ「backgroundColor」をそのまま検索よりはmessageはUILabelのオブジェクトだから「backgroundColor UILabel」というようにキーワードを増やして検索した方がいいでしょうね。UILabelでダメなら派生元のUIViewとかね。

 ここら辺は、みなさん心得てるとおりです。

 

 なので、ここではそれとは別の、Xcodeのクイックヘルプを使う方法も紹介しておきます。

 Xcodeにはクイックヘルプという、クラスやプロパティ、メソッドを調べる機能が用意されているんですよ。

 

 ↓それがこれだ!

 

 

 クイックヘルプに出てくる説明文は英語なんで、なかなか敷居が高いと思いますが、それでもリンクたどって関連するクラスやプロパティ、メソッドを見つけたり、それを元にググるってことはできます。

 そうすると、日本語で解説してるサイトにぶち当たる可能性があるわけです。

 あと、上のビデオで紹介したDocumentation and API Reference画面で検索すると、Apple提供のサンプルコードを見つけたりもできるのよ。

 ここら辺はプログラミングに慣れた者には結構おいしいかも。

 なんせSwiftやObjective-Cは世界共通言語ですから〜。

 プログラミング初心者は、まあ、最初に言ったように入門サイト探してSwift Playgroundsなんかで学習しましょう。

 このリブートキャンプ by Swiftでも、極力説明していくつもりっす。

 

 

 

 英語読めるならガイドなんかもオススメ。

 対象のクラスやメソッドの使い方ガイドです。

 

 

 

 ガイドはありがたいけど、さすがに英語は〜という人は、ググるしかないんですが、そういう時にも検索に使えそうなキーワードが見つかったりするので、まあ諦めずに頑張れ。

 サンプル読んでて、知らない単語に突き当たった時の対処法はそんなとこです。

 

 んじゃ、そもそも、そのサンプルにたどり着くために、iPhoneにどんな機能があるかを調べるにはどーするのというと、このサイトです。

 

 ↓アップル・デベロッパー・サイト

https://developer.apple.com/jp/

 


 

 当然ですな。

 総本山。このサイト以上の情報源はあり得ません。ただし英語です。

 最初の日本語ページに騙されちゃダメ。ちょっと読み進めるとすぐ英語ページ飛ばされるから。

 ちなみに。一番上の「開発」タグをクリックすると、開発に関する情報ページが表示されます。

 

 

 最初に漁るのはWWDCのビデオがいいかな。

 

 

 2013〜2016年のもあるけど、基本最新の年からみるといいです。

 

WWDC 2017 Keynote

 
 で、新機能の大まかな説明、あとは興味のある機能別に観るって感じなりよ。

 こいつも英語なんで、わからない人にはさっぱり(しかもプレゼンしてるの、喋りのプロじゃないので、興が乗ってくるとマシンガントークになってくるし…)だけど、キーワードは得ることができるわけで、それ使ってググりましょう。

 

 何よりキーワードを見つけることが重要。

 

 キーワードをアップル・デベロッパー・サイト内で検索することも可能っす。

 

 

 例えばUIViewで検索してVideoでフィルタリングするとこんな感じ。

 

 

 キーワードを見つけてググって、日本語の説明サイト見つけて、サンプル見つけて、知らない単語出てきたらまた調べて、そんな繰り返しっす。

 ラノベ本のあとがきにも書いたけど

 

  心配ばっかして時間を無駄にせず、とりあえず突っ走ってみてください。

  意外となんとかなります。飛んでから着地点考えましょう。

 

 で、ちょっとだけ朗報。

 アップル・デベロッパー・サイトのガイドを訳した

 

 日本語ドキュメントのページ

 

があります。

 非常にありがたいし、アップル・デベロッパー・サイトのページからもリンクが貼られているんで公式だと思うんですが、たまにリンクが消えます。今も消えてる。

 とりあえず、上に貼ったURLは健在みたいなんで、そこでFAQでも紹介してる以下のガイドを読みましょう。

 

iOSアプリケーション プログラミングガイド

iOS View プログラミングガイド

iOS View Controller プログラミングガイド

 

 Apple純正のガイドを読みたいなら、ここら辺から読むのが順当だと思われ。

 もっとも、ここら辺は「iPhone アプリ 開発」で見つけたサイト読みながら勉強でもいいと思います。

 あとSwift言語に関しては究極の説明書が、iBooksでタダで読めます。

 

 

 まあ、英語なんですがね。

 あらゆる日本語のSwift解説本はこれを原本にしてます。してなきゃ嘘。

 ここら辺も「Swift入門」あたりで見つけたサイト読むのでいいんじゃないかとは思うが…

 興味がある人はiBooks開いてStoreを

 

 Swift Programming

 

で検索だ。

 

 長々話したけど、次回からは通常運転で行きます。

 サンプル用意して、上で書いた

 

   message.backgroundColor = UIColor.orange

 

の説明や、画面タップへの反応なんかを説明入れつつやって行きます。

 

 ↓こんな感じのアプリはどー作るのか?

 

 

サンプル:

http://tetera.jp/xcc/book-sample/RPG.zip

 

 ぶっちゃけ、こういうのはUnityとかUnrealEngine、Cocosなんかを使えばいいんですけどね。直接作ったほうがいいのはTwitterとか小遣い帳、ノートとか言ったユーティリティ系ですな。

 ただ、そういうのは地味なので、とっかかりとしてはこっちの方がいいんじゃないかと思われ。

 

 ちょっと長くなってるけど、やってることは画面の貼り付けがほとんどなんで、腕試しに、ヘルプやグーグル駆使して調べてみてください。

 答え合わせは次回。

 ちなみにViewControllerクラス定義中に出てくるプロパティ

    let script = [
        "雨の日はだるい…\n今日は学校休んじゃおっかな〜",
        "誰だ"
    ]

 

は、ノーヒントだと厳しいので配列という情報だけ教えときます。「swift Array」なんかでググってみてね。

 デワデワ。

 

AD