第
4
章
簡単
!VR3(00)
分クッキング
74
回生
harady
4.1
始まりと終わりのプロローグ
こんにちは。74回生のharady(原井)です。今回初めて部誌を書くので多分初めましてだと思います。偉大なる先輩方の精進っ ぷりを指をくわえて眺めていたら、気づいたらもう中3になってました。嘘やろ...。時がたつのは早いので皆さん気を付けま しょう。 今回の文化祭に向けて僕は、VRゲーム「寿司(が)打」を作りました。この部誌では、このゲームをUnity+Oculusで3(00*4 以上)分かけて作った様子をまとめました。一応ツールなどは小冊子にまとめたのですがここにも書いておくと、材料は • スペックの高いパソコン • VR機器(Oculus,VIVE...) • 開発ソフト(Unity,Unreal Engine...) • 技術 • やる気 です。VRゲームはおろか、普通のゲームですらUnityで完成させたことがなかったのでUnityの使い方として良くない点があ るかもしれませんが、大目に見て下さい。また作り始めたのが4月に入ってからなので、随所に手抜き工事の痕跡が残っています。 許ちて。それと表記揺れがあるかもしれませんが、見逃して下さい。 それでは「寿司(が)打」制作記の始まり始まり∼4.2
概要
まず、何をするにしても、行動計画を立てることは重要です。このゲームの制作過程を数段階に分けて書くと、 • どんなゲームにするか • モデル用意 • 配置&テクスチャ決め • プログラミング といった感じになるかと思います。以降ではこれに従って書いていきます。4.3
どんなゲーム?
このゲームのコンセプトは初めから決まっていました。「寿司の気持ちになるゲーム」です。回転寿司の寿司の気持ちになるVR ゲームを作ったら面白いんじゃね?w、というネタ会話からすべては始まりました。 作る前から決めていた仕様は • プレイヤーは皿の上 • 回る• 捕食者が取りに来る
ぐらいでしょうか。書いてから気付きましたが、ただの回転寿司ですね。これらの実装はプログラミングの項にまとめます。
4.4
下拵え
制作を開始する前に少し準備が必要です。まずVR対応するUnityのProject側の設定をしなくてはなりません。これは簡単 で、上のメニューバーからEdit→ProjectSettings→Player →Other Settings→Virtual Realty supportedにチェックを入れ るだけです。Oculusを接続していたらおそらく自動で認識されます。
あとOculusの公式が配布しているOculusPlatformとOVRとOvrAvatarをUnityにインポートして下さい。これらの詳しい 使い方はググって...。一応OvrAvatarの使い方だけ説明すると、OvrAvatar→Content →Prefabs→ LocalAvatarをヒエラル キーにコピーすればよいです。カメラにはOVR Camera RigとOVR Managerをアタッチします。
4.5
モデルが無いと始まらないよ
!
いざ制作スタート! ...モデルが、無い...。3Dモデルが無いゲームを3Dゲームと呼んでいいのか?断じて否だ!
はい、というわけでまずモデルを用意するところから始めましょう。自分の欲しい3Dモデルは、WebのフリーモデルやUnity のAsset Storeを探せば大抵見つかりますが、探すのに時間が掛かるし、目的のモデルが見つかるとも限りません。そんな時は自 分でモデルを用意してしまいましょう!(嘘つけ絶対こっちのほうが時間掛かるやろ)
モデル制作はBlenderというフリーソフトを使って行いました。Blenderの使い方はkota氏が部誌にまとめていますが皿とレー ンの作り方を大雑把にまとめると、
皿
断面の半分を作ってスクリューモディファイアで1周し、それに再分割曲面モディファイアを適用した...んだと思います。覚え てません... テクスチャはUV展開して然るべき場所にネットで見つけた六角形の画像を加工して貼り付けました。
第4章 簡単!VR3(00)分クッキング 4.6どこに置くの?
レーン
直線部分と円周部分を分けて作りました。円周部分の作り方は皿と同じです。テクスチャはめんどくさかったのでUV展開せ ず、Blenderのマテリアル割り当て機能を使いました。
完成したらオブジェクトの原点?(Pivot)をCtrl+Alt+Shift+Cで重心に動かしましょう。これを怠るとUnityでの作業がとて もやりにくくなります。
Blender を使う上で覚えておいたほうが良いショートカットがいくつかあります。Aキーや UnDoのCtrl+Z やReDoの Ctrl+Shift+Zなどは必須だと思います。他にもたくさんあるのでググるなりなんなりして下さい。
できた3Dモデルを.fbxでメッシュのみエクスポートしておきます。(.blendのままでも良いみたいなのですが、ライトなどが くっついてきて邪魔だったので.fbxにしました)。ここで問題になるのが座標系です。Blenderは右手座標系のZ-up、Unityは左 手座標系のY-upなのでBlenderで作ったモデルをそのままエクスポートするとUnityにインポートする際に向きが変わってしま います。エクスポートするときに左下のメニューで前方をZ、上をYに設定し、トランスフォームを適用にチェックを入れましょ う。これをしないと後々少しめんどくさいことになります。
4.6
どこに置くの
?
さぁUnityを使うぞ! ...どうやって画面を作るんだ...
Unityを使ったゲーム制作は、まずモデルを配置するところから始まります。まずはUnityのメニューバーのGameObject → 3D Object→Cubeで立方体を作りましょう。こいつを拡大して床にします。このままでは白色1色で味気ないのでテクスチャを 設定します。Asset Storeで見つけたフリーの木の床のテクスチャを使いました。 床ができたら次はレーンの配置です。先程作ったレーンをUnityにインポートして(0,~,0)に置きます。Y座標は上下を表すの で適宜調整しましょう。インポートする際はモデルとテクスチャを一緒にインポートしましょう。そうしないとモデルにテクス チャがつきません(多分)。 レーンが置けたら次は皿を設置します。皿を動かすプログラムの関係で円周部と直線部の境目に置きました。ここで僕は気付き ました。なんか皿がのっぺりしてる...
この問題の解決には少し時間がかかりました。Blender側でマテリアルをいじっても全然反映されないのです。考えてみるとこ れは当たり前で、Blenderで設定しているのはあくまでBlenderでレンダリングする際の設定なので、この設定がUnityに反映さ れる訳がないのです。という訳でUnity側でマテリアルを編集しましょう。 めでたく皿が光るようになりました。やれやれ、やっとできた...ダメでした。ちょっと前に書いたBlenderのエクスポート設 定を知らなかった自分は普通に皿を回転させて使っていたのです。ここに大きな罠が潜んでいて、Unityにおいて回転されたオブ ジェクトのx,y,z軸は回転する前と角度が変わってしまうのです。モデルをもう一度エクスポートし直せばいいのですが、そうと 知らなかった当時の僕は皿のモデルの親にEmptyを作り、Emptyを回転させることで解決しました。この問題はこのあと腕を実 装するときにも再び発生します。何はともあれひとまず問題は解決しました。 あとは適当に壁や天井を作りましょう。ここは本質ではないので手抜きです。 天井を設置すると太陽光(最初からあるDirectional Light,平行光線)が通らなくなり画面が暗くなります。そこで天井の中心付 近にPoint Lightを1個設置しました。 これで一通り配置できました。お次はプログラミングです。一番面倒、というかこれが本編かもしれません。
4.7 No Programming No Creating game ~
とある似非プログラマーの死
~
おい、このゲーム動かねぇぞ! 当たり前だろ、プログラム1個も書いてないんだぞ! はい。プログラムのないゲームが動くはず がないのでプログラミングしていきましょう。ちなみに言語はC#です。
まずはプレイヤーの移動スクリプトです。回転寿司ですのでレーンの上をレーンに沿って動く必要があります。ここからはスク リプトを貼り付けて解説するスタイルで行きます。ちなみにファイル名は適当です。というわけで移動スクリプト...の前に一つ。
第4章 簡単!VR3(00)分クッキング 4.7 No Programming No Creating game ~とある似非プログラマーの死~
都合上スクリプトの名前をゲーム内での名前と変えている場合があります。本来スクリプトの名前とclassの後に書くものは同じ でなければなりません。
移動スクリプト
Move.cs
usingSystem.Collections;
usingSystem.Collections.Generic;
usingUnityEngine;
public classmoveOther: MonoBehaviour {
Vector3 center;
Vector3 center2;
float starttime;
// Use this for initialization
voidStart() {
center= GameObject.Find("center").transform.position;
center2=center;
center2.x= -center.x;
starttime=Time.time; }
// Update is called once per frame
voidUpdate () {
if (transform.position.x> 4f) {
transform.RotateAround(center2,Vector3.up, -180f / 14f *Time.deltaTime); }else if(transform.position.x< -4f) {
transform.RotateAround(center,Vector3.up, -180f/ 14f*Time.deltaTime); }
else if(transform.position.z< 0) {
transform.position += newVector3(0.5f *Time.deltaTime, 0, 0); }
else{
transform.position += newVector3(-0.5f* Time.deltaTime, 0, 0); } } } もっと短くなるかもしれませんが、これをもとに説明していきます。 最初の3行はおまじないだと思ってて下さい。"名前空間"でググると大体わかると思います。 次の public~もUnityでスクリプトを作ると最初から書いてある部分で、変更してはなりません。 実際の処理は次の行からです。最初の数行では処理に使う変数を定義しています。変数とは色々な型の値を取り扱うもので、座 標を表す変数や整数を表す変数など様々なものがあります。ここでは移動する為に必要な座標を表す変数と時間を記録する変数を 定義しています。 ’//’はコメントアウトです。//をかいた行は無視されるのでコメントを書くことができます。
次の Void Start() で Start 関数を定義しています。Start のあとの’{’から、数行下の’}’までが Start 関数です。関数とい うのは、足し算引き算等の様々な処理をまとめて記述したもので、関数を呼び出すだけで、関数内で書かれた処理がすべてまとめ て行われます。Start 関数というのはUnityがスクリプトを実行するときに、最初に1回だけ実行される関数で、ここで値の代入 やオブジェクトの初期配置等の処理を行います。今回のスクリプトでは皿を動かすときの目印となる地点の座標と、タイマーの最 初の時間を決めています。
次の Void Update() で Update 関数を定義しています。Update 関数はUnityが毎フレーム実行する関数です。フレームとい うのはすべての処理を始めてから終わるまでの時間で、1秒間に数十から数百回フレームが加算されます。フレーム数はプログラ ムの重さによって変わります。重いゲームでは、処理に時間がかかるので、必然的にフレーム数は落ちます。秒間フレーム数は常 に変化するので、移動用の関数などを Update 関数内で使う場合には後述する処理が必要です。 では Update() 関数内の移動処理を解説していきます。はじめのifは条件分岐です。()内の条件を満たしていると{}内の処理が 行われます。その次のelse内に書かれた処理は直前のif文の条件を満たしていない場合に実行されます。else ifは直前のif文の条 件を満たしていない、かつ()内の条件を満たしているときに実行されます。詳しく見ていきましょう。 3 つの()内で皿が今どこにいるかを判断しています。直線部なのか円周部なのか、みたいな感じです。直線部なら trans-form.position(皿の場所)のX座標を1秒に0.5ずつ増やし、円周部では transform.RotateAround() 関数でcenterという座標 を中心に毎秒180/14°回しています。Vector3というのは3次元ベクトルを表す型で、Time.deltaTime は先程書いた Update 関数の問題点を解決する為に書いています。Time.deltaTime でそのフレームを処理するのにかかった時間(秒)を取得すること ができます。毎フレームで秒速*秒だけ処理を行うことで一定の変化を表現できるというわけです。長くなるので次からは一部抜
粋して載せていこうと思います。 このゲームでは腕が飛んでくる仕様なのでお次は腕を生成するスクリプトと生成した腕を動かすスクリプト。その前に腕の説明 をしておくと、現状Unityの標準の3DモデルであるCylinderを利用しています。文化祭本番では腕のモデルになってる...かも しれません。まずは生成から
腕
腕を生成 eatSushi.cspublic classeatsushi :MonoBehaviour {
Transform arm_point;
Transform dish;
public GameObject arm_pf;
float time;
// Use this for initialization
voidStart() {
arm_point=transform.Find("arm");
dish=GameObject.Find("Main Camera").transform;
Vector3 add= arm_point.transform.position;
add.x =add.x +Random.Range(-0.5f, 0.5f) - 0.5f;
add.y += Random.Range(-0.5f, 0.5f);
arm_point.transform.position =add;
arm_point.transform.LookAt(dish);
time= 0;
Instantiate(arm_pf,arm_point.transform.position,arm_point.transform.rotation); }
// Update is called once per frame
voidUpdate() {
time+= Time.deltaTime;
if (time > 5f) {
Instantiate(arm_pf,arm_point.transform.position, arm_point.transform.rotation);
time = 0; } } } ちょっと長いですね...では解説していきます。 まずこのスクリプトは捕食者に対してアタッチします。 はじめの Transform はオブジェクトの位置や角度などをまとめて記憶する型です。座標と角度を指定して使う関数の引数に指 定できます。GameObject は、1つのオブジェクトの持つ情報をすべて格納できる型です。 Start関数内では生成すべき腕を読み込み、所定の座標に乱数を足した座標を生成し、Instantiate() で生成しています。ま た、一定時間ごとに生成する為にタイマーを設定しています。
Update関数内で5秒ごとに生成する処理を記述しています。Start 関数内で処理を開始した時間を記録しておき、Time.time で取得した今の時間との差が5を超えたときにタイマーを0にセットし、腕を生成すればいいわけです。
お次は腕を動かすスクリプト。命名が適当だけど許ちて。 腕を飛ばす
Shot.cs
public classmomove: MonoBehaviour {
Transform dish;
// Use this for initialization
float starttime;
int attack;
voidStart () {
dish=GameObject.Find("TrackingSpace/CenterEyeAnchor").transform;
//transform.Rotate(new Vector3(1, 0, 0) * 180);
transform.LookAt(dish);
starttime=Time.time;
attack= Random.Range(0, 4); }
// Update is called once per frame
voidUpdate() {
if (attack == 0) normalAttack();
else if(attack== 1) fastAttack();
elseballisticAttack(); }
voidnormalAttack() {
transform.LookAt(dish);
第4章 簡単!VR3(00)分クッキング 4.7 No Programming No Creating game ~とある似非プログラマーの死~
transform.Translate(Vector3.up *Time.deltaTime * 0.75f); }
voidfastAttack() {
transform.LookAt(dish);
transform.Rotate(newVector3(1, 0, 0) * 90);
transform.Translate(Vector3.up *Time.deltaTime * 1f); }
voidballisticAttackfh() {
transform.Translate(transform.up *Time.deltaTime* 1.5f); }
voidballisticAttacklh() {
transform.LookAt(dish);
transform.Rotate(newVector3(1, 0, 0) * 90);
transform.Translate(Vector3.up *Time.deltaTime * 2f); }
voidballisticAttack() {
if (Time.time-starttime < 3f) {
ballisticAttackfh(); } else{ ballisticAttacklh(); } } } 長い...。この関数は腕自体にアタッチします。生成するスクリプトから制御しようと思ったのですが、複数生成されたオブジェ クトのそれぞれに個別の処理をすることができなかったので、腕自体にアタッチしました。結果的にこのほうがコードが書きやす くなってると思います。
腕には3種類の飛ばし方を設定しました。Start 関数内でランダムに切り替えています。また Transform 型の dish にVRの 目を指定し、そこをめがけて腕が飛ぶようにしています。この仕様によって目の前に腕が迫ってくる演出ができます。
3種類それぞれの説明をする前に1つだけ。各関数のどれも、移動する前にRotateしていたり、移動の方向もオブジェクトに対 する前方ではなく上方になっています。ここには大きな罠(?)が潜んでいて、Unityの円柱はもともと前方が側面になっているの です(多分)。腕の親にEmptyを設定して、このEmptyを回せば解決する気がするのですが、実験している時間がなかったのでこ のような形になっています。
では3種類を見ていきましょう。
normalAttackはnormalなAttackです。最もゆっくり飛んできます。最初にdish(目の中心)の方向を向き、少し上に書いた 処理を行い、上方向(要するに皿の方向)めがけて秒速0.75で飛ばしています。
fastAttackはfastなAttackです。速いです。処理方法は normalAttack と同じですが、速度が秒速1になっています。 ballisticAttackは ballisticAttackfh と ballisticAttacklh から出来ています。まず上に飛んで行って、そこから皿 めがけて飛んでくる仕様です。飛び始めてからの時間3秒以下の時 ballisticAttackfh が実行され、腕は秒速1.5で上へ飛んで いき、その後 ballisticAttacklh が実行され下向きに秒速2で飛んできます。 どれも飛ばし方自体は大したことありませんね。 では次。パンチ&当たり判定です。多分ここが一番大変でした。飛んできた腕をパンチする部分と、消しきれなかった腕が顔に 当たる処理です。2つとも貼ります。
パンチ
&
当たり判定
hit.csusingSystem.Collections;
usingSystem.Collections.Generic;
usingUnityEngine;
usingUnityEngine.VR;
public classhit :MonoBehaviour {
float vl; Vector3 dif; Vector3 dif1; Rigidbody rb; AudioClip sound; die Die; int score = 0;
// Use this for initialization
voidStart () {
rb =this.GetComponent<Rigidbody> ();
dif= InputTracking.GetLocalPosition(VRNode.RightHand);
sound =GetComponent<AudioSource>().clip;
Die= GameObject.Find("CenterEyeAnchor").GetComponent<die>(); }
voidOnTriggerEnter(Collider other) {
if (other.gameObject.tag == "enemy") {
Destroy(other.gameObject);
if (vl > 2f) {
Ddie();
GetComponent<AudioSource>().PlayOneShot(sound); }
} }
// Update is called once per frame
voidUpdate() {
dif1=InputTracking.GetLocalPosition(VRNode.RightHand) -dif;
vl =Vector3.Magnitude(dif1);
vl =vl /Time.deltaTime;
dif= InputTracking.GetLocalPosition(VRNode.RightHand); }
voidDdie() {
Die.combo++;
Die.score += Die.scorep;
Die.hit = 0; }
第4章 簡単!VR3(00)分クッキング 4.7 No Programming No Creating game ~とある似非プログラマーの死~
die.cs
public classdie :MonoBehaviour {
public inthit = 0;
public intcombo = 0;
public intscorep = 2000;
public intscore = 0;
// Use this for initialization
voidStart () { }
voidOnTriggerEnter(Collider other) {
if (other.gameObject.tag == "enemy") {
hit++;
Destroy(other.gameObject); }
}
// Update is called once per frame
voidUpdate () { if (hit >= 6) { hit = 0; combo = 0; } if (combo >= 5) { scorep += 10000; } } } 上が (右) 腕と用スクリプトで下がプレイヤーへの当たり判定用のスクリプトです。右腕と書いたのは、スクリプト中で RightHandと書いてある部分を左腕ではLeftHandにする必要があるからです。VR機器のデータを取り扱う場合には上のスク リプトのように using UnityEngine.VR を記述する必要があります。上のスクリプトで音を鳴らす処理をしている箇所があり ます。音はAsset Storeなどで探しましょう。さすがに自作する気力はありませんでした。音が用意出来たら右腕(OvrAvatarを 使っている場合)Tracking Space直下のRightHandAnchorにアタッチします。
パンチ
先に上のスクリプトの処理の中身を書きます。上のスクリプトではパンチに関する判定を行っています。具体的には自分の腕が 飛んできた腕に一定の速度以上でぶつかったときに飛んできた腕を消すという処理です。では説明していきます。
初めの変数の宣言で Rigidbody と die という新しい型が登場しています。Rigidbody はUnityが物理演算の為に使う項目 です。die 型の変数を宣言すると、その変数がdie.cs(下のスクリプト)に書いてある内容を取得する為に使えるようになります。 Start関数内で die 型のDieに、CenterEyeAnchor(目の中心)にアタッチされたdie.csを代入しています。あるオブジェクトに 付いている要素を取得するには、対象のオブジェクト.GetComponent<取得したい要素>() を実行すれば良いです。対象のオブ ジェクトは、対象がアタッチ先の GameObject の場合は書かなくてもよいですが(わかりやすくする為にthisと書いてもよい)、そ うでない場合は GameObject.Find("対象の名前") で対象の GameObject を発見できます。またdifに右腕の座標(現実世界にお ける)を代入しています。
OnTriggerEnter関数は物体が他の物体に当たった時に呼び出される関数です。関数の中身は自分で記述します。この関数を利 用する為には衝突する物体と衝突される物体の双方にColliderとRigidbodyコンポーネントがアタッチされている必要がありま す。()内のotherは関数の引数です。ここに衝突した相手の情報が入って関数が呼び出されます。衝突した相手のtag(詳細はグ グって)がenemyの時に衝突相手を消します。この場合だと飛んできた腕が消えます。また次のif文は衝突時のプレイヤーのパン チの速さによって分岐します。パンチが一定速度以上の時に音が鳴り、Ddie関数が呼ばれます。Ddie 関数は下のdie.csで定義し た combo を増やす処理とスコアを加算する処理とhitを帳消しにする処理を記述しました。
パンチの速度の検知が少し大変でした。試行錯誤の結果、現在の拳の座標(dif1)と1フレーム前の拳の座標(dif)の3次元ベク トルの差を取得してベクトルの長さを計算し、Time.deltaTime で割っています。なぜ Time.deltaTime で割るかですが、理由 は簡単で、速さ=距離/ 時間だからです。ベクトルの長さは Vector3.Magnitude() で求められます。この関数は与えられた座 標の sprt(x*x + y*y + z*z) を返します。
図: 3次元ベクトルの長さ はじめはRightHandAnchorのUnity内での座標を取得して処理しようと思ったのですが、皿ごと動くので常に値が変わってし まうという問題があり、次に皿に対する相対座標でやろうとしたのですがそれも上手くいかず困っていたのですが、普通にコント ローラーの現実の座標を取得することで処理できました。ちなみにここではUnityの標準の機能を使ってコントローラーの位置を 取得していますが、別にOculusの機能を使っても構いません。 パンチ判定はUpdate関数内で行っています。毎フレーム更新されるのでいつOnTriggerEnterが呼び出されても大丈夫です。 では下のスクリプトの解説に移りましょう。下のスクリプトはCenterEyeAnchorにアタッチします。 対プレイヤー当たり判定
comboは見ての通りコンボです。scorepはスコアをどれだけ加算するかを示しています。combo の数に応じてこの値を増やしま す。score も見ての通りスコアです。3つとも public と書いていますが、これを書くことによってこの変数が他のスクリプトか ら参照できるようになります。今回はhit.csで3つの値を加算するのでそれぞれ public をつけています。このスクリプトは目の 中心にアタッチされています。目の中心を中心とする球状に当たり判定が存在し、ここに飛んできた腕が当たると、(パンチに失敗 すると)飛んできた腕が消え、hitが加算されます。hitが6以上になるとコンボが途切れます。hit.csの Ddie 内の処理によって、 プレイヤーが飛んできた腕をパンチした際にhitが0になるよう設定されているので、6連続で飛んでくる腕を触ることすらでき なかった場合のみコンボが途切れる仕様です。
スコア表示
お次はスコア表示。これはスコアの計算の実装は済んでいるので表示するだけです。スクリプトを書く前にスコアを表示する場 所を用意して、そこにCanvasをWorldSpaceで設置し、直下に白色のImageとTextを2つ配置しました。Textが意味不明に ぼやけましたが、Canvas ScalerのDynamic Pixel Per Unitの値を大きくすることで解決します。やりすぎ注意。片方は単純に Scoreという文字列を書くだけです。もう片方はその少し下に配置し、先ほど計算したscoreの値を表示します。Canvasの下のど の順番で並べるかで表示順が変わるので気を付けて下さい。
では表示スクリプト。
NowScore.cs
usingSystem.Collections;
usingSystem.Collections.Generic;
第4章 簡単!VR3(00)分クッキング 4.8終わりと始まりのプロローグ usingUnityEngine;
public classNowScore :MonoBehaviour {
Text targetText;
die Die;
// Use this for initialization
voidStart () {
targetText=GetComponent<Text>();
Die= GameObject.Find("CenterEyeAnchor").GetComponent<die>(); }
// Update is called once per frame
voidUpdate() {
targetText.text=Die.score.ToString(); }
}
このスクリプトはスコアを表示する為のTextにアタッチします。
Textを扱う際には using UnityEngine.UI を書きます。このスクリプトは少し理解しにくいです。
初めに Text 型の targetText を宣言しています。ここに Start 関数内でスコアを表示する為のTextという GameObject のText要素を代入します(わかりにくいですね)。またDieにはCenterEyeAnchorのdieを代入します。あとは簡単です。フ レーム毎にtargetText.text(targetTextの文字列)に Die.score を代入すれば良いだけです。ただし Die.score は int(整数)で targetText.textは string(文字列)なので Die.score を ToString() で文字列に変換する必要があります。
ちなみに画像に使われているフォントはGreen EnergyフォントとMKSD-UltraLightフォントです。左のフォントはとある飲 料で見たことがある人がいるかもしれません。
ハイスコア
PlayerPrefs機能を使っています。詳細はググって下さい。4.8
終わりと始まりのプロローグ
どうでしたか?VR3(00*4)分クッキング。初めて部誌を書くので読みにくい文章になってしまったかもしれません。あるいはス クリプトの印象しか残らないかも...。まぁこの部誌でVRゲームの作り方やゲーム制作の手軽さが少しでも分かってもらえたら嬉しいです(絶対手軽さは伝わりませんねw)。今回のゲーム制作で僕は初めてUnityでゲームを完成させました。またBlenderも初 めて使いました。すべての工程の感想としては、「なにか問題が起こった時に原因を考えて直す作業や、自分の作りたい物をモデリ ングするのは楽しい」ということでしょうか。また一つアドバイスをすると、わからない部分が出てきたり謎のエラーが発生する ことはよくあります。そんな時はすぐにググりましょう。Google先生は常に私たちに道を示してくれます。あと、ベクトルの長さ の図は吉岡先輩に作って頂きました。ありがとうございました。 ...なんかめちゃくちゃ堅苦しくなりましたね(ほんまか?)。偉大なる先輩方に倣ってネタ性に溢れるクッソ面白い部誌を書くつ もりだったのですが...。どうやらまだ精進が足りないようです。 今回のゲームはNeutralさんのタイピングゲーム「寿司打」から名前を貰っています。部員もよくやる(?)とても素晴らしいタ イピングゲームです。皆さんも挑戦してみて下さい。筆者は雑魚なので高級コース15000円ぐらいが限界です。プロタイプerに なりたい。 部誌を書き始めたのが本番数日前なので誤字等あるかもしれませんが大目に見て下さい...。まだ文化祭が終わってないなら是非 寿司(が)打をやってみて下さいね。ではまた来年の部誌で会いましょう!