Unityスクリプト / ゲーム内の時間編
インドネシアのどこか
みなさんこんにちは🌚
最近日本酒が臭く感じなくなってぐびぐび飲めるようになってきてしまったブルーノです。別に一人で飲む機会が多いわけではないので友達と飲むときしか影響はないのですが自分の体が恐ろしくなってきました笑
さて今回は、ゲーム内の時間の概念とその扱い方についてやっていきたいと思います。
ゲームの時間管理
ゲームの中の時間は我々の世界とは違い、フレーム単位で進んでいきます。じゃあそれは何秒なの?と言われるとこれまた設定次第なので一概に何秒とは言えませんが、とにかく我々の1秒と同じではありません。そのフレームの設定から逆算すれば1秒をゲーム内で測れますが、毎回時間を扱う際にそのゲームと我々の時間の比率を計算するのはめんどくさいですよね。そこでUnityEngine.Timeクラスのtimeプロパティを使うことで、起動後から呼び出されるまでの時間を我々の時間で測ってくれます!
UnityEngine.Timeクラス
public sealed class Time
timeプロパティ
public static float time { get; }
逆にフレームを測りたい場合は同じくTimeクラスのframeCountプロパティを使用します
frameCountプロパティ
public static int frameCount { get; }
ちょっとみてみましょう
7行目でまず座標を作り、22行目でTimeクラスからそれぞれframeCountとtimeプロパティを使っています。結果は以下の通りです
フレームと我々の時間の進みはやはり全然違うようですね。
ゲーム内の時間はフレーム単位で進むことはわかりましたが、では我々の時間基準でオブジェクトを動かしたい場合や進行させたいときは時間をただ刻み続けているtimeプロパティじゃあまり意味がありませんね。そこで使われるのがdeltatimeプロパティです。このdeltatimeプロパティは呼び出される直前のフレームから現在のフレームまでにかかった時間を我々の時間単位に直してfloat型で返してくれます。つまりめっちゃ早いです。なんでそれで時間が測れるんだよって思いますがつまり、1秒が60フレームのゲームなら1/60の値を返すので、1秒に動いてほしい値にかけることでその1/60の値になります。それを1秒間に60回かけるのでうまく1秒にその値が収まるという理屈だそうです。厳密には違うそうです笑
では例を見ていきましょう
これをCubeにつけます
およそ1秒で一周していますね。室伏みたいですね。このdeltatimeプロパティは今後ゲームにしろアプリにしろ必須になってきそうですね。
フレームレートの設定
UnityはUpdateメソッドが毎回呼び出され更新することでゲームが動いてるように見えます。このUpdateメソッドが1秒間に呼び出される回数のことをフレームレートと言います。この回数はモニタのスペックに影響され、その画面が1秒に描画できる回数分がデフォルトでは設定されます。この画面の1秒に描画できる回数を垂直同期周波数(カッコイイ)というのですが、この設定を変更することもできます。エディタ画面上部の[Edit]から[Project Setting]の[Quality]を開きます
インスペクターにQuality Settingが表示されます。
このメニューの下側「Other」の欄のVSync Countから変更できます。
デフォルトの「Every V Blank」は垂直同期周波数のことを表します。「Don't Sync」は垂直同期しないことを表し、「Every Second Sync」はEvery V Blankの半分の回数になります。
基本的に垂直同期しないという設定は使いませんがEvery Second Syncのように更新回数を減らせばモバイル向けアプリの動作を軽くしたりできます。
処理の分割 - コルーチン
RPGゲーなどの場合、次のマップの読み込みやエフェクトの描画、入力の受付など、様々な処理が同時に行われてますが、もし1フレームに次のマップの読み込み全てを行わせていたらとてもじゃないですがPS4のオープンワールドなんかは時間がかかってしまいます。マップの読み込みだけでなく、派手なエフェクトの描画なども処理が遅れれば処理落ちし、それがひどいとストレスがすごいですよね。そこでUnityでは、C#がもともと持っているコルーチンという機能を使ってその作業を何フレームにも分割させられるそうです。コルーチンは関数の途中で処理を中断し、その関数から抜け、再度呼び出された時に中断した部分から処理を行える機能です。
コルーチンはC#の「IEnumeratorインターフェイス」で表されます。インターフェイス懐かしいけど難しかった😓これとyield return文を使うことで書くことができます。
そしてIEnumeratorインターフェイスを呼び出すにはStartCoroutine()メソッドを使います。
StartCoroutine()メソッド
public Coroutine StartCoroutine(IEnumerator routine);
routineの場所にIEnumeratorインターフェイスを記述します。
手順としては
IEnumeratorインターフェイスを記述
↓
その中の中断するポイントでyield return文を書く
↓
StartCoroutine()メソッドで呼び出す
となります。実際にちょっと書いてみます
13行目〜30行目にIEnumeratorインターフェイスのRotateRoutineを記述し、その中にyield return null文を入れています。nullは「空っぽ」のことで、特に何もアクションをせずにここで処理を中断するのですが他にも色々なアクションをここで起こすことができます。例えばここに
StartCoroutine() →別のコルーチンに入る
WaitForSeconds() →一定時間待機する。
といったメソッドを入れることができます。とても便利!
さてこのスクリプトではfor文の中で「Vector3変数の r 文だけ回転するという処理を90回繰り返し」for文を抜け、向きを90度変えてcount変数に+1するというのを繰り返すものになっており、count変数が4になった場合初めて文が終わる仕組みになっています。コルーチンは関数の状態を保持してくれるのでこの中でcount変数を宣言しても再び呼び出したときにリセットされないし、rの中身もしっかり保持されていますね。
結果は以下のようになります
4回向きが変わったところで止まりました。Startメソッドの中で書いたものがずっと動き続けたり中身がずっと保持されてるなんて現実世界の考え方にすごく近くなっていますね。これだけわかればますます直感的にゲームをみんなが作れるようになるんじゃないか....?
ほんとはコルーチンはそれ単体で記事を書く必要がありそうなくらい便利で奥深そうですが今回はここまでにしておきます。
今年2018年のUnityカンファレンスイベントの早割チケットを実は購入しました!ちっともスキルも伴ってない実戦経験皆無の素人ですがたくさん刺激をもらっておこうと思います😄それまでは勉強だ😤
Unityスクリプト / コンポーネント編
みなさんこんにちは🌚
ゴッドイーターが面白くてアニメゲームアプリと全部やってしまっているブルーノです。ディストピア世界って好きなんですよねー。3が楽しみです!
さて今回はスクリプトからのコンポーネントの操作についての基礎を学んでいきたいと思います。コンポーネントといえば、シーン上から追加するには画面上部の[Component]もしくはゲームオブジェクトのインスペクター上の[Add Component]ボタンから追加することができ、目に見えるものからその性質まで色々な機能を持たせることができましたね。
コンポーネントの追加
全てのコンポーネントはUnityEngine.Componentクラスから派生しています。スクリプトを書く際に派生させているMonobehaviourクラスもまたこのComponentクラスから派生しており、スクリプトもコンポーネント(部品)として扱われることを表しています。さて、そのコンポーネントの追加ですが、スクリプトでこれを行うにはAddComponent()メソッドを使用します。
AddComponent()メソッド
public Component AddComponent(Type componentType)
public T AddComponent<T>() where T : Component
一つめのcomponentTypeにはコンポーネントの型を表すTypeオブジェクトを指定します。
二つめは前にやったジェネリックを使って型を指定しています。
dreameaters5239.hatenablog.com
dreameaters5239.hatenablog.com
ジェネリックメソッドは中身の型をメソッド名の<>で表すことで中の同じ名前の部分が全て型パラメータの型になる便利なメソッドでしたね。言葉で今回の例を表すならば「<T>のコンポーネントを追加する」のTの部分に<スクリプトの名前>だったり<摩擦係数の名前>だったりを入れるといったとこでしょうか。
例の上の文は、斜線の部分にコンポーネント名を入力します。また、componentTypeを入力する際は「typeof」キーワードをつけて戻り値はComponent型となります。例をちょっとみてみましょう
今回はスクリプトを二つ用意し、2つめのスクリプトには常にy軸を回転させることしか書いていません。一つめのスクリプトの9行目でまずCubeを生成し、次の10行目でBruno_Script02を追加しています。
くるくる回っていますね。
さて、先ほども言いましたが、AddComponent()メソッドで返される値はComponent型になって返ってきます。もちろんコンポーネントは皆Componet型を基として派生しているので動作上何も問題はありませんが、それを取得したり編集したりする場合その派生先、今回だったらBruno_Script02型として運用できた方が安全性も高まります。型キャストやas演算子を用いて2行で書くこともできますが、ジェネリックを使用すれば一行で収められます。例をみてみましょう。
Bruno_Script02にAnglesプロパティを追加し、回転量をBruno_Script01から設定しています。これができるのもBruno_Script02型として扱っているためその中のAnglesにアクセスできています。ちなみにさっきのメソッドで扱おうとしたら
「Component型にはAnglesなんてものはないよ!」と怒られました。やはり基底クラスの中で探すようですね。。。
コンポーネントの取得
では次にオブジェクトに付いているコンポーネントの取得をしてみます。
コンポーネントの取得はGetComponent()メソッドで行います。
GetComponent()メソッド
public Component GetComponent(Type componentType)
public T GetComponent<T>() where T : Component
AddComponent()メソッドの時の「Add」部分が「Get」に置き換わっただけですね。使い方も同じです。例を書いてみます。
今度はcubeにあるBruno_Script02の情報を取得し、その情報がなければAddComponentで追加するという流れです。
結果は同じですね。
コンポーネントの削除
スクリプトからオブジェクトを削除するにはDestroy()メソッドを使用します。
使い方はゲームオブジェクト編の時と同じです。
dreameaters5239.hatenablog.com
例を作成してみます。
15行目にDestroy()メソッドを作り、5秒後に回転量が格納されているrot変数を削除します。
5秒後に止まりました。
プロパティをエディタから編集
コンポーネントの状態はインスペクターから覗くことができ、変数をpublicにしておけば変数の値をインスペクター上に表示することもできます。しかし参照型のフィールドをpublicにしておくのはどこからでも容易にアクセスできる状態にしてしまうことに他なりません。そこで、privateな変数をインスペクター上に表示して編集できるようにすることができます。そこで使われるのがUnityEngine.SerializeField属性になります。
UnityEngine.SerializeField属性
public sealed class SerializeField : Attribute
また長い名前ですね。使い方の例を載せます。
private変数の手前に[SerializeField]とつけています。
インスペクターから値を入力することで回ります。
これにより、privateな変数である_x, _y, _zがインスペクターに表示されました。紛らわしいのですが、このインスペクターの名前は_(アンダースコア)の後のものを大文字にしているのでこのインスペクターには9行目は表示されていません。アクセッサの仕様ということでしょうか。これで安全性を強化できますね。
必須コンポーネントの指定
では最後に、先ほどやった属性の別のものも重要そうだったのでまとめておきます。
今まで作ったスクリプトの中にも、別のスクリプトが必要なものがいくつもありました。そのスクリプトだけをつけても意味がない場合、もしくは他のコンポーネントが必要な場合、普通であればコンパイルエラーを起こしますよね。その時に何が足りないかがすぐわかると良いですよね。そこで今度はUnityEngine.RequireComponent属性を使うことでそのスクリプトが依存しているコンポーネントを明示することができます。
UnityEngine.RequireComponent属性
public sealed class RequireComponent : Attribute
実際に見てみましょう
Bruno_Script01のクラスよりも頭に[RequiredComponent(typeof(Bruno_Script02))]とありますね。このスクリプトがBruno_Script02に依存していることを表します。そしてBruno_Script02はDebug.Logで"I'm awakend"と言うだけです。
実行するとメッセージが表示されました。さあ本番はここからです。エディタからBruno_Script02を除こうとすると...
Bruno_Script01は02に依存しているため削除できません。と表示されました。こういったゲーム内だけでなく開発側からのサポートをスクリプトから行うこともできるんですね。今回はここまでにしておきます。
いやーどうしても毎回この勉強は記事が長くなりがち&ハテナの山です。最近は講義の方も忙しくなってきて、英語の勉強もしなければならなくなってきました。別に英語は嫌いじゃないんですがどうしても単調になりがちですね。根気のない私にはプログラミングの勉強の方が山あり谷ありで楽しいです😊
今日講義で聞いたのですが、英語の勉強は「将来役立つから」とか「学校で覚えなきゃいけないから」といった直接的な理由だと苦手な人は続かないそうです。そういったときは自分の好きなことに結びつけて考え、実際に活用してみると良いそうです。私だったら洋ゲーに多く触れる、とかスクリプトの理解を容易にする、とかですかね。実際英語が少しできるだけでだいぶ助かってます😀
まーでも勉強をやる理由は自分の世界を広げるために他ならないですよね。自分のしたいことができたとき、自分の中にどれだけあらゆることに知識があるか、見聞があるかでその中身の充実度が変わってきますから。それに大学入るまで気づかないなんて勿体無かった....°(ಗдಗ。)°.
Unityスクリプト / ゲームオブジェクトの相関性編
みなさんこんにちは🌚
家事に勉強に大忙しのブルーノです。大量の卵をうまく消費する方法はないものか...
さて今回は、またこれも基礎的な内容ですがゲームオブジェクトの親子関係、その設定の仕方をスクリプトで学んでいきたいと思います。
ゲームオブジェクトの親子関係について
あるゲームオブジェクトを別のオブジェクトにドラッグ&ドロップするとそのオブジェクトの子になり、傘下に入るというのはこれまでなんども経験してきました。
こんな風になりましたね。エディタ上では設定することが簡単なこの操作ですが、スクリプト上で制御するにはTransformクラスのparentプロパティを使い、以下のように行います。
parentプロパティ
public Transform parent{get; set;}
あるゲームオブジェクトAを別のゲームオブジェクトBの子に設定したい場合、親となるAのtransformプロパティから取得したTransformオブジェクトを、ゲームオブジェクトBのtransformプロパティから取得したTransformオブジェクトのparentプロパティに設定します。何いってるかわからないと思うので実際に書いてみます。
子のtransform.parentプロパティに親のtransform情報を入れていますね。結果は以下のようになります。
一瞬でこれらのオブジェクトとその親子関係が築かれました。個人的にはとてもわかりやすい例なのですが、ラディッツは兄貴だから悟空より上ではとかいうのはこの際気にしないでください。
ゲームオブジェクトの移動について
シーン内のゲームオブジェクトの移動には、変形ツールの以下の上下左右に伸びた矢印から行いますよね。
これも親子関係を引き継いでおり、親を動かすと全く同じように子もついてきます。これは子の座標が親の座標を参照して得られているからです。このような座標をローカル座標といい、親のような何者にも属さない世界から絶対的な座標を与えられているものはワールド座標といいます。
オブジェクトの空間内におけるワールド座標は、positionプロパティで表されています。
positionプロパティ
public Vector3 position{get; set;}
以下のように書きます。
結果は以下の通りになります。
インスペクターを見てわかる通り座標がpositionプロパティで設定されたものになっていますね。
さて、今やったpositionプロパティはワールド座標を表すプロパティですが、子の親との距離、つまりローカル座標を変更したい場合、また別のプロパティを使います。それがlocalPositionプロパティです。そのままですね。
先ほどのを少しだけ変え、CubeをSphereの親にしました。そしてSphereをCubeの少し隣をキープするよう指定しました。
子であるSphereは自由に動かせますが親であるCubeを動かすとSphereも一緒についてきますね。ゲームなどでカメラを追従させるの等に使えそうです。
では移動について最後に、先ほどやった二つのプロパティはワールドにしろローカルにしろいきなり決められた座標に移動するので前者は常に座標を考えなくてはならず、後者は親依存の距離を常に保つだけなので単純な移動としては使いにくいです。指定した向きに指定した量だけ移動させることができればより移動の考え方が楽になりますよね。そこでTranslate()メソッドが役に立ちます。
Translateメソッド
public void Translate(Vector3 translation);
public void Translate(Vector3 translation, Space relativeTo);
public void Translate(Vector3 translation, Transform relativeTo);
translationパラメータに移動量のVector3型のベクトルもしくはfloat型の(float x, float y, float z)を指定します。
SpaceというのはTranslateで移動させる向きと量をオブジェクトを軸とするか世界を軸とするかを設定できるSpace列挙型というものです
Space列挙型
public enum Space
この列挙型には自身を軸とするSelfメンバと世界を軸にするWorldメンバが宣言されています。いずれかをrelativeToパラメータに入力して使います。
Transformを入れた場合はそのtransformパラメータを軸とします。つまり他のゲームオブジェクト等を軸として移動させられるわけですね。ここで自身のtransformを入れればSpace.Selfと同じになります。
実際に見てみましょう
x座標が3より大きくなれば左に1ずつ、つまりxが-1、逆にxが3より小さくなれば右に1ずつ、つまりxが+1されるようになっています。21行目の(_direction * 0.1f ~ の後に座標軸の情報を入力できます。
ひたすら左右に移動しますね。
ゲームオブジェクトの回転
ゲームオブジェクトの回転は変形ツールのリサイクルのようなマークで行いますよね。
これにも軸があり、シーン上ではX, Y, Z を自由に回転させられます。
オブジェクトの向きをスクリプトから変更するにはTransformクラスのrotationプロパティで変更します。
rotationプロパティ
public Quaternion rotation {get; set;}
rotationプロパティはQuaternion構造体という四元数を格納する構造体を計算し簡単なX, Y, Zで表してくれるのですが、私のような数学が苦手な人を含む一般の人には四元数を入力したQuaternion構造体は手動ではとても用意できないのでQuaternion.Eulerメソッドというものを併用します。これはX, Y, Zをパラメータとして送るとそれを四元数に計算しQuaternion構造体として使用してくれるすごいメソッドなのです。なんだかコンパイラみたいですね。例を載せます
Quaternion.Eulerメソッドのおかげで我々でもわかりやすい形式で角度を指定できます。
カクンってなってます。カクンって。
そしてこれもワールド座標での向きなので、ローカル座標の向きも指定できます。それがlocalRotationプロパティです。
localRotationプロパティ
publicQuaternion localRotation{get; set;}
使い方は先ほどのlocalPositionプロパティ等と同じです。例を載せておきます。
左から、手前に45度、左の角度を軸としてYに45度、真ん中を軸としてZ軸に45となっています。
ローカルときたら次は単純な回転ですね。これにはRotate()メソッドを使います。
Rotate()メソッド
public void Rotate(Vector3 axis, float angle);
public void Rotate(Vector3 eulerAngles, Space relativeTo);
axisに方向、angleにその量を入力するか、eulerAnglesに回転量、その後に軸を指定することで使うことができます。簡単そうなのは下の方ですね。
ゆっくり回転してます。。。
ゲームオブジェクトの拡縮
さて最後に大きさの変更の仕方を学んでおきます。シーン上のゲームオブジェクトの拡縮にはでっかくなってる感じのボタンから行えますね
スクリプトでこれを行う場合はTransformクラスのlocalScaleプロパティを用います。
localScaleプロパティ
public Vector3 localScale{get; set}
実はこの大きさ(Scale)だけは常に親を継承するのでローカルしかなく、逆にワールド座標系のサイズ指定を行うことはできません。一応ワールド座標系の実際のサイズを取得したい場合はlossyScaleプロパティから取得できるのですが、読み取り専用プロパティなのでこれに値を入れてサイズを変更といったことはできません。
lossyScaleプロパティ
public Vector3 lossyScale{get;}
では実際に書いていきます。
まずは親のみサイズ変更してみます。すると...
子供もおっきくなりました。
では次に子に同じようにスケールを与えると...
めっちゃでかくなりました。今回はここまでにしておきます。
いやー久しぶりの投稿ときたらこれですよ。普段から使えるツールバーのメニューもスクリプトで制御しようとしたらこんなに色々あるんですね。でもゲーム中は自由にツールバーで動かしながらゲームを進行できるわけではないのでこれらの知識は非常に活きてくるはずです!!
最近はソシャゲにも色々手を出していて、ゴッドイーターのオンラインとレゾナントオプスを両方ともやっています。ソシャゲって据え置きや製品ゲームとは全くシステムものめり方も違いますよね。これも勉強しなければ...
Unityスクリプト / ゲームオブジェクト編
みなさんこんにちは🌚
新年度が開始して色々やることや把握することが増えたブルーノです。リアルが忙しくなってもこっちをまったり進めていきます🙄
今回は、スクリプトから直接行えるゲームオブジェクトに関する操作について勉強していきます。ゲームオブジェクトの中身の操作というよりは、生成や管理などを今回はまとめます。
UnityEngine.GameObjectクラス
今更ですがスクリプトからゲームオブジェクトを生成したりアクセスしたりするにはこのGameObjectクラスを使います。newキーワードでインスタンス化すればスクリプトからオブジェクトの生成ができます。その際のコンストラクタは以下のように指定することができます。
GameObjectクラスのコンストラクタ
public GameObject()
public GameObject(string name)
public GameObject(string name, System.Type, components)
string nameにゲームオブジェクトの名前、System.Typeにはその型、そしてそのゲームオブジェクトに付属させるコンポーネント名を指定することができます。
何もパラメータを渡さずに実行してみました。
[New Game Object]が追加されました。
CreatePrimitiveメソッド
今新しくゲームオブジェクトを生成しましたが、シーン上に目視できるようになるためには物体の形を示すメッシュやそれを描画するレンダラーなどのコンポーネントを必要とします。先ほどのコンストラクタからコンポーネントを指定する他に、CreatePrimitiveメソッドを利用することでゲームオブジェクトに基本モデル(プリミティブ)を追加することができます。
CreatePrimitiveメソッド
public static GameObject.CreatePrimitive(PrimitiveType type);
typeの欄には基本モデルの図形の種類を指定します。
CreatePrimitiveメソッドで生成できる全ての基本モデルを適当に生成しました。PlaneとQuadの違いはポリゴンの数で、Planeは多くの頂点とポリゴンを持ち、Quadは4頂点2ポリゴンで構成されています。
Instantiateメソッド
エディタ上でゲームオブジェクトをコピーアンドペーストするだけで簡単にゲームオブジェクトを複製することができますが、これをスクリプトから行うこともできます。
Instantiateメソッド
public static Object Instantiate(Object original);
public static Object Instantiate(Object original, Vector3 position, Quaterion rotation);
originalパラメータに複製するゲームオブジェクトを指定し、positionに複製する場所、rotationにその向きを指定します。positionとrotationを指定しないと複製元のオブジェクトと重なったり同じ向きになったりします。
先ほどのスクリプトのキューブを複製しました。
Destroyメソッド
ゲーム中にシーン中に作り出した弾やアイテム、エフェクトなどは消さなければいつまでも残り続けてしまいます。そこでこのDestroyメソッドを使ってオブジェクトを削除することができます。
Destroyメソッド
public static void Destroy(Object obj, float t);
objに削除するオブジェクトを、tには削除するまでの時間を指定できます。tを指定しなかった場合は0と同じですぐに削除されます。
複製元のCubeを5秒後に削除します。
なお、ゲームオブジェクトを削除する目的でこのメソッドを削除するオブジェクトのスクリプトに組み込み、パラメータに「this」を入れると、削除されるのはオブジェクトじゃなくてそのスクリプトになります。
Findメソッド
シーン上のゲームオブジェクトをスクリプトで名前から検索することができます。
Findメソッド
public static GameObject Find(string name);
nameパラメータにシーン上の名前を指定します。この名前による検索は負荷の高い処理であるため、Update()メソッドなどのフレーム単位で乱用するのは望ましくないそうです。
「Cube」という名前のオブジェクトを検索し、cubeという変数にその情報を格納します。そして、Updateメソッドでその名前のオブジェクトを回転させます。もしCubeという名前のゲームオブジェクトがそのシーン上に見つからない場合は例外が投げられます。
今回はここまでにしておきます。
色々便利なメソッドがあるようですね!!私は体で覚える派なのでこういったものを取り入れたゲームをどんどん作って実践していきたいと思います。頭の中のアイデアを早く形にできるようになりたいです。
Unityスクリプト / 開発目線編
みなさんこんにちは🌚
すっかり暖かくなり、日が昇る時間も早くなって本格的に生活リズムを学校生活モードに戻しつつあるブルーノです。部活も始まり忙しくはなりますが、勉強の方も続けたいと思います!!
さて今回からは、Unityで使える、必須!というスクリプトを勉強していきたいと思います!見栄えのいいモデルや綺麗なサウンドももちろん大事ですが、世界の挙動を知らなければ面白いゲームは作れない!というわけでどんどん勉強していきます!今回は開発者用必須スクリプト編です!
UnityEngine.Debugクラス
デバッグ中にゲームの情報を出力したり、ゲームを一時停止したりすることができるメソッドを内包するまさにデバッグ用のクラスです。
任意の文字列を出力
DebugクラスのLogメソッドを使うと、Unityエディタ上でゲームを再生している間に、Consoleビューにパラメータとして渡した文字列を表示させられます。
Logメソッド
public static void Log(object message, object context)
[object message]の部分に文字列を入力すると、Consoleビューにこの文字列が表示されます。このコードが実行されたタイミングがわかるというわけですね。
[object context]の部分にはそのシーン上のゲームオブジェクト名を入力することで、デバッグログ選択時にそのオブジェクトをオートフォーカスしてくれます。つまり、ここに this 等を入れることで、このデバッグログがどのオブジェクトから出力されているかも表示してくれるというわけです。
Logメソッド以外にもLogErrorメソッドと、LogWarningメソッドというものも存在します。これらはその名の通り、先ほどのデバッグログをエラーや警告として発信してくれるメソッドです。コンソールビューでのエラー等が見やすくなるということですね
LogErrorメソッド
public static void LogError(object message, object context)
LogWarningメソッド
public static void LogWarning(object message, object context)
詳しい書き方はDebug.Logメソッドと同じですね。実行すると以下のようになります。
ゲームを一時停止
Unityエディタでゲームを実行中、一時停止ボタンかCtrl + Shift + P でゲームを一時停止できます。しかしこの停止のやり方は、デバッガーが自分の目押しで止めるため、特定の瞬間で止めるのはほぼ不可能です。そこで、Debug.Break()メソッドを使うと、スクリプト上からゲームを一時停止できます。気になる瞬間に組み込むことでその編集を容易にできますね。
Breakメソッド
public static void Break();
実行すると以下のようになります。
実行した瞬間に一時停止されました。あれ、Breakの後のエラーや警告も実行されてるじゃないかと思いますが、Breakが止めるのはそのフレームの更新後なので、そのフレーム中の処理は実行されてしまうのです。
とりあえず超基本のスクリプト、開発編はここまでにしておきます。
スクリプトが大事と冒頭では述べましたが、サウンド作りやモデリングができなければもちろんいけないですよね。何から手をつければ良いのやら...
Unity / GUI(Audio Mixer - オーディオミキサー編)
ロスロケ島
みなさんこんにちは🌚
大学の卒業式を終えて先輩方がいなくなってしまいとても悲しい反面おめでたい気持ちも感じられるブルーノです。昔から出会いと別れを頻繁に繰り返す生活を送ってきましたがここまで思い入れがあった方々は初めてでした😢私も自分の勉強を頑張っていきたいです!
さて今回は、BGMやSE、つまり音楽の扱い方を学んでいきたいと思います!
Audio Mixer
まずは恒例のアセットストアからサウンドをダウンロードしたいと思います。
今回使うのはこちらの無料の「Warped Fantasy Music Pack」です。
まずはBGMを配置します。「BGM」という名前で空のゲームオブジェクトをシーン上に配置し、Audio Sourceコンポーネントを追加します。
AudioClipに好きなBGMを配置し、[Loop]の欄にチェックを入れればBGMが流れ出します!
では次にAudioMixerを使ってみましょう
プロジェクトブラウザのメニューから新たにAudioMixerを用意します。ここからクリエイトするのは何気に初めてです。
なんか他にもたくさん作ることができるものがあって目移りしそうです笑
Audio Mixerに「Main Mixer」と名前をつけてみましたので開きます。
新しいウィンドウです。そして、先ほど作ったBGMのAudio Sourceのインスペクターの
OutputにこのMainMixerを指定します。
この状態で再生を始めると、Mixerのウィンドウの上に「Edit in Play Mode」というボタンが現れます。Unityのエディターは基本的に再生中の変更は再生が終わると元の状態に戻されてしまいますが音楽は実際に聴きながら編集しなければ難しいため、このEditボタンがあるのです。
さてエディットモードですが、この画面でいう-10と書かれたツマミを上下させると音量が変更できます。ミキサーのインスペクターからも変更でき、数字を入力して変更もできます。
[Add Effect]という欄がありますね。今あるエフェクトはAttenuation、英語で「減衰」とかいう意味だそうです。これで音量を調整できます。そして他にもエコーや歪み等のエフェクトをここから追加できます。
ちなみに今ここにはMasterという全ての音を一緒にしたグループしかありません。BGMとSEを分けてそれぞれ別のエフェクトをかけたい場合は一度エディットモードを終了し、先ほどのAudioMixerウィンドウの左真ん中の[Group]を追加することで別々に編集することも合わせた時の音楽を編集することもできます。
みやすくてやはり便利ですね😀今回はここまでにしておきます。
人の縁は不思議なものでつながりを実感することでいくらでもやる気や力が湧いてきます。ちゃんと仲の良い関係を築けることが何かを成し遂げるためには不可欠だなあと最近しみじみと思います。一人で生きていける人間は極僅かですもんね。
Unity / GUI(Button・スライダー編)
ライダル・マウント
みなさんこんにちは🌚
久しぶりの投稿になります。フォートナイトにはまっているもののCODとかのようなFPS系のゲームをやったことがないのでちっとも敵を倒せないブルーノです。でも勝てないのに楽しいって変ですよね笑
さて今回は他の様々なGUIの機能を使っていきたいと思います!
Button
ほぼ全てのアプリにある代表的なGUIとしてボタン(Button)がありますね。Unity UI ならこれを簡単に扱うことができます。
ヒエラルキーもしくは画面上部の[Game Object]から[Button]を選択します
前回のUIがプロジェクトタブに残っていますね笑
ゲームシーン左上にレガシーUIの時のようにボタンが配置されました。ボタンの中には[Text]というゲームオブジェクトも入っていますが、これはボタンに書かれる文字のことなのでボタンに文字が要らなければ消してしまっても構いません。
ボタンの配置
さあButtonのインスペクターを見てみると前回のSpriteの時のようにレクトツールやアンカーが使用可能なのがわかります。
レガシーGUIの時はUIを作成した後さらにスクリプトコンポーネントを作りましたが、UnityUIは下の「On Click」という欄から簡単に設定できます。
右下の+をクリックし、作用させるゲームオブジェクトを選択します。今回は例として[Directional Light]を設定します。
[No Function]の箇所から使用する関数を選択し、[Runtime Only]の部分は発動するタイミングを選べます。たったこれだけで、レガシーUIの時のように色々スクリプトを書かずにボタンの設定画できます。しかも処理にあまり負荷がかからない!!
さて、ボタンといえば、アプリ等でボタンをタップしたりすると音が鳴るものもありますよね?そんな風に、ボタンにSEをつけることもできます。
まず、Buttonのインスペクターの[Add Component]から[Audio] > [Audio Source]を追加します。
使う音声はアセットストアから用意します。
今回はこちらを使わせていただきます。
Audio Sourceの[Audio Clip]から流す音声を選択すれば良いのですが、このままでは音楽は流れません。先ほどのように、[OnClick]からこのButtonを追加し、そのFunctionをこのAudio Clipにしなければなりません
色々メソッドがありますが、この中のPlay()メソッドで、SEを鳴らすことができます。ただしもう一つ!このままではシーン再生時にも音がなってしまうので、Audio Sourceの中の[Play on Awake]の項目のチェックを外しておきましょう。これで大丈夫です。
スライダー
今度はよくゲームのオプション等で光度調整や音量調整に使われるスライダーを設定しましょう。今回は回るキューブの回転する速さを変更するスライダーを作ります。
Cubeを新しく作り、以下のスクリプトをつけます。
これはY軸を中心に1秒で一周回転するスクリプトで、このスピードを調節するスライダーを作ります。
UI > Sliderを選択します。
インスペクターを見てみましょう。大事なのは下の方のMin ValueとMax Valueで、左から右へのスライダーの移動具合でこの間の数値がfloat値で変化します。
変更する値ですが、このスクリプトをスライダーにつけ、この値を変更できるよう[On Value]から先ほどのように指定します。
これで再生するとスライダーの位置によって回転のスピードが変化するようになりました!
このように様々なUIを手軽に、そして他のコンポーネントをつけることができるのです!!今回はここまでにしておきます。
現在Youtubeでバンダイからデジモンアドベンチャーの映画の「僕らのウォーゲーム!」が無料公開されてますね。この映画は私のバイブルとでもいうくらい子供の頃大好きだった映画で、何百回と見ました。デジモンも新しいアプリが出るようなのでとても楽しみですね。。。😍