コイン落としゲーム①

Unity入門3

  • このスライドまでに【Unity入門3】まで終わっているかと思います。
  • ココでは、今までやった事のおさらいとして【コイン落としゲーム】を作成したいと思います。(ゲーセンとかにある感じのヤツです)
  • 今まで学んだ内容がほとんどになりますので、一つ一つの操作は説明しません。忘れた所は過去のスライドを読み直してください。
    • もちろんどうしてもわからない場所は質問してください。
  • 下の文字をクリックすると【Unity入門1】が開きますので、とりあえず開いておいたら便利です。

はじめに

  • 完成はこんな感じです。
    • ※画像は雑なイメージです。

完成図(イメージ)

  • Unityを起動し、新しいプロジェクトを作りましょう。
  • 名前は何でも良いですが、ここでは【CoinGame(コインゲーム)】で行きます。
  • [Location](ロケーション)は、ドキュメントの中の、自分のフォルダを指定してください。
    • ​※わからないければ必ず聞いてください。
  • ​​​プロジェクトが開けば、まずはScene(シーン)を保存しましょう。
  • ココではScene名も[CoinGame]としています。
    • ​※何でも良いです。

新しいプロジェクトを作成

  • まずはステージを作りましょう。
  • HierarchyからCubeオブジェクトを4つ作成し、合体させて以下の感じに仕上げます。
  • まずは全体像を確認してください。
    • 詳細は次ページ。

ステージ作成

  • 各オブジェクトの値は以下の感じです。
  • 名前は自由ですが、後々どれのことかわからなくならないように、気をつけましょう。

ステージ作成

  • 次に動く床を用意しましょう。(今は動かないですが)
  • 以下の感じでいきます。Pusher(プッシャー)という名前です。

動く床作成

  • この床はRigidbody(リジットボディ)を設定します。(方法は過去のスライドで)
  • Rigidbodyの項目の中で、下記の部分を変更します。
    • ※説明は次ページ
  • [Is kinematic](イズ キネマティック)をチェックをすると、物理演算(ぶつりえんざん)が無効になります。
  • 物理演算とは、普段Unityが勝手にやってくれているもので、「カベにぶつかった時に跳ね返される」とかのことです。
  • この【動くカベ】は、【他のカベ】をすり抜けて動かしているので、物理演算が有効だと吹き飛ばされてしまいます。そのため、無効にします。
    • ※試しにやってみても良いです。
  • ​ただし、動かせないわけではなく、スクリプトからは動かす事はできますし、他のコインを押したりはできます。
    • 他のオブジェクトからの影響は受けない】という感じです。

動く床作成

  • ちなみに、その上の[Use Gravity](ユーズ グラビティ)は重力をつけるかどうかです。
  • チェックが付いていると【重力を使う】、チェックがないと【重力を使わない】です。
  • 今回のケースだと、重力はどっちでも良いのでそのままにしています。
    • ※板の動かし方や、形状をアレンジした場合は、重力ありだと問題になる場合もありますので、その場合は外しておきましょう。
  • 真っ白だとわかりにくいので、色をつけておきます。
    • 何でも良いですが、それぞれのオブジェクトが見分けやすい状態にしましょう。
  • ここでは以下の配色にしました。(なんだかキモい色ですが、見やすさ重視です)

色をつける

  • さて、やっとプログラミングです。
  • 【床を動かす】ためのC#のスクリプトファイルを作成します。
  • 名前はMove(ムーブ:移動)にしています。
    • ここからの操作は【Unity入門2】【C#入門1】【C#入門2】の内容が出てきますので、とりあえず開いておいて、後で見直せるようにしておけば良いと思います。
      • 画面右下にリンク置いてます。

動く床作成

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Move : MonoBehaviour {

	// Use this for initialization
	void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
		
	}
}
  • さて、まずはどんなプログラムにするのか?その完成イメージを固めるのが大事です。
  • まず、やりたい事は「動く床を作成する」事です。
  • その””自体はもうすでに出来ていますよね?
    • つまり後は【動かす】プログラムを作れば良いと言うことです。
      • ※当たり前に思えるかも知れませんが、意外と【何をすれば良いか】を見失うこと多いので、【目的】を確認することは非常に大事です。
  • じゃあその【動かす】とは具体的になんでしょう?
  • それは 【床の座標(今回はZ軸)を変える】という事です。
    • もちろん一回だけ変えるのではなく「+の方向に動いたら、次は-の方向に動かし、それを繰り返させる」ことが必要です。
    • このように具体的に考えていけばスクリプトを作りやすくなります。

どんなプログラムか?

  • まずは、必要なフィールドを用意します。
  • 今回はStartメソッドもUpdateメソッドも使いますので、そのままで。(下では省略してます)

動く床のスクリプト

public class Move : MonoBehaviour {

        public float length;
	public float speed;
	Vector3 startP;
  • 一つ目の[public float length]と、その下の[public float speed]は、名前の通りlength(れんぐす:長さ)speed(スピード:速さ)を設定するための変数として用意しています。
  • この2つは、あとでinspector(インスペクター)ビューから数字を入れるためにpublic(パブリック)をつけています。
  • 一番下の【Vector3 startP】の、[Vector3](ベクトル3)は座標や傾き(方向)を指定するクラスでしたね。
    • 後で座標を保存しておくために、その変数を用意しています。
  • 次にStartメソッドの中を作りましょう。※Startメソッドはゲームの最初だけ実行される処理でしたね。

動く床のスクリプト

void Start () {
		startP = GetComponent<Rigidbody>().position;
}
  • これは、さっき作った変数【startP】に、【スタート時の座標】を保存しているコードです。
  • [GetComponent<Rigidbody>().position](ゲットコンポーネント<リジッドボディ>.ポジション)が、Inspectorビューの【rigidbodyコンポーネントの座標】という意味です。
  • 似たメソッドでオブジェクト自身の座標transformコンポーネントのposition)】を指定する[transform.position]メソッドがありますが、rigidbodyの座標】とtransformの座標】は基本的に同じです。
  • ただ、動かす時の内部的な処理が違いますので、基本的に
    • rigidbodyコンポーネントを追加しているオブジェクトは【GetComponent<Rigidbody>()().position】を使う。
    • rigidbodyコンポーネントがないオブジェクトは【transform.position】を使う。
      • と使い分けてください。
  • ちなみにtransform.position】は省略した書き方で、【GetComponent<Transform>()().position】でも同じ意味になります。
    • ​※尚、短く書けるのは[transform]だけです。残念!(前のバージョンは他も短く書けたけど禁止になった)
  • 次にUpdateメソッドの中を作りましょう。
    • ※Updateメソッドはフレームごとに何度も実行される処理でしたね。

動く床のスクリプト

