Help us understand the problem. What is going on with this article?

今日からはじめるUnity

Pref.

Unityの初心者向け講座資料です.
「Unityは触ったことがないけど,いつか触ってみたいんだよね...」という方.
あたなも今から始めましょう.Unity.

プログラミングは完全に初めてという方はドットインストールなどのサイトで学習してから見ると導入が早くなるかもしれません.if文って何?変数って何?というレベルだと結構辛いかもしれません...
ここではUnityとはなんぞや.というところからUnityで実際にブロック崩しを作ってみるところまでやります.

この記事を読めば初めてUnityを触る人でもこういったものが作れます。(・ω・。)
43g214.gif

「え!?...始めるのが怖い!?...(バッカお前...)俺がついてるだろ」(小並感)
一度言ってみたかった()

Unityの完成プロジェクトをGitHubにおいておきました.
https://github.com/nmxi/UnityBreakOut

間違いがあったらコメントを頂けると幸いです.(よろしくお願いします...)

Env.

Unity (2018 1.5f1 から 2019.1.12f1 あたりのVersion.2019.3以降のUIがアップデートされたものもボタンなどの見た目は違いますが基本的に同じです.)
※Unityアップデートによって少しずつUpdateしています.

Windows 10 64bit または MacOS 10.14以上

Contents

Ⅰ.Unityとは

Unityとはゲームエンジンです.
ゲームエンジンとは,

  • 描画
  • サウンド再生
  • UI(ユーザーインターフェイス)管理
  • データ作成,管理

などの要素を揃えた「ゲームを作るための統合開発環境」のことです.
つまりこのゲームエンジンを使えば誰でも簡単にゲームを作ることが可能になります.

ゲームエンジンの代表的なものは以下があります.

エンジン 主な開発言語 得意なこと 対応プラットフォーム
Unity C# ぶっちゃけ何でも PC,Mobile, WebGL, WindowsStore, Xbox, PS4, NintendoSwitch, tvOS, PSVita, Facebook etc...
Unreal engine 4(UE4) ブループリント, C++ 3D/2Dゲーム開発,アートの作成など PC, Mobile, HTML5, WindowsStore, Xbox, PS4, NindentoSwitch etc...
RPGツクール javaScript 2D-RPGゲーム PC, Mobile
吉里吉里 TJS(js Like Lang.) ノベルゲーム Windows, Mobile

※PC = Windows, MacOS, Linux
※Mobile = Android, iOS

他にも無数に存在しています.
殆どのゲームエンジンは得意な分野を絞り開発されているものが多数です.

しかし
Unityは進化を重ね,現在ではゲームを作るためだけに使われているわけではありません.

今回はUnityの初心者向けの資料なのでUnityにクローズアップして書いていくのですが,
初めに言いますとUnityはめちゃくちゃプロトタイプ作成に強いです.
こんなものが作りたいな~的なことを思ったときに簡単にUnityを触れるようになっておくと
短時間で思いをカタチにできます.

他のツールは得意な分野を絞り開発されていると先ほど記述しました.
極端に書きます.
ノベルゲームを作りたい...となったときの開発に必要な機能は全部吉里吉里に入ってるし,
RPGゲームをつくりたい...となったときに必要なものは全部RPGツクールに入っています.

ではこれらを
ノベルゲームを作りたい => Unityでつくるか
RPGゲームを作りたい => Unityでつくるか
に置き換えてみます.Unityはゲームエンジンですが,ノベルを作るために特化したゲームエンジンではないし,RPGゲームを作るために特化したゲームエンジンでもありません.

つまりUnityは殆どのことをしようとしたときに必要な機能が8割方なゲームエンジンです.
これじゃ別にUnityじゃなくても...と思ったそこのアナタ.
Unityはエディタの拡張が簡単にできます(初心者からすると難しいですが...)

聞いた話ですが
Unityを開発されておられる方々はUnityを〇〇に特化したゲームエンジンにしたいわけではなく,ユーザが作りたいものをカタチにするために使って欲しい.だから8割方の機能はUnityで提供するから,あとの少し足りない部分はユーザが自分自身で機能を拡張して,自分専用のエディタにしてね!
と言うことみたいです.

奥深い.( ノ゚Д゚)

(という話は聞いたことがありますが...100%では無いのでその辺りはお願いします...)

また3Dを扱える点,そして動画も作れる点から見てみます.
3DCGで動画を作成するならMayaとかBlender,Houdiniの仕事じゃない?と思う方もいると思いますが,
確かに最終的な画作りのクオリティーはそれらのツールはこの上ないほど最強ですが,Unityがそれらのツールに比べて強いのが
リアルタイム3DCGレンダリングの点です.

例えばゲームの中でイベントムービーを流すとなったとします.
ムービーの前でシナリオが2分岐したら,ムービーを2通り用意しなければならなくなりました.
2つ寸劇を作る,つまり動画ファイルを2つ作成するならば前者のツールで構わないと思いますが,
Unityならゲームの内のモノとかをプログラムで制御してあげることで,動画をリアルタイムに描画することが可能です.
結果1個寸劇の制御の塊を作ってあげれば良くなります.
このときリアルタイムに描画するというのとクオリティーを損なわないという相反する話が出てくるのですが,Unityはそのクオリティーの問題と”リアルタイムに”ということを解決してくれます
(ちょっとその辺を詳しく説明するのは難しい...)

手っ取り早いのはこの動画を見てみて下さい.
ADAM : Episode1

image.png

こういったクオリティーの映像がリアルタイムに制御できます.(フォトリアルのコンテンツとかに効く)


とりあえず話を戻して初めに知ってもらいたいUnityについてのことは4点.

  • Unityを手軽に使えるようになるとプロトタイプ作成が容易
  • Unityはゲームだけでなく動画やゲーム以外のアプリも作れる
  • Unityのエディタは拡張できる
  • Unityはリアルタイムレンダリングに強い

ということでUnityを実際に使ってものを作っていきましょう!

Ⅱ.Unityのインストール

まずUnityをインストールしましょう.
UnityにはPersonalやPlus,Proといったエディションが存在します.

エディション 月額 制限によってできないこと
Personal 無料 スプラッシュスクリーン変更,Ads,アプリ内課金 etc...
Plus ¥4,200 アナリティクス可視化, プレミアムサポート, ソースコードアクセス
Pro ¥15,000
Enterprise
Education 教育版

