ファイル分割での変数共有

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

ファイル分割での変数共有

#1

投稿記事 by オーヤルガー » 12年前

こんばんは。
今までは一つのファイルにソースコードを全て書いていたのですが,
今回は初めてファイル分割を利用したプログラミングに挑戦しています。
製作しているものはDxLibを用いたシューティングゲームです。

コード:


#include "DxLib.h"
#include "Player.h"
#include "Enemy.h"
#include "Keyboard.h"


extern int Key[256];

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
        ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen( DX_SCREEN_BACK ); 

			PlayerInit();
			EnemyInit();

        while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 && gpUpdateKey()==0 && Key[KEY_INPUT_ESCAPE]==0){

			PlayerUpdate();
			PlayerDraw();

			EnemyUpdate();
			EnemyDraw();

        }
        
        DxLib_End(); 
        return 0;
}  

今,このmain関数の中に自機のショットと敵の当たり判定を行う関数を追加したいと考えています。


bool HitJudge(int enemy_x, int enemy_y, int enemy_size, int shot_x,int shot_y, int shot_size)

ですが敵に関する変数や構造体等は別ファイル(Enemy.cpp)で定義されており、
自機のショットに関する情報はPlayer.cppの中でしか定義されていません。

なのでmain関数でenemy_xなどを引数とする場合,仮引数をmain関数にextern宣言しなければならないと思います。

しかし、プログラムを複雑にしないためにmain関数でのextern宣言はできるだけしたくない状況です。

このような場合は、どう処理するべきでしょうか。
他に方法はありますでしょうか。
宜しくお願いします。

beatle
記事: 1281
登録日時: 12年前
住所: 埼玉
連絡を取る:

Re: ファイル分割での変数共有

#2

投稿記事 by beatle » 12年前

複数ファイルでのグローバル変数の共有は、基本的にヘッダファイルにすべてのextern宣言を書き、どれか1つのcppファイル(cファイル)に実体を定義します。

・・・なのですが、オーヤルガーさんの書き込みに1つ疑問点があります。
どうしてenemy_xをHitJudge関数の引数にしているのでしょうか?
enemy_xはexternするかどうか悩むくらいなのでグローバル変数なのだと思いますが、もしそうならHitJudge関数にenemy_xを渡す必要はありませんよね。
グローバル変数なのですからHitJudge関数は引数として与えられなくとも、enemy_xを利用することができます。

よく言われる話ですがグローバル変数はなるべく使わない方が良いということになっています。
もちろんグローバル変数をどうやってextern宣言するかとか、技術としては身につけないといけませんが、実際にはなるべく使わないという姿勢が必要かなと思います。

オーヤルガー

Re: ファイル分割での変数共有

#3

投稿記事 by オーヤルガー » 12年前

回答ありがとうございます。

自分自身、まだexternについてよく理解できていないようです。

つまりは、他のファイルから変数を共有する場合は、
その変数はグローバル変数になってしまうという認識で合っていますか?

また、この当たり判定処理関数を実装する場合は、
グローバル変数を一つも使わないでmain関数に書くことは不可能ですか?

グローバル変数が一つもないプログラムが書きたいです。

nil
記事: 428
登録日時: 12年前

Re: ファイル分割での変数共有

#4

投稿記事 by nil » 12年前

大抵の場合
enemy_xを返すだけの関数EnemyGetXなんかを定義します。

beatle
記事: 1281
登録日時: 12年前
住所: 埼玉
連絡を取る:

Re: ファイル分割での変数共有

#5

投稿記事 by beatle » 12年前

関数の外に(staticを付けず)変数を定義したら、他のソースコードやヘッダファイルでextern宣言しようがしまいが、グローバル変数になります。

コード:

// hoge.cpp
int hoge;
変数hogeは他の場所でextern宣言されようがされまいが、グローバル変数です。
グローバル変数を他の場所からも参照したいというときにextern宣言します。

コード:

// foo.cpp
extern int hoge;
extern int hoge;の意味は「このソースファイル(foo.cpp)ではhogeの実体は定義しないけれども、どこかにあるhogeを利用します」ということです。
オーヤルガー さんが書きました: つまりは、他のファイルから変数を共有する場合は、
その変数はグローバル変数になってしまうという認識で合っていますか?
グローバル領域に実体を定義するからグローバル変数になります。他のファイルから共有しようがしまいが。

また、変数を共有するためにその変数をグローバル変数にする必要はありません。
グローバル変数にせずに共有するためには、グローバル領域(関数の外側)でstaticをつけて変数を定義し、ファイル内専用の静的変数にした上で、SetHoge(), GetHoge()などの関数を作るというやり方や、
malloc()などでヒープ領域に変数を確保してそのポインタを共有するやり方などがあります。

