自作ゲームをリリースしたので工夫ポイントをゆるく解説する〜波打つメッセージウインドウを作る〜
この記事は Otaku Social(おたそ~)Advent Calendar 2023 18日目の記事です。
紫展示棟(第二会場)はこちら。
以前リリースした個人開発ゲームでちょっと工夫した内容を、諸々の知識に初めて触れる方でも飲み込めるくらいざっくり噛み砕いて解説する記事を目指して執筆しました。
また、今回使用した技術は全体的に古め(検索すると2015年前後の記事が頻出する)です。ご了承ください。
リリースしたもの
全END見るだけなら15分、全選択肢回収するなら30分前後で遊べる短編ノベルゲームです。女子二人の友情もの。
人死にの描写があったり、メイン二人の関係と別のところで百合が咲いていたりと諸々人を選ぶ作品なので、プレイの際は概要欄をご一読ください。
プレイして頂くと記事の内容がわかりやすいかと思いますが、未プレイでも問題なく読める内容です。
でもプレイして頂けるとすごくすごく嬉しいです。
基本的なこと
今回の作品はティラノスクリプトというツールをお借りして作成しました。
詳細に関しては公式サイト様や有識者様方による解説記事を読んで頂ければと思うのですが、こちらのツールはテキストベース(いわゆる「プログラミング」という言葉でイメージされる画面)でノベルゲームを作成することができるツールです。
このツールの特徴として、HTML5製であり、CSSやJavaScriptを用いて様々な工夫ができるという点があります。
ざっくり言えば、webページを作成するのと同じ規格を用いてゲームを作成できるため、リッチなwebページに用いられているような技術も転用できるということ!
中でもJavaScriptは動的な処理が可能なものです。
ものすごく簡単に言うと、JavaScriptを使用することでユーザー・プレイヤーの操作がその場で(ページの移動・再読み込みを挟まずに)画面上へと反映される、という動きを実現できます。
さらに、ソース内で読み込むことで通常のJavaScript数行分の内容を簡単な記述のみで実現できるライブラリというものも存在します。いわゆる拡張パックですね。
JavaScriptをうまく用いることで、ティラノスクリプト内で様々な演出をすることが可能です。(CSSを使った演出方法もたくさんありますが、今回のメインではありません)
何をしたか
そんなこんなでカスタマイズ性が激高なティラノスクリプト、どうにか変わったことをして爪痕を残した~い!!
ということで筆者が考えたのは、キャラの感情に応じて激しさが変わる「波打つメッセージウインドウ」でした。
どういうこと?
こういうこと!
左のキャラの心情と連動させることで、「自分の選択でゲーム内に変化が起きた」という没入感を味わってもらいつつ独自性も出しちゃうぞ~!という狙いでした。
実際どうやったのか
まず、波のアニメーション、それも高さが変動するようなものを一から実装しようとするとめちゃめちゃ難しいです。少なくとも筆者の技術力ではできません。
なので、今回はwavifyというプラグインを使用してやりたい動きを実現しました。
プラグインとは、ライブラリによって拡張されたプログラムに対して特定の機能を追加する追加拡張パックのようなものです。
必要なもの
SVGファイル
jQuery
TweenMax
wavify
最後のwavify以外なんも知らんが!?という方も多いと思うので、簡単に解説します。
まずSVGファイル。
SVGはJPGやPNGと同じ画像拡張子の一つですが、例に挙げた二種との違いとしてベクター形式であることが挙げられます。
ベクター形式とは、大まかに言うと数式で表現された画像形式です。そのため、どんなに拡大縮小・変形してもぼやけないという特性があります。
さらに、SVGはXMLというデータ記述用の言語(マークアップ言語)で形成されているため、通常の画像ファイルのように外部ファイルを読み込まなくてもゲームプログラム内に文字で記述して表現することができます。
続いてjQuery、TweenMax。
先ほど少し出てきたJavaScriptのライブラリ、すなわち実装を楽にする拡張パック(のようなもの)です。
恥ずかしながら、詳細な仕組みを解説できるほどの理解度・力量は今の筆者にはないので、今回は「そういうもの」くらいに考えて頂ければと思います。
両者の違いは、すごくざっくり言うと製作者やできること(TweenMaxはアニメーション特化、など)といった点です。
※2023年12月現在、TweenMaxは同開発元の新ライブラリ・GSAPに概ね切り替わっているようで、公式サイト・公式配布元を見つけることができませんでした。
また、GSAPでwavifyを動かす方法、及びそもそもの互換性の有無については未確認なので、本記事の内容を真似してみたい!という方はお気を付けください。
必要ファイルの配置・読み込み
ここからは、具体的にゲームプロジェクト内のどこに何をするのかといった話になります。なので、実際にティラノスクリプトを触ったことがある/触ってみたい人向けの内容になるかもしれません。
最初に、必要なファイルのセットアップを行います。
先ほど出てきた必要なものをそれぞれの持ち場に配置する作業です。
JSライブラリに関しては、CDNといってURLをプログラム内に記載して使えるようにする導入方法も多く使われています。
ですが、今回はティラノスクリプトのお膝元であるゲーム配信サイト・ノベルゲームコレクションの投稿規約にある
という項目に準拠する形で、ダウンロードしたファイルをゲームプロジェクト内に配置する方法で実装を行います。
(とは言ったものの、この項目の解釈が合っているか心配なので有識者の方がいらしたらコメント等で教えて頂けると幸いです)
というわけで、jQuery、TweenMax、wavifyのファイルをそれぞれダウンロードします。
ダウンロードしたファイルは、ゲームプロジェクト内のtyrano/libsフォルダに配置します。
JavaScriptやCSSで追加したいファイルがある場合、ここに置いたものを呼び出して使っていくことになります。
呼び出して……と書いた通り、libsフォルダに置いただけではライブラリやプラグインは動いてくれません。
index.htmlに以下のような記述をする必要があります。
<script type="text/javascript" src="./tyrano/libs/TweenMax.min.js"></script>
<script type="text/javascript" src="./tyrano/libs/jquery.wavify.js"></script>
<script type="text/javascript" src="./tyrano/libs/wavify.js"></script>
簡単に言うと、「src=の場所にあるJavaScriptファイルを呼び出すよ」といった意味合いです。
index.htmlはゲーム全体の実行ファイルとなり、一番最初に読み込まれるファイルです。なので、ここで上記の呼び出しを行うことでゲーム内でライブラリやプラグインを使えるようになります。
続いて、先ほど読み込みを行わなかったSVGファイルです。
紹介の箇所でも少し触れましたが、今回はコード内で定義する形でSVGファイルを実装します。
実際のコードは以下の通りです。
SVGの追加
[iscript]
$(".message0_fore").append('<div style="position: absolute; top: 0px; left: 0px; pointer-events: none; z-index:999"><svg id="svg" width="2200px" viewBox="0, -180, 1200, 250"> <path id="wave" d=""/></svg></div>');
f.setWave();
[endscript]
こちらはdata/scenario/first.ksに記述します。これはゲームを起動したあと最初に読み込まれるシナリオファイルで、動的な処理などを書いておくファイルです。
[iscript][endscript]はティラノスクリプト内でJavaScriptの記述をするためのタグ、 $(".message0_fore")から始まる横長の行がSVGを追加する記述です。
f.setWave();については後述します。
この横長の記述では、ティラノスクリプトが自動で生成してくれるメッセージウィンドウの下にSVGを追加するような動きをしています。
「そんなことしなくても普通にSVG書けるのでは?」と思った方もいるかもしれません。
なぜこんなことをしているかを説明するには、簡単にですがティラノスクリプトのつくりを説明する必要があります。
ティラノスクリプトでは、HTMLの要素をレイヤー(層)として重ね合わせることで、ゲーム画面や機能が形作られています。
ユーザーがゲーム制作をする際は、「キャラクターを登場させるタグ」「背景を読み込むタグ」など専用のタグを打ち込むことでそれぞれの要素が自動で適切なレイヤーに配置されるつくりになっています。
先ほども少し触れましたが、SVGはマークアップ言語で記述できるので、HTMLの記述として組み込むことができます。
ティラノスクリプトではHTMLを組み込むタグがあるので、これを使えばよい気もしますが……
おわかりいただけただろうか……
つまりこうなるってこと!
今回の目的は「メッセージウインドウを波打たせること」、すなわち「メッセージウインドウの画像をSVGに置き換えること」です。
なので、専用タグを使う以外の方法でSVGを組み込む必要が出てきます。
というわけで、先ほど紹介した記述でメッセージウィンドウのレイヤー(message0_fore)の後ろ(下)にSVGを追加しました。
……と偉そうに解説しましたが、実は先ほどの記述はティラノスクリプトの製作者・シケモクMKさんに直接ご相談して考えて頂いたものです。
この場をお借りするのもなんですが、本当にありがとうございました!
(シケモクMKさんが技術相談を受け付けていらしたタイミングでご相談させて頂きました。いつでも同様のご対応を頂けるとは限らないので、ご迷惑がかからないようよろしくお願いいたします)
波を動かす
先ほどの記述で一瞬だけ登場したf.setWave();の出番です。
この記述ではsetWaveという処理を呼び出しています。
その内容がこちらです。
f.setWave = function setWave(){
tf.larger_width = $.getLargeScreenWidth();
var svg = $('#svg') ;
if(tf.larger_width === false){
svg.attr('width', '2200px');
svg.attr('height', f.waveHeightSP);
document.getElementById("svg").setAttribute("viewBox",f.viewBoxSP);
myWave= $('#wave').wavify({
height: f.waveSP,
bones: 3,
amplitude: f.waveSP,
speed: f.speed
});
}else{
svg.attr('height', f.waveHeight);
document.getElementById("svg").setAttribute("viewBox",f.viewBox);
myWave= $('#wave').wavify({
height: f.wave,
bones: 3,
amplitude: f.wave,
speed: f.speed
});
}
}
簡単に言うと、
・画面サイズに合わせてSVGのサイズを変更
・SVGにviewboxの値をセット
・波打たせる対象のSVGを指定
・wavifyに波の高さ、速さの値をセット
という動きをしています。
前2つは画面の横幅いっぱいにSVGを表示させるための調整と捉えてください。
3つ目は、myWave= $('#wave').wavify({})の部分です。「wave」というidを持った波を対象にするよ、という指定を行っています。
先ほどSVGをセットした時に出てきた横長コードを辿るとpath id="wave"という記述があると思います。
ここでSVGのパス(描画部分)に「wave」というidを振っているため、この処理内で指定して動かすことができています。
今回キモになるのは、4つ目のwavifyに波の高さ、速さの値をセットというところです。
実はwavify、単純に画像を波打たせるだけではなく速さや高さなども数値で調整できます。
height、bones、amplitude、speedと縦に並んでいるのが設定箇所です。
それぞれ高さ、アーティキュレーション数(すみません、こちらちゃんと把握できていません……)、振幅、速度を意味しています。
先ほど「数値で設定できる」とお伝えしましたが、上のコードではbone以外のところにf.〇〇という文字列が入っていることにお気づき頂けたかと思います。
これは変数と言って、様々な値を入れる箱のような役割をしています。(変数の概念に触れたことのある方は百万回聞いたであろう例えですみません)
最初の方に出てきた、JavaScriptはデータの受け渡しができるという点がここで活きてきます。
今回の実装では、選択肢を選んだ際、それぞれの分岐先で各変数に値をセット→setWaveに送る、という用途で使っています。
実際の記述はこんな感じ。分岐に入ったところで変数をセットして、先ほどのsetWindow等諸々ひっくるめたメッセージウィンドウのセット処理(この中身については長くなるので割愛します)を呼び出しています。
[eval exp="f.wave += 10"]
[eval exp="f.waveSP += 3"]
[eval exp="f.viewBox ='0, -180, 1500, 230'"]
[eval exp="f.viewBoxSP ='0, -120, 600, 205'"]
[eval exp="f.speed = .35"]
[windowSet]
キャラクターの心情と同期……みたいなことを書きましたが、蓋を開けるとかなり単純なつくりです。
正直、このあたりもっとスマートな実装方法があったのでは?と思っています。求む有識者。
おまけ:メッセージウィンドウの色変え
今回の実装では、喋っているキャラクターに応じてメッセージウィンドウの色が変わる仕様になっています。
こちらは、キャラ名を変数に保存するプラグインをお借りした上で、その時喋っているキャラの名前に応じた色をSVGに付けるという処理をキャラが切り替わるたびに走らせています。
色変え部分だけ抜き出すとこんな感じ。
CSVの色変えはwavifyの機能ではなくCSSで行っています。
if(f.charaName =='koshiya'){
$('#wave').css('fill',' rgba(68,28,21,0.7)');
}else if(f.charaName =='yuruki'){
$('#wave').css('fill','rgba(28,49,68,0.7)');
}else{
$('#wave').css('fill','rgba(28,49,68,0.7)');
}
余談ですが、作中では伏せているキャラ名を裏ではめちゃめちゃ使っているのでなんだか恥ずかしいです。
おわりに
ここまでお目通しくださり本当にありがとうございました!
自分でも予想していなかったくらい長い記事になってしまいました。
今回の実装を改めて振り返ってみるとほとんど人様の技術にタダ乗りした結果な気がしなくもありませんが、執筆を通してティラノスクリプトやJavaScriptが持つ可能性や、それに対するワクワク感を再確認することができました。
そして、人に向けて何かを解説することの難しさも痛感しました……。
拙い記事ではありますが何かの参考になれば、また、本記事を通してこれらの技術に興味を持ってくださる方、自分も何かを作ってみようと思ってくださる方がいらしたらとても嬉しいです。
質問やここもっと詳しく!などあればお気軽にお申し付けください。できる限りでお答えしたく思っています。
ご指摘や不足内容の補足等も、なるべく優しくお伝え頂けると大変助かります。
ノベルゲームコレクションでは、現在フリーゲームの祭典ティラノゲームフェス2023が開催中!!
本記事で取り上げた作品は参加しておりません!!なぜなら2022年の作品だから!!!
2023年要素すらない記事を発表してよかったのか?場違いすぎでは?という疑念が半端ないですが、長年出せずにいた解説記事を出すきっかけをくださったおたそ~アドカレと主催のもりかぷさん、本当にありがとうございます!お邪魔しました!!
改めまして、アドカレへのリンクは以下です。
他の参加者さん方の記事もぜひ読んでみてください!
【青展示棟】Otaku Social(おたそ~) Advent Calendar 2023
【紫展示棟】Otaku Social(おたそ~) Advent Calendar 2023