現在誰でもPersonal版を無料で使うことができます.
Unityのバーションは執筆時点でUnity2018.1ですが,2年前にでていたUnity5以前はもっと無料枠(Personal)の機能制限が厳しく,凝ったことをしたくなったときに辛いものでした.
現在は無料枠でも辛い機能制限は特にないので起動時のMade with Unityのロゴ(スプラッシュスクリーン)を消したい,とかUnityエディタの色を白から黒にしてカッコよくしたいとかなければPersonalで良いと思います.
自分はエディタを黒にしたいだけのためにPlusに入っています(笑
もしかしたらCloud Build(Unityで作ったものをCloudで自動的にビルドしてくれるUnityのサービス)を利用したりするときに少し有料版の方がクールタイムや,容量が緩和されていたかもしれません.

また,Unityで作った売上でニコニコし始めたらPersonal版で儲けていい金額や資産額が条件で決まっているので,Plus,Proライセンスを購入する必要がでてきます.(結構な額行かないと関係ないですがw)

ということで各エディションのだいたいの違いを分かって頂けたと思いますので,
Personalを公式ページよりダウンロードしてインストールしましょう.

https://store.unity.com/ja
このURLからPersonal版を試す→条件に同意→OSに合わせたインストーラーをダウンロードしてください.

image.png

ダウンロードが完了したらインストーラーを起動させます.
インストールを進めて行くと以下のような画面になると思います.
UnityでAndroid用アプリ開発をする予定ならばAndroid Build Supportにチェックを入れ,
iPhone用アプリを開発するならばiOS Build Supportにチェックを入れて下さい.
もしもここでチェックを入れなくても後で追加が可能なので,とりあえずPCで動作すれば良いという人は
デフォルトのままでNextを押して次に進んで構いません.

image.png

インストールが完了し,Unityを起動させると初回起動時にUnityのアカウントでのログインを要求されると思います.Unity IDを持っていない方は公式ページでアカウントを作成してください.

https://unity3d.com/jp
このURLの右上の人のマークからUnity IDを作成できます.

Ⅲ.Unityプロジェクトを作成する

Unityをインストールしログインした後,またはUnityを起動した後に以下の画面が表示されます.

3r2qwfeads.png

この画面でUnityのプロジェクトを作ったり過去に作ったものを開いたりすることができます.
過去にプロジェクトを作成したことがあるとぼかしが入っているところに過去に作成したプロジェクトの一部が表示されています.
Unityを初めてインストールした環境ではまだプロジェクトは何もないので右上のNewをクリックして新しいプロジェクトを作成しましょう.
Newをクリックすると以下の画面になると思います.今回の講座ではブロック崩しを作ってみるのでProject nameに「Breakout」と入力します.それ以外の項目はそのままで右下のCreate Projectをクリックします.

image.png

Ⅳ.Unityエディタを理解する

プロジェクトを作成するとUnityエディタが起動する思いますが,初めてエディタの画面をみると私もはじめ見たときに思ったのを覚えていますが,「何すればいいのか分かんねぇ~(´・ω・`)」ってなるのでまずUnityのエディタの説明を書きます.
以下がプロジェクトを初めて作ってUnityを起動したときの画面です.

4tw2egfravsd.png

UnityのエディタはUnityのウィンドウの中に複数のタブが配置されています.それぞれのタブはUnityの細かく分けた機能を担っています.

  • ①ヒエラルキータブ(Hierarchy)
  • ②シーンタブ(Scene)
  • ③インスペクタータブ(Inspector)
  • ④プロジェクトタブ(Project)

Play, Pause, Stepボタン
これはタブではありませんが,作ったものを実際に動かしてみるときに使うボタンです.
左からPlay,Pause,Stepボタンになります.

  • Play : 動作開始(実行)
  • Pause : 一時停止.これをクリックしてからPlayを押すと1フレーム目で一時停止される.
  • Step : 一時停止した状態でクリックすると1フレーム時間が進められる.デバッグに便利.

①ヒエラルキータブ
現在シーン内に存在しているオブジェクトを管理できるタブ.
Unityをイメージで説明しますが,仮想3D空間があってその中でオブジェクト(物体)を配置して,その仮想空間内にあるカメラに写ったものがアプリとして操作するときの画面になります.
ちょっと分かりにくいかな?....
イメージ的にはこんな感じ.

image.png

厳密にいうとカメラもオブジェクトの1つなのですが....
とにかくヒエラルキータブはオブジェクトを作成したり削除したり,選択したりできます.

②シーンタブ
ヒエラルキータブの説明に貼ったイラストのUnityのプロジェクト内の3D空間の様子がリアルタイムで見れます.
シーンタブでオブジェクトの直接操作や配置確認がリアルタイムで行えます.

③インスペクタータブ
オブジェクトの細かい設定ができます.
このタブ使わずして何も作れない!

④プロジェクトタブ
スクリプト(C#言語で書かれたプログラム)やマテリアル(後述),画像ファイルなどといったプロジェクト内に存在するファイル一式が管理できます.ここに直接ドラッグ&ドロップするとUnityのプロジェクト内に画像などを取り込むことができます.

上の画像には重なって見えてないタブや表示されていないタブですが以下のタブは重要なので説明しておきます.

ゲームタブ(Game)
最終的にアプリで動作するときの画面.デフォルトのタブの配置ではシーンタブと重なっていますがPlayすると全面に出てきます.この画面ではオブジェクトの位置を調整したりはできませんが「マウスで実際画面操作をしたらこうなる」みたいな機能を実装してあったりすると,最終的な書き出し後のマウス操作のデバッグができたりします.

コンソールタブ(Console)
デバッグログが表示されます.スクリプトの記述にエラーがあったり,実行時にエラーが起きたりするとここに表示されます.スクリプトでエラーが出たりしたときは赤文字で表示され,そのエラーをダブルクリックすることで実際にプログラムのどこでエラーが起きているのか,ジャンプすることが可能です.(場合によってはできない時もありますが)

以上がとりあえず重要な代表的なタブですが,他にも無数にタブは存在しています.ここでは説明しませんが左上のWindowからタブを新しく表示することができます.Profilerタブとか開発には後々開発現場には不可欠になってきたりします...(Play時のCPUの負荷とか細かく見れる)

またデフォルトのタブの配置は上の画像の通りになっていますが,Unityをガリガリ使っていくとだんだんとデフォルトだと使いづらくなってきます.そのときはそれぞれのタブ名をドラッグすることでタブの配置を自由に変更可能なので,変更しましょう.
タブの配置の保存,プリセットの呼び出しはUnityのウィンドウの右上にあるボタンから可能です.(これを使いこなすと作業効率が変わる)

以下の画像のLayersの右のボタンです.現在はDefaultの配置が選択されています.
image.png

ちなみに私の愛用しているタブ配置はこれです.(みんなこの配置使おうぜ(´・ω・`)....個人的Unityタブ配置のすゝめ)

image.png

Ⅴ.シーンについて理解する

