Hiragi(GKUTH)の日常
理系大学生の日記

龍神録2の館の機能追加その1

アバター
Hiragi(GKUTH)
記事: 167
登録日時: 14年前
住所: 大阪府
連絡を取る:

龍神録2の館の機能追加その1

投稿記事 by Hiragi(GKUTH) » 7年前

 新しい章が出るまでちょくちょく機能追加などしていこうかと思います。
今回はゲーム内の処理時間がどのぐらいかと言うのを計測してグラフを描画してやろうというお話です。
Profilerクラスを新たに作り、開始と終了時にメンバ関数を呼ぶと任意フレーム間の平均値を取って
平均フレーム時間を棒グラフで描画してくれるというものです。Fpsクラスを参考にしました。いずれFpsクラスの機能をProfilerに内包したい...
相変わらず美しいとはいい難いソースですが...

Profiler.h

CODE:

#pragma once

#include 
#include 

class Profiler {
public:
	Profiler() : _begin(0), _end(0), _enableFlag(false) {}
	void update();
	bool draw() const;
	void begin() { _begin = GetNowHiPerformanceCount(); }
	void end() { _end = GetNowHiPerformanceCount(); }
	void setMode(bool enableFlag) { _enableFlag = enableFlag; };

private:

	std::list _list;
	std::list _ave;
	LONGLONG _begin, _end;
	int _counter;
	bool _enableFlag;
	const int SAMPLE_LEN = 240;
	const int AVE_LEN = 10;

};
Profiler.cpp

CODE:

#include "Profiler.h"
#include 

void Profiler::update() {
	double differ = (double)(_end-_begin)/1000;
	int listLen = _list.size();
	int aveLen = _ave.size();

	_counter++;
	_ave.push_back(differ);
	if (aveLen > AVE_LEN) {	//サンプル数を超えたらポップ
		_ave.pop_front();
	}

		//平均の長さフレーム毎に平均をとる
	if (_counter%AVE_LEN == 0) {
		double sum = 0;
		for (auto itr = _ave.begin(); itr != _ave.end(); itr++) {
			sum += *itr;
		}
		sum = sum / AVE_LEN;

		_list.push_back(sum);
		if (listLen > SAMPLE_LEN) {	//サンプル数を超えたらポップ
			_list.pop_front();
		}
	}
}


bool Profiler::draw() const {
	if (_enableFlag != true) {
		return false;
	}

	int i = 0;
	int red = GetColor(255, 64, 64);
		//グラフの表示位置の設定
	const int START_X = 64, START_Y = 64;
	const int SIZE_X = SAMPLE_LEN, SIZE_Y = 128;

		//枠を描画
	DrawBox(START_X,START_Y,START_X + SIZE_X,START_Y + SIZE_Y, red, false);

		//棒グラフを描画
	for (auto itr = _list.begin(); itr != _list.end(); itr++,i++) {
		double current = *itr * 20;
		double x = START_X + SIZE_X - i;
		double y_1 = START_Y + SIZE_Y - current;
		double y_2 = START_Y + SIZE_Y;

		DrawLine(x, y_1, x, y_2, red);
	}
	DrawFormatString(START_X, START_Y, red, "%.2f ms", _list.back());
	return true;
}


アバター
Dixq (管理人)
管理人
記事: 1662
登録日時: 14年前

Re: 龍神録2の館の機能追加その1

投稿記事 by Dixq (管理人) » 7年前

次章を早く作らなければ・・・ツイッターでもまだかなーってつぶやいてる人いるし・・。

変数名にFlagはおすすめしないっす。
職場でもこういう変数名が出てきたら真っ先に指摘されます。
結局Flagって何をするのか忘れたときに見返してもよくわからないのです。

setModeというメソッド名ではなく
enable();
disable();
というメソッド名にした方がより分かりやすいでしょう。

アバター
usao
記事: 1889
登録日時: 12年前

Re: 龍神録2の館の機能追加その1

投稿記事 by usao » 7年前

名前の付け方で気になるのは Flag 側よりもむしろ enable の側.
何の有効無効を表すフラグなのかわからない.

アバター
Dixq (管理人)
管理人
記事: 1662
登録日時: 14年前

Re: 龍神録2の館の機能追加その1

投稿記事 by Dixq (管理人) » 7年前

drawableかどうかを表しているようなのでそこがわかるようにしたいですね

アバター
usao
記事: 1889
登録日時: 12年前

Re: 龍神録2の館の機能追加その1

投稿記事 by usao » 7年前

描画したくないなら単にdraw()を呼ばなければ良いのであって
描画したいかどうかはこのクラスを使う側の都合なのだから
そもそもそんなフラグをこのクラスに持たせるのが,なんか違う感.

アバター
へにっくす
記事: 634
登録日時: 13年前

Re: 龍神録2の館の機能追加その1

投稿記事 by へにっくす » 7年前

有効か無効かで色が変わるとかならわかる気がする。
無効だったら描画しないとは手抜きですな。(笑)

アバター
Dixq (管理人)
管理人
記事: 1662
登録日時: 14年前

RE: 龍神録2の館の機能追加その1

投稿記事 by Dixq (管理人) » 7年前

いや、インスタンスの所持元は一律
update
draw
は必ずやるとしてその中のステータスにより描画をdisableするのはありですよ。
むしろゲームプログラムの基本であるupdateとdrawの呼び出しを呼び出しもとが理解して管理するのはさけるべきです。
さもないとポリモーフィズムを利用した一括管理ができなくなります。

アバター
usao
記事: 1889
登録日時: 12年前

Re: 龍神録2の館の機能追加その1

投稿記事 by usao » 7年前

そういう共通インタフェースなのだとして…
draw()を一括コールする側にはProfilerを描画disableできるやつに包んだ状態で渡しとくとか,
あるいは,単に一旦一括コールリストから除外するとかいう方法を考えたりするんだけど,
そういうのだと無駄に面倒なのかな.

アバター
Hiragi(GKUTH)
記事: 167
登録日時: 14年前
住所: 大阪府
連絡を取る:

Re: 龍神録2の館の機能追加その1

投稿記事 by Hiragi(GKUTH) » 7年前

色々指摘がありましたが、とりあえずすぐできそうな事をしてみました。
Profilerは一つ上のLooperが持ってるので、シーンと同じ深さでDrawなりUpdateなり書いてます。デバッグモード時だけ有効とか
幾つかの機能を全て内包してProfilerにするならばLooperからProfilerの各機能の有効無効を切り替えるメソッドを呼ぶことになるのでしょうか、
今後更に機能追加して、例えば計算部、描画部や、音声やエフェクト、弾など細かい所での計測を考えるのならばそれはそれでまた大幅な設計の変更が必要な気がします。
やったこと無いのでどういう風に実装するのかパッとは思いつかんのですが...

Profiler.h

CODE:

#pragma once

#include 
#include 

class Profiler {
public:
	Profiler() : _begin(0), _end(0), _isDrawable(false) {}
	void update();
	bool draw() const;
	void begin() { _begin = GetNowHiPerformanceCount(); }
	void end() { _end = GetNowHiPerformanceCount(); }
	void disable() { _isDrawable = false; }
	void enable() { _isDrawable = true; }

private:

	std::list _list;
	std::list _ave;
	LONGLONG _begin, _end;
	int _counter;
	bool _isDrawable;
	const int SAMPLE_LEN = 240;
	const int AVE_LEN = 10;

};
Profiler.cpp

CODE:

#include "Profiler.h"
#include 

void Profiler::update() {
	double differ = (double)(_end-_begin)/1000;
	int listLen = _list.size();
	int aveLen = _ave.size();

	_counter++;
	_ave.push_back(differ);
	if (aveLen > AVE_LEN) {	//サンプル数を超えたらポップ
		_ave.pop_front();
	}

		//平均の長さフレーム毎に平均をとる
	if (_counter%AVE_LEN == 0) {
		double sum = 0;
		for (auto itr = _ave.begin(); itr != _ave.end(); itr++) {
			sum += *itr;
		}
		sum = sum / AVE_LEN;

		_list.push_back(sum);
		if (listLen > SAMPLE_LEN) {	//サンプル数を超えたらポップ
			_list.pop_front();
		}
	}
}


bool Profiler::draw() const {
	if (this->_isDrawable == false) {
		return false;
	}

	int i = 0;
	int red = GetColor(255, 64, 64);
		//グラフの表示位置の設定
	const int START_X = 64, START_Y = 64;
	const int SIZE_X = SAMPLE_LEN, SIZE_Y = 128;

		//枠を描画
	DrawBox(START_X,START_Y,START_X + SIZE_X,START_Y + SIZE_Y, red, false);

		//棒グラフを描画
	for (auto itr = _list.begin(); itr != _list.end(); itr++,i++) {
		double current = *itr * 20;
		double x = START_X + SIZE_X - i;
		double y_1 = START_Y + SIZE_Y - current;
		double y_2 = START_Y + SIZE_Y;

		DrawLine(x, y_1, x, y_2, red);
	}
	DrawFormatString(START_X, START_Y, red, "%.2f ms", _list.back());
	return true;
}

Looper.cpp

CODE:

Looper::Looper() {
	Image::getIns()->load();
	Parameter parameter;
	_profiler.enable();
	_sceneStack.push(make_shared(this, parameter));	//タイトルのシーンを作ってpush
}

/*!
@brief スタックのトップのシーンの処理をする
*/
bool Looper::loop() {
	_profiler.begin();
	Keyboard::getIns()->update();
	Pad::getIns()->update();
	_sceneStack.top()->update();	//トップスタックの更新
	_sceneStack.top()->draw();		//トップスタックの描画
	_profiler.end();
	_profiler.update();
	_profiler.draw();
	_fps.draw();
	_fps.wait();
	return true;
}

Rittai_3D
記事: 525
登録日時: 12年前

Re: 龍神録2の館の機能追加その1

投稿記事 by Rittai_3D » 7年前

draw()がboolを返す必要ってありますかね?
return ; で十分な気がします。現時点で、戻り値を使っている訳でもなさそうですし。
何か意図があるならば申し訳ないです。

あと、update()内のfor文はrange based for を使うか、std::accumulate() を使うとシンプルに書けますよ。

アバター
Hiragi(GKUTH)
記事: 167
登録日時: 14年前
住所: 大阪府
連絡を取る:

Re: 龍神録2の館の機能追加その1

投稿記事 by Hiragi(GKUTH) » 7年前

>>Rittai_3D
なんとなく返してます。特に意図はないのですが、今後使われる可能性もないと思いますがとりあえず無いよりゃある方がいいだろとか言う脳死判断でつけました
range-based forすごい使いやすいですね、Pythonのinみたいでよい。しかしインデックスの取得に別変数が必要なのがウーンと言った感じですが
std::accumulate()もコレはコレで素晴らしい、知ってるのと知らないのでは全然違いますね...