void Update () {
	float z = length * Mathf.Sin(Time.time * speed);
}   
  • ここが山場です。
  • 最初に確認した【Z座標を+したり、-したりする】を繰り返す部分がこの部分です。
  • 今回はその処理に三角関数を使っています。
  • 三角関数とは高校(中学?)の数学で習う内容で、”さんかく”という親しみやすい名前の割には、けっこう難しいので、細かいことは数学の授業で習ってください。
    • 自分で勉強したい時は、このサイトとかわかりやすいかなと思います。
  • sin(サイン)、cos(コサイン)、tan(タンジェント)という3つの要素があって、今回はsin(サイン)を使います。(実際はもうちょっとあるけど使わない)
  • 上のコード内の​【Mathf.Sin()】(マス エフ.サイン)の部分がsin関数を使うメソッドです。
  • 三角関数自体は、無理に理解しなくても良いので「プログラミングでの使いかた」を理解しておいてください。

動く床のスクリプト

void Update () {
	float z = length * Mathf.Sin(Time.time * speed);
}   
  • [Mathf.Sin()]の引数に入れられた値は、ラジアン(弧度:こど)という角度(平面角)の単位で認識されます。
  • ​私達が普段、角度で使う0〜360度の数値は度数法(どすうほう)と言いますが、ラジアンを使うのは弧度法(こどほう)と言い、角度の単位が違います。
  • ​三角関数と同じく数学的な要素なので、それほど詳しく理解しなくてもOKです。
    • 大事なのは【どんな結果が返ってくるのか?】でしたね。​
      • ​続きは次。
  • さて、先ほどの【Mathf.Sin()(マス エフ.サイン)の引数を見てみましょう。
  • 左の【Time.time】(タイム.タイム)のはゲームが開始してからの時間が入っています。
    • ​つまり時間が経つごとに、中の数字が勝手に増え続けています。
  • 右の【speed】は、最初に作った変数です。これは自分で調節出来る値です。
  • この2つが掛け合わされて、Mathf.Sin()の引数に入っています。

動く床のスクリプト

  • ​​​​​実は不思議な事に、【Mathf.Sin()】に、値を与えると必ず【-1から1までの間の数】が返ってきます!!​(float型で
  • Time.timeの数値は増え続けますがMathf.Sin(Time.time * speed)】の結果が絶対に1を超えることはありません。
    • 1を超えると-(マイナス)方向に反転し、また-1を超えると+方向に反転することを繰返します。
  • その反転するまでの速さを【* speed】で調整しているわけです。
    • ※つまり【* speed】の部分はなくても動きます。ゆっくりになりますが。
  • さらに【length * Mathf.Sin(Time.time * speed)】の部分で【length(レングス)と-1から1までの間の数掛け合わすと、【lengthの数値の上下幅で】値が増減します。
    • ※たとえば、もしlengthが3なら-3から3の間の値、lengthが100なら-100から100の値になる。
  • つまり、【Mathf.Sin()が​​​​​必ず【-1から1までの間の数】になることを利用してどの範囲だけ動くのか?】を指定出来るのです。
  • 最後に、それを変数zに代入しています。
  • 後は、この【変数zの座標に動かす】という命令をくり返させれば、特定の範囲だけ動き続けることになります。
    • この部分は次で追加します。

動く床のスクリプト

void Update () {
	float z = length * Mathf.Sin(Time.time * speed);
        GetComponent<Rigidbody>().position = startP + new Vector3(0,0,z);
}   
  • 変数z分、座標を移動させる】のが、上の赤枠部分です。
  • 先ほども出てきた【GetComponent<Rigidbody>().position】に【startP + new Vector3(0,0,z);】を代入しています。
  • ​【startP + new Vector3(0,0,z)】は、【スタート時の座標(startP)に変数z分を足す】という処理です。
  • これをGetComponent<Rigidbody>().position】に代入することで、オブジェクトのRigidbodyの座標、つまりオブジェクト自身の座標がその座標に動きます。
  • ココまで出来たら、実際にPusherオブジェクトにアタッチしましょう。
  • ​その後にinspectorビューから、値を設定します。
  • ​まずは【length = 1.5】【speed = 1.5】ぐらいで動かしてみて、動きを確認してください。
  • ​ちゃんと動けば成功です!lengthで指定した範囲幅(-1.5から1.5)の間で行ったり来たりするはずです。
    • ​後は数値をイジって、自分好みの設定にしてください。(ゲームが成り立つ範囲にすること)

動く床のスクリプト

	void Update () {
		float z = length * Mathf.Sin(Time.time * speed);
                transform.position = startP + new Vector3(0,0,z);
        }   
  • さて、ちょっと話を戻します。
  • [Mathf.Sin()](マス エフ.サイン)についてですが、先ほど書いたとおり【引数に値を与えると-1から1までの値が返ってくるメソッドでした。
  • ​この引数にTime.time(ゲーム開始からの時間)を入れていますが、ぶっちゃけココは、「増えていく値」ならなんでも良いです。
  • 例えば以下の感じで、自分で数が増え続ける変数を作り、それを使っても良いです。
    • 細かい事を言うと[Time.time]ならフレーム処理に影響されないので、正確に一定の速度になります。
        float t;
	void Update () {
		t += 0.1f;
		float z = length * Mathf.Sin(t * speed);

		transform.position = startP + new Vector3(0,0,z);
		Debug.Log(Time.time);
	}
  • 試したら、元に戻しておきましょう。

コンソール出力

  • このように色々試したい時に、「実際に数字がどう変わっているのか?」を知りたい事は多いと思います。
  • そのためのメソッドとして【Debug.Log()(デバック.ログ)というものがあります。
  • このメソッドは、引数に与えられた値を【Console(コンソール)】画面に表示します。(Paiza.ioみたいに確認出来ると言うこと)
  • 下のようにUpdateメソッド内に記入します。とりあえず変数zの変化を見てみましょう。
  • Console】の画面は、[Project](プロジェクト)ビューのタブを[Console]に切り替えます。
    • ※切り替える場所は次のページ。
	void Update () {
		float z = length * Mathf.Sin(Time.time * speed);
                transform.position = startP + new Vector3(0,0,z);
                Debug.Log(z);
        }   

コンソール出力

  • 左下の画像の赤枠をクリックするとコンソール画面が表示されます。
  • では、ゲームをスタートして数値の変化を見てみましょう。
  • 右下の画像のように、どんどんログが表示されればOKです。
    • 確認出来れば【Debug.Log()】は消しておきましょう。
  • 尚、【Console】は、本来エラー内容など確認する際にも使われます。
  • 開発する際には非常に良く使いますので、覚えておきましょう。

プログラミングで使う数学

  • さて、今までのプログラミングではあまり出会わなかった【数学(物理学)的要素】が色々出てきましたね。
  • 何度も言っている通り、数学(物理学)な知識がないとプログラミングが出来ないというわけではありません。
  • ただし、ゲーム開発の分野では数学(物理学)的要素は非常に良く使われます。
    • というか【使われないことなどない】レベルです。
  • なのでゲームエンジニア(クリエイター)を目指したければ、数学や物理学は重要になります。
  • 学生時代は「数学の勉強なんて役に立たねーよ」なんて思いがちですが、ゲームエンジニアの分野ではめちゃくちゃ役に立ちます。
  • ​もちろんゲーム以外の分野でも、知っておいた方が良い知識は沢山あります。
  • 今から学校で習える人はめちゃラッキーと思ってください!数学(物理学)あと英語は、学生時代にがんばって学んでおかないと、後悔しますよ…
  • 以下の条件のスクリプトを【新しく】作ってください。(名前は何でもOK)
    • 条件①:inspectorビューから。速さを変化させられるように、変数speedを用意する事。
    • 条件②:inspectorビューから。動く距離を変化させられるように、変数lengthを用意する事。
    • 条件③:[Mathf.Sin()](マス エフ.サイン)を使って、アタッチしたオブジェクトのy軸を、1フレームごとに移動させる事。
    • 条件④:完成したスクリプトをすでにある「カベのオブジェクト(Backなど)」のいずれかにアタッチし、実際に動作を確認する事。
      • ※出来たら見せてください。その後に元に戻します。

試してみよう

  • 続いてはコインをつくりましょう。
  • 今まではCubeばかりでしたが、はじめてCylinder(シリンダー)を使います。シリンダーとは円柱(えんちゅう)のことです。
  • 作り方は以下の感じです。
    • 名前は[Coin](コイン)にしています。
    • 最初は大きな円柱が出てきますが、グッと縮めてコイン型にします。

コインを作成

  • CoinにもRigidbody(リジッドボディ)を追加しましょう。
  • 数値はイジる必要はないので、そのままです。

コインを作成

  • ここで一旦ゲームプレイしてみましょう。
  • コインの形と当たり判定が’違っていることがわかるでしょうか?
    • 拡大してみるとわかりますが、緑の枠が当たり判定です。
      • 拡大方法がわからない?それは次のページで。
  • 拡大縮小するためには、Sceneビューにマウスのポインターを合わせ、ホイールを回すだけで可能です。
  • それ以外にも左上のツールを押すことで、さまざまな操作が可能です。以下にまとめておきます。

拡大などなど

  • ①【手のマーク】の状態は、Sceneビューをクリックしながら動かすと、上下左右に視点をずらすことができます。
  • ②【上下左右の矢印】の状態は、クリックしたオブジェクトの座標(Position:ポジション)をマウスで動かす事が出来ます。
  • ③【回転した矢印】の状態は、クリックしたオブジェクトの回転(Rotation:ローテーション)させることが出来ます。
  • ④【外側に広がった矢印】の状態は、クリックしたオブジェクトの大きさ(Scale:スケール)を、座標軸ごとに変えることが出来ます。
  • ⑤【□】の状態では、クリックしたオブジェクトの大きさ(Scale:スケール)を、角を伸ばすような操作で変えることが出来ます。
  • また、それぞれはキーボードの「Q,W,E,R,T」で切り替える事も出来ます。
    • ※次ページにも続きます。

Q

W

E

R

T

  • またキーボードの左下らへんの[Altキー](オルト)を押すと押している間だけ【目のマーク】に変わります。
    • この状態で、ホイールを動かすと、マウスポインターを中心に拡大縮小されます。
      • さらにマウスの左クリックも押しっぱなし’にしながらマウスを動かすと、目線の角度が変えられます。
  • ちなみにあんまりグリグリ動かしていると、元に戻すのが大変なので注意。
  • 尚、開発画面の視点をいくら動かしても、ゲーム上の視点は変わらない(カメラオブジェクトが映している)ですが、これを一致させる方法もあります。
    • カメラオブジェクト(Main Camera:メインカメラ)をクリックしている状態で、Ctrl+Shift+Fキー(コントロール+オルト+エフ)を押します。
      • するとゲーム上のカメラが、開発画面のカメラと同じアングルになります。

拡大などなど

コインを作成

  • さて、話を戻します。
  • コインの周りを囲む緑の枠(当たり判定)のことを、Collider(コライダー)と言うんでしたね。
  • つまりこのコランダーを変更しなければいけません。
  • 現在付いているinspector(インスペクター)ビューには、「CapsuleCollider」(カプセルコライダー)というのが付いています。
  • これは名前通り、円状の当たり判定になっていますので、これを削除します。
    • 削除は[Remove Component](リムーブコンポーネント)でしたね。

コインを作成

  • このままだと当たり判定がないので、BoxCollider(ボックスコライダー)を追加します。
  • Inspector(インスペクター)ビューの一番下の[Add Component](アド コンポーネント)をクリックしPhysics】(フィジックス)、【BoxCollider(ボックスコライダー)をクリックで追加できます。

コインを作成

  • こんな感じになると思います。
  • このようにColliderコライダー)は、オブジェクトの形に合わせてカンタンに張り替えれます。
  • このままでも、ある程度はOKなのですが、よく見ると円の部分が角ばっていますよね?
  • 今回はもう少しリアルな動きにしたいので、別のColliderを使いましょう。
  • 先ほどと同じ操作で、今度は[Mesh Collider](メッシュ コライダー)を選択してください。
    • 追加出来たら、[Box Collider]は削除しちゃいましょう。