Unityでブロック崩しを作るのに必要な知識が揃うまで,あと一歩のところにきました.
Unity初心者で「は?(´・ω・`)」ってなる要素の1つ「シーン(Scene)」の説明をします.

先程プロジェクトを作成しました.プロジェクト名は「Breakout」,つまりブロック崩しという名前でプロジェクトを作りました.
そしてプロジェクトの中にシーンと概念があります.それぞれのシーンはゲームの中のその名の通りシーンを保存できます.

以下のイラストを見て下さい.シーンのイメージ的にはこんな感じ.

image.png

上の図だとそれぞれのシーンでやることの割り振りはこんな感じ

  • Title Scene : タイトル画面のシーン
  • Main Scene : ゲームで遊ぶシーン
  • Result Scene : 結果を表示するシーン

今回Breakoutを作るのを例として3つシーンを割り振ってみました.
(1つのシーンでタイトル画面から結果を表示するまでを行うやり方もありますが,複雑になるのでここでは説明しません.)

それぞれのシーンの中でそれぞれオブジェクトの配置などを行っていきます.そして最終的にアプリを実行したらTitle Sceneが起動して,スタートを押したらMain Sceneに行って...ゲームオーバーしたらResult Sceneに移って...って感じ.

そういったことを考えながらシーンの割り振りはします.
Unityのプロジェクトの中には必ず1つ以上のシーンが存在しなければなりません.
シーンファイルの拡張子は.unityです.

プロジェクトタブ上でシーンファイルはUnityマークで表示されます.画像はMainシーンのファイル.
image.png

Ⅵ.実際にブロック崩しを作る

では今度こそ実際にUnityでブロック崩しを作っていきましょう.

1.シーンを作成

プロジェクト作成後の以下の画像と同じ状態から説明を書きます.
image.png

プロジェクトタブの中にSceneフォルダがあるのでクリックして開きます.
32qew.gif

開いたらSampleScene.unityがありますが,これはプロジェクト作成時に自動的に作られる空のSceneです.
これを右クリックして名前をMainに変更します.
23wer456.gif

Mainシーン以外にもシーンで説明したように今回はタイトルシーン(Title)と結果を表示するシーン(Result)が必要なので,
プロジェクトタブ内を右クリック → Create → SceneでTitleシーンとResultシーンを作成します.
r6jeyhtrgs.gif

これで3つのシーンが用意できました.
image.png

2.Mainシーンにオブジェクトを配置

これからMainシーンを編集するのでMainシーンをクリックしてMainシーンの編集に入ります.
現在どのシーンを編集しているかはヒエラルキータブで確認できます.
今はここがMainになっていることを確認して下さい.

image.png

Mainシーンにどういったオブジェクトが必要か,オブジェクトを配置する前にMainシーンの完成図をもう一度細かく確認してみましょう.

image.png

まずゲームを行うフィールドとなる「球がどこかに行かないようにする箱」が必要ですね.
次にその箱の中で転がす球.
そしてプレイヤーが操作する「球を跳ね返すためのBox」,最後に球の標的となる「ブロック」が必要ということを確認しておいて...
実際に配置していきます.

ヒエラルキータブを右クリックして
3D Object → Cube
を選択することでシーン上にボックスが配置できました.
kt7jur6bynhgrvet.gif

ヒエラルキータブにCubeが追加されましたが,これは「球がどこかに行かないようにする箱」の底部分(床)にしたいので分かりやすいようにオブジェクトの名前を変更しましょう.
Cubeを選択 → 右クリック → Rename
でオブジェクトの名前変更が可能です.取りあえず「Yuka」としました.
h4gr43we.gif

ヒエラルキータブでYukaオブジェクトを選択してからインスペクタータブを見てみましょう.
以下の画像のようなものが表示されていると思います.
image.png

これは今作成した"Yuka"オブジェクトに追加されているコンポーネントの一覧になります.
コンポーネントとはオブジェクトに追加されている性質のことです.
Unityにおいて全てのオブジェクトはコンポーネントによって様々な性質を与えられます.
文章だけではココもつまずきやすいと思うので,コンポーネントの説明をした以下のイメージイラストを見て下さい.

image.png
ここに書かれたコンポーネントはそれぞれのオブジェクトが持っているコンポーネントの全てではありませんがまずこれらはオブジェクトを作成したときに初期から与えられているコンポーネント以外に,「このオブジェクトは〇〇をするために存在しているから,このコンポーネントは必要だよね」ということに基づいて書いてあります.
次のような感じ...

  • Playerオブジェクト : これはゲームのヒロインで人間だからまず床の上を歩くよね?だったら当たり判定をつけるColliderコンポーネントをつけて,重力も必要だからRigidBodyコンポーネントをつけよう.PlayerControllerコンポーネントについては後述します.
  • Catオブジェクト : これもヒロインと同様床の上にいて...当たり判定と重力が必要だから...ColliderコンポーネントとRigidBodyコンポーネントをつけよう.Catコンポーネントについては後述します.
  • 床オブジェクト : 床は,とりあえずヒロインと猫が床をすり抜けなければ良いから,当たり判定をつけよう...Colliderコンポーネント
  • 街灯オブジェクト : 街灯は光源だよね,だったらLightコンポーネントをつけよう....あ,ここには書いてないけど街灯の柱部分にColliderコンポーネントを追加して当たり判定つけてもよかったかも....

こういったような考え方でコンポーネントをオブジェクトに与えていきます.

では作業に戻ってUnityのヒエラルキータブで"Yuka"を選択してからインスペクタータブを見てみて下さい.
image.png

まず上からTransformコンポーネントがあり,2つめにCube(Mesh Filter)コンポーネント,その次にMesh Renderコンポーネント,Box Colliderコンポーネントと続いていると思います.
1つずつ説明すると...

  • Transformコンポーネントは必ずオブジェクトが持たなければならないコンポーネントで消せません.空間上のどこにこのオブジェクトがあるのか,回転角情報,大きさの情報が格納されています.これを動かしてオブジェクトの位置や大きさを変化させたりします.
  • Cube (Mesh Filter)コンポーネントは今は知らなくて良いです(複雑なので...)簡単に書くと描画系に関係するコンポーネントです.
  • Mesh Rendererコンポーネントも今は知らなくて良いです.これも描画に関係する.(消すとオブジェクトは存在するのに見えなくなったり...)
  • Box Colliderコンポーネント,名前の通りこれは箱の形状をした当たり判定をつけるコンポーネントです.

つまり,もうYukaオブジェクトは当たり判定を持った箱です.
68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3138313830372f65613630623865382d646265332d313065312d383736342d3962626634643033643738322e706e67.png

"Yuka"は今回の作るものの完成形イメージイラストに書いた「球がどこかに行かないようにする箱」の底にしたいので,
Transformコンポーネントのスケール値をいじって平たい床にします.

ヒエラルキータブのYukaを選択してからインスペクタータブのTransform-Scaleの値を
x=15, y=0.2, z=10に変更します.
image.png
できたらSceneタブを見てみましょう.
image.png
平たい箱の底になりました.

ここでSceneタブの操作方法について簡単に説明しますが,
以下の操作でSceneタブの視点をグリグリ回したり移動したりできます.これになれると3D空間内の配置を把握しやすくなります.
873fweuhijk.gif

Windowsの場合

操作 方法
特定オブジェクトを中心に回転 Alt + 左クリックドラッグ
拡大 / 縮小 マウスホイールを回す
視点移動 マウスホイールを押し込みながらドラッグ
視点の回転 右クリックドラッグ
特定オブジェクトへフォーカス ヒエラルキーでオブジェクトを選択してからマウスカーソルをSceneタブ上にもっていき"F"キー

Macの場合(トラックパッド利用時)

操作 方法
特定オブジェクトを中心に回転 option + 1点ドラッグ
拡大 / 縮小 垂直スワイプ
視点移動 option + command + 1点ドラッグ
視点の回転 2点ドラッグ
特定オブジェクトへフォーカス ヒエラルキーでオブジェクトを選択してからマウスカーソルをSceneタブ上にもっていき"F"キー

制作本編に戻ります.
次に球がどこかに行かないようにする箱の壁を作成します.
これがないと箱の中で球を転がしたときに球がどこかに飛んでいってしまいますヾ(´∀`)ノ

Yukaオブジェクトを作ったときと同じ要領で,
ヒエラルキータブで右クリック → 3D Object → Cubeを選択します.
ここではこれを2回行ってそれぞれの名前を"Kabe"にしてください.
image.png

