見出し画像

昔作ったFlashゲームをUnityで移植した日記

本腰入れてUnityで遊べるようになろうかな、と思い立ったので、
10年以上前に作ったFlashゲームを移植してWebGLで書き出してみました

できあがったものがこちら

このnoteはたぶんこんな人に向けて書きました:

  • 簡易的なゲーム(一人で短期間に作れるくらい)を作るとき、どんなことを考えて何するのかに興味がある人

  • なんかFlashゲーの話とかを聞いてノスタルジックな気分になりたい人

  • めちゃめちゃ暇だからなんでもいいから他人の日記が読みたい人

技術ブログというよりは、ゲームつくりながらおもしろかったことをつらつら紹介してみたかった日記です

かいた人も数学苦手なのにちょくちょく数学の話がでてくるんですが、中学高校で習ったはいいが日常に使い道のなかった謎の計算や公式が、実は大人になってからこういうたのしいことに使えるみたいだぜ!!! っていう人生の伏線回収のおもしろさ(大げさ)がちょっと伝わったらうれしいなって思いながら書いたので、
よかったらあたたかい目で斜め読みしてやってください

まずはデコンパイル

プロジェクトファイルがもう手元になかったので、swfファイルをhugflashとかでデコンパイルしました
ちなみに当時AdobeのFLASH作成ソフトは持っておらず、フリーソフトのParaFla!のお世話になって作ってました

当時のコード(AS3)を読みやすくするためだけにVSCodeにActionScript用の拡張を入れたら

出てきたのが怪文書

デコンパイル時に余計な文字列が入っちゃったのかな? などと思えたらどれほどよかったでしょう
何種類かのソフト使ったのに全部同じ†怪文†が出てくるし、まあ記憶が無くても自分のことは自分が一番わかってるんだよね
コイツは間違いなく自分で書いてるよ

当然移植にあたって解読にいちいち苦労した いやむしろ当時よくこの理解度で動くもの作ったな 逆にすごいぞ

イラスト・背景の話

全部自分で描いたはず たしかSAIと板タブで

プレイ中の背景
操作オブジェクト・妨害オブジェクト

プレイ中の画面では背景のコントラストを全体的に下げ、
操作オブジェクトと妨害オブジェクトは主線をくっきりはっきり・コントラスト強めの違うタッチにすることで、
混ざって見づらくならないように健気な工夫をしていた

タイトル画面

タイトル画面は、暗い緑の背景にクレヨンみたいなブラシでチョークっぽい色の線を描いて
教室の黒板風の文字とボタンにした
赤のチョークって蛍光色じゃないとけっこうみづらいよね なんでそれを再現したんだ?

タイトル横の蛍光青チョークで書いたデコレーション(?)の動きは
単純に3~4枚の画像をパラパラ漫画の要領で動かしてるんですけど、
こんな感じでとくに意味はなくともプルプル動くものが画面上にあるとなんとなく愉快だな、っていう着想は
たしか当時よくみかけたウゴツールから得たような気がします

”防害”

……文句は10年前の僕に言いに行ってくれ、で通すつもりだったんだけど
まあタイトル画面くらいちゃんとしとくか、と思い直してクソコラ技術で直しました

ここを
こうして
こう

音まわりの話

音、埋め込めなかったから文字が続きます 適当に読み飛ばすか実物聞きながら読んでもらえたらうれしいです

BGMはなんの問題もなくmp3で取り出せた
SEがRAWでしか出てこなかったから、一回Audacityで取り込んでからwav書き出ししました
プロジェクトファイルに当時WAVで入れたデータがRAWで埋め込まれてたのかな?

たしか音も全部自前で作ったから著作権上の心配はいらなかった……はず
BGMは確実に書いた SEもMIDIで作った……気がするんですけど……万が一借り物だったら訂正します

タイトルBGMは素朴にゲームのタイトル画面っぽい感じの曲(?)をさくっと書いた覚えがあります
そんなに長く見る画面でもなかろう、ということでループ短め・トラック数少なめ・細かい調整なしでもそれなりに鳴る電子音での省エネ編曲

自分で全部やると迷惑も自分にしかかからないから、好きに手を抜ける力の入れどころを自分の判断で選べるのは真面目にいいところだなあと思います

メインテーマの方は、小学校モチーフのゲームということで鍵盤ハーモニカとリコーダーに主旋律を張らせました
もちろん鍵盤ハーモニカの音源なんて持ってなかったのでたぶんハーモニカ 似たような音やろってことでね 10年前から雑すぎる