コインを作成

  • [Mesh Collider](メッシュ コライダー)のMesh(メッシュ)の意味ですが、ポリゴン(多角形)の集合体(あつまったもの)のことをメッシュと言います。
    • Unityの3D画面上のオブジェクトは基本的にすべてメッシュです。
  • そして[Convex](コンヴェクス?発音不明)とは、凸面の事です。
    • つまり【​[Mesh Collider](メッシュ コライダー)の[Convex](凸面)に対して Colliderを設定する】という意味になります。
  • 追加出来たら、[Convex]という項目にチェックをつけてください。
  • ここで一旦ゲームプレイしてみましょう。
  • 良い感じでコインが落ちてる状態だと思います。
  • 次は、このコインをバンバン出していけるように変更していきます。
  • バンバン作っていくためには、Prefab(プレハブ)を使いましょう。
  • coinオブジェクトをPrefabにしてください。
    • Prefabが出来たら、元のオブジェクトは削除しましょう。

コインを作成

  • ちなみに前回の【ボール飛ばしゲーム】と違って、今回は【撃つ玉(コイン)】も【飛ばされる玉(コイン)】も同じオブジェクトで大丈夫ですね。
  • では、新しいスクリプトファイルを作りましょう。
    • 名前は[CoinCreate](コインクリエイト)にします。
  • コインの出し方はいくつも考えられますが、今回は【クリックした場所に飛ばす】ような形にしたいと思います。
  • 【クリックした場所】に飛ばすのは、以前の【ボール飛ばしゲーム】でもやりましたね?なので、その時のスクリプト[Bullet Create]を流用して作っていきます。※下のコード
    • このスクリプトを忘れた人は、ざっとでも見返しておいてください。ココらへん

コインを飛ばす

