皆様、はじめまして。
C++、DXライブラリでゲームを制作している者ですが質問させてください。
今、BGMとSEを実装しようと思っています。
単発で読ませて鳴らすというのは出来るのですが
各クラスがなるべく散らからない様にしたくて
サウンドクラスというものを作り、各クラスでは再生関数、停止関数だけ
記述する方法を模索しております。
自分は各シーンごとにクラス分けしています。
ネットで調べたところ、どのクラスからも呼べる(playできる)様に
staticで作ったメンバ関数を持つサウンドclassを作ればいい、とありました。
(ちなみにメインCPPにはシーンを管理するシーンマネージャーしかおいてません)
で、そうすべき理屈はわかってるつもりなのですが、
実際に鳴らすとなると疑問があります。
自クラスで別のクラスの関数を呼ぶのには、自クラスにて
ポインタ宣言して、そこにその別のクラスをインスタンス化してから
呼び出さなければなりませんよね?
(例 自クラスにて 別クラスインスタンス名->メンバ関数名(); 等 )
作ったサウンドクラスのメンバ関数、
たとえばstatic void play(int snum)やvoid playbgm(int snum)を、
呼ぶ各クラスでいちいち上記ポインタ宣言してサウンドクラスのインスタンス化をしてやらなければ
ならないのでしょうか???
また、サウンドクラスのメンバ関数に
void loadFiles()というファイル読み込み関数を作り、
その定義にてゲーム中に使いたいすべてのBGM,SEをハンドルに読み込ませています。
これを実行するのはサウンドクラスのインスタンス化で実行されるコンストラクタ内で
いいのでしょうか?
しかしその場合、各クラスでインスタンス化なんてしていたら、
メモリが大変なことになりそうな気がしますが、それは思い過ごしでしょうか?
それとも、そもそも各クラスで毎度インスタンス化すること自体間違ってますか?
要点をまとめますと
〇各クラス内で呼びたいサウンドクラスはどこでインスタンス化するのか
〇そのサウンドクラスのメンバであるファイル読み込み関数はコンストラクタ内、初期化内?
よろしくお願い致します。
staticで作ったメンバ関数を持つサウンドclassの扱い
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 14年前
- 住所: 東海地方
- 連絡を取る:
Re: staticで作ったメンバ関数を持つサウンドclassの扱い
staticなメンバ関数、メンバ変数はインスタンスを生成する必要はありません。プログラム起動時に実体が生成されます。
【補足】 クラス名::メンバ関数名();で呼び出すことができます。たぶん、何処かでC++の勉強の過程で見ていると思います。
あるいはシングルトンにしてしまうのも手です(こちらの方が扱いやすい)。
【補足】 クラス名::メンバ関数名();で呼び出すことができます。たぶん、何処かでC++の勉強の過程で見ていると思います。
あるいはシングルトンにしてしまうのも手です(こちらの方が扱いやすい)。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: staticで作ったメンバ関数を持つサウンドclassの扱い
初期化は普通シーンマネージャークラス(CSceneManager)の初期化のタイミングで行うとおもいます。
ロードに関しては、重すぎるためとかで使うシーンごとに分割ロードしたい場合もあるのでなんとも…。
いちばん簡単なのは初期化と同時に全ての楽曲をロードするのが一番簡単です。
あとインスタンス化が気になるのであればサウンドクラスのポインタを渡して使用するのはどうでしょうか。
この場合インスタンス化とロードは一回で、
そのインスタンスを使いまわしています。
便利ですねポインタ渡し。
あと、これが不細工だと思うなら、
デザインパターンのシングルトンを使ってみてはいかがでしょうか?
デザインパターン編 第9章 Singletonパターン
http://www.geocities.jp/ky_webid/design ... n/009.html
ロードに関しては、重すぎるためとかで使うシーンごとに分割ロードしたい場合もあるのでなんとも…。
いちばん簡単なのは初期化と同時に全ての楽曲をロードするのが一番簡単です。
あとインスタンス化が気になるのであればサウンドクラスのポインタを渡して使用するのはどうでしょうか。
// CSceneManager.h
public CSceneManager
{
public:
Init();
static CSoundManager* GetSound(){ return m_pSound; };
private:
static CSoundManager* m_pSound;
}
// CSceneManager.cpp
CSoundManager* CSceneManager::m_pSound = NULL;
void CSceneManager::Init()
{
// ここでしかnewしないよ!
m_pSound = new CSoundManager();
m_pSound->LoadSound();
}
// 自クラス
void CHoge::Update()
{
CSoundManager* pSound = CSceneManager::GetSound();
pSound->Play(// 鳴らしたい曲);
}
そのインスタンスを使いまわしています。
便利ですねポインタ渡し。
あと、これが不細工だと思うなら、
デザインパターンのシングルトンを使ってみてはいかがでしょうか?
デザインパターン編 第9章 Singletonパターン
http://www.geocities.jp/ky_webid/design ... n/009.html
Re: staticで作ったメンバ関数を持つサウンドclassの扱い
解答をありがとうございます。お二人様の意見をもとに
デザインパターンのSingletonを使って、サウンドクラスを自クラスでインスタンス化したものを
各クラスで呼び出す形にしようと思います。
ですが、ビルド後、タイトル画面が実行される時にエラーが出てしまいます。
エラーはTitle.cppでサウンドクラスの再生関数を記述すると起こり、コメントアウトすると
ちゃんとゲームは表示されますのでSingletonのミスでは無く、
サウンドクラスをうまく扱えてないと思われます。。。。
ソースを記述しますので、おかしい場所を教えて頂けないでしょうか?
また本末転倒ですが、例外処理の「ファイナル読込エラー」まで表示されますので
ファイル自体が読み込まれてない??感じです(ファイル名やパスは確実にあってるんですが)。
サウンドクラスのコンストラクタ内に記述したthis->loadFiles();が実行されてないのでしょうか、、
どうかご教示をお願いいたします。
<SoundBox.h>
<SoundBox.cpp>
<Title.cpp>のDraw関数のところ
デザインパターンのSingletonを使って、サウンドクラスを自クラスでインスタンス化したものを
各クラスで呼び出す形にしようと思います。
ですが、ビルド後、タイトル画面が実行される時にエラーが出てしまいます。
エラーはTitle.cppでサウンドクラスの再生関数を記述すると起こり、コメントアウトすると
ちゃんとゲームは表示されますのでSingletonのミスでは無く、
サウンドクラスをうまく扱えてないと思われます。。。。
ソースを記述しますので、おかしい場所を教えて頂けないでしょうか?
また本末転倒ですが、例外処理の「ファイナル読込エラー」まで表示されますので
ファイル自体が読み込まれてない??感じです(ファイル名やパスは確実にあってるんですが)。
サウンドクラスのコンストラクタ内に記述したthis->loadFiles();が実行されてないのでしょうか、、
どうかご教示をお願いいたします。
<SoundBox.h>
#pragma once
#include "DxLib.h"
#include <vector>
using namespace std;
class SoundBox
{
public:
static SoundBox* getSoundIns();
static vector<int> sounds;
static int bgm;
static void loadFiles() throw(int); //読込
static int set(int shandle); //登録
static void play(int snum); //再生
static void stop(int snum); //停止
static void playbgm(int snum); //BGMの再生
private:
SoundBox(void);
~SoundBox(void);
static SoundBox* instance;
};
#include "SoundBox.h"
SoundBox::SoundBox(void)
{
this->loadFiles();
}
SoundBox::~SoundBox(void)
{
}
//シングルトンのためのゲッター
SoundBox* SoundBox::getSoundIns()
{
if(instance==0)
{
instance = new SoundBox();
}
return instance;
}
SoundBox* SoundBox::instance = new SoundBox();
//サウンド関連クラスのメンバ関数の記述
//SoundBoxクラスメンバ変数の実体
vector<int> SoundBox::sounds;
int SoundBox::bgm = -1;
//●サウンドハンドルの登録(登録インデックスを返す)
int SoundBox::set(int shandle){
sounds.push_back(shandle); //曲リストの末尾に追加
return( sounds.size()-1);
}
//●サウンドの再生
void SoundBox::play(int snum){
PlaySoundMem(sounds.at(snum) , DX_PLAYTYPE_BACK);
}
//●サウンドの停止
void SoundBox::stop(int snum){
StopSoundMem(sounds.at(snum));
}
//●BGMの再生(現在のBGMは停止)
void SoundBox::playbgm(int snum){
int newbgm = sounds.at(snum); //ローカル変数宣言 sounds(←vector)の番号
if(bgm == newbgm)return; //今かかっているBGMと同じなら何もしない
StopSoundMem(bgm); //再生中のBGM(番号)を停止
bgm = newbgm;
PlaySoundMem(bgm , DX_PLAYTYPE_LOOP); //ループ再生する
}
//●サウンドファイルの読み込み
void SoundBox::loadFiles()throw(int){
int sh;
try{//例外処理の設定
//ファイルが読めなければ-1を返し、外部エラー。そうで無ければ、soundBoxに格納
if( (sh=LoadSoundMem("sound/bgm01.wav")) == -1)throw(-5); //0
SoundBox::set(sh);//set関数にてvectorにぶちこむ
}
catch(int errcode){
MessageBox(NULL,"ファイナル読込エラー","メッセージ",MB_OK);
return;
}
}//ファイルの読込
//描画
void Title::Draw(){
SoundBox::getSoundIns()->playbgm(0);//←ここでサウンドクラスの呼出ししてます
BaseScene::Draw();//親クラスの描画メソッドを呼んでます
DrawString(0,20,"タイトル画面",GetColor(255,255,255));
DrawString(0,40,"Sキーで選択先変更、Xキーで決定",GetColor(255,255,255));
//カーソルの描画
if(cursor % 2 == 0){
DrawGraph(190,260,cursorgh,TRUE);//カーソルを上に
}else{
DrawGraph(190,280,cursorgh,TRUE);}//カーソルを下に
}
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 14年前
- 住所: 東海地方
- 連絡を取る:
Re: staticで作ったメンバ関数を持つサウンドclassの扱い
気になること。
・インデントが乱れている。
・Drawでplaybgm
・SoundBox::getSoundIns()ではなくSoundBox::getInstance()の方が素直でしょう。
・throw(-5)はエラーをちゃんと定義しましょう。
エラーの原因
・Dxlib_Init()前にインスタンスが生成されて、loadFiles()されているのが原因です。
明示的にインスタンス生成して初期化したほうが良いです。
その他
・staticじゃなくても良い物。
vector<int> SoundBox::sounds;
int SoundBox::bgm = -1;
とかはstaticじゃ無くても良いでしょう。
・インデントが乱れている。
・Drawでplaybgm
・SoundBox::getSoundIns()ではなくSoundBox::getInstance()の方が素直でしょう。
・throw(-5)はエラーをちゃんと定義しましょう。
エラーの原因
・Dxlib_Init()前にインスタンスが生成されて、loadFiles()されているのが原因です。
明示的にインスタンス生成して初期化したほうが良いです。
その他
・staticじゃなくても良い物。
vector<int> SoundBox::sounds;
int SoundBox::bgm = -1;
とかはstaticじゃ無くても良いでしょう。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: staticで作ったメンバ関数を持つサウンドclassの扱い
返答をありがとうございます。
>・Drawでplaybgm
Title::Update()内に移しました。
>・SoundBox::getSoundIns()ではなくSoundBox::getInstance()の方が素直でしょう。
そうですね、修正しました。
>・throw(-5)はエラーをちゃんと定義しましょう。
>・Dxlib_Init()前にインスタンスが生成されて、loadFiles()されているのが原因です。
明示的にインスタンス生成して初期化したほうが良いです。
すみません、この二点の意味がまだよくわかりません。
もう少し具体的に教えていただけないでしょうか?
エラーの定義というのは(-5)を受け取った場合のものですか??
参考にしてる例外処理のソースには
catch(int errcode){
MessageBox(NULL,"ファイナル読込エラー","メッセージ",MB_OK);
return;
しかありません。。。エラーが出た時(すなわちファイル読み取りできない場合)エラーメッセージの窓も出ますし。。
それと、自分としてはmain.cppのDxlib_Init()よりも前にloadFiles()しているつもりが無いのです、、
>・staticじゃなくても良い物。
vector<int> SoundBox::sounds;
int SoundBox::bgm = -1;
これらをstaticじゃ無くならすと、SoundBox.cpp内の関数で
bgmやlistのsoundsが「静的でないメンバは~」のエラーとなり赤字になります。。。
初心者ゆえに、お門違いな返信となっていましたら申し訳ございません。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 14年前
- 住所: 東海地方
- 連絡を取る:
Re: staticで作ったメンバ関数を持つサウンドclassの扱い
-5だと意味不明なのでconst intとかenumで定義してくださいって事です。throw(-5)はエラーをちゃんと定義しましょう。
Dxlib_Init()実行前にLoadSoundMem()は出来ないか、出来てもDxlib_Init()実行時にハンドルが全て消されて無効になります。Dxlib_Init()前にインスタンスが生成されて、loadFiles()されているのが原因です。
なので順番的に初期化はDxlib_Init()の後でなくてはいけません。つまり、グローバルなインスタンス生成と同時に初期化してはいけないことになります。
リンク先の例に有りましたが、静的ローカル変数を使う方法でインスタンス生成すればタイミングを制御することはできますよね?
シングルトンパターンの場合は、static なのはGetInstance()と static Singleton* msInstance;だけで良いです。これらをstaticじゃ無くならすと、SoundBox.cpp内の関数で
bgmやlistのsoundsが「静的でないメンバは~」のエラーとなり赤字になります。。。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: staticで作ったメンバ関数を持つサウンドclassの扱い
エラーの原因
>・Dxlib_Init()前にインスタンスが生成されて、loadFiles()されているのが原因です。
>明示的にインスタンス生成して初期化したほうが良いです。
この意味が理解でき、自己解決致しました。
場所的にちょっと不細工な気がするんですがどうですか?
もっと適材適所な場所ありますでしょうか?
↓
>・Dxlib_Init()前にインスタンスが生成されて、loadFiles()されているのが原因です。
>明示的にインスタンス生成して初期化したほうが良いです。
この意味が理解でき、自己解決致しました。
場所的にちょっと不細工な気がするんですがどうですか?
もっと適材適所な場所ありますでしょうか?
↓
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
ChangeWindowMode(TRUE); //ウィンドウモードにする
SetGraphMode(512,480,8); //ウィンドウサイズ変更 DxLib_Init()の前に打つ
if(DxLib_Init() == -1) return -1; //DXライブラリ初期化
SetDrawScreen(DX_SCREEN_BACK);
SoundBox::getInstance()->loadFiles(); ←ここにこじいれ、実行させましたら、サウンドを読込し、エラー無しになりました。
while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0&& CheckHitKey(KEY_INPUT_ESCAPE)==0 ){//画面更新 & メッセージ処理 & 画面消去
Update******
Draw********
}
DxLib_End(); // DXライブラリ終了処理
return 0;
}
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 14年前
- 住所: 東海地方
- 連絡を取る:
Re: staticで作ったメンバ関数を持つサウンドclassの扱い
そこに他の初期化も並ぶのなら違和感はないと思います。
loadFiles()なのかInitalize()なのかは他のクラスとの統一性で決めてください。
loadFiles()なのかInitalize()なのかは他のクラスとの統一性で決めてください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。