プレイするゲームがないなら、自分で作ればいいじゃない!
ということで初心者が Unity を使って「ゲームを作る」ゲームをやっていきます!
今回は「フレームレート設定」の記事です
フレームレートの設定
実行時にPCがフル稼働している音が聞こえたので
フレームレートを「60」に設定してみる
※1秒間に60回更新するようにする
プロジェクト設定の編集
「編集」⇒「プロジェクト設定」⇒「品質」
「VSync数」を同期しないに設定する
システム変更用のオブジェクトを作成
フレームレート数はスクリプトから変更するため
システム用に空のオブジェクトを作成する
オブジェクトにC#スクリプトを追加
新しくC#スクリプトを作成して、上記で作成したオブジェクトにアタッチします
※今回は GameSystem.cs をアタッチしました
オブジェクトをプレハブにする
ヒエラルキービューのオブジェクトを選択して
プロジェクトビューにドラッグ&ドロップするとプレハブが作成されます
ヒエラルキービューで色が変化していたらブレハブ化成功です
※プレハブについては次回する予定です
スクリプトの編集
続いてフレームレートを設定するために、スクリプトを編集していきます
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameSystem : MonoBehaviour
{
public static GameSystem instance { get; private set; } = null; // シングルトン
private void Awake()
{
if (instance == null)
{
// インスタンスがない場合は代入
instance = this;
// シーン切り替え時に消さないようにする
DontDestroyOnLoad(this.gameObject);
}
else
{
// ある場合は2つ目なのでゲームオブジェクトを消す
Destroy(this.gameObject);
return;
}
// 初期設定
SetFps(60);
}
// フレームレートの設定(1秒間に何回 Update が実行されるか)
public void SetFps(int fps)
{
// Update()が実行される周期
Application.targetFrameRate = fps;
// FixedUpdate()が実行される周期
Time.fixedDeltaTime = 1.0f / (float)fps;
}
}
private void Awake()
スクリプトのインスタンスがロードされたときに呼び出されます
Start() より先に呼び出される関数
この中でフレームレートを設定する関数を呼んでいます
public void SetFps(int fps)
「Application.targetFrameRate」: Update() が呼ばれる周期を変更する
・フレーム数を代入する
「Time.fixedDeltaTime」: FixedUpdate() が呼ばれる周期を変更する
・ミリ秒を代入する
fixed の方は現状使用していないため、設定する必要はない
その他
instance やシングルトンなど書いていますが
これらはシーンの切り替え時に便利な処理になります
実行してみると…
開発環境によって結果は変わると思いますが
私の環境ではプレイヤーの移動スピードがメチャクチャ遅くなりました
60で設定したことにより Update() の処理回数が減ったのが原因です
移動値を調整して再び実行すると前の状態に戻りました!
いちいち移動値の設定が必要なのか?
フレームレートの設定が完了し、動作も元に戻りましたが…
フレームレートを変更するたびに調整しないといけないのか?
という疑問が出てきます
今はまだプレイヤーだけなのですぐ終わりましたが
弾や敵、その他色々なものを追加した後に
「フレームレートを30にしたい」
となった場合、全てを漏れなく調整し直せるでしょうか?
フレームレートに合わせて移動させる
やはり調整するのは面倒なので、スクリプトでなんとかしましょう
PlayerController の Update() を編集しました
void Update()
{
// 横(Ⅹ)方向の入力
float fHorizontalInput = Input.GetAxisRaw("Horizontal");
// 縦(Y)方向の入力
float fVerticalInput = Input.GetAxis("Vertical");
// 位置を更新
float add_x = fHorizontalInput * fMoveSpeed * Time.deltaTime;
float add_y = fVerticalInput * fMoveSpeed * Time.deltaTime;
transform.Translate(add_x, add_y, 0);
// 試しにFPSを下げてみる
if( Input.GetButtonDown("Fire1") )
{
GameSystem.instance.SetFps(30);
}
}
Time.deltaTime
この値は「前のUpdateから今のUpdateまで何秒かかったか」という値です
単純計算ですが、下記に近い値が入っているはず
・30フレーム:0.03333…
・60フレーム:0.01666…
「移動距離=速度」だったのが
「移動距離=速度 × 時間」となり
フレームが変化してもある程度近い値を求めることができるようになります
transform.Translate(x,y,z)
position に代入していましたが、Translate を使うと現在の値に加算してくれる
コード量が減って便利
GameSystem.instance.SetFps(int)
これは今回作成したスクリプトを試しに呼び出して
「60フレームから30フレーム」に変更しています
再び実行すると…
再び移動スピードが遅くなる
これは時間をかけるようにしたためなので、最後に移動値を調整して実行
これでフレームレートを変更しても、移動スピードがほぼ変わらず動くようになりました!
サンプル動画
フレームレートの変化に対応できたが…
今回の対応は処理落ちした時にも有効なのですが
例えば弾幕ゲーにしたとして、弾がたくさん出て処理落ちした場合
自機や弾の移動がワープしたかのような動作になってしまうような気がします
気づかないうちに弾に当たったりする可能性があるかもしれないので
2Dシューティングでは対応しない方がよかったかもしれません
そのまえに処理落ちを直せよって感じなのですが(笑)
さいごに
今回はPCの異音が気になってフレームレート設定になりました
次こそは弾を発射させたい!
コメント