public class BulletCreate : MonoBehaviour {
    public float power;
    public GameObject pre;
    void Update () {
        if(Input.GetMouseButtonDown(0)){
            GameObject bullet = Instantiate(pre);
            bullet.transform.parent = transform;
            bullet.transform.localPosition = new Vector3(0, 0, 0);
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            Vector3 dir = ray.direction;
            bullet.GetComponent<Rigidbody>().velocity = dir * power;
        }
    }
}
  • では、新しいスクリプトに、前回の内容(前ページからのコピペでOK)を貼り付けます。
    • 当然、クラス名は新しく作ったものに合わしてください。
  • 保存したら、このスクリプトを前回と同じようにカメラオブジェクトに貼り付けます。
  • その後、Inspectorビューから変数preに、さっき作ったcoinのPrefabを代入します。
  • 現時点で前回と同じようにコインを飛ばす事はできると思います。カンタンです。
    • このように【再利用】を考えてプログラムを作る事は非常に大事です。

コインを飛ばす

  • ただ、このままでは好きな場所にコインを飛ばすことが出来るため「コイン落としゲーム」としては成り立ってません。(コインを直接、谷底に落とせてしまうので)
  • そのためコインを飛ばせる場所を【背面のカベ(Back)をクリックした時だけ】に制限します。
    • 下の画像の赤色のカベです。
  • では、スクリプトを修正します。
public class BulletCreate : MonoBehaviour {
    public float power;
    public GameObject pre;
    void Update () {
        if(Input.GetMouseButtonDown(0)){
            RaycastHit hit;
	    if(Physics.Raycast(ray, out hit,100)){
		if( hit.collider.gameObject.name == "Back" ){	

                }
            }
            GameObject bullet = Instantiate(pre);
            bullet.transform.parent = transform;
            bullet.transform.localPosition = new Vector3(0, 0, 0);
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            Vector3 dir = ray.direction;
            bullet.GetComponent<Rigidbody>().velocity = dir.normalized * power;
        }
    }
}

コインを飛ばす

  • if (Input.GetMouseButtonDown(0)) 】の中に、if文がさらに2つ増えていますね?
  • 背面のカベ(Back)をクリックした時だけ】を追加するために、rayが何かにぶつかったなら】と、もし、ぶつかったのがカベ(Back)なら】の2つが必要になるわけです。
    • 詳細は次ページ。
  • 先ほど追加したコードは【Ray(レイ)が、どのオブジェクトにぶつかったかを判定する時】に書く、お決まりの書き方です。
    • まるっと覚えてしまう方が良いでしょう。
  • まず【RaycastHit hit】という変数を作っています。
  • RaycastHit】(レイキャストヒット)とは【Rayがぶつかったオブジェクト】を入れておくためのクラスです。
    • つまりぶつかったオブジェクトが、この変数【hit】に入ることになります。

out修飾子に関しては、ちょっとややこしいので別の機会にやります。

コインを飛ばす

  • 次は、2つのif文のうち、もし、rayが何かにぶつかったなら】を表す【if (Physics.Raycast(ray, out hit,100))】の部分です。
  • Physics.Raycast()】(フィジックス.レイキャスト)とは、Rayとオブジェクトの衝突(しょうとつ)を判定する時に使うメソッドです。
    • 第1引数に開始位置(どのrayなのか?)※今回は変数rayしかないのでray
    • 第2引数に衝突したオブジェクト変数hitoutという修飾子をつけて指定します。
    • 第3引数にどこまでの距離を調べるの(今回は100の距離)
      • ​を指定します。
  • ​​このように指定すると、【カメラの位置から、100までの距離の間で、何かしらのオブジェクトにぶつかた時】という条件分岐が可能になります。​​​​​​

コインを飛ばす

  • ​​​​残りのif文もし、ぶつかったのがカベ(Back)なら】を表す【if ( hit.collider.gameObject.name == "Back" )】はカンタンです。
  • hit.collider.gameObject.name(ヒット.コランダー.ゲームオブジェクト.ネーム)は【hit変数の中の入っているオブジェクト(つまりぶつかったオブジェクト)の名前】という意味です。
  • ​それを【=='Back'】で比較する事でもし、ぶつかったのがカベ(Back)ならという条件判定になります。
  • これで背面のカベ(Back)をクリックした時だけ】の判定が出来るようになりました。​​​​
  • まだ、このコードでは玉は飛びません。
  • なぜなら【背面のカベ(Back)をクリックした時だけ】という判定や、前のゲームで作った【クリックした場所に飛ばす】というコードはありますが、並んでいる順番がおかしいからです。
  • このコードを正しく並び替えて、ちゃんとコインを飛ばせるようにしましょう。
    • 逆にいうと後は正しく並び替えるだけで完成です。コードの追加も訂正もいりません。
    • ヒント:【if (Physics.Raycast()】の引数で使う【変数ray】は、先に作っておかないといけませんね。
public class BulletCreate : MonoBehaviour {
    public float power;
    public GameObject pre;
    void Update () {
        if(Input.GetMouseButtonDown(0)){
            RaycastHit hit;
	    if(Physics.Raycast(ray, out hit,100)){
		if( hit.collider.gameObject.name == "Back" ){	

                }
            }
            GameObject bullet = Instantiate(pre);
            bullet.transform.parent = transform;
            bullet.transform.localPosition = new Vector3(0, 0, 0);
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            Vector3 dir = ray.direction;
            bullet.GetComponent<Rigidbody>().velocity = dir.normalized * power;
        }
    }
}

試してみよう

  • 完成しましたか?
  • どんどんコインを出してみるとわかるかも知れませんが、実は少し変な所があります。
    • 動く床(Pusher)の上に乗ったコインが、なぜか止まったままで動いてませんよね?(他のコインに押されると動く)
    • 正しい動きは下の動画のように、【動く床の上のコイン】は動く床と同じように動くはずです。

確認しよう

  • これは【動かす方法】の問題で、実は【GetComponent<Rigidbody>().position】というのは、瞬間移動と同じ動きをします。
  • つまり【途中】がないので、コインは元の場所に置き去りにされた状態になり、一緒に動いてくれないわけです。
  • 言い方を変えると、瞬間移動だと【移動途中は物理演算がされない】ということになります。

コインとPusherを合わせる

void Update () {
    float z = length * Mathf.Sin(Time.time * speed);
    GetComponent<Rigidbody>().MovePosition(startP + new Vector3(0,0,z));
}
  • 変更できたら、ちゃんと動く床とコインが一緒に動くか確かめてみましょう。
  • これを解決するためには移動途中も物理演算される】方法で動かす必要があるわけです。
  • この移動途中も物理演算されるメソッドとして【GetComponent<Rigidbody>().MovePosition】というものがありますので、こちらに変更して見ましょう。
  • 下のように【GetComponent<Rigidbody>().MovePosition】に変えてみましょう。
  • ちゃんと「コイン」と「動く床」が一緒に動くようになりましたか?
  • このようにただ「動かす」方法も色々あります。

コインとPusherを合わせる

  • 基本的な動きでも、
    • Transformコンポーネントで動かすのか?
    • Rigidbodyコンポーネントで動かすのか?
  • や、そこからさらに、
    • ​​position(座標:途中経過を計算せず、ワープのような動き)で動かすのか?

    • MovePosition(座標:途中経過も計算する動き)で動かすのか?

    • velocity(速度)で動かすのか?
    • AddForce(力)で動かすのか?
  • など考えることは沢山あります。

  • また、これに【回転・方向】などの要素も考えなければ思ったとおりの動きにはなりません。

  • 「物体を動かす」というのは単純なようで、実はかなり難解なのです。

  • まぁぼちぼち学んでいきましょう。

  • さて、ちょっと細かな点ですが、もう1つイジる場所があります。
  • さきほどの[GetComponent<Rigidbody>().MovePosition](ゲットコンポーネント<レジットボディ>ムーブポジション)は、物理演算をしながら動かすメソッドでしたね。
  • この物理演算のタイミングですが、実はUnityの物理演算は【必ず一定の間隔(デフォルトでは0.02秒:50fps)】で計算されています。
  • ただ、それをくり返しているUpdateメソッドは【フレームごと】に処理されていましたよね?
    • つまり【物理演算のタイミング】と【動かすメソッドタイミングズレてしまうのです。
  • ​するとどういう事になるかというと「突然グンッと動いたり」「ほとんど動かなかったり」という現象がおきます。つまり[カクつく]というヤツです。(このゲーム程度ではあまり影響は少ないですが)
void FixedUpdate () {
		float z = length * Mathf.Sin(Time.time * speed);
		GetComponent<Rigidbody>().MovePosition(startP + new Vector3(0,0,z));
}

コインとPusherを合わせる

  • というわけで、実は物理演算があるRigidbodyがある)オブジェクト動かす場合は【Updateメソッドは使いません】
  • 変わりに【FixedUpdate ()】(フィクスドアップデート)というメソッドが用意されています。
  • ​これは【物理演算のタイミングと同じ間隔で呼び出されるメソッドです。
  • ​​​​​​​これを使えばカクつきにくいゲームになりますので変更しておきましょう。
    • Update ()】→FixedUpdate ()】にするだけです。
  • ここで、「じゃあ常に[FixedUpdate()]で良いんちゃうん?」って思うかも知れませんが、そんな事はありません。
  • 例えばマウスやキーボードなどのクリックは【フレームごと】の処理です。
    • これはプレイヤーが見ている画面の更新もフレームごと】なので当然ですね。
  • もし、FixedUpdateメソッドの中に書くと【クリックした時】と【クリック判定をするメソッド】のタイミングがズレます。
  • すると【クリックしても反応しない時間】が生まれてしまいます。