main関数の中でローカル変数を作り、その変数を必要とする関数全てに引数として渡す、という手法もありますね。

アバター
Dixq (管理人)
管理人
記事: 1661
登録日時: 13年前
住所: 北海道札幌市
連絡を取る:

Re: ファイル分割での変数共有

#6

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

サンプルでこんなの作ってみました。
プロジェクト一式はこちら
http://dixq.net/code/SampleEnemyManager.zip

サンプルでは
EnemyはEnemyManagerが所持し、管理しています。
EnemyManagerの関数はmain.cppからコールしています。
敵の情報はEnemyManagerが知っていますから、敵の情報を知りたい時はEnemyManagerに問い合わせるという造りです。

こうすればグローバル変数無しに他のモジュールから変数の取得が可能かと思います。
main.cppのtest関数をご覧下さい。
main.cppで特定の敵の座標を表示していますが、グローバル変数は使っていませんので安全です。
参考程度にどうぞ

main.cpp

コード:

#include "DxLib.h"
#include "EnemyManager.h"

void test(){
	int index = EnemyManager_GetEnemyNum()-1;
	const Enemy_t* Enemy = EnemyManager_GetEnemy(index);//No.最大値-1の敵を取得
	DrawFormatString(0,0,GetColor(0,255,255),"Enemy[%d]->y=%.1f", index, Enemy->y);
}

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
	ChangeWindowMode(TRUE),DxLib_Init(),SetDrawScreen( DX_SCREEN_BACK );

	EnemyManager_Initialize();

	while(!ScreenFlip()&&!ProcessMessage()&&!ClearDrawScreen()&&!CheckHitKey(KEY_INPUT_ESCAPE)){
		EnemyManager_Update();
		EnemyManager_Draw();

		test();
	}

	DxLib_End();
	return 0;
}
EnemyManager.h

コード:

#pragma once

#include "Enemy.h"

// 初期化する
void EnemyManager_Initialize();

// 更新する
void EnemyManager_Update();

// 描画する
void EnemyManager_Draw();

// 敵の数を取得する
int EnemyManager_GetEnemyNum();

// i番目の敵を取得する
const Enemy_t* EnemyManager_GetEnemy(int index);
EnemyManager.cpp

コード:

#include "EnemyManager.h"

static const int ENEMY_NUM = 10;
static Enemy_t mEnemyList[ENEMY_NUM];

// 初期化する
void EnemyManager_Initialize(){
	for(int i=0; i<ENEMY_NUM; i++){
		Enemy_Initialize(&mEnemyList[i]);
	}
}

// 更新する
void EnemyManager_Update(){
	for(int i=0; i<ENEMY_NUM; i++){
		Enemy_Update(&mEnemyList[i]);
	}
}

// 描画する
void EnemyManager_Draw(){
	for(int i=0; i<ENEMY_NUM; i++){
		Enemy_Draw((const Enemy_t *)&mEnemyList[i]);
	}
}

// 敵の数を取得する
int EnemyManager_GetEnemyNum(){
	return ENEMY_NUM;
}

// i番目の敵を取得する
const Enemy_t* EnemyManager_GetEnemy(int index){
	return (const Enemy_t *)&mEnemyList[index];
}
Enemy.h

コード:

#pragma once

struct Enemy_t {
	float x, y;
	float speed;
};

// 初期化する
void Enemy_Initialize( Enemy_t *Enemy );

// 更新する
void Enemy_Update( Enemy_t *Enemy );

// 描画する
void Enemy_Draw( const Enemy_t *Enemy );
Enemy.cpp

コード:

#include "Enemy.h"
#include <DxLib.h>

//初期化する
void Enemy_Initialize( Enemy_t *Enemy ){
	Enemy->x	 = (float)GetRand(640);//試しに適当にバラバラの位置にする
	Enemy->y	 = 0;
	Enemy->speed = 0.5f+GetRand(1000)/500.f;//0.5~2.5の乱数を格納
}

//更新する
void Enemy_Update( Enemy_t *Enemy ){
	Enemy->y += Enemy->speed;//下へ参ります
}

// 描画する
void Enemy_Draw( const Enemy_t *Enemy ){
	DrawCircle((int)Enemy->x, (int)Enemy->y, 10, GetColor(255,255,255), TRUE);
}

オーヤルガー

Re: ファイル分割での変数共有

#7

投稿記事 by オーヤルガー » 12年前

皆様、回答ありがとうございました。
理解できました。

Get_Enemy_xやGet_Enemy_Numというような関数をつくればできますね。
ありがとうございます。

閉鎖

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