描画リストについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Pelon

描画リストについて

#1

投稿記事 by Pelon » 8年前

初めて利用させていただきます。リアルで周囲にあんまりc++に詳しい人がいないので質問させていただきます
c++について勉強をしながらゲームを作っておりまして、どういった構造でプログラムを組めばいいんだろう、と探していたところ下記urlのサイトを見つけました
http://rudora7.blog81.fc2.com/blog-entry-968.html (勝手に貼っていいのかな……?)

そこに載っていたプログラムをそのまま使うのも面白くないので以下の改変を加えました
・std::shared_ptr<>をstd::unique_ptr<>に
・listに対応したvector→listに対応したunordered_mapに変更(なんとなく名前がかっこよかったから)、listの並び順を格納
・描画オブジェクトの描画順変更処理を、要素の削除→挿入から、list.splice()を使った要素の場所移動に変更 等…

このように組んでみたところ、ちゃんと想定した動作をしてくれました。以下がそのプログラムです(ちょっと長いです)

drawmngr.h

コード:

#pragma once
#include <list>
#include <unordered_map>
#include <memory>
#include "drawbase.h"
#include "drawer.h"
#include "Singleton.h"

class Drawmngr : public Singleton<Drawmngr>
{
public:
	Drawmngr();
	~Drawmngr();
	bool AddDraw(std::unique_ptr< Drawer >& tDrawer,int& ObjectId);
	bool ChangePriority(const int& ObjectId,int& Priority);
	bool DeleteDraw(const int& ObjectId);
	bool Draw();
	bool GetSetNum();
	void ChangeSetNum(bool);
	
private:
	std::list< std::unique_ptr< Drawer > > m_Drawerlist;//描画オブジェクトリスト
	std::unordered_map<int,unsigned int> m_DrawObjectOrder;//リストの要素のObjectIdに対応した並び順格納コンテナ
	bool SetNumFlg = true;
	
};
drawmngr.cpp

コード:

#include "drawmngr.h"


Drawmngr::Drawmngr() 
{

}

Drawmngr::~Drawmngr()
{

}

bool Drawmngr::Draw()
{
	bool result = false;
	if (!m_Drawerlist.empty())//リストが空なら何もしない
	{

		for (auto itr = m_Drawerlist.begin(); itr != m_Drawerlist.end();)
		{
			if (m_DrawObjectOrder.find((*itr)->GetObjectId()) == m_DrawObjectOrder.end())//ObjectOrderに無いなら削除
			{
				itr = m_Drawerlist.erase(itr);
			}
			else
			{
				((*itr)->Draw());//描画
				++itr;
			}
		}

		if (GetSetNum())//unordered_mapにリストの並び順を記録する ObjectIdを指定するとリストの何列目かわかる
		{
			unsigned int Num = 0;//一時変数
			for (auto itr = m_Drawerlist.begin(); itr != m_Drawerlist.end(); itr++, Num++)
			{
				m_DrawObjectOrder[(*itr)->GetObjectId()] = Num;
			}
			ChangeSetNum(false);//フラグが立った時しか更新しない

		}
		result = true;
	}
	return (result);
}

bool Drawmngr::AddDraw(std::unique_ptr<Drawer>& tDrawer,int& ObjectId)
{
	bool result = false;
	
	if (tDrawer != NULL)
	{
		for (auto itr = m_Drawerlist.begin(); itr != m_Drawerlist.end();)
		{
			if ((*itr)->GetPriority() > tDrawer->GetPriority())//優先度が高ければ
			{
				tDrawer->SetObjectId(ObjectId);
				itr = m_Drawerlist.emplace(itr, std::move(tDrawer));//挿入
				m_DrawObjectOrder[ObjectId];//後で代入する 今はキーだけ設定しておく

				result = true;
				break;
			}
			else
			{
				++itr;
			}
		}

		if (result == false)
		{
			tDrawer->SetObjectId(ObjectId);
			m_Drawerlist.emplace_back(std::move(tDrawer)); //末尾に挿入
			m_DrawObjectOrder[ObjectId];
			
			result = true;
		}
		ChangeSetNum(true);//要素を変更したら並び順を再振り分け
	}
	return (result);
}