Update()とFixedUpdate()

  • このように基本的にはフレームごと】の処理の方が多いので、Updateメソッドが基本とし、FixedUpdateメソッドは、スクリプトから物理演算をさせる処理だけに使います。
  • つまり「Rigidbodyを動かす処理だけ、FixedUpdate()を使うとだけ覚えておいてください。
  • さて、今のままだとスタートした時にコインがまったく用意されていないので、「落とす」ことが出来るようになるまで、何度もコインを発射しないといけません。
  • そのため「ゲームスタート時にコインを用意しておく」プログラムを作りましょう。
    • キレイに整列して並べておくことも出来ますが、今回は実際のコイン落としに似せたいので、ランダムに配置されるようにします。
      • ※coinは黄色にしていますが、自由に色も変えてください。

最初にコインを用意する

  • コイン自体はすでにある[Coin]を使えば良いので、スクリプトだけを考えます。
  • スクリプトも[CoinCreate]スクリプトに追加で記入することにします。
  • 以下の画像の状態にしてください。
    • 今度はスタート時だけの処理なので、Startメソッドを追加しています。
      • ※解説は次ページ。
public int startCoin;

void Start () {
	int x,y,z;
	x = Random.Range(-4, 4);
	y = Random.Range(0, 20);
	z = Random.Range(0, 4);
	Instantiate(pre, new Vector3(x, y, z), Quaternion.identity);
	
}

最初にコインを用意する

  • Startメソッドの外の変数【startCoin】(スタートコイン)は最初に用意しておくコイン数を入れるための変数です。後でinspectorビューから設定したいので、public(パブリック)にしています。
public int startCoin;

void Start () {
	int x,y,z;
	x = Random.Range(-4, 4);
	y = Random.Range(0, 20);
	z = Random.Range(0, 4);
	Instantiate(pre, new Vector3(x, y, z), Quaternion.identity);
	
}
  • 尚、初期化までする場合は、[int x=0,y=0,z=0;]というように書く事もできます。
  • 今回のようにxyzなど関連性のある変数ならいいですが、なんでもかんでも省略するとめちゃ解りづらくなるので、基本は略さない方が良いでしょう。

最初にコインを用意する

  • [int x,y,z]の部分は複数の変数を同時に宣言する書き方です。つまりこれは下記と同じ意味です。
  • [Random.Range](ランダム.レンジ)はその名の通り、乱数を返してくれるメソッドです。
  • 第1引数に開始の値、第2引数に終わりの値を設定すると、その間の値をランダムで出してくれます。
  • 今回はint型にしていますが(-4.0f,4.0f)などとするとfloat型double型にも自動でしてくれます。
    • ※ちなみint型なら(-4,4)なら【-4から3】までの整数が候補に選ばれます(4は含まれない)が、float型double型だと-4.0から4.0】までの数が候補に選ばれます(4自体も含まれる)
  • つまり上のコードでは、変数x,y,zに、それぞれの乱数を代入しているということですね。
public int startCoin;

void Start () {
	int x,y,z;
	x = Random.Range(-4, 4);
	y = Random.Range(0, 20);
	z = Random.Range(0, 4);
	Instantiate(pre, new Vector3(x, y, z), Quaternion.identity);
	
}

最初にコインを用意する

  • 最後に【Instantiate()】(インスタンシエイト?)は、すでに何度か使っていますが、Prefab(プレハブ)をインスタンス化(実体化)するためのメソッドでしたね。
  • 今までは【Instantiate(pre)】とだけ指定してましたが、今回は座標も指定して作るために引数が増えています。
    • 第1引数は、今まで通りオブジェクトにするPrefabを指定します。
    • 第2引数が座標の指定で【new Vector3(x, y, z)】とすると、先ほどの乱数の座標になります。
    • 第3引数は【回転】を指定する引数で、【Quaternion.identity】(クォータニオン.アイデンティティ)とすると回転していないという事を表します。つまり、無回転というのを表しています。
      • ※今回、【回転】は何でもいいので、指定しなくて良いんですが、【Instantiate()】メソッドの第2引数に[new Vector3()]を指定した場合、この回転に関する指定もしなければいけない(エラーになる)ので、無回転を指定しています。
public int startCoin;

void Start () {
	int x,y,z;
	x = Random.Range(-4, 4);
	y = Random.Range(0, 20);
	z = Random.Range(0, 4);
	Instantiate(pre, new Vector3(x, y, z), Quaternion.identity);
	
}

