ニコ生ゲームを作ろうと思ったらすぐコピペしよう その7

[2022/12/20加筆]
以下の記事は、FPS60で音ゲーを作る内容です。
ただし、色々プレイ時の反応を見ていると音ズレがやはりあるようです。

開発者がテストプレイしたときの処理と比べて、プレイヤーのPCの処理が極端に速いか、プレイヤーのスマホ等の処理が遅いかするとズレが起きます。
タイミングの判定が甘くなりますがgame.jsonFPSを30にする設定も検討ください。

 


第7回のゲームはFPS60の音ゲーです。

楽曲ファイルを用意すれば譜面データを作って遊べると思います。

譜面データの作り方も解説します。

 

以下がサンプルです。ファイルのBGMとSEはアツマールとは違って自作です。

・シンプル音ゲー ファイル アツマール 



■目次

  • BGM差し替え
  • タイミング計測
  • 譜面作成
  • 制限時間設定
  • タイトル文字
  • SE差し替え
  • ラインモード設定
  • イメージモード設定
  • エフェクトの選択
  • タイミング判定の緩和
  • その他の設定




 

BGM差し替え

BGMはいろんなサイトで公開されているのでお借りしてきましょう。

私はよく https://dova-s.jp/ というサイトで検索します。ニコニコモンズもいいですね。

 

BGMが用意できたらoggファイルとaacファイルに変換し、audioフォルダに入れ、

akashic scan assetをやります。

 

ファイル名はbgmにしたほうが楽です。変える場合はmain.jsの中の"bgm"も書き換えましょう。

今回のファイルに入ってる曲は作曲ソフトのテンプレをつなげた自作のものですが、まあ使い回す人はいないと思います。

 


タイミング計測

曲のスピードはまちまちなので合わせていきます。

558行目ぐらいにある long と short という値を設定します。フレーム数で設定します。fps60だと1フレームが0.017秒です。

  • short 最短で押す可能性があるタイミング。20~30ぐらい。秒数で0.5秒ぐらい
  • long 曲の繰り返しに合わせた長めのタイミング。shortの8倍など。100~300。
       譜面を書きやすくするためのものなので16倍などでもいい

 

もう一つの値としてstartも設定します。shortの繰り返しが曲の再生開始からどれぐらいで開始するかを表します。曲のイントロ次第なのでマイナスになったり数百になることもありえます。今の所一桁の例が多いです。

 

 

これらの値を計測する方法ですが、ゲームのデバッグモードを利用します。

11行目にあるdebugmode を debugmode = true;に書き換えてakashic-sandboxでテスト起動します。

 

ゲームをテスト起動できたら、まずタップの対象になりそうな最短のタイミングを等間隔でタップしていきます。曲に合わせていい感じに譜面を作るのはまだ先です。

 

押すたびに画面に数値が出ますがこれはメモる必要はありません。下側にstartとshortの推奨値が出るのでこれをmain.jsに入力します。

startの値は画面に収まりきらなくなって曲が終わるぐらいまでは計測しましょう。精度が上がります。さらに5回ぐらいやり直して平均を取るのがベストです。

 

longの値も計測してもいいですが、shortの値の8倍などを計算して入れても大体合うと思います。

どの値も少数になっても大丈夫ですが、マイナスが許されるのはstartだけです。

 

当然ながらゲームをリリースするときは debugmode = false; に戻しましょう。

 

 

譜面作成

譜面データは564行目にあるような形で入力します。

 

        let table = [
            [  ,  ,  ,  , 0,  ,  ,  ],
            [ 0,  ,  ,  , 0,  ,  ,  ],
            [ 0,  ,  ,  , 0,  ,  ,  ],
            [ 0,  ,  ,  , 0,  ,  ,  ],

            [ 0,  ,  ,  , 0, 0,  ,  ],
            [ 0,  ,  ,  , 0, 0,  ,  ],
            [ 0,  ,  ,  , 0, 0,  ,  ],
            [ 0,  ,  ,  , 0, 0,  ,  ],

            [ 0, 0,  ,  , 0, 0,  ,  ],
            [ 0, 0,  ,  , 0, 0,  ,  ],
            [ 0, 0,  ,  , 0, 0,  ,  ],
            [ 0, 0,  ,  , 0, 0,  ,  ],

            [ 0,  , 0,  , 0,  , 0,  ],
            [ 0,  , 0,  , 0,  , 0,  ],
            [ 0,  , 0,  , 0,  , 0,  ],
            [ 0,  , 0,  , 0,  , 0,  ],

            [ 0,  , 0,  ,  , 0, 0, 0],
            [ 0,  , 0,  ,  , 0, 0, 0],
            [ 0,  , 0,  ,  , 0, 0, 0],
            [ 0,  , 0,  ,  , 0, 0, 0],

            [ 0,  ,  ,  ,  ,  ,  ,  ],
        ];

1行ごとに一つの配列がありますが、配列の長さはlong/shortです。

long = 192、short = 24なら配列の長さは8です。一つのlongの期間の中の8つのタイミングを表しています。

タップを要求するタイミングでは数字を入れ、要求しない場合は空白を入れます。空白には半角スペースを2つ入れていますが単に見た目を揃えるためです。

 

タイミングの数字は基本は0ですが、フレーム数を入れて微妙に遅らせることもできます。shortの半分の値を入れれば裏拍的なタイミングも可能です。

マイナスとshortより大きい値は不可です。処理上の問題でshortとの差が1より小さくても読み取られなくなります。

 

また、最初の数カ所はタイミング用の画像を出すのが間に合いません。step/2/shortにあたる2~3個のタイミングは数字を入れてもタイミング用画像が出てきません。

 

longの区切りがうまく行かずに一つずれてしまうこともあります。その場合はstartの値にshortをいくつか足したり引いたりして調整してください。

 

 

最終的にテストプレイしてみてタイミングがずれていると感じるなら計測値は無視してstartの値を1や2足したり引いたりするのが良いです。

 

 

制限時間設定

制限時間を設定しておくと終了の文字が出るようになります。

すべてのタイミング用画像がでて1,2秒たったあたりになるように数字を設定します。

 

制限時間はまずmain.jsの54行目のtimelimitに入力します。

 

もう一箇所ニコ生ゲーム用にゲームそのものを終了させる制限時間を設定します。game.jsonの方の最後にあるtotalTimeLimitに値を入力します。

こちらの値は説明を見る時間とロード時間を吸収するために15~20秒余裕を持って設定します。main.jsの制限時間が65秒だったので17秒加えて82秒としています。

 

 

タイトル文字

タイトル文字は471行目のtextを変えれば変わります

        let titlefont = new g.DynamicFont({
            game: g.game, fontFamily: "sans-serif", fontWeight: "bold",
            size: 96, fontColor: "hsl(180 , 100%, 50%)", strokeWidth: 2, strokeColor: "hsl(180 , 100%, 50%)",
        });
        new g.Label({// タイトル文字
            scene: scene, text: "シンプル音ゲー", parent: warmuplayer,
            font: titlefont, fontSize: 72,
            x: g.game.width/2, y: 115, anchorX: 0.5, anchorY: 0.5, opacity: 1,
        });

 

文字数が多くて収まらない場合はfontSizeを72から60などにします

文字色を変えるときは468行目のfontColorとstrokeColorを変えます。

最初の180という数字でシアンになっているので0なら赤、60なら黄色になります。

 

 

SE差し替え

タップした時に鳴るSEはドラムかなにかの音を作曲ソフトから自前で用意しています。

 

適当な効果音サイトから持ってくればBGMと同じように差し替えられます。

ファイル名はseにしておくと楽です。oggaacが必要です。

 

SEは冒頭の間を極限まで削ると、押した瞬間に音がなってる感触が得られます。0.1秒刻みぐらいで切り詰めるといいです。

 

 

ラインモード設定

タップするターゲットが出る位置を変更することができます。

12行目linemodeをfalseにするかtrueにするかで変わります。

  • linemode = false 画面内のランダムな場所に発生 花火太鼓と同じ ハード
  • linemode = true 画面下寄りのライン上に発生 花火太鼓2と同じ イージー

 

 

イメージモード設定

13行目imagemodeをtrueにすれば、タップするターゲットを画像に変更できます。

 

画像を変更する場合はimageという名前で用意します。画像のサイズが変わる場合はakashic scan assetをやってください。

 

画像のサイズがタップできるエリアに相当します。外周の空白が多い画像にすればタップの判定を甘くすることができます。標準で入れてある画像は200x200です。

 

 

エフェクトの選択

エフェクトは標準でいくつか用意しているので238行目辺りでどれを使うか選択してください。

複数のエフェクトを使うこともできますが重くなる恐れがあるのでおすすめしません。重くなって曲の進行に対してゲームの進行が遅れると、音ゲーの前提が崩れそうです。

 

エフェクトの発生数も変えられます。しかしこれも過剰にすると重くなりかねません。

 

画像やアニメーション画像を使うタイプもあります。エフェクト用のアニメーション画像素材もウェブ上で公開されている事があります。

 

用意されている画像は適当に作ったやつなので差し替えてもらうのもいいと思います。使ってもらっても構いませんが。

 

タイミング画像の残留時間

タイミング画像はタップしたあとも一定時間残るようになっています。

画像のズレから早すぎたのかおそすぎたのか判断するためです。

 

しかし次の画像が見づらいというフィードバックが来ました。ごもっともです。

 

時間を短くする場合は次の214行目の最後の数字を変えてください。

        scene.setTimeout*1 target.destroy();
        }, 1000);

 

ミリ秒で指定するので200 にすれば0.2秒になります。

数字を0にするのはやったことがありませんがうまく処理されないかもしれません。

 

 

タイミング判定の緩和

タップしたタイミングは1フレーム単位で判定することができます。

しかし、そもそも曲と譜面のタイミングのズレが完璧とは限らないのに、プレイヤーの1フレームのズレをとがめるのは少々納得感にかけます。

 

そこで220行目と221行目判定が近いとすべて満点にする処理を追加しています。

    point += 0; //タイミング判定の緩和 0~3推奨
    if (point > 100) point = 100;

 

point += 2; のようにすると、ズレが2フレームまでは100点になります。

花火太鼓2は0フレームにしてみました。

花火太鼓の方は2フレームにしていましたが、総合で満点を出された方は一人でした。

 

ちょっと反省点なのが画像の重なりでタイミングのズレを見れるようにしたせいで、満点にしても画像はズレてしまいます。

判定を厳しくして理不尽な感じさせるのとどちらがいいかというところですね。

 

緩和は入れつつ動かす方の四角のサイズを少し小さくすれば良かったかもしれません。

190行目のwidthとheightの指定に -10 等を書き加えれば小さくできます。

 

 

その他の設定

タップするターゲットの四角は140行目辺りで調整できます。

  • size 四角の大きさ 大きくするとタップしやすい 標準150
  • edge 四角の枠の太さ 標準10
  • swing 四角が移動する距離 小さくすると遅くなる 標準1000
  • step 四角が発生するフレーム数 大きくすると遅くなる 標準120 整数のみ

 

 


この記事以外にも、コピペできそうなコードや解説を公開しています。
こちらに記事のリンクがまとまっていますので御覧ください。

*1:) => {
            if (!target.destroyed(