できたらKabeをヒエラルキータブで選択した状態でインスペクタータブでコンポーネントを確認してみましょう.
TransformタブのPositionが以下の画像のようになっていることがあると思います.
image.png
x,y,zがなんかよく分からん数字に....
こうなっていたらトランスフォームタブの右上の歯車アイコンを押してResetを選択してみて下さい.
コンポーネントが初期化され,全ての値がキレイになると思います.
78y43u2hfwie.gif
この時点で「自分なってないけど...」って人もいると思いますが,このぐちゃぐちゃな数字は後々「なんかオブジェクトキレイに配置できねぇ!(# ゚Д゚)」ってことに繋がりかねないので,オブジェクトを作成したときにTransformの値がもしもぐちゃぐちゃになっていたらResetを行うことを癖付けておきましょう.
"Kabe"は2つ作りましたよね?もう1つの"Kabe"オブジェクトのTransformも確認しておき,ぐちゃぐちゃならResetしましょう!
(ぐちゃぐちゃな値になってしまう理由は,私がとある会社で昔Unityの初心者講座を受けたときに,Unityは裏で複雑な計算頑張って計算してるからこその誤差なんだよ(笑)と教えられました,実際はなんでなんだ?未だに分からん)

"Kabe"オブジェクトのTransformの中の値を変更して壁を作っていきます.それぞれのKabeオブジェクトのTransformコンポーネントの値は以下にしてください.
image.png

image.png

それぞれのオブジェクトのTransformの値がちゃんとできていると現在以下の形になっていると思います.
image.png

壁が半分できました.
ではヒエラルキータブを見て下さい.
ヒエラルキータブに現在Kabeが2つ存在しているのでそれらをShiftを押しながら左クリックをして2つ選択します.
その後Ctrl + D(MacならCommand + D)で複製(Duplicate)します.すると壁が4つになったと思います.
オブジェクト名に含まれるカッコは無視しても消してもどちらでも構いません.
3764y8f2qjuehwdi.gif

複製したらそれらのTransformコンポーネントのpositionの値を
z=5 → z=-5
x=7.5 → x=-7.5
のように変更して対象化しましょう.
できたら以下のように「球がどこかに行かないようにする箱」が完成します.
image.png

ではこの箱を管理しやすいようにしましょう.
ヒエラルキータブで右クリック → Create Emptyを選択し
"GameObject"という名の空オブジェクトを作成して下さい.
これはインスペクターを確認すると分かると思いますが,名の通りTransformコンポーネントしかコンポーネントを持っていないと思います.
またここでも,Transformコンポーネントの値がぐちゃぐちゃならResetって下さいね(●´ω`●)
そしたら名前を"GameObject"から"Hako"にでも名前を変えましょう.
image.png

名前を変更したら,Yukaオブジェクトと複数のKabeオブジェクトをHakoの子オブジェクトにします.
先程のKabeを複製をした時のようにShift + 左クリックで複数選択して,ドラッグして"Hako"オブジェクトの中に入れます.
すると"Hako"オブジェクトの配下に"Yuka"と"Kabe"が入ったと思います.
uirvsjdkn2.gif

このように子オブジェクトにすることで親オブジェクト(ここでは"Hako"オブジェクト)を動かすことで子オブジェクトも追従して動くようになり,箱を移動させたければ"Hako"オブジェクトを移動させれば良くなり,管理が楽になります.

7843yuwdjhokif2eq.gif

ここまでくればオブジェクトの配置については,ほぼマスターできたと思いますので,その流れで「球」と「プレイヤーが操作する球を跳ね返すためのBox」も作っていきましょう.
68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3138313830372f65613630623865382d646265332d313065312d383736342d3962626634643033643738322e706e67.png

ヒエラルキータブで
右クリック → 3D Object → Sphere で球を作成,
右クリック → 3D Object → Cube でBoxを作成して下さい.

名前も以下のように変更しちゃいましょう.
Sphere → Ball
Cube → Player

完了したらインスペクターヒエラルキータブはこんな感じになっていると思います.
image.png

Transformコンポーネントの値もそれぞれ変更しましょう.
Ballオブジェクト
image.png

Playerオブジェクト
image.png

変更できたらSceneタブは以下のようになると思います.
image.png

またカメラの位置と回転角も調整しておきます(後々楽なので...)
ヒエラルキータブで"Main Camera"を選択し,インスペクターでTransformの値を以下のように設定しておいて下さい.
image.png

このように設定することでブロック崩しゲームを上から見ながら行うような視点になります.

これでオブジェクトの配置は終わりです.
:
...え?ブロック崩しの"ブロック"が無いって?
それは手動で何個も等間隔に並べるの面倒でしょ?ということで後でプログラムを組んで楽します.

3.マテリアルを設定する

色々動かす前に今オブジェクトは真っ白だと思います.
マテリアルについて学習するのを兼ねて,箱と球に色をつけてみましょう.

マテリアル(Material)とは材質のことです.
現在オブジェクトを作成して材質の設定を何も行っていないので,全て"Default-Material"(真っ白なマテリアル)がオブジェクトに適応されています.
マテリアルを色々と設定してあげることでゲームの絵作りのクオリティーに差が出ます.細かいことは解説すると難しいのでココでは書きません.
とりあえず現在のマテリアルのイメージは以下のイラストを参照して下さい.

image.png

「テクスチャとかノーマルマップとはなんぞや?」という人も現時点では特に問題ありません.
とにかく今は表面の材質を設定するためにはマテリアルを作成し,オブジェクトに適応させれば良いということだけを覚えておいて下さい.

Unityで作業の解説に戻ります.
プロジェクトタブのAssets/
右クリック → Create → New Folderを選択し,新しいフォルダをプロジェクト内に作成します.
名前は,"Materials"にしましょう.
また,そのフォルダの中入り
右クリック → Create → Materialを選択し,新規マテリアルを作成します.
新規マテリアル名は"Yuka"に設定しましょう.
5h4rgetwfd.gif

これで"Yuka"オブジェクト用のマテリアルが作成されました.名前は今回"Yuka"に設定しましたが,特に命名規則は存在しないので,"Yuka-mat"とかでもOKです.

ではマテリアルの設定をしていきます.
プロジェクトタブの"Yuka"マテリアルを選択し,インスペクタータブを見て下さい.
image.png

インスペクタータブに"Yuka"マテリアルの設定が表示されていると思います.
これらの値を変化させることで,このマテリアルを適応したオブジェクトの表面の材質を変化させることが可能になります.

今回は箱の床の色を試しに黒にしてみましょう.
Albedo(アルベド)の横の現在の設定色が表示されているところをクリックして,カラーピッカーが開かれるので,黒を選択しましょう.
mnu7t6yhr5b.gif

表面が黒に設定された"Yuka"マテリアルができました.
ではこれを"Yuka"オブジェクトに適応したいと思います.
プロジェクトタブの中の"Yuka"マテリアルをドラッグして,シーンタブに表示された”Yuka”オブジェクトにドロップするとオブジェクトにマテリアルが適応されます.

erfwrwegvw.gif

同様に"Kabe"オブジェクトと"Ball","Player"にもマテリアルを作成して適応してみます.
プロジェクトタブに先程作成したMaterialsフォルダの中に"Kabe","Ball","Player"マテリアルを新規作成します.
各マテリアルのAlbedo(アルベド)を好きな色に設定して,対象のオブジェクトに適応してみて下さい.
できたら以下のようになると思います.
image.png

これでマテリアルを作って適応する基礎は概ね理解できたと思います.

4.ボールを動かす

コンポーネントの説明のイラストに出てきて後述するとしていた,自作コンポーネントについての説明をします.
イラストの以下の部分の話ですね68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3138313830372f35333531373765312d636237632d366361612d333236352d3463613933393262396139622e706e67.png

オレンジの枠で囲んだ以外に挙げたコンポーネントの例はUnityにもとから入っているコンポーネントになります.しかしイラストに沿って説明すると,「プレイヤーをキーボード操作によって移動させたい,ジャンプさせたい」とか「猫は動物なのでしっぽを一定間隔で揺らしたい...」とかの機能が欲しくなったときに,もとから入っているコンポーネントだけでは機能不足で実装ができません.
そこでC#言語を利用したスクリプトを書いてあげることで自作のコンポーネントとして動作し,思い通りの実装が可能になります.

では実際に現在Unityで作っているブロック崩しでここから追加したい機能を考えてみましょう...

現時点では以下みたいな機能が欲しいと思われます.

  • キーボードの操作によって"Player"オブジェクトを左右動くようにしたい.
  • ゲーム開始時にブロック崩しの的である「ブロック」を並べたい

ではスクリプトを書いていきましょう.
またプロジェクトタブ内のAssets/に新しいフォルダを作成し,名前を"Scripts"にします.
作ったScriptsフォルダに移動し,右クリック → Create → C# Scriptを選択します.
新しいスクリプトファイルが作成されるので,名前を"Controller"にしましょう.
image.png

ファイルができたらダブルクリックをすることで予め設定されたエディタ(デフォルトだとVisual Studio)が起動し,プログラミングを行う画面になると思います.そこで以下のように記述してみて下さい.

Controller.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Controller : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {
        if (Input.GetKey(KeyCode.LeftArrow)) {
            transform.position += transform.forward * 0.1f;
        }else if (Input.GetKey(KeyCode.RightArrow)) {
            transform.position -= transform.forward * 0.1f;
        }
    }
}

っとココで疑問を持たれた方が多いと思いますが,スクリプトを作成して開くとはじめから

  • void Start()
  • void Update()

の2つが存在しています.これは特殊な関数で"MonoBehaviour"を継承しているスクリプトの中に存在するとUnityが

  • Start : 実行時に初めに1回呼ぶ
  • Update : 毎フレーム呼ぶ

という決まりがあります.「?」という方は
Startは初めに1回だけ呼ばれて,Updateは毎フレーム呼ばれるということだけを覚えておいて下さい.

上記のプログラムで実際に書き加えた部分は以下の4行だけです.

if (Input.GetKey(KeyCode.LeftArrow)) {
    transform.position += transform.forward * 0.1f;
}else if (Input.GetKey(KeyCode.RightArrow)) {
    transform.position -= transform.forward * 0.1f;

これを毎フレーム呼ばれるUpdate()の中に書いていますので,何回も実行されます.
上の書き足した4行のプログラムを分かるように日本語で説明すると

1行目: もしも左矢印キーがおされたら
2行目: このコンポーネント(スクリプト)を持っているオブジェクトのTransformコンポーネントのpositionの値のz方向に0.1を足しなさい.
3行目: もし左矢印キーが押されていないけど右矢印キーが押されていたら
4行目: このコンポーネント(スクリプト)を持っているオブジェクトのtransformコンポーネントのpositionの値をz方向に0.1を引きなさい.

こんなようなことが書いてあります.
これを書いてエディタ上でスクリプトを保存し,Unity側に戻ります.
Playerオブジェクトをヒエラルキータブで選択しておきインスペクタータブにPlayerのコンポーネントが表示させておいてから,今書いたスクリプトをドラッグ・アンド・ドロップすることで,Controllerコンポーネントを追加できます.

h45trewfq.gif

Controllerコンポーネントが追加されたら実際にPlayボタンを押して実行してみましょう.
キーボードの左右の矢印キーでPlayerが左右に動けばOKです.
,muryetwr.gif

では次にボールを最初に動かすスクリプトを書きましょう.
プロジェクトタブでAsset/Scriptsの中に"StartShot"という名前のスクリプトを作成しましょう.
image.png

"StartShot"を使って
ゲームが開始したら"Ball"に初速が与えられるようにします.
こんな感じにしたいと思います.
65etwre.gif

"StartShot"スクリプトの中身はこのように記述して下さい.

StartShot.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class StartShot : MonoBehaviour {

    // Use this for initialization
    void Start () {
        transform.eulerAngles = new Vector3(0, Random.Range(30, 120), 0);
        gameObject.GetComponent<Rigidbody>().AddForce(transform.forward * 500);
    }

    // Update is called once per frame
    void Update () {

    }
}

書き足した部分は Start()の中の

transform.eulerAngles = new Vector3(0, Random.Range(30, 120), 0);
gameObject.GetComponent<Rigidbody>().AddForce(transform.forward * 500);

の二行です.

1行目: このスクリプトがアタッチされているオブジェクトのTransformの回転角情報をx=0, y=ランダムで(30~120), z=0にする.
2行目: このスクリプトがアタッチされているオブジェクトにアタッチされている"RigidBody"コンポーネントのAddForce関数を呼ぶ.

まず適当にBallの正面方向をランダム回転させて毎回同じ方向にボールが動き始めないようにして...
AddForce関数でBallが現在向いている方向に力を500で加えるといったプログラムになります.

Unityのエディタ側に戻り,今作成したスクリプトをBallオブジェクトにアタッチしてみましょう.
m7un6ybv.gif

試しに実行してみて下さい.
気づきにくいですが,画面左下にエラーが出ませんでしたか?
詳細を確認してみましょう.プロジェクトタブの裏に隠れているコンソールタブ(Console)を見てみて下さい.
There is no"RigidBody" attached to the "Ball" game object ~~と出ているかと思います.

なぜでしょう...

答えは2行目でこのスクリプトをアタッチしたオブジェクトにあるRigidBodyコンポーネントといっていましたが,今Ballオブジェクトには"RigidBody"コンポーネントは含まれていません.
ですのでスクリプトでRigidBodyを呼んでるけど持ってないよ(# ゚Д゚)ということだったんですね.

このようにエラーが出た時はコンソールタブを確認してみるとなんで動かないのかを確認して先に進むことができますので,活用しましょう.

ちなみにコンポーネントの説明のときに重力が必要だから....RigidBodyコンポーネントを追加して...と書いていましたが,詳しく言うとRigidBodyコンポーネントはオブジェクトに物理特性を持たせるためのコンポーネントです.結果重力の計算もしてくれるわけですね.

ヒエラルキータブでBallオブジェクトを選択して,インスペクター上でRigidBodyコンポーネントを追加してみましょう.
image.png

ではもう一度実行してみましょう.

4h5gert.gif

あれ?エラーは出なくなったけど,思っているBallの動きじゃない...って感じですよね.
RigidBodyコンポーネントが摩擦の計算もしているので,ボールの速度が減衰してしまうわけです.
では設定をさらに追加して理想の動作にしていきましょう.

プロジェクトタブでAssets/Materialsの中で
右クリック → Create → Physic Materialを選択
で新規Physic Materialを作成して下さい.名前は"NoFriction"にしましょう.
image.png

Physic Materialは日本語でいうと物体の物理特性マテリアルです.
衝突するオブジェクトの摩擦や跳ね返り効果を調整するのに使います.

プロジェクトタブで"NoFriction"を選択してから,インスペクタータブで値を以下の画像のように設定しましょう.
image.png

  • Dynamic Friction : 動摩擦,オブジェクトが動いているときに使用される摩擦.
  • Static Friction : 静止摩擦,オブジェクトが静止しているときに仕様される摩擦.
  • Bounciness : どのくらい弾性があるか.この値を適度に上げるとゴムみたいなオブジェクトになります.
  • Friction Combine : 衝突するオブジェクト間の摩擦をどう処理するか.
  • Bounce Combine : 衝突するオブジェクト間の跳ね返し度合いをどう処理するか.

これらの値を画像のように設定したことで
摩擦が全く働かない,弾性が1(100%),つまり何にあたっても必ず跳ね返る物理特性マテリアルが完成しました.
これを"Ball"のSphere ColliderコンポーネントのMaterialに追加してみて下さい.
image.png

ではもう一度気を取り直して実行してみましょう.

k65jyrter.gif

ちゃんと理想通りに動きました( ´ー`)フゥー...

5.ブロックを作る

現在,ボールは動くようになりましたがブロック崩しなのに"ブロック"がありません.
最初に書いたとおりブロックをヒエラルキータブから3D Objectを選択して...複製して...で配置してもいいのですが
面倒くさいので,別の方法でやります.

Prefab(プレハブ)という機能を使います.
プレハブとはオブジェクト指向プログラミングの話に置き換えていうと,

  • クラス = Prefab(プレハブ)
  • オブジェクトインスタンス = Prefabから作られたインスタンス

になります.オブジェクト指向言語でのプログラミングが未経験だと理解しにくいので,またイラストでイメージを描いておきます.

image.png

ではボックスのPrefab(プレハブ)を作成しましょう.

ヒエラルキータブに新規Cubeオブジェクトを作成し,Boxに名前を変えて下さい.
Transformの値は以下の画像のように変更して下さい.

image.png

シーンタブはこの様になっていると思います.
image.png

マテリアル設定を行ってBoxの色を設定しておいても構いません.私は今回黄緑色に設定してみました.

プロジェクトタブでAsset/に新規フォルダで"Prefabs"という名前のフォルダを作ります.
image.png

この作成したフォルダにBoxオブジェクトをヒエラルキータブからドラッグ・アンド・ドロップします.
6j75hgreq.gif

こうしてプロジェクトタブの中にできたものがBoxのPrefab(プレハブ)です.
プレハブを作成したのでヒエラルキータブの中にあるBoxオブジェクトは削除して構いません.

ではスクリプトを書いてゲーム開始時にBoxのPrefabを複数回インスタンス化してブロック崩しの”ブロック”を並べて見ましょう.

Asset/Scriptsに新規スクリプトでBoxInitというスクリプトを作成しましょう.
image.png

開いたら以下の様にスクリプトを書いて下さい.

BoxInit.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BoxInit : MonoBehaviour {

    public GameObject boxObjPrefab;
    public GameObject boxesObj;

    void Awake() {
        for (int x = 0; x < 8; x++) {
            for (int y = 0; y < 5; y++) {
                GameObject g = Instantiate(boxObjPrefab, boxesObj.transform);
                g.transform.position = new Vector3((2f + (1f * y)), 0.4f, (-4.2f + (1.2f * x)));
            }
        }
    }

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }
}