最初にコインを用意する

  • ちなみに[Quaternion](クォータニオン)というのは、またもや数学的要素で、日本語でいうと四元数(しげんすう)と言い、3Dゲームなどでは回転の計算でよく使われています。
  • ただ非常に難解で、数学的に理解をするのはかなり難しいので、詳しくは触れません。
    • このサイトの解説がわかりやすいですが、まぁ今は気にしなくてもいいです。

最初にコインを用意する

  • さて、現在のコードでは、最初にコインが一つ出てくるだけです。
  • 下記のコードを少し修正して最初にコインが100個出てくるようにしてください。
    • ヒント:繰り返し文を使い、startCoinの回数分繰り返しましょう。
      • 尚、おそらくスタートした時に、何個かコインがフロアー落ちることがありますが、特に問題ないものとして進めます。
public int startCoin;

void Start () {
	int x,y,z;
	x = Random.Range(-4, 4);
	y = Random.Range(0, 20);
	z = Random.Range(0, 4);
	Instantiate(pre, new Vector3(x, y, z), Quaternion.identity);
	
}

試してみよう

  • 良い感じに出るようになりましたか?
  • ランダムな場所に作るとどうしても最初に飛んでいってしまうコインがでます。
  • ランダムではなく、少しづつ座標を変えながら置いていけば防げますがこのまま進めます。
    • 規則正しく並べたい場合は、自由に変更してみてください。
  • 他には、コインを飛ばす時に横になって飛んでいきますが、これを縦にしてもおもしろいかも知れません。(実際のコインゲームは大体縦で転がっていきます)
    • 最終的にどうするかは自由ですが、Prefab(プレハブ)の[Coin]のRotation(ローテーション)の値を変えてみて、色々試してください。
  • ちなみに上の画像のようにすると、コインが縦に飛んで行きます。

コインの飛び方を変える

  • 次は以下のようなゲームシステムを作っていきましょう。
    1. 最初に100個のコインを持っている。
    2. コインを投げるごとに1減っていく。
    3. 画面手前にコインを落とせた場合のみ、落とした枚数分、手持ちのコインが増える。
    4. コインの増減を画面端に表示させておく。
  • 1の部分は変数に値を代入するだけですので、考えるまでもありません。
    • 後は2の【コインを減らす】という処理と、
    • 3の【コインを増やす】という処理と、
    • 4の【現在のコイン数を表示させておく】処理だけです。カンタンですね。

ゲームシステムを作る

  • このコイン数を変えるロジック部分は、一つのスクリプトにまとめておきたいので、新しいスクリプトを作ります。
    • 名前は[CoinNum]にしておきましょう。(NumはNumber:数字の略)

ゲームシステムを作る

  • まずは最初のコイン用の変数【coinStock】(コインストック)を作ります。
  • 今回はprivate(プライベート)をつけています。
  • privateをつけると、「そのクラスのみ」アクセスが可能になるんでしたね。つまりは、[CoinNum]クラス内だけでしか使えない変数というわけです。
    • これがどういう意味を持つかは、また後でやります。

ゲームシステムを作る

public void CoinDown(){
	coinStock--;
}
  • 次に[コインを減らす]処理として【CoinDown】というメソッドを作ります。
  • 中身は【coinStock--】だけです。
    • --(デクリメント)は1減らすという意味でしたね?(正確には1減らした数を代入し直す)
  • ​このメソッドを別クラスから呼び出せば、先ほどprivateにした変数【coinStockの数を減らすことが出来るわけです。
  • ​でも、なんだかムダに手間がかかって面倒くさい感じがしますよね?
  • 実際、変数coinStockprivateじゃなく、pubilc(パブリック)にしておけば、直接別のクラスから数字をイジれます。
    • つまりCoinDown】メソッドを作る必要もないのです。
  • でも、わざわざ面倒くさいことをするのには、ちゃんとわけがあります。
    • ​※​次ページに続く。

カプセル化

  • では、先ほどの変数coinStockpublic(パブリック)にした場合を考えてみましょう。
  • 【直接イジれる状態】というのは【どんな値でも入れられてしまう】という事です。
  • つまり間違って+100や、関係のない値("こんにちは"など)を代入してしまう可能性もあるということです。※C#なので、キャストできない型が指定されたらその時点でエラーが出ますが。
  • 自分一人で作っている時や、単純なプログラムの場合は「気をつければええやん」って話ですが、複数人で分担して作っていたり、複雑なプログラムの場合は、ミスしてしまう可能性は十分あります。
  • そのため、プロの世界では基本的に、このように【なるべくイジれないように】プログラムが作られます。
  • このような作り方を【カプセル化】と言います。
  • また、カプセル化は間違いを防ぐだけではなく「 内部がどうなっているか隠す(隠蔽:いんぺい)」という役割もあります。
  • 隠蔽できることによって、プログラムの大事な部分は隠しながらも、その機能だけを他者に使ってもらえたりも出来るわけです。
  • たとえば、色んな企業で「うちの、このプログラム(API)使っても良いよ」とプログラムを公開することはあるのですが、カプセル化しておけば、勝手に中身を書き換えられたり、作り方を盗まれる危険を防ぐことも出来るというわけです。
    • (公開する理由は様々ですが)​
  • ​​​​​​ 今回は、そのカプセル化も用いて設計していきましょう。

coinを増やすメソッド

  • さて、続いては[コインを増やす]処理です。
public void CoinUp(){
	coinStock++;
}
  • これも単純で[++](インクリメント)は1増やすという処理でしたね。
  • こんだけです。