bool Drawmngr::ChangePriority(const int& ObjectId,int& priority)
{
	bool result = false;
		if (m_DrawObjectOrder.find(ObjectId) != m_DrawObjectOrder.end())  //ないなら何もしない
		{
			unsigned int from = m_DrawObjectOrder[ObjectId];
			auto fromitr = std::next(m_Drawerlist.begin(), from);
			if ((*fromitr)->GetPriority() == priority)//優先順位変更なしなら終了
			{
				return (result);
			}

			unsigned int to = 0;
			unsigned int tmpnum = 0;

			for (auto itr = m_Drawerlist.begin(); itr != m_Drawerlist.end(); itr++, tmpnum++)
			{
				if ((*itr)->GetPriority() < priority)
				{
					to = tmpnum;
					continue;
				}
			}
			m_Drawerlist.splice(std::next(m_Drawerlist.begin(),to),std::move(m_Drawerlist),std::next(m_Drawerlist.begin(),from));
			(*fromitr)->SetPriority(priority);
			//要素を変更したら並び順を再振り分け
			unsigned int Num = 0;
			for (auto itr = m_Drawerlist.begin(); itr != m_Drawerlist.end(); itr++, Num++)
			{
				m_DrawObjectOrder[(*itr)->GetObjectId()] = Num;
			}

			result = true;
		}
	
	return (result);
}

bool Drawmngr::DeleteDraw(const int& ObjectId)
{
	bool result = false;
	if (m_DrawObjectOrder.find(ObjectId) != m_DrawObjectOrder.end())//ObjectIdが登録されているなら
	{
		m_DrawObjectOrder.erase(ObjectId);
		ChangeSetNum(true);//要素を以下略
		result = true;
	}
	return (result);
}

bool Drawmngr::GetSetNum()
{
	return SetNumFlg;
}

void Drawmngr::ChangeSetNum(bool SetNum_)
{
	SetNumFlg = SetNum_;
}#include "drawmngr.h"


Drawmngr::Drawmngr() 
{

}

Drawmngr::~Drawmngr()
{

}

bool Drawmngr::Draw()
{
	bool result = false;
	if (!m_Drawerlist.empty())//リストが空なら何もしない
	{

		for (auto itr = m_Drawerlist.begin(); itr != m_Drawerlist.end();)
		{
			if (m_DrawObjectOrder.find((*itr)->GetObjectId()) == m_DrawObjectOrder.end())//ObjectOrderに無いなら削除
			{
				itr = m_Drawerlist.erase(itr);
			}
			else
			{
				((*itr)->Draw());//描画
				++itr;
			}
		}

		if (GetSetNum())//unordered_mapにリストの並び順を記録する ObjectIdを指定するとリストの何列目かわかる
		{
			unsigned int Num = 0;//一時変数
			for (auto itr = m_Drawerlist.begin(); itr != m_Drawerlist.end(); itr++, Num++)
			{
				m_DrawObjectOrder[(*itr)->GetObjectId()] = Num;
			}
			ChangeSetNum(false);//フラグが立った時しか更新しない

		}
		result = true;
	}
	return (result);
}

bool Drawmngr::AddDraw(std::unique_ptr<Drawer>& tDrawer,int& ObjectId)
{
	bool result = false;
	
	if (tDrawer != NULL)
	{
		for (auto itr = m_Drawerlist.begin(); itr != m_Drawerlist.end();)
		{
			if ((*itr)->GetPriority() > tDrawer->GetPriority())//優先度が高ければ
			{
				tDrawer->SetObjectId(ObjectId);
				itr = m_Drawerlist.emplace(itr, std::move(tDrawer));//挿入
				m_DrawObjectOrder[ObjectId];//後で代入する 今はキーだけ設定しておく

				result = true;
				break;
			}
			else
			{
				++itr;
			}
		}

		if (result == false)
		{
			tDrawer->SetObjectId(ObjectId);
			m_Drawerlist.emplace_back(std::move(tDrawer)); //末尾に挿入
			m_DrawObjectOrder[ObjectId];
			
			result = true;
		}
		ChangeSetNum(true);//要素を変更したら並び順を再振り分け
	}
	return (result);
}

bool Drawmngr::ChangePriority(const int& ObjectId,int& priority)
{
	bool result = false;
		if (m_DrawObjectOrder.find(ObjectId) != m_DrawObjectOrder.end())  //ないなら何もしない
		{
			unsigned int from = m_DrawObjectOrder[ObjectId];
			auto fromitr = std::next(m_Drawerlist.begin(), from);
			if ((*fromitr)->GetPriority() == priority)//優先順位変更なしなら終了
			{
				return (result);
			}

			unsigned int to = 0;
			unsigned int tmpnum = 0;

			for (auto itr = m_Drawerlist.begin(); itr != m_Drawerlist.end(); itr++, tmpnum++)
			{
				if ((*itr)->GetPriority() < priority)
				{
					to = tmpnum;
					continue;
				}
			}
			m_Drawerlist.splice(std::next(m_Drawerlist.begin(),to),std::move(m_Drawerlist),std::next(m_Drawerlist.begin(),from));
			(*fromitr)->SetPriority(priority);
			//要素を変更したら並び順を再振り分け
			unsigned int Num = 0;
			for (auto itr = m_Drawerlist.begin(); itr != m_Drawerlist.end(); itr++, Num++)
			{
				m_DrawObjectOrder[(*itr)->GetObjectId()] = Num;
			}

			result = true;
		}
	
	return (result);
}