Unityくん、デフォルトだとイントロつきBGMのイントロ以外の部分だけループ再生するやつができないんですねえ……
当時できるつもりで作った曲なので(FLASHにはBGMのループ箇所を指定する機能がデフォルトであった)
移植したらループ再生の切れ目が目立っちゃったのはまあまあ不満

イントロつきBGM実装用のアセットもあるみたい
ただ有料だったりするので、もっと本格的に使いたくなったらまた検討します

実装の紹介1 腕の描画

マウス追従で動く腕


腕を3つのパーツに分かれたイラストで構成

「上腕」「前腕」「手」のパーツに分かれたイラストが、
肘、手首にあたる箇所でくっついて適切な角度・座標で表示されるようにすることで
プレイヤー操作対象の「腕」を表現しています。
「肘が伸び切ってしまったらそれ以上前に手を出せない
(→それ以上前に傘が倒れていってしまったら見送るしかなくなる)」
という部分がゲーム性の一部を担っているので、なんとなく「腕っぽいな」と思ってもらえるように表示したい

たぶん今時はJointとかIKとかそういうやつをゴニョゴニョして作れるやつだと思うんですけど、
10年前の自分が自力で座標出してがんばってそれっぽく見せてたので
せっかくだからそのまま移植しました。

すうがく

「三角関数なんて見るの大学入試以来だわ~」って思いながら作った記憶が朧気ながらある
今は「三角関数なんて見るの10年前にFLASHゲーム作って以来だわ~」なのでますますわからん
怪文書でも昔書いたスクリプトが残っててよかった

実装の紹介2 傘の動き

傘のバランスをとるゲームなので、傘の動きはいわばこのゲームのキモにあたります。
で、その傘の動きをどうやって計算してるかというと

次のフレームの傘のx座標※
=現在の傘のx座標 + (現在の傘のx座標  - 手のx座標) * 0.2

※「傘の上端(取っ手部分)の座標」を傘のx座標として計算
傘を乗せた手をマウスで動かすゲームなので、
傘の下端の座標 = 手の座標=マウス座標

これだけです。けっこうシンプル。
x座標が決まってしまえば、傘のy座標と角度はまた三平方の定理とか三角関数とかで計算できます。

なおこの動きの計算に物理的根拠などはまったくない
見た目がなんとなくそれっぽいからヨシ!

このゲーム「おもいかさ」っていう難易度アップオプションがあるんですが、
「おもいかさ」オプションをつけると、上の式で掛けている定数が0.2から0.4になります。
こうすると傘が普段の倍傾くようになるので、バランスをとるのがよりシビアになって難易度が上がります

実装の紹介3 当たり判定

当たり判定用の関数を使っている部分のコード(ここ自体はまあわかる)
当たり判定用の関数(冒頭の怪文書)

は?

というわけで全部書き直しました ahantei関数、値返してなくない? テレパシー? なんでこれで動いてた??

計算の内容自体はたぶん書き直す前も同じだったと思います

傘を線分、妨害オブジェクトの当たり判定を半径rの円とみて、
傘の線分と鉛筆の中心の座標の距離がr以下のとき「当たった」と判定します

直線と点の距離の求め方はなんか昔数学でよく見たような気がするやつ
式が長いから一見ちょっと複雑だけど、式変形だけならたぶん中学数学の範囲
数式の内容をこんなコードに落としてパソコンくんに判定してもらうことになる
(このコードは上の図に完全対応させたけど、
bは定数だから変数にしないで直接代入しちゃってOK)

細かい話をすると傘が直線じゃなくて線分だから、先にy座標で切っておかないと傘の延長線上の絶対当たってないところで当たったと判定されたりする

当たり判定は四角形で取るほうがよく見かけるし手っ取り早かったんだけど、
このゲームの場合は下みたいなとき見た目上かなり理不尽になるから、
傘の当たり判定をどうしても線で取りたくて線と点の距離を使いました

実装の紹介4 ゲームがだんだん難しくなるようにする

「画面上の妨害オブジェクト数の上限」「妨害オブジェクトの出現頻度」をそれぞれ変数で表し、経過時間に応じてこれらの変数を変化させることで、ゲームがだんだん難しくなる実装をしました。