今回書き足したのは以下の11行です.

public GameObject boxObjPrefab;
public GameObject boxesObj;

void Awake() {
    for (int x = 0; x < 8; x++) {
        for (int y = 0; y < 5; y++) {
            GameObject g = Instantiate(boxObjPrefab, boxesObj.transform);
            g.transform.position = new Vector3((2f + (1f * y)), 0.4f, (-4.2f + (1.2f * x)));
        }
    }
}

日本語で説明すると

1行目,2行目 : ゲームオブジェクト型の変数を定義.
4行目 : AwakeとはStartよりも早く呼ばれるイベント関数です.Awakeに書くとStartよりも先に実行されます.
5行目~10行目 : for文で横8×縦5にBoxのPrefabをインスタンス化しています.
7行目 : 一旦"g"というGameObject型の変数を作りその中にPrefabをインスタンス化しています.boxesObj.transformというのはこの後説明します.
8行目 : 変数"g"にインスタンス化して入れられたゲームオブジェクトのtransform.positionの値をfor文を使って個々の座標に移動させる.

ということをやっています.

AwakeやStart以外にもたくさん"イベント関数"がUnityでは定義されていて,呼ばれるタイミングも様々です.
詳しいことはUnity Documentationを確認すると分かりやすいです.

このスクリプトを"Hako"オブジェクトにアタッチしてみてください.
image.png

先程のスクリプトとは何か違いますね?

  • Box Obj Prefab
  • Boxes Obj

の2つの項目が追加されているのが分かります.これはBoxInitスクリプトの1,2行目でPublicというアクセス修飾子を書いたことによって,インスペクター上からスクリプトの変数の中に直接ゲームオブジェクトを入れることが可能になりました.

7行目のInstantiate関数とは
第1引数ではインスタンス化するオブジェクト(prefab)を指定.
第2引数ではどのオブジェクトの子オブジェクトとしてインスタンス化するか指定しています.

つまりスクリプトの7行目でInstantiate関数を使ってBox Obj Prefabに代入されたゲームオブジェクト型のモノをインスタンス化しています.Box Obj Prefabという項目は今回そこに繋がっています.
BoxesObjはBoxオブジェクトの親オブジェクトにするオブジェクトを今回は入れてあげます.

BoxInitスクリプトの2つの変数について理解したところで現在"None (Game Object)"になっているところにオブジェクトを指定しましょう.

  • Box Obj Prefab にはBoxのPrefabをアタッチ
  • Boxes Obj には"Boxes"という空のオブジェクトを作成してアタッチ

rtewgeq.gif

できたらPlayしてみましょう.
以下のようにBox(ブロック崩しの”ブロック”)が配置されたかと思います.

45g34rwef.gif


ここまでで

  • Scene (シーン)
  • Component (コンポーネント)
  • Material (マテリアル)
  • Pysic Material (フィジックマテリアル)
  • Prefab (プレハブ)

と様々なことを理解してきたと思います.分からないことがあったら記事をさかのぼって見たり,Unityの公式のドキュメントを読んだりすることで更に学習を深めて行けると思います.
初めての方はここまで結構長い道のりに感じるかもしれませんが,今までの部分は慣れてしまえば感覚でできてしまう部分なのでご安心を...₍₍(ง˘ω˘)ว⁾⁾
(自分もココら辺までは最初結構辛かったです.)


6.球でブロックを壊せるようにする

形はほぼ完成したので,だんだんゲームのシステムの構築に入って行きます.
現在球がBoxにあたっても消えないので,消えるようにしましょう.

Asset/Scriptsに新規C#スクリプトで"Destroyer"という名前のスクリプトを作成しましょう.
image.png

Destroyerの中身は以下です.

Destroyer.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Destroyer : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }

    private void OnCollisionEnter(Collision collision) {
        Destroy(gameObject);
    }
}

追記した部分は以下3行です.

private void OnCollisionEnter(Collision collision) {
    Destroy(gameObject);
}

OnCollisionEnterは当たり判定が何かしらあったときに呼ばれるイベント関数です.
当たってきたオブジェクトの情報が変数"collision"に代入されます.
しかし今回は球以外当たるものが無いので何かしらのオブジェクトが当たったときはこのスクリプトをアタッチしている自分自身をDestroy(削除)するようにしています.(collisionに代入された情報をif文とかを使って照合することで当たってきたオブジェクトが何なのかを判別できます.)

image.png

このスクリプトをBoxプレファブにアタッチすればよいのですが,ちょっとしたテクニックを紹介します.

一旦プロジェクトタブからヒエラルキータブにBoxプレファブをドラッグ・アンド・ドロップして手動でインスタンス化して下さい.
378wu2ehi.gif

手動でインスタンス化したらヒエラルキータブでBoxを選択してインスペクタータブで"Destroyer"スクリプトをアタッチして下さい.
image.png

アタッチできました.
しかしながら今は以下みたいな状況です.
image.png

これだとPlayボタンを押して実行したときにPrefabの情報をもとにBoxの配置が初期化されるのでDestroyerがアタッチされていないものが配置されてしまいます.
現在インスタンス化したオブジェクトだけDestroyerスクリプトをアタッチしています.これをインスタンス化もとに反映させてみましょう

DestroyerをアタッチしたBoxのインスペクターの上の方に以下のようなPrefab [Select][Revert][Apply]というボタンが表示されていると思います.
image.png

これをクリックすることで以下のようなことができます.

  • Select : インスタンス元のPrefabをプロジェクトタブ内で選択
  • Revert : インスタンス元のオリジナルの状態にリセット.
  • Apply : このインスタンス後に変更した内容をPrefabに反映

今回のような時はApplyですね!

-/-/-/-/-/-/-/-追記(2019-06-29)

Unity2018.3からちょっと変わりました.Unity2018.2以前を使用している場合は無視して進めて構いません.

今まではApplyボタンをクリックするときに,どの値や部分をアップデートしたか分かりませんでしたが
変更点をApplyをする前に確認できるようになりました.

また,ここでは詳しく書きませんがPrefabのできることが少し変わったのでApplyボタンの場所が少し変わりました.(2018.3以降は厳密にはPrefabの仕組みを深くまで理解した上でApplyした方が本当は良かったり...でも今は気にしなくて大丈夫だと思います!)

4eg35rtwfd.gif

-/-/-/-/-/-/-/-

Destroyerスクリプトをアタッチした状態でApplyをクリックします.
するとBox PrefabにもDestroyerスクリプトがアタッチされました.

Destroyerスクリプトをアタッチするために手動インスタンスしたBoxオブジェクトはヒエラルキータブから削除して下さい.

実行確認してみましょう.
ちゃんと球がボックスに当たったら消えるようになりましたか?
h5ybtrv4ew.gif

7.ゲームのシステムを作っていく

Mainシーンでやることもいよいよ大詰めです.
まずヒエラルキータブで空のオブジェクトを作成し,名前を"Master"にしましょう.
image.png

ゲームの進行情報の管理はこういった名前をつけたオブジェクトで集中管理してあげると,後々大きな規模のゲームを作るときにも役に立ちます.

プロジェクトタブでAssets/Scriptsに”GameMaster”というスクリプトを新規作成しましょう.
image.png

このスクリプトでは以下の仕事を担わせます.

  • 時間を計測してBoxが全てなくなったらゲームを終了する.
  • ゲーム終了時の結果をResult Sceneに引き継ぐ

GameMasterスクリプトの中身は以下です.

GameMaster.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class GameMaster : MonoBehaviour {

    public int boxNum;
    public float nowTime;

    // Use this for initialization
    void Start () {
        nowTime = 0;
    }

    // Update is called once per frame
    void Update () {
        nowTime += Time.deltaTime;
        if (boxNum <= 0) {
            GameOver();
        }
    }

    public void GameOver() {
        SceneManager.LoadScene("Result");
    }
}

4行目 : using UnityEngine.SceneManagementこれを追加しないと25行目が動きません.
8,9行目 : boxNumは現在存在するボックスの数.この次その値を変化させるものを書きます.nowTimeはゲームが開始してからの秒数を入れます.
18行目 : nowTimeに今までに経過した時間を入れています.Time.deltaTimeとは前のフレームから経過した時間を取得できます.Update()は毎フレームに実行されているのでその経過時間を毎フレーム足すことで経過時間を取得することができます.
24行目 : publicメソッドを作成しました.ゲーム終了時にはこのメソッドを呼べばOKにしておきます.
25行目 : SceneManager.LoadScene("Result");はResultという名前の”シーン”に移動しろ.という命令です.初めに結果を表示するシーンを"Result"と名付けたのを覚えていますでしょうか?ゲームオーバーしたら結果を表示するので,GameOverメソッドの中に入れました.

とりあえずこのスクリプトをMasterオブジェクトにアタッチしましょう.
アタッチしたらインスペクターのGameMasterスクリプトのboxNumの変数をボックスが最初BoxInitスクリプトのfor文内でインスタンス化される数,40を代入しておきましょう.(5*8=40)
image.png

これだけではBoxNumに変化は起きないので,Destroyerスクリプトに機能を追加しましょう.
"Destroyer"スクリプトとは球がボックスに当たったときにボックスを削除するという機能を持ったスクリプトでした.このボックスが消えるときにMasterオブジェクトの持つGameMasterスクリプトのboxNumという値を変化させればOKですね!

以下新しいDestroyerスクリプトの中身です.

Destroyer.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Destroyer : MonoBehaviour {

    public GameObject masterObj;

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }

    private void OnCollisionEnter(Collision collision) {
        masterObj.GetComponent<GameMaster>().boxNum--;
        Destroy(gameObject);
    }
}

7行目 : public GameObject masterObj; Masterオブジェクトが格納される変数
20行目 : masterObjの中にあるGameMasterという自作コンポーネント(スクリプト)のboxNumを1マイナスしろという命令を追加しました.

今度はDestroyerのmasterObjの中にprefabをインスタンス化するときにMasterオブジェクトを指定してあげることが必要になったので,そちらも書きます.

ボックスをインスタンス化しているBoxInitスクリプトに2行足して下さい.

BoxInit.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BoxInit : MonoBehaviour {

    public GameObject boxObjPrefab;
    public GameObject boxesObj;

    void Awake() {
        GameObject masterObj = GameObject.Find("Master");  //<=====これ
        for (int x = 0; x < 8; x++) {
            for (int y = 0; y < 5; y++) {
                GameObject g = Instantiate(boxObjPrefab, boxesObj.transform);
                g.transform.position = new Vector3((2f + (1f * y)), 0.4f, (-4.2f + (1.2f * x)));
                g.GetComponent<Destroyer>().masterObj = masterObj;  //<=====これ
            }
        }
    }

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }
}

11行目 : GameObject型変数masterObjの中にMasterオブジェクトを現在実体化しているオブジェクトから”Master”という名前がつくオブジェクトを探して格納.
16行目 : インスタンス化したboxオブジェクトの中のDestroyerコンポーネント(スクリプト)のmasterObjという変数に11行目で取得したMasterオブジェクトを格納.

こうすることでDestoryerスクリプトの変数の中にMasterオブジェクトを代入できます.

以上でボックスが全てなくなると"Result"シーンに移るようになります.
また,左右に動くPlayerオブジェクトよりも下に球が行ってしまったときにゲームオーバーにしたいので,以下のスクリプトも作りましょう.

プロジェクトタブでAssets/Scriptsに新規C#スクリプト"KabeOut"を作りましょう.
image.png

中身は以下です.

KabeOut.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class KabeOut : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }

    private void OnCollisionEnter(Collision collision) {
        GameObject.Find("Master").GetComponent<GameMaster>().GameOver();
    }
}

書いたのは以下の3行です.

private void OnCollisionEnter(Collision collision) {
    GameObject.Find("Master").GetComponent<GameMaster>().GameOver();
}

何かこのスクリプトがアタッチされたオブジェクトに当たったら,Masterオブジェクトの持つGameMasterコンポーネント(スクリプト)のGameOverメソッドを呼べという意味になります.
このスクリプトを下の壁のみアタッチしてみましょう.
4h534g2ev.gif

下の壁に当たったらゲームオーバーして,"Result"シーンに移るようになりました.
Resultシーンに移らないよ!って人は少し下に解決方法「ここでですが1つ」から書いてあるので,参照願います.
432.gif

8.Resultシーンを編集する

ゲームオーバーした後Resultシーンに来ますが,まだ何も表示されません.
寂しいので"Game Over !"などの文字と結果を書きましょう.

今までMainシーンを編集していたので,プロジェクトタブからAssets/Scenes/Resultをダブルクリックして,Resultシーンの編集に移ります.
image.png

このとき以下のようなダイアログが現れた場合はMainシーンが保存されていないけどどうする?という問いかけなのでSaveを選択しましょう.
image.png

ヒエラルキータブのUnityマークの右側がResultになっていることを確認しましょう.なっていたら現在編集しているシーンはResultシーンです.
image.png


ここでですが1つ
現在複数のシーンに渡って編集していますが,複数画面の編集をした後の実行で出るかもしれないのが以下のエラー.

image.png

これが出た場合は左上の
File → Build Settingsを開き
エラーが出ているシーン(今回なら"Result")をScenes In Buildの項目にドラッグ・アンド・ドロップしてから実行すればOKです.
Scenes In Buildの中に登録されたSceneが最終的なアプリを書き出ししたときに含ませるSceneの全てになります.

j6h45g32.gif

もしこのエラーが出た方は以上を参考に解決して下さい.

またScenes In Buildのシーン名の並び順はシーンの起動順が関係あるので,もしもアプリ実行時に後に編集するタイトルシーンから起動せずに「いきなりゲーム(Main シーン)が始まるんだけど...」って人はScenes In Buildの並び順も確認してみて下さい.右側の数字の小さい順に起動します.

image.png

この設定ができたら,Build SettingsのWindowを×ボタンで閉じます.
右下のBuildとかはアプリの最終的な書き出しになってしまいますので,今は押さないで下さい.


エラーの話から戻します.

ヒエラルキータブ上で
右クリック → UI → Textを選択で
テキストをオブジェクトを作成して下さい.
Textが作成されたら見やすいようにシーンタブを操作して下さい.
65jht4ergw.gif

ヒエラルキータブでTextを選択した状態でシーンタブで"T"キーを押すことでRect Toolになります.
Rect Toolを使って文字枠の大きさを調整して下さい.
3uwireo.gif

引き続きTextを選択した状態でインスペクター上のTextコンポーネントの値を以下のように変更します.
image.png

  • Text : 表示する文字列
  • Font Size : 67
  • Alignment : 文字の配置

この3項目を変更しました.変更後こんな感じになります.白い枠が現在設定されているGameタブの表示範囲です.
image.png

また,ゲームの結果を表示したいのでGameOverのテキストの下にもう1つTextを作成します.
今作成したGameOverというTextを複製して下に移動させると簡単です.
下に移動してから文字枠の大きさも大きくしておくと良いでしょう.
6e56jsaez.gif

このTextに結果を入れます.
image.png

では結果をMainシーンから持ってこれるようにしましょう.
イメージはこんな感じです.
image.png

シーンからシーンにデータを渡す方法は他にもありますが,今回はC#スクリプトでstatic classを作りその中のstatic変数で受け渡しをします.

static classについての説明はUnity公式チュートリアルを参照してみてください
https://unity3d.com/jp/learn/tutorials/topics/scripting/statics

プロジェクトタブでAssets/Scriptsに”DataSender”という名前の新規C#スクリプトを作成して下さい.
image.png

その中身は以下の様にして下さい.

DataSender.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public static class DataSender {
    public static string resultMessage;
}

今までに比べてとちょっと書き方が異なっています.今まではクラス名の右側に: MonoBehaviourと付いていましたが今回は付いていません.また変数の定義の行にもstaticと入っています.書かないと引き継げないので気をつけて下さいねヽ(`-´)ノ

できたら,Mainシーンで使っている以下の2つのスクリプトをちょっと書き足します.

  • GameMaster.cs
  • KabeOut.cs
GameMaster.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class GameMaster : MonoBehaviour {

    public int boxNum;
    public float nowTime;

    // Use this for initialization
    void Start () {
        nowTime = 0;
    }

    // Update is called once per frame
    void Update () {
        nowTime += Time.deltaTime;
        if (boxNum <= 0) {
            GameOver(nowTime.ToString("F0") + "秒でクリアできた!");  //<=====秒数をstring型にキャストして引数へ
        }
    }

    public void GameOver(string resultMessage) {   //<=====引数をもたせた
        DataSender.resultMessage = resultMessage;  //<=====受け取った引数をstatic変数へ格納
        SceneManager.LoadScene("Result");
    }
}

KabeOut.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class KabeOut : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }

    private void OnCollisionEnter(Collision collision) {
        GameObject.Find("Master").GetComponent<GameMaster>().GameOver("ゲーム失敗.また挑戦しよう"); //<=====文字列を引数へ
    }
}

これでMainシーン側からのメッセージの引き渡しはできたので,Resultシーン側で,Resultシーンが読み込まれたときに文字列を受け取るようにしましょう.

プロジェクトタブで新規C#スクリプト,"TextDataFetcher"を作成しましょう.
image.png

中身は以下のようにします.

TextDataFetcher.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TextDataFetcher : MonoBehaviour {

    public Text resultMessageText;

    // Use this for initialization
    void Start () {
        resultMessageText.text = DataSender.resultMessage;
    }

    // Update is called once per frame
    void Update () {

    }
}

8行目 : Text型のresultMessageTextを定義
12行目 : このスクリプトが読み込まれたときにDataSenderクラスのresultMessageの中身をresultMessageTextのTextに入れる.

ということをやっています.このスクリプトを使えるようにしましょう.
Resultシーン内にMainシーン同様に空のオブジェクト(Empty Object)を作成し,名前を"Master"に設定して下さい.
image.png

作成できたらMasterオブジェクトに今書いた”TextDataFetcher”スクリプトをアタッチして下さい.
image.png

インスペクタータブをみると分かるようにResult Message Textという項目があります.
ここに「結果を入れる方のTextオブジェクト」をアタッチします.
3gwe.gif

ではメッセージがちゃんと代入されるか実行してみましょう.
今は"Result"シーンを編集しているのでそのまま実行すると結果の画面が再生されるだけなので,
まず,Assets/Scene/Mainをクリックして,"Main"シーンを開いて下さい.
ダイアログが出たらSaveをクリックして下さい.

Mainシーンが開けたらPlayボタンを押して実行してみましょう.
3bwe32qf.gif

メッセージがしっかり表示されていれば,OKです.

9.タイトル画面をつくる

最後の工程です.
タイトル画面,すなわち"Title"シーンを編集します.
プロジェクトタブでAssets/Scenes/Titleをダブルクリックし,"Title"シーンを開いて下さい.
とりあえず毎回の如くインスペクタータブで空のオブジェクト(Empty Object)を新規作成し,名前を"Master"にします.

image.png

また,右クリック → UI → Textで新規テキストも作成します.

image.png

Resultシーンを編集したときと同様,テキストの大きさを整えてあげて分かりやすいようにタイトルを作ります.
ちなみにゲームはスペースキーを押したら始まるようにするので「Space key Start」とか書くと分かりやすいかもしれません.

以下は例です.

image.png

文字が見づらい...って思った人は,Main Cameraオブジェクトの中にあるCameraコンポーネントの"Clear Flags"を"Solid Color"に設定し,"Background"の色を変えると背景色が単色になります.

image.png

image.png

ではスペースキーを押したらMainシーンに移るようにしましょう.
方法は「こうやればできるんじゃない?」と想像つくようになってきましたでしょうか?

プロジェクトタブでAssets/Scriptsに新規C#スクリプト"SpaceStart"を作成し,中身を以下のように書き換えます.

SpaceStart.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class SpaceStart : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {
        if (Input.GetKey(KeyCode.Space)) {
            SceneManager.LoadScene("Main");
        }
    }
}

4行目 : usingを忘れずに...
15~17行目 : スペースキーが押されたらMainシーンに移動するようにしています.

このスクリプトをMasterオブジェクトにアタッチして下さい.

image.png

10.完成品を動かしてみる

これで一通り完成しました!

では遊んでみましょう\(^o^)/

ちゃんと動きましたか?...

お疲れ様でした.


これ失敗する結果は確認できるけど,クリアしたときの画面が正常に出るかはBoxを全て消さないといけないので,デバッグ性最悪ですね(#・∀・)==⊃

Ex.発展項目

制作方法の本編は全て終わりましたが,以下機能を実装したら更に理解を深められると思います.

  • タイトル画面の背景を画像にしてみる.(初級)
    ヒント: UI/Imageを使って...
    image.png

  • MainシーンのYukaオブジェクトにテクスチャを貼ってみる.(初級)
    ヒント: MaterialのアルベドにTextureを設定
    image.png

  • 光らせてみる
    ヒント: MaterialのEmission設定,Directional Light無効化.(中級)
    image.png

  • ポストプロセスをやってみる(中級)
    ヒント: 「光らせてみる」からの応用.Unity PostProcessStack v2で検索検索♪
    参考gifはこのURL先で見てね.
    imgur

  • Result画面でスペースキーを押したらTitleに戻るようにする.(初級)
    ヒント: スペースキーを押したらゲームスタートの応用
    43g214.gif

Ref.

https://docs.unity3d.com/Manual/index.html
https://www.sejuku.net/blog/6616#i
https://techacademy.jp/magazine/2553

nmxi
最近は https://www.kemomimi.dev の方に記事書いてます
https://www.kemomimi.dev
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした