ひっっっっさしぶりに #Unity1Week に参加して〆切をぶっちした話
ひっっっっっっっっさしぶりにNote書きますね。
この度はタイミングが合いそうだったのでメッチャ久しぶりに #Unity1Week に参加したのを振り返る話です。
サクッと紹介すると、 Unity1Weekは1週間でお題にそったりそわなかったりする簡単なゲームを作ってアップしようぜ!っていう緩めのイベントです。
今回のお題は「1ボタン」でした。
何か海外のゲームジャム感ありますね。確か大学に入学した直後にやらされたゲームジャム的なやつのお題も "One Button Game"だった気がしなくもないです(記憶が無くなってきてる…
今回作ったゲーム
そのお題から今回は「呪いのゲーム」というVTuberになって一部で噂になってるゲームを配信しよう!っていうゲームを作りました。ネタバレありになる内容な為数分で終わるので良かったら先に遊んでみてください!(宣伝)
という感じのゲームを作ったので何か振り返ってみようと思います。
無計画に適当に書き始めたら大分だらだらと長い物になってしまったので、暇な時にでも…
ゲームを考える
====== ここからネタバレ ======
「1ボタン」のお題からゲームを考えた時に、ミニゲーム的なのは何か色々出来そうなきがしたのですが、せっかくなら終わった後にもっと作りたくなる物が良いなーというわがままを考えつつ、既存の1ボタンのゲームって何があったかな~と考え始めました。
(ミニゲームでも発展出来る可能性は全然あるし、結局ミニゲームともいえるような物を作ってるので何を言ってるんだろうコイツ感ありますね…)
余談ですがミニゲームといえば他の人も上げてましたが桜井さんの動画でカービィの話がありましたね。
それで考えてるうちに「つぐのひ」シリーズの遊びって右から左に進むだけだから1ボタンで完結するんじゃね?とふと思い立って、更に自作ゲームで今後作りたい物の一つにホラゲーもあったので試しに作ってみるか!ってなりました
つぐのひシリーズ
ちなみに上のついーとでも言っている通りつぐのひを遊んだ事が無いので操作は想像で言ってます。配信は結構されてるのでそれらを見たイメージでやってます
↑は猫町めるるさん( https://twitter.com/NekomachiMell )の配信
ホラゲーの内容を考える
さてつぐのひをぱk…リスペクトするというのを決めたのでぼんやり作りたいなーと思ってたホラゲネタと合わせる落としどころ考えて行きました。
元々そのうち作りたい物で考えてたのが「VTuberになって呪われたホラゲを配信し、結果配信中にゲーム内のお化け的な物が配信者にリア凸してやられる」というものでした。それ以外は何も決めてないぼんやり具合。
VTuberになって配信する~の部分はそのまま素直に行けそうでしたので、ボタン押しっぱなしで進むゲーム部分をどうするかが主な所。そして作る手間、特にアートの手間をどう削るかを考えがら進めてました。
つぐのひそのままの右から左に進む形式にすると自分のキャラを何かしら用意しないと行けないか、何かモクモクさせて誤魔化すとかになるから難しいなーと思いました。
それなら後ろから前へ行く形式なら3Dにすれば自キャラ表示無くても誤魔化せるかなーと思い、更にまんまつぐのひをぱk…参考にするのはつまらないのでこの方向で行く事にしました。
という事でここまでの要素をまとめると:
VTuberの配信画面がある
1ボタンを使ってボタン押しっぱなしにしたら進行する
ゲーム内ゲームは前へ前進し続ける事で進行
これを決めるだけで大分文字数使いましたね。
一番やりたい事を定める
ゲームの方向性を先に考えてしまいましたが、先に進める前に「今回一番やりたい事」を自分の中で決めました。
今回は元々ぼんやり考えてたネタの事もあり「ゲームの幽霊的な物がVTuberにリア凸する」の所が一番やりたい所全部それを中心に組み立てようる事にしました。
これを決めておく事でやる事とやらない事を決める時にも「↑を良い感じに実現するにはこの要素は必須か?」を考えられるので、これを基準に進めていきました。
仕事の話をしてるんだっけ?
ゲームを作っていく…前にVTuber画面を作る
方向性は考えたので、細かい事は下地や必要な要素を作りながら考えて行きました。
取り合えず可愛い物から作るマン
コンセプト的な話をした後から優先度をひっくり返す感じですが、やる気の問題でVTuberの配信画面部分を実装していきました。
今回VTuberの配信画面部分はuGUIを使って作成しました。
主な理由は手っ取り早く作りたかったからですね!
まずはL字に適当にImageを置いて外枠を作りました。
その後、今回のkawaii要素の配信用のVTuber画像を用意しようと記憶やブックマークを漁り、今回はMEllさん( https://twitter.com/PinkCat13_ )の作品を購入して使わせて頂きました。なんか上でアートを減らす話をしていたはずなのに嬉々として買いに行ってるやつがいる。
今回は凝った事をせずにこの子の画像をImageに入れ込み、表情差分を入れる時に画像を差し替えるだけにしています。クロスフェード入れるのそんな手間はかからないけど費用対効果悪そうなので置いておきました。
データ周りの準備をする
次はコメント欄を~と行く前に、喋ってる時の設定各種とコメント欄用のテキストデータ作成環境を用意しました。
CSVやExcelでデータを作った事は過去の自作ゲームではありましたが、Google Spread Sheet(GSS) を使った事が無かったので、今回は今後の事も考えてGSSで作る環境を用意しました。ちなみに仕事ではUnityとGSSで動くものを作った事はあるのですが、全く違うやり方を試してみました(↓宣伝?)
今回はUnityWebRequestを使ってcsv形式でGSSからデータを落としてくる手法を取りました。細かい所は変えてますが、内容的にはこちらを参考にさせて頂きました:
https://dokuro.moe/unity-how-to-import-google-spreadsheet-data-directly/
GSSからデータを落とす方法の詳細は記事を読んで頂いて、そこから主に下記の変更を加えました
ConvertCSVtoJaggedArray() をcsvをまず書き出して、そこからcsv読み込みクラスでの読み込みに変更
Editor以下にスクリプトを作ってメニュー上から動くようにし、GSSReaderを使ってScriptableObjectを最終的に書き出すように変更
UniTaskを使うように変更
csv読み込みを使うようにしたのは記事のままだと改行等を対応が出来ていないというcsvあるあるの対応の為です。
csv読み込みはこちらのを参考にさせて頂いて以前作成しました:
最終的にScriptableObjectに書き出してるのは後々データをゲームで扱うのを楽にする為にで、それをエディターのみで行いたい為Editor以下で扱っています。
UniTaskにしてるのは単なる趣味です。使いやすい。
という事でなんやかんや変更をしたのでGSSを用意します
これを共有設定で「リンクを知っている全員<観覧者」に変更します。これをしないとUnityWebRequestで取ろうとアクセスできないので必須です。
余談ですが、この条件の影響で仕事に使うには難しいかなーという感じで、自作ゲームなら物によっては許容範囲かなーという感じで今回これを試しました。
Timeline対応しておく
今回演出部分は一部除いて大体Timelineで作る事にしたので、VTuber部分をTimelineを使って更新していく準備もしておきました。ちなみに一部はTimeline力無くてもうスクリプトでパパっとやろうとなったダメなやつです orz
そんなに凝った事をしないだろうという本来ならダメそうな予測で今回はVTuber部分用のPlayableBehaviourとPlayableAsset(Clip)だけを用意しました。ボイスを入れる可能性も考えてボイスの有無用のboolも入れてあります。
public class VTuberTextClip
: PlayableAsset
{
[SerializeField]
private int m_id;
[SerializeField]
private bool m_isPlayVoice;
public int ID => m_id;
public bool IsPlayVoice => m_isPlayVoice;
public override Playable CreatePlayable(PlayableGraph graph, GameObject owner)
{
var playable = ScriptPlayable<VTuberTextBehaviour>.Create(graph);
var behaviour = playable.GetBehaviour();
behaviour.Clip = this;
return playable;
}
}
public class VTuberTextBehaviour
: PlayableBehaviour
{
public VTuberTextClip Clip { get; set; }
private bool m_hasPlayed = false;
public override void ProcessFrame(Playable playable, FrameData info, object playerData)
{
if (Clip == null)
{
return;
}
if (m_hasPlayed)
{
return;
}
m_hasPlayed = true;
VTuber.Talk.Play(Clip.ID, Clip.IsPlayVoice);
Debug.Log($"VTuberTextBehaviour.ProcessFrame({Clip.ID}, {Clip.IsPlayVoice})");
}
}
多分もっとちゃんとしたやり方がある気がしますがこんな感じで適当に動きそうな物を用意したらTimeline上でPlayable Trackを追加してクリップを追加していきます。
上記画像にあるサウンドのTrackはボイスの尺を図って演出作りやすくする為にあるので、大体後でミュートにしてから消してます。
演出を大体Timelineで作った結果、今回は16個になってました。多いのか少ないのかは知らないです。
テキスト表示
画面を見せながらスルーしてましたが、今回はテキスト表示は全部Text Mesh Proを使用しています。
VTuber部分はuGUIを使っているのでTextMeshProUGUIコンポーネントを使用し、ゲーム内ゲームでは3D空間上に出すのでTextMeshProを使用しています。
フォントは日本語フォントからTextMeshPro用のデータを作って使いました。"TextMeshPro 日本語"で検索すれば沢山出てきます。ありがたい。
テキスト表示であった問題
UnityRoomにいざアップした時に起こった問題でエディターではおこらなかったのですが、画面下の方のVTuberの喋ってる事読み上げテキストが表示されなくなっていました。
具体的な原因は調べていなく、大雑把な予想で回避したのでいつかちゃんと見た方が良さそうですが、恐らく原因は同じフォントアセットをTextMeshProとTextMeshProUGUIで同じタイミングで使用している事でした。
なのでいったん同じフォントから新たにアセットを書き出し、TextMeshProUGUIにのみ使用するように変更しました。
あまり効率の良い回避方法では無いと思いますので、そのうちもう少しちゃんと調べた方が良さそうな案件でした。
コメント欄実装
喋る所や読み上げの部分は実装したので(ボイス再生は飛ばします)次はコメント欄の実装に入りました。
コメント欄自体は完全に雰囲気作りの為にあれば良いやという感じでしたので、見た目はかなり大雑把になってます。綺麗にしろと言われても画力と絵心は無いですが。
実装にはuGUIのScrollViewでも出来るのですが、そのまま使うとパフォーマンス的な問題もあり、更にだいぶ前に買ってから積んでたEnhancedScroller v2を良い機会なので試してみました。
使い方はこちらを参考にしました
Enhanced Scrollerで用意したコメント欄にコメントを追加するのもTimelineで行っており、基本同じ感じで実装してます。
スパチャ実装
実装自体はアップ30分前ぐらいにやったのですが、スパチャを完全に再現するのは時間の都合上やりたいけどしなくて良いかなと思い色付けだけにしておきました。色付けはImageの色を変えるだけでやりました。雑ですが雰囲気が出てると…良いな…
呪いのゲームを作っていく
配信画面の実装をしたので今度こそゲームを作って行きました。
当時のスクショが無いのですが、いったん黒い空間に細長いキューブを置いてマウスの左ボタンを押している真っすぐ歩いていく機能だけまず用意しました。
トリガー作り
まだまだ仕様をあまり思いついて無かったので(悲しみ)取り合えず最低限必要そうな物を用意しておこうと思い、まず触ったら色々する物を必要そうな分用意しておこうってなりました。
public abstract class BaseTrigger
: MonoBehaviour
{
[SerializeField]
private bool m_disableOnCollision = true;
protected GameObject m_gameObject;
private void Awake()
{
m_gameObject = gameObject;
}
private void OnTriggerEnter(Collider other)
{
OnTriggerEnterImpl(other);
DisableOnCollision();
}
private void DisableOnCollision()
{
if (m_disableOnCollision)
{
m_gameObject.SetActive(false);
}
}
protected abstract void OnTriggerEnterImpl(Collider other);
}
みたいなのを用意してから触ったらTimelineを再生するのを用意します
public class TimelineTrigger
: BaseTrigger
{
[SerializeField]
private PlayableDirector m_director;
protected override void OnTriggerEnterImpl(Collider other)
{
StartTimeline();
}
private void StartTimeline()
{
m_director.Play();
}
... その他
そしてこれをColliderがついてるオブジェクトに入れてTimelineを指定します。
これと同じ感じで
音を鳴らす
VTuberに話させる
UnityEventで登録したイベントを発火する
のを更に追加してプレハブ化していきました。
空間作り
イベントを色々起こせるようになりましたが、この時点の黒い空間に床に見立てたCubeを1個置いてる事の問題に作ってる自分でさえ自分が前進できているのかがわからないという致命的な問題がありました。
解決策はいくつかあると思いますが、一つとして空間に物を配置して行こうとしたのですが、アート素材必要になるし、理由付けを考えたくなるのであまり物は置かず思わせぶりな事を書いてあるテキストを主においていく方向にしました。
床を作る
もう一つのわかりやすい解決策は良い感じの床を用意する事でしたが、絵心が無さ過ぎて良い感じのが出ませんでした…なので何かそれっぽくなりそうなのを手間かからない形で無理くり用意しました。
ノイズに使ってるテクスチャを張り付けてUVスクロールをするようにする事でそれっぽい見た目を目指しました。ただ、UVスクロール無い方が自分が動いた時わかりやすいのでは?と今考えれば思い始めたので、悩ましいです…
もくもくさせる
ただただ黒い空間があるのも寂しいし、これも進んだ時にわかりやすくならないかなというのと、恐らく最近サイレントヒル2をやった影響でフォグを出してもくもくすることにしました。
手っ取り早くやりたかったので今回はVolumetric Fog & Mist 2というアセットを使いました。
これは置いて適当に設定するばそれっぽいフォグが出てくれましたので、適当に設定してプレイヤーの方にフォグが向かうようにしました。ただこれも動いて無い方がもしかしたらプレイヤーが動いてるのわかりやすいかも知れないので今考えると悩ましいですね…
問題点
うすうす出していましたが、今回の空間作りでは結局プレイヤーが前進している事が文字が無い箇所ではわかりにくかったという感想もありましたので、そこは中々悩ましつつ反省です…
イベント作り
シナリオとイベントを考える際、オチは一番最初に決めたので、そこを基準日考えて行きました。大体こんな感じで考えてました
最後は「幽霊的な何かが配信者にリア凸する」
↓
じゃあプレイヤーがたどり着くのを配信者の部屋にしよう
↓
プレイヤーがたどり着くのが部屋なら幽霊的な物とプレイヤーは
・同じ位置
・後ろ
・同一人物
のどれかだな
↓
せっかく前進のみで後ろが見えないので後ろから何かに追いかけられるのを入れるか。これならアートコストかからないし。
↓
色々やってみたい事はあるが時間ガガガ…ただこれだけだと部屋にたどりついた時の助走が無さ過ぎるので何か欲しい
↓
幽霊がリア凸する配信者の配信見てたら笑えるよな
↓
配信画面が映ってるタブレットをゴール直前に落とすか!
↓
それをするならコメント欄に幽霊っぽいやつ欲しいから入れるか。
みたいな感じでやって行って、コメントのデータ作りは最後の方にやったのでその場のノリでやってました。
こんな考えを元にイベント発生を配置していくとこんな感じになりました。
追いかけ演出
追いかけ演出はそんなに凝った事をしないでプレイヤーの後ろに3Dサウンド設定になってる足音のAudioSourceがついてるオブジェクトを配置し、徐々にプレイヤーに近づけて行きました。
更にプレイヤーとの距離が近づいていくにつれて足音のピッチをどんどん高くしていき、足音がどんどん早くなってる感を出しています。
ついでにそれっぽさを出す演出として心臓の鼓動の音も一緒に流すようにしています。
プレイヤーの動きも早くしようかと考えた事もあったのですが「幽霊的な物とプレイヤーは同一人物」にしてもしなくてもそのままで行けるのを目指して入れました(自分の考えた仕様/シナリオを信じないスタイル)。
デバッグ機能
今回そんなに凝ったゲームでは無いのであまり面白いデバッグ機能は用意してないのですが、基本タイムラインで演出を作っているのでZキーを押すと時間経過を10倍にする機能を入れてあります。主にタイトル画面とエンディング(なのかあれ?)用です。
#if UNITY_EDITOR
private void Update()
{
if (Input.GetKey(m_fastSpeedKey))
{
Time.timeScale = m_fastSpeedMultiplyer;
}
else
{
Time.timeScale = 1.0f;
}
}
#endif
これ以外に、今回BoxColliderが山盛りなので選択してなくても見えるようにしたかったのでシーンビュー上では常時見えるようにしました。上にあるトリガーが並んでるスクショはこれで表示されているBoxColliderです。
今回はこちらを参考にさせて頂きました
https://hacchi-man.hatenablog.com/entry/2020/01/31/013000
ボイスどうしよう
今回完全にボイスあり前提の物を作っていますが、仕様とシナリオというか展開の詳細を詰めるのがあまりにも遅すぎた為誰にも相談していない状況でした。
とぼやいてたらこんなリプを貰いまして
おーくまねこさんのボイスは需要無いので一生出ません。CV:諏訪部さんになりたい人生だった。
とその場のノリで返したら
と来たので
という、多分大体の人ならこれで終わる冗談な話ですが、社交辞令を間に受けるマンなのでその後DMでどうですか~?と聞いたら引き受けて貰えました。ありがたし・・・
今回ボイスを引き受けてくれた柿ノ葉すしさん(https://twitter.com/Kakinoha_s)は主にTwitchで配信をしている配信者の方なので、皆さん是非見に行ってください!この記事で一番大事な所です!!
仮ボイス
今回セリフを決めるのがメッチャ遅かったこともあり、仮ボイスをVOICEVOXで作って演出を先に作って行きました。VTuberが喋るテキストデータから.wavファイルを作成しています。
実装はこちらを参考にさせて頂きました
この中の文字列を送る所をテキストデータが入っているScriptableObjectを読み込みテキストごとに作成を送るようにしています。
この仮ボイスを入れてた版がかんな感じでした。
ちなみにこれは柿ノ葉すしさんにこんな感じのゲームのボイスをお願いしたいんですって時に作った動画です。最終版とはちょこちょこ違います。
最後に
以上だらっだらとジャンルも絞らずメモ書き的に書いて来ましたが、ここまで脱落していない凄い皆さんに改めて言いたい事だけ最後に書いておきます
柿ノ葉すしさんの配信をミテネ!
改めて載せますが、今回ボイスをやってくださった柿ノ葉すしさん(https://twitter.com/Kakinoha_s)の配信を是非見に行ってみてください!
MEllさんのSkebとSKIMAミテネ!
今回のVTuberのバニーちゃんのイラストを描いたMEllさん(https://twitter.com/PinkCat13_)はSkebとSKIMAでイラストを色々やっていらっしゃるので、是非見に行ってください!
https://skima.jp/profile?id=11947
意見、感想マッテマス!!
今回は数分で終わる前提で内容を考えましたが、30分ぐらいのフルバージョンも今後作りたい欲はあるので、その参考の為にも意見、感想お待ちしてます!!
ゲーム内ゲームの内容は多分全トッカエにはなるとは思うけど…
次こそは締め切りを守りたい!!!
長文にお付き合いいただきありがとうございました!!