「画面上の妨害オブジェクト数の上限」を変数maxで表すには、
妨害オブジェクトPopの抽選を行う条件を「現在の画面上の妨害オブジェクト数がmaxの値未満のとき」とすればOK。

問題は「出現頻度」をどうやって変数で表すか、ということでまたクソパワポをご用意しました
これが一番最初に作ったパワポだからいうても多分本稿のクソパワポの中で一番読みやすい 気を抜くとすべての文章を赤太字で書き始めるんだ クソパワポの申し子だから

このゲームだとあたりくじの本数(妨害オブジェクトの種類)は4じゃなくて3だったし
実際には消しゴムが出やすく・鉛筆は出にくく偏るように
あたりくじによって本数を変えてたり、はずれくじの元の本数も30じゃなかったりするんですが
hindo変数の考え方はおおよそこの図の通りなのでそのまま掲載しました

その他の雑記

デバッグ用に無敵モードにしてたら開発者になったみたいで楽しかったので、無敵モードで遊べる隠し操作をこっそり仕込みました
こういうの仕込むのもなんかまるで開発者になったみたいで楽しい

無敵イエーーーーーーーーイ

このゲームについてはまるでじゃなくて開発者のはずなんですけど なんだろう 実感っていうか……

Textオブジェクトに直接指定していた文字列が全部消えた(使ったFlashのエミュレータもデコンパイラも対応してなくて読めなくなってた)
のでHow to Playはいま全文書き直しました 説明は10年たってもまるでうまくなっていない
スクリプト内に書いた文字列は残ってたから、あだ名のネーミングとかはほぼ当時のままです

Twitterに結果をつぶやくときのURLの書式は10年前と変わっていたので
新書式に合わせて書き直しました

このTwitterロゴめっちゃ懐かしくない?
(移植版には使いませんでした)

Animator・Animationを使ってみてちょっと使い方わかったのはデカかったかなと思ってます

Animationの編集画面

今回はタイトルの横をプルプルさせたり

マウスを乗せてるボタンの背景をチカチカさせたり

ヒットエフェクトの透明度を変えながら回転させたり

単純な使い方しかしなかったんですが、
たとえば待機モーションから歩く・走る・何かのアクションをする……みたいなキャラクター操作のモーション遷移を作るときなんかは本格的にこれを使うことになる はず

ハマったところ

以下、移植時にハマったところを備忘録的につらつら並べます これ自体が誰かの役に立つかはあやしいんですけど、
「こういうことで詰まったり解決したりを繰り返してつくっていくよ」の参考にはなるかもしれない

UIの重なり順が思い通りにならない

ボタンの上に意図しない順番で別のボタンが重なっているせいで押せないとか、見えてるボタンと違うボタンが押されるとかが頻発したんですが、
ソートレイヤーの活用でだいたい全部解決した 重なり順の制御に超便利じゃんソートレイヤー

UIに限らず、Z座標で要素の重なり順をひとつひとつ決めていく古来の2Dやってたら脳の血管いくらあっても足りないところだった 最近の開発環境ってエライ

また今回ハマった件、上で別のUIがマウス操作を受け取っていると下のボタンに届かないのを利用して、
オプション画面の背景に透明なクソデカテキストボックスを置くことで、オプション画面を閉じるまではオプション画面より下の要素が反応しないようにしました

あとボタンが全然動かないと思ったら、Canvasを入れ子にするときは子のCanvasのほうにもCanvas Raycasterコンポーネントをつけないと
配下のUIがポインター操作を受け取らないらしい 普通Canvasってあんま入れ子で使わないのかも?しれない?

スクリプト上でFindしたGameObjectをいじろうとしたらエラーになる

GameObject.Find("ゲームオブジェクトの名前")、任意のゲームオブジェクトを簡単に取得できて便利だからついつい多用しちゃうんだけど
対象のGameObjectがActiveでないと見つからないから、Activeになってなくて見つけられなかったGameObjectのプロパティを取得したり設定したりを試みたとき「無を取得するな🚫」ってエラーで怒られます

Findした要素を扱うときは先に存在確認するのが行儀のいい使い方なのだろうと思う
ただ、そもそもActiveかどうかが動的に切り替わる要素をスクリプト内でいじりたいときは
やっぱり格納するためのpublic変数をスクリプト上で作って、ちゃんと先にインスペクターから紐づけておくのが吉か

座標の変換と計算がなんもわからん