public void OnGUI(){
	GUI.color = Color.black;
	string label = "残りのコイン:" + coinStock;
	GUI.Label(new Rect(0,0,200,50),label);
}
  • 最後は文字を表示させる部分です。
  • 以前は、テキスト表示のオブジェクトを作っていましたが、今回はスクリプトのみで文字を表示させて見ましょう。
  • OnGUI】(オンジーユーアイ)メソッドを呼び出すと、Hierarchy(ヒエラルキー)ビューで[UI]→[Text]で、オブジェクトを作るのと同じ事が出来ます。
  • GUI.color = 】の部分で、文字の色を指定しています。(今回は[Color.black]、つまり黒)
  • string label = 】は、表示する内容を変数にしています(今回は"残りのコイン:" + coinStock
  • GUI.Label()】は、UIの場所や内容を表示するメソッドです。
    • 第1引数の[new Rect(0,0,200,50)]のRect(レクト)とはrectangle(レクトアングル)の略で、日本語でいうと長方形を意味します。
      • Rect()の引数はそれぞれ(左からの開始位置、上からの開始位置、右の終わり位置、下の終わり位置)を指定できます。※数字を変えてどう変わるか確かめましょう。
    • 第2引数で、表示する内容を指定しています。(先ほど作った変数labelを表示させています)

文字を表示させるメソッド

  • これで必要なメソッドは揃いました。
  • 空のオブジェクト【CoinNumを作り、このスクリプトを貼り付けてから、動かしてください。
    • 現時点では、左上にテキストが表示されればOKです。
  • 後は、
    • コインを打つ時に【CoinDown】メソッドを、
    • コインを手前に落とした時に【CoinUp】メソッドを、
      • それぞれ呼び出せば、表示されるコインの数が増減するはずですね。

文字を表示させるメソッド

  • では【CoinDownメソッドを、呼び出す場所(コードを書く場所)とは、当然【CoinCreate】ですね。
    • ここに追加で書いていきます。

文字を表示させるメソッド

public CoinNum coinNum = new  CoinNum();
  • しかし!Unityの場合はこの作り方が禁止されています!
  • Unityでは通常のC#の方法とは違って以下のように作ります。
  • 【=】から右側が丸々不要になります。
  • もちろん、まだ変数の中身は空の状態ですので、後でInspectorビューからスクリプト(CoinNum)を代入します。
    • つまりこの行動が= new  CoinNum();】と同じになると考えてください。
  • Unityでは、【自分で作った別クラス(スクリプト)】 は、このようにインスタンス化します。
    • ちょっとややこしいですが覚えておきましょう。
  • まず別クラス(スクリプト)のメソッドを使うためには、その型(クラス)のインスタンスが必要でしたね。
  • C#で、他のクラスのインスタンスを作る方法は以下でしたね。

文字を表示させるメソッド

  • さて、この変数【coinNum】は【CoinNum】クラスのメソッドがつかえますので、【coinNum.CoinDown()(大文字、小文字に注意)を【玉が発射される場所】に付け足せば良いでしょう。
if( hit.collider.gameObject.name == "Back" ){	
    coinNum.CoinDown();
    //他のコードはしょうりゃく
}
  • 最後に、玉を飛ばすオブジェクト(MainCamera)のinspector(インスペクター)ビューに【CoinNum】が増えているはずなので、そこに、空オブジェクトの【CoinNum】を貼り付けましょう。(コインナムばっかでややこしくなってしまった…色でわけています)
    • こうして初めて【CoinNum】クラスのメソッドが、CoinCreate】から使えます。

制限をかける

if ( 0 < コインの数 ){
     コインを飛ばすプログラム;
}
  • ちゃんと減るようになりましたか?
  • 実は、現時点ではコインの数が0以下になっても、コインを撃つことが出来てしまいます(なんの制限もかけていないので当然です)
  • 次は【0以下になるとコインが出ない】ようにしていきましょう。
  • さて、まずは考え方です。
  • 0以下ならコインを出さない」というプログラムを素直に考えると、下記の感じになると思います。
  • もうすでに「コインを飛ばすプログラム」(CoinCreate)はあるので、後は「コインの数」を調べられば良いだけです。
  • しかしここで問題があります。「コインの数」とは変数【coinStock】でした。
    • でもこの変数はprivate(プライベート)が付いているため、他のクラス(コインを飛ばすスクリプト)から呼び出す事ができませんでしたね。
    • 呼び出せないということは比較できないので「0より大きいのか?」がわからない事になります。
    • こんな時は「値を返すだけのメソッド」を用意しておく事で、対処できます。
      • ※次に続く
  • [CoinNum]スクリプトに「CoinStockの値を返す」だけのメソッドを作ってください。
    • ヒント①「値を返す」とは、言い方を変えれば「戻り値」です。
      • つまり「戻り値としてcoinStockを返すメソッドを作る」という事です。
    • ヒント②:戻り値の返すには、return(リターン)が必要です。ココらへんを確認。

試してみよう

  • さきほど作ったメソッドを使い、コイン数が0以下なるとコインが出ないようにしてください。
  • 尚、作っている最中はcoinStockの数を5ぐらいにしておきましょう。(100個も打ってるとめんどくさいので)
    • ヒント①:カンタンなので特になし。どこでif文を使うか?それだけです。

試してみよう

  • 次は【CoinUp】メソッドを使ってコインを増やす処理を作っていきます。
  • さて、まずは考え方です。増えるための条件は「画面手前に落ちる」でしたね。
  • 以前作ったボールを飛ばすゲームと同じように、画面手前に「見えないオブジェクト」を用意しておいて、それにコインが触れると点数が上がる(CoinUpが呼び出される)感じで良さそうです。
  • では、早速オブジェクトを作っていきます。※名前は[CoinUpFloor]にしています。
    • ベースはCubeオブジェクトで良いでしょう。以下の感じで仕上げてください。
  • 後は、見た目を消すために【Mesh Renderer】(メッシュレンダラー)を削除するか、チェックを外すのを忘れないでください。
    • また、トリガー(判定)だけの存在にしたいので【BoxCollider(ボックスコライダー)】の【is Trigger(イズトリガー)】にチェックもしておきましょう。※詳しくはココらへん

coinを増やす処理

  • 次に、このスクリプトを作ります。※名前は同じく【CoinUpFloor】にしています。
  • 前のゲームで作った 【Hit】スクリプトを使いまわせそうですのでもって来ましょう。
    • ※クラス名はもちろん変えてください。​内容を忘れたならココらへんをチェックしておきましょう。
  • 今は上の感じのハズです。
  • タグ("scoreUp")を"coin"に変えておきましょう。
  • Score.score++】も今回は使いませんので、消しておきましょう。
public class Hit : MonoBehaviour {
	void OnTriggerEnter ( Collider co  ){
		if(co.gameObject.tag == "scoreUp"){
			Score.score++;
		}
	}
}

coinを増やす処理

  • そして、忘れないうちに、Prefab(プレファブ)の【coin】にタグをcoinと設定しておきましょう。※詳しくはココらへん
  • 以下の感じになったらOKです。
  • CoinUpFloorオブジェクトにアタッチしておきます。
public class CoinUpFloor : MonoBehaviour {
	void OnTriggerEnter ( Collider co  ){
		if(co.gameObject.tag == "coin"){
			
		}
	}
}

coinを増やす処理

試してみよう

  • 先ほどのCoinUpFloorスクリプトから【coinUp】メソッドを呼び出し、点数が増えるようにしてください。
    • ヒント①:条件部分は出来上がっていますので、処理の部分を書くだけです。
      • ※必要なフィールドは別途追加してください。
    • ヒント②:少し前にやった問題とほとんど同じです。

試してみよう

  • 現在のCoinUpFloorスクリプトのままでは、コインが消えてもオブジェクトが削除されずに残ってしまっています。
    • ​見た目にはわかりませんが、内部的にどんどん処理が重くなります。
  • ゲットしたコインのオブジェクトはちゃんと削除されるようにしましょう。
    • ​ヒント①:削除するメソッドは下です。

エフェクトを付ける

  • これで、ゲームの大枠が出来ました。
  • 後は少し味付けをしましょう。
  • 次からは、今までやってこなかった「effect(エフェクト)」部分を少し考えていきます。
  • エフェクトとは「効果」みたいな意味で、ようは見せ方などの演出部分の事です。
    • エフェクトはかなり色々あるので、とりあえずは一番よく使われるエフェクトであるparticle(パーティクル)を使ってみましょう。
    • particleとは粒子(りゅうし)のことで、キラキラキラーン★みたいな感じに見せることが出来ます。(下の画像)

particleを作る

  • 実際にやって行きます。
  • 考え方としては、particle(パーティクル)も「一つのオブジェクト」として作成します。
  • まず、Hierarchy(ヒエラルキー)ビューのCreate(クリエイト)から[Particle System](パーティクルシステム)を選択します。
  • すると、キラキラを発生させるオブジェクトが出てきます。このparticle発生機の事を【emitter(エミッター)】と言います。
  • 後はコイツを使って、「コインが消えた時(コインが増える時)」にキラキラさせてみましょう。

particleを作る

  • まずは、キラキラの設定を変えてみましょう。
  • inspector(インスペクター)ビューの[Particle System](パーティクルシステム)をいじれば色々変えれますが、かなり項目が多く、複雑なので今回はよく使われる場所をいじりましょう。
    • ​次に続く。

particleを作る

  • Duration(デュレーション)
    • 継続時間の事で、何秒パーティクルを出すかの指定です。ただし下のループ設定がオンだと延々ループするだけです。
  • Looping(ルーピング)
    • ループさせるかどうかです。ループさせるとずっと出続けるので基本オフにしておきましょう。
  • Start Lifetime(スタートライフタイム)
    • パーティクル自体の寿命です。発生してから消えるまでの時間ということです。
  • Start Speed(スタートスピード)
    • パーティクルの初速です。勢い良く飛び出すかどうかです。
  • Start Size(スタートサイズ)
    • 一粒一粒の大きさです。
  • Start Color(スタートカラー)
    • 色です。
  • Gravity Modifer(グラビティモディファイア)
    • 重力の設定です。プラスの数字で下に、マイナスの数値で上にいく感じです。

 

※次ページにサンプル値をのせておきますので、参考にしてください。

particleを作る

サンプル

particleを作る

  • 今作ったエミッターをPrefab(プレハブ)にしましょう。
  • コインなどと同じで、「同時に複数出現するオブジェクト」なのでPrefabにしてから使います。
    • 作り方はコインの時と同じなので、説明は省きます。
  • Prefabにすると以下の感じで表示されると思います。
  • 名前も【GetEffect(ゲットエフェクト)】に変更しています。
  • Prefabが出来れば元のオブジェクトは削除しておいてください。

エフェクトを作るスクリプト

  • では準備が整ったところで、スクリプトを書いて行きましょう。
  • 今回考えるべき事は、以下の2点です。
    1. コインをゲットした時にエフェクトを表示させる。
    2. 終わったら消す。
  • すでにコインをゲットした処理(コインが増える処理)は出来ていますので、そこに追加して行きましょう。そう、もちろん【CoinUpFloor】スクリプトです。
Instantiate(effectPre,co.transform.position,Quaternion.Euler(-90,0,0));
  • 上が、Prefabを作る処理です。もう何度も使っている[Instantiate()]メソッドですね。
    • 第1引数は、対象のPrefabを指定でした。
    • 第2引数は、座標でしたね。
      • co.transform.position】とはco(ぶつかったオブジェクト:つまりコインのこと)の座標のことです。
    • 第3引数は、回転の指定でしたね。
      • Quaternion.Euler(クォータリオン.オイラー)】とは、またもや四元数のメソッドの1つで、四元数をオイラー角というわかりやすい座標の指定方法に変換してくれるメソッドです。
      • 上記のように引数にxyzの値を与えると、それぞれの軸の角度を指定できます(-90,0,0)であればx軸にだけ-90度回転させているという感じです。
      • これはInspectorビューの【Transform】の【Rotation】の項目と同じです。
        • 回転させておかないと上に飛んでくれないための処理です。

試してみよう

  • CoinUpFloorスクリプトの適切な場所に、エフェクトを呼び出す処理を追加してください。
    • ​ヒント①:下がその処理です。(前ページと同じ)
    • ヒント②:必要なフィールドを用意しておかないといけません。
      • 型はGameObjectで、後でinspector(インスペクター)ビューから代入できるように作りましょう。
Instantiate(effectPre,co.transform.position,Quaternion.Euler(-90,0,0));
  • 完成すれば、実際にエフェクトが出来る事を確認してください。
    • ※エミッターのPrefabを代入する事を忘れないようにしてください。

エフェクトを削除するスクリプト

  • さて、ここまでうまく出来れば、見た目上は問題無い状態にはなっていると思います。
  • 後は、内部的な処理として、不要になったエミッターを削除できるスクリプトを作ります。
  • これをして置くことで、ずっと遊べるゲームになります。(逆に削除しておかないとどんどん処理が重くなるクソなゲームになってしまいます)
  • この処理には、新しいスクリプトに作りましょう。
    • 名前は何でも良いですがココでは【EffectDestroy】(エフェクトデストロイ)にしておきます。
    • 中身を作る前に【GetEffect】(エミッターのPrefab)に先にアタッチしておきましょう。

エフェクトを削除するスクリプト

ParticleSystem particle;

void Start () {
	particle = GetComponent<ParticleSystem>();
	Destroy(gameObject, particle.main.duration);
}
  • ここはカンタンな処理だけです。
  • 一番上で【ParticleSystem(パーティクルシステム)】という型のフィールドを作っています。
    • これはParticleを操るための型です。名前は【Particle】にしています。
  • Startメソッドで、これにParticleSystem】を入れています。
    • ​これはInspectorビューの【ParticleSystem
  • 最後のDestroy(デストロイ)も、何度か使ってますが、オブジェクトを削除するメソッドです。
    • 第1引数にオブジェクトの種類(今回は普通にGameObjectでOKです)を指定します。
    • 第2引数に削除するまでの時間を指定します。
      • ここで使っている【particle.main.duration】(パーティクル.メイン.デュレーション)よく使う形なので、丸々覚えておいてください。
      • main.duration(メイン.デュレーション)は、inspectorビューで指定したduration(継続時間)の事です。まぁ寿命みたいなもんです。
  • ここまで出来たらエラーが出ないか試しておきましょう。

お試してみよう

  • 今あるコインとは別に、以下な条件の【ボーナスコイン】を追加してください。
    • 条件①:大きさや色、形は自由ですが、今あるコインとは別にすること。
    • 条件②:落とすと50コイン増える処理にすること。
    • 条件③:15秒など特定の間隔で出て来ること。
    • 条件④:エフェクトも通常のコインとは別のものを設定すること。

お疲れ様です

  • ひとまずコイン落としゲームはこれで完成です!
  • 他にもアイテムなど追加すればもっと面白いゲームになりますので、力試しに挑戦してみてもいいでしょう。(プッシャーをもっと激しく動かせるようになるアイテムなど)
  • または今まで学んだ内容を使って、1からオリジナルゲームを作ってみてもいいでしょう。
    • 次のステップに進む場合は言ってください。

コイン落としゲーム Unity入門2_1

By kinocode

コイン落としゲーム Unity入門2_1

  • 3,753