ページ 11

モジュール間の構造体の受け渡し

Posted: 2012年6月16日(土) 03:07
by きょーこあん
初めまして、早速ですが質問させてもらいます。
現在龍神録プログラミングの館を一通り終えて、
新・ゲームプログラミングの館のゲームプログラミング設計に沿って内容を1章からやっているのですが、
8章キーコンフィングに対応させようでモジュール間の構造体データを渡す方法がわからずに困っています。
具体的には

コード:

#include "../../../include/Dxlib.h"
#include "../include/define.h"
#include "../include/struct.h"

unsigned int stateKey[256];

configpad_t configpad;

------途中省略-------

int CheckStatePad(unsigned int Handle){
        if(0<=Handle && Handle<PAD_MAX){
                return pad.key[Handle];
        }
        else{
                printfDx("CheckStatePadに渡した値が不正です\n");
                return -1;
        }
}
key.cppで定義したconfigpadを

コード:

#include "../../../include/Dxlib.h"
#include "../include/struct.h"
#include "../include/define.h"
#include "../include/key.h"

-------途中省略---------
void calc_ch(){
        ch.cnt++;
        ch.img=(ch.cnt%24)/6;
		if(CheckStatePad(configpad.left)>0)//左が押されていたら
                ch.x-=3;//座標を左に
        if(CheckStatePad(configpad.right)>0)//右が押されていたら
                ch.x+=3;//座標を右に
}
------以下省略--------
ch.cppのcalc_ch内CheckStatePadに渡してやりたいです。

http://dixq.net/g/d_05.html
ここを見てポインタで渡してやらないといけないというのはわかるのですが、
メインからcalc.cpp内calc_mainを呼び出してcalc_mainからcalc_chを呼び出す構造にしているので、
メインにconfigpad_t configpad;を定義してポインタでchとKeyに渡すのかな?と考え、
上記のポインタ記述を参考に

コード:

#include "../../../include/Dxlib.h"
#include "../include/key.h"
#include "../include/load.h"
#include "../include/graph.h"
#include "../include/ini.h"
#include "../include/calc.h"
#include "../include/struct.h"

configpad_t configpad;
---途中省略----
calc_main(&configpad);
---以下省略----
とメイン関数を変更し、

コード:

#include "../../../include/Dxlib.h"
#include "../include/char.h"

void calc_main(configpad_t *configpad){
	calc_ch(&configpad);
}
calc.cppを変更してみましたが、ポインタがうまく渡せて無いようで
error C2660: 'calc_main' : 関数に 1 個の引数を指定できません。
とエラーコードが出て私の知識では完全に手詰まり状態です・・・
どうかアドバイスのほうをお願いしますm(_ _)m

知識はC言語の入門書を学習し終えたレベル。
ポインタに関しては配列までしか扱ったことがなく、構造体がどう扱われるのか理解してないです。
環境は OS:Windows7 HomePremium 32bit
      コンパイラ:VC++2008 EE です。

Re: モジュール間の構造体の受け渡し

Posted: 2012年6月16日(土) 06:09
by h2so5
calc_chの定義に引数がないので構造体のアドレスが渡せません。
calc_mainと同じように定義すれば良いです。

コード:

void calc_ch(configpad_t *configpad){
        ch.cnt++;
        ch.img=(ch.cnt%24)/6;
        if(CheckStatePad(configpad->left)>0)//左が押されていたら
                ch.x-=3;//座標を左に
        if(CheckStatePad(configpad->right)>0)//右が押されていたら
                ch.x+=3;//座標を右に
}

Re: モジュール間の構造体の受け渡し

Posted: 2012年6月16日(土) 06:36
by tamaneko
ポインタは難しいですよね。僕はC言語の超入門書すら挫折したレベルで
ポインタはほとんど解らないですが、僕がポインタを使った場合の
コードにしてみました。確実に動かないと思いますが。

ch.cppの
void calc_ch(){ // 関数に引数がないので関数に何も渡せない
.....
}

void calc_ch(configpad_t& configpad){ // configpad_tのポインタを渡すように変更
.....
}
に修正

calc_main(&configpad); // 関数の引数で何を渡したいか解りますが、肝心の型部分が抜けている

calc_main(configpad_t& configpad); // 抜けていた型を入れた
に修正

コード:

void calc_main(configpad_t *configpad){ // 関数の引数の型は&なのに*ではエラーになる
    calc_ch(&configpad);	// &でアドレスを取得したらポインタのポインタになる
} 

コード:

 
void calc_main(configpad_t& configpad){ // &に変更
    calc_ch(configpad);	 // configpadがすでにポインタだからconfigpadをそのまま使う
} 
に修正

あと
void calc_ch(configpad_t& configpad);
をどこかに追加

Re: モジュール間の構造体の受け渡し

Posted: 2012年6月16日(土) 16:17
by きょーこあん
>>h2so5さん
返答ありがとうございます。
引数の記述漏れがある状態で質問してしまうとは・・・OTL
calc_chのほうでの引数を変更したところC2660は消えましたが、
configpad_t が定義されて無いとcalc.cppからエラーが出て、
struct.hをincludeしてみましたが、
構造体configpad_t * とconfigpad_t **は関連がありませんと出ました。

>>tamanekoさん
返答ありがとうございます。
なるほど、ポインタとして呼び出してるからもう一度ポインタとするとエラーが出るんですね。
(上記のエラー文からして2重にポインタが定義されている?)
教えて頂いた記述の方法で動作しましたのでコードを貼っておきます。
main.cpp

コード:

#include "../../../include/Dxlib.h"
#include "../include/key.h"
#include "../include/load.h"
#include "../include/graph.h"
#include "../include/ini.h"
#include "../include/calc.h"
#include "../include/struct.h"

