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