カメラ領域とキャンバススケールを可変で作ってしまったので、スケーリングとかアス比・オフセット周りの座標操作でアッッッッホほどハマった
ワールド座標単位、ローカル座標単位、ピクセル値、キャンバス幅、スクリーン幅、キャンバスの参照解像度、キャンバスのスケール……といろんな数字が大暴れしている中で、アス比が変わると左右または上下に発生する余白は何と何をかけてどの関数で変換して何から引けば取り除けるんだ??????などとめちゃめちゃ苦しんだ

いろいろ表示させて理解しようとした痕跡

移植元はFlashの表示サイズ固定で公開してたから、pixel数をハードコーディングしながら作ってあったんだけど……
正直可変にする意味がほぼないことを考えると、これも表示サイズ固定して中に定数ゴリゴリ書いちゃうのが(時間パフォーマンス的に)正解だったように思う可変で作ったお陰でスマホでも一応遊べるようになったのはよかった
スマホ向けの設定まったくなにもしなくても動くとは思ってなかった、すげえやUnity

まあ今回の移植の主目的はUnityの勉強なので、ここでハマった時間も座標操作の扱いに慣れるための勉強料だったと考えることにする
ちなみにアス比が変わったりすると各座標が意図しないところに設定されるの、公開時まで直らなかったのでプレイ中のスケーリング非推奨です 勉強料ドブですねえ!!!!!

ビルド・公開まわりで発生した問題

再生ボタンを押したら大方問題なく動くようになったし、さあビルドして公開しちゃうぞ~~ってとこでやはりというか数時間ハマった

・Update関数にフレームレートの変更が反映されない
たぶんWebGLビルド固有の問題?
Unity上では Application.targetFrameRate = 15; 設定が効いてたんですが、ビルド後はガン無視されて60fpsで動いてた

プロジェクト設定の「固定時間ステップ」を変更して、フレームレートを固定したい処理にはUpdate関数のかわりにFixedUpdate関数を使ったらあっさり解決しました

ここの固定時間ステップに固定したい1fあたりの秒数を入力

元のFLASHが15fpsでフレームごとの処理を書いてたから、60fps(Unityくんのデフォルト)だと妨害オブジェクトが4倍速で飛んでくるとか、さむいひ(フレームごとに手のx座標がランダムに震える)の見た目がやたらキモくなるとかいろいろ弊害があった
理想の話するとfps変更に対応できるようにしたいけどまあ今回はいいや~

・サーバーの1ファイルあたりのサイズ制限に引っかかる
コンパイルしたファイルの中で大きいやつは1つ3~5MBくらいあるんですけど、無料レンタルサーバだと1ファイルあたり3MBまでのところが多くてなかなか置けず、結局XFREEのPHPプランを借りて解決した
無料で1ファイルあたりの上限30MB、めちゃめちゃありがたい ただしHTTPS接続は非対応

安いとこなら月額数百円くらいで1ファイルあたりの上限は100MBとかになるし、HTTPSにも追加料金なしで対応できたり独自ドメイン使えたりするので
定期的にWebでなんか公開するなら無料にこだわらない方が絶対いいと思います

・アップロードしたやつが動かない
Chromeのデバッグツール覗いたらゲームファイルの圧縮をブラウザ上で展開できてなかったっぽい
.htaccessファイルを書き換えて対応するのがいいみたいなんだけどうまくいかなかったので、

ビルド設定>プレイヤー設定>公開設定

ここにチェック入れてビルドしたら無事動きました
これだとちょっと展開が遅くなるらしいけど、無圧縮で置くよりは(容量的な意味で)こっちの方が多分マシでしょう

おわりに(あそんでくれてありがとう)

紹介したかった話はだいたいこんなもんかな? たぶん

公開したらさっそく何人か遊んでTwitterに呟いてくれて本当にありがたい限りです ちょううれしい~~〜!!!!!!
遊ぶハードルを下げるためにどうにかブラウザ上で動かせるサーバーを探した甲斐がありました

「ひたすら等速直線運動で物を投げてくるクラスメートは輩すぎる」
「足を動かせ」
「プレイヤーはいじめられてるのかな」
「消しゴムくらい耐えろよ」
「俺だけダルシムモードにしてほしい」
などのコメントを拝見してニッコニコになってます

せっかくUnityの勉強をしたので次は3Dバカゲーとかにも挑戦してみたい
きがむいたらまたがんばりま~す

この記事が気に入ったらサポートをしてみませんか?