int state;
configpad_t configpad;
//ループで必ず行う3大処理
int ProcessLoop(){
        if(ProcessMessage()!=0)return -1;//プロセス処理がエラーなら-1を返す
        if(ClearDrawScreen()!=0)return -1;//画面クリア処理がエラーなら-1を返す
        GetHitKeyStateAll_2();//現在のキー入力処理を行う
		GetHitPadStateAll(&configpad);  //現在のパッド入力処理を行う
        return 0;
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){
    ChangeWindowMode(TRUE);//ウィンドウモード
    if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化

    while(ProcessLoop()==0){//メインループ
		switch(state){
			case 0:
				load();//データロード
				first_ini(configpad);
				state=100;
				break;
			case 100:
				calc_main(configpad);
				graph_main();//描画
				break;
			default:
				printfDx("不明なstate\n");
				break;
		}

        if(CheckStateKey(KEY_INPUT_ESCAPE)==1)break;//エスケープが入力されたらブレイク
        ScreenFlip();//裏画面反映
    }

    DxLib_End();//DXライブラリ終了処理
    return 0;
}
calc.cpp

コード:

#include "../../../include/Dxlib.h"
#include "../include/char.h"

void calc_main(configpad_t& configpad){
	calc_ch(configpad);
}
ch.cpp

コード:

#include "../../../include/Dxlib.h"
#include "../include/define.h"
#include "../include/key.h"

ch_t ch;

int img_ch[2][12];

void load_ch(){
        LoadDivGraph( "../dat/img/char/0.png" , 12 , 4 , 3 , 73 , 73 , img_ch[0] ) ;
}
void calc_ch(configpad_t& configpad){
        ch.cnt++;
        ch.img=(ch.cnt%24)/6;
		if(CheckStatePad(configpad.left)>0)//左が押されていたら
                ch.x-=3;//座標を左に
		if(CheckStatePad(configpad.right)>0)//右が押されていたら
                ch.x+=3;//座標を右に
}
void graph_ch(){
        DrawRotaGraphF(ch.x+FIELD_X,ch.y+FIELD_Y,1.0f,0.0f,img_ch[0][ch.img],TRUE);
}
void ini_ch(){
	ch.x=FIELD_MAX_X/2;
        ch.y=FIELD_MAX_Y*3/4;
}
一応このコードでおかしな点などが指摘されなければ解決にしたいと思います。
ただ個人的にはせっかくCheckStatePadでKeyの内容を呼び出しているので、
そのまま構造体configpadの内容を必要に応じて渡せたらいいのに・・・と思いました。
key内に

コード:

int CheckLeft(){
        if(CheckStatepad(configpad.left >0)) return 1;
        else return 0;
}
こんな感じで上下左右設けてcalc_ch内でCheckStatepadの代わりに呼んであげればいいのかな?
(思いついたなら試せよと突っ込まれそうですが用事で外出するため試す時間が・・・w)
また進展があったら解決扱いにするか含めて報告させて頂きます。

Re: モジュール間の構造体の受け渡し

Posted: 2012年6月16日(土) 22:27
by h2so5
きょーこあん さんが書きました:>>h2so5さん
返答ありがとうございます。
引数の記述漏れがある状態で質問してしまうとは・・・OTL
calc_chのほうでの引数を変更したところC2660は消えましたが、
configpad_t が定義されて無いとcalc.cppからエラーが出て、
struct.hをincludeしてみましたが、
構造体configpad_t * とconfigpad_t **は関連がありませんと出ました。
僕の方法でも、calc_ch(&configpad); を calc_ch(configpad); に変えれば動くと思います。
説明不足で申し訳ありません。

本題です。
tamanekoさんの方法でも問題はないのですが、tamanekoさんが使っているのはポインタではありません。
これは参照といってC言語ではなくC++の機能です。&演算子を使うところなど表記はポインタと似ていますが、別の機能ですのでご注意ください。
詳しくは「C++ 参照」で検索するなどして調べてみてください。

また、修正点として今回の場合は参照先の変数の内容を変更しないので

コード:

void calc_main(configpad_t& configpad)
void calc_ch(configpad_t& configpad)

コード:

void calc_main(const configpad_t& configpad)
void calc_ch(const configpad_t& configpad)
に変えるのがベターです。

Re: モジュール間の構造体の受け渡し

Posted: 2012年6月17日(日) 06:53
by きょーこあん
>>h2so5さん
再び返答ありがとうございます。
h2so5 さんが書きました: 僕の方法でも、calc_ch(&configpad); を calc_ch(configpad); に変えれば動くと思います。
説明不足で申し訳ありません。
どちらかというとtamanekoさんの返答でポインタを2重に定義してると気づきながら、
それを踏まえてh2so5さんの方法も試さなかった私の手落ちですね・・・すみません。

本題の方、確認してきました。
なるほど、参照のほうがその場に在るのと同じ扱いになるのでポインタより分かり易いですね。
ただここで参照に逃げるとこのままズルズルとポインタの理解がアヤフヤなままになりそうなので、
今回はポインタでやっていこうと思い、元々の記述に近いh2so5さんの方に戻して修正しました。
またcalc_mainに関しては数値を変更しないのでポインタの必要は無いということでmainの&を外しました。

constに関してもとても参考になりました。
ただ今回は&を外してポインタでなくなったのでconstを定義しなくてもいい気がします。
(&を外したことでアドレスではなく値になったので変更ができないと思ったため)
間違ってたらご指摘お願いしますm(_ _)m

今回でモジュール間のポインタによる構造体の受け渡しは問題なく成立したので解決にします。
回答を下さった方々本当にありがとうございました!

(コードに関しては前回とほとんど変わらず前回と文章で推測できると思ったので記述しませんでした。)