bool Drawmngr::DeleteDraw(const int& ObjectId)
{
	bool result = false;
	if (m_DrawObjectOrder.find(ObjectId) != m_DrawObjectOrder.end())//ObjectIdが登録されているなら
	{
		m_DrawObjectOrder.erase(ObjectId);
		ChangeSetNum(true);//要素を以下略
		result = true;
	}
	return (result);
}

bool Drawmngr::GetSetNum()
{
	return SetNumFlg;
}

void Drawmngr::ChangeSetNum(bool SetNum_)
{
	SetNumFlg = SetNum_;
}
他のヘッダやmain.cpp等については上記urlのものとほぼ同じで、本題とあまり関係ないので貼らないでおきます

いわゆる描画マネージャ、というやつです

ここからが質問といいますか――――ちょっとした疑問も含みますが――――本題です。
自分は上記のように組みましたが、何分独学なもので、頓珍漢な組み方をしているのではないか、気づきにくい危険なコードがあるのではないか……と不安に駆られました
なので、もしそういうところがあれば指摘してもらいたいな、と思っております
構造的にもっとすぐれた書き方がある、例えばこうだ……のような改善案もいただけたらな、と、思っております
また、単純に自分が書いた(まあ改変みたいなものなんですが)コードを見てもらいたいなという気持ちもあり
こうして質問という形で投稿させていただきました
当方はc++歴約3か月程度の初心者です どうぞよろしくお願いします

Math

Re: 描画リストについて

#2

投稿記事 by Math » 8年前


drawmngr.cppの142行が変ですね。
全コードと”想定した動作”がどういうものか詳しく書いていただくとテストができますが コードを見るだけでは時間がかかりすぎます。
当方はWindows10,VS2017Communityですが 環境もおしえてください。

Pelon

Re: 描画リストについて

#3

投稿記事 by Pelon » 8年前

Mathさん、返信ありがとうございます
どうも142行の#include "drawmngr.h"以下は間違って複数貼り付けてしまっていたみたいです 申し訳ない
”想定した動作”というのは描画オブジェクトの描画、リストへの登録、削除、オブジェクトの優先度変動による要素の並び替えのことです。(でも実はあまりテストはしていなかったり)
投稿してからしばらく考えてみましたがやっぱり無駄が多かったと判断して組みなおしてみました
以下コードです

drawmngr.h

コード:

#pragma once
#include <list>
#include <unordered_map>
#include <memory>
#include "drawbase.h"
#include "drawer.h"
#include "Singleton.h"

class Drawmngr : public Singleton<Drawmngr>
{
public:
	Drawmngr();
	~Drawmngr();
	bool AddDraw(std::unique_ptr< Drawer >& tDrawer,int& ObjectId);
	bool ChangePriority(const int& ObjectId,int& Priority);
	bool DeleteDraw(const int& ObjectId);
	bool Draw();
	void ListSort();
	void ChangeSortFlg(bool);
	static bool sortlist(std::unique_ptr< Drawer >& Drawerlhs, std::unique_ptr< Drawer >& Drawerrhs)
	{
		return Drawerlhs->GetPriority() < Drawerrhs->GetPriority();
	}//DrawerListソート用関数
	
private:
	std::list< std::unique_ptr< Drawer > > m_Drawerlist;//描画オブジェクトリスト
	std::unordered_map<int,Drawer*> m_pDrawer;//Listのユニークポインタからの生ポインタ格納
	bool SortFlg = false;
	
};
drawmngr.cpp

コード:

#include "drawmngr.h"


Drawmngr::Drawmngr() 
{

}

Drawmngr::~Drawmngr()
{

}

bool Drawmngr::Draw()
{
	bool result = false;
	if (!m_Drawerlist.empty())//リストが空なら何もしない
	{

		for (auto itr = m_Drawerlist.begin(); itr != m_Drawerlist.end();)
		{
			if (m_pDrawer.find((*itr)->GetObjectId()) == m_pDrawer.end())//unordered_mapに無いならListから削除
			{
				itr = m_Drawerlist.erase(itr);
			}
			else
			{
				((*itr)->Draw());//描画
				++itr;
			}
		}

		result = true;
	}
	return (result);
}

bool Drawmngr::AddDraw(std::unique_ptr<Drawer>& tDrawer,int& ObjectId)
{
	bool result = false;
	
	if (tDrawer != NULL)
	{
		for (auto itr = m_Drawerlist.begin(); itr != m_Drawerlist.end();)
		{
			if ((*itr)->GetPriority() > tDrawer->GetPriority())//優先度が高ければ
			{
				tDrawer->SetObjectId(ObjectId);
				itr = m_Drawerlist.emplace(itr, std::move(tDrawer));//挿入
				m_pDrawer[ObjectId] = (*itr).get();

				result = true;
				break;
			}
			else
			{
				++itr;
			}
		}

		if (result == false)
		{
			tDrawer->SetObjectId(ObjectId);
			m_Drawerlist.emplace_back(std::move(tDrawer)); //末尾に挿入
			auto itr = m_Drawerlist.end();
			itr--;
			m_pDrawer[ObjectId] = (*itr).get();//生ポインタを取得
			
			result = true;
		}
	}
	return (result);
}

bool Drawmngr::ChangePriority(const int& ObjectId,int& priority)
{
	bool result = false;
		if (m_pDrawer.find(ObjectId) != m_pDrawer.end())  //ないなら何もしない
		{

			if ((m_pDrawer[ObjectId])->GetPriority() == priority)//優先順位変更なしなら終了
			{
				return (result);
			}

			(m_pDrawer[ObjectId])->SetPriority(priority);//生ポインタから要素へアクセス
			result = true;
			ChangeSortFlg(true);
		}
	
	return (result);
}

bool Drawmngr::DeleteDraw(const int& ObjectId)
{
	bool result = false;
	if (m_pDrawer.find(ObjectId) != m_pDrawer.end())//ObjectIdが登録されているなら
	{
		m_pDrawer.erase(ObjectId);//listの要素はDrawmngr::Draw()で消す
		result = true;
	}
	return (result);
}

void Drawmngr::ListSort()
{
	if (SortFlg)
	{
		m_Drawerlist.sort(&sortlist);
		ChangeSortFlg(false);
	}
}

void Drawmngr::ChangeSortFlg(bool flg)
{
	SortFlg = flg;
}
いくらか見やすくはなったでしょうか
要素の並び替えが起こったときソートするように、unordered_mapにユニークポインタからget()を使って生ポインタを格納するようにしました

それからこれはするのを忘れていた質問なんですが、unordered_mapはなかなか便利なコンテナだと思うのですが、ゲーム制作に向いているのでしょうか?

環境はwindows7,visual studio community 2017です。問題点があれば指摘等、よろしくお願いします

Math

Re: 描画リストについて

#4

投稿記事 by Math » 8年前

全コード(うごくもの)すべて(*.h)を送ってください。
============================
http://dixq.net/board/board.htmlを一読の上
  1. 自分は今何がしたくて

  2. どう取り組んで(作ったプログラムはどれで

  3. どのようなエラーやトラブルで困っていて

  4. 自分は何が解らないのか、知りたいのか

  5. 今のCの知識はどの程度なのか
等を
(どう質問していいか解らない時は、以下のテンプレをコピペして、)

各項目に対して答える形で記載して下さい。

[1] 質問文
 [1.1] 自分が今行いたい事は何か
 [1.2] どのように取り組んだか(プログラムコードがある場合記載)
 [1.3] どのようなエラーやトラブルで困っているか(エラーメッセージが解る場合は記載)
 [1.4] 今何がわからないのか、知りたいのか

[2] 環境  
 [2.1] OS : Windows, Linux等々
 [2.2] コンパイラ名 : VC++ 2008EE, Borand C++, gcc等々

[3] その他
 ・どの程度C言語を理解しているか
 ・ライブラリを使っている場合は何を使っているか

を詳しく記してください。

Pelon

Re: 描画リストについて

#5

投稿記事 by Pelon » 8年前

やっぱり質問に具体性が足りないのがよくなかったかもしれません
とはいえ自分の中でも何を聞きたいのか曖昧でまとまりそうにありません
とりあえず上記のコードを自分でテストしていきながら問題点を探りつつ作っていこうと思います
またどうしても質問したいときに質問したいことを具体的にまとめてからトピックを立てるようにします、反省です
というわけで、一旦解決とさせてください。Mathさん、返信ありがとうございました

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: 描画リストについて

#6

投稿記事 by usao » 8年前

オフトピック
> std::shared_ptr<>をstd::unique_ptr<>に

使い勝手というか使い方が,別物になってしまいそうだが……?

返信

“C言語何でも質問掲示板” へ戻る