分割コンパイルの際の二重定義について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
dast
記事: 41
登録日時: 13年前

分割コンパイルの際の二重定義について

#1

投稿記事 by dast » 13年前

ブロック崩しを作っていたのですが、ソースが長くなってきたので分割しようと思い、次のように分割したら何故かint.hの変数が二重定義されている扱いになってしまいました。

main.cpp

コード:

#include "solution/header/GV.h"
#include "solution\header\struct.h"
#include "solution\header\define.h"
#include "solution\header\int.h"
#include <math.h>


extern int GetHitKeyStateAll_2(int GetHitKeyStateAll_InputKey[]);

double xzahyou,yzahyou;


TamaPara_t TP;

ZikiPara_t ZP;


typedef struct{
	int x,y,maxx,minx,maxy,miny,stage,maxhp,hp,canbreak,enemy,flag;
	//中心のx,y座標,右端のx座標,左端のx座標,下のy座標,上のy座標,登場ステージ,最大HP,HP,倒せるかどうか,敵かどうか,存在フラグ
}BlockDeta_t;
BlockDeta_t BD[Block_Order_Max]={
	/*中心のx,y座標,右端,左端,下端,上端,登場面,最大HP,HP,倒せるか,ノルマ,存在フラグ*/
	 {    273,  233, 259, 232, 247, 220,     1,     1, 1,       1,     1,         1},
	 {    245,  233, 259, 232, 247, 220,     1,     1, 1,       1,     1,         1},
	 {    217,  233, 229, 204, 247, 220,     1,     1, 1,       1,     1,         1}
};
typedef struct{
	int x,y,maxx,minx,maxy,miny,stage,maxhp,hp,canbreak,enemy,flag;
	//中心のx,y座標,右端のx座標,左端のx座標,下のy座標,上のy座標,登場ステージ,最大HP,HP,倒せるかどうか,敵かどうか,存在フラグ
}BlockOrder_t;
BlockOrder_t BO[Block_Order_Max]={
	/*中心のx,y座標,右端,左端,下端,上端,登場面,最大HP,HP,倒せるか,ノルマ,存在フラグ*/
	 {    273,  233, 259, 232, 247, 220,     1,     1, 1,       1,     1,         1},
	 {    245,  233, 259, 232, 247, 220,     1,     1, 1,       1,     1,         1},
	 {    217,  233, 229, 204, 247, 220,     1,     1, 1,       1,     1,         1}
};

void ZikiOut(){//ミス時の処理
	ZP.outmode=1;ZP.atmode=0;TamaStop=1;ZP.imgcnt=0;
}

void TamaMove(){//玉の動作
	if(TamaStop==0){
		TP.x+=(int)(TP.sp*cos(TP.ang*PI));
		TP.y+=(int)(TP.sp*sin(TP.ang*PI));
	}
}

void GamenTamaAtariJudge(){//画面端と玉の当たり判定の衝突判定及び処理
	if(TP.y<=min_y+TP.at){//画面上
		TP.y=min_y+TP.at;
		TP.ang=2.000-TP.ang;
	}
	if(TP.y>=max_y-TP.at){//画面下
		if(ZP.outmode==0){
			ZikiOut();
		}
		/*TP.y=max_y-TP.at;
		TP.ang=2.000-TP.ang;*/
	}
	if(TP.x<=min_x+TP.at){//画面左
		TP.x=min_x+TP.at;
		TP.ang=3.000-TP.ang;
	}
	if(TP.x>=max_x-TP.at){//画面右
		TP.x=max_x-TP.at;
		TP.ang=3.000-TP.ang;
	}
}

int ZikiTamaHazikiJudge(){//自機のはじき判定と玉の当たり判定の衝突判定
	int i;
	double x,y,r;
	if(ZP.img==12||ZP.img==13||ZP.img==14||ZP.img==15){//その場攻撃
		x=(double)(ZP.x)-(double)(TP.x);//(自機の攻撃判定の中心のx座標)-玉のx座標
		y=(double)(ZP.y)-(double)(TP.y);//(自機の攻撃判定の中心のy座標)-玉のx座標
		r=(ZP.haziki)+(TP.at);
	}
	if(ZP.img==16||ZP.img==17||ZP.img==18||ZP.img==19){//左攻撃
		x=(double)(ZP.x-9)-(double)(TP.x);//(自機の攻撃判定の中心のx座標)-玉のx座標
		y=(double)(ZP.y)-(double)(TP.y);//(自機の攻撃判定の中心のy座標)-玉のx座標
		r=(ZP.haziki)+(TP.at);
	}
	if(ZP.img==20||ZP.img==21||ZP.img==22||ZP.img==23){//右攻撃
		x=(double)(ZP.x+9)-(double)(TP.x);//(自機の攻撃判定の中心のx座標)-玉のx座標
		y=(double)(ZP.y)-(double)(TP.y);//(自機の攻撃判定の中心のy座標)-玉のx座標
		r=(ZP.haziki)+(TP.at);
	}
	
	if(sqrt(TP.sp*TP.sp)>sqrt(r*r)){//移動した距離が(ZP.haziki)+(TP.at)より長ければ
		double prey = TP.y-TP.sp*sin(TP.ang*PI);//1フレーム前の表示y座標
		double prex = TP.x-TP.sp*cos(TP.ang*PI);//1フレーム前の表示x座標
		double imay = TP.y;//現在の表示y座標
		double imax = TP.x;//現在の表示x座標
		double px,py;
		for(i=0;i<sqrt(TP.sp*TP.sp)/sqrt(TP.at);i++){//進んだ分÷当たり判定分ループ
			if(ZP.img==12||ZP.img==13||ZP.img==14||ZP.img==15){
				px=prex-ZP.x;
				py=prey-ZP.y;
			}
			if(ZP.img==16||ZP.img==17||ZP.img==18||ZP.img==19){
				px=prex-(ZP.x-9);
				py=prey-ZP.y;
			}
			if(ZP.img==20||ZP.img==21||ZP.img==22||ZP.img==23){
				px=prex-(ZP.x+9);
				py=prey-ZP.y;
			}
			if(px*px+py*py<r*r){
				TP.x=(int)prex;
				TP.y=(int)prey;
				return 1;
			}
			prex+=TP.at*cos(TP.ang*PI);
			prey+=TP.at*sin(TP.ang*PI);
		}
	}
	if(x*x+y*y<r*r){//当たり判定内なら
		return 1;//当たり
	}
	return 0;
}

int ZikiTamaAtariJudge(){//自機の当たり判定と玉の当たり判定の衝突判定(要検証)
	int i;
	/*double x,y,r;*/
	double x=(double)(ZP.x)-(double)(TP.x);//自機の当たり判定の中心のx座標-玉のx座標
	double y=(double)(ZP.y+9)-(double)(TP.y);//自機の当たり判定の中心のy座標-玉のy座標
	double r=ZP.at+TP.at;//自機の当たり判定-玉の当たり判定
	if(sqrt(TP.sp*TP.sp)>sqrt(r*r)){//玉が移動した距離が(ZP.at)+(TP.at)より長ければ
		double pretx = TP.x-TP.sp*cos(TP.ang*PI);//1フレーム前の玉の表示x座標
		double prety = TP.y-TP.sp*sin(TP.ang*PI);//1フレーム前の玉の表示y座標
		double ptx,pty;
		for(i=0;i<sqrt(TP.sp*TP.sp)/sqrt(TP.at*TP.at);i++){//玉が進んだ分÷玉の当たり判定分ループ
			ptx=pretx-ZP.x;
			pty=prety-ZP.y+9;
			if(ptx*ptx+pty*pty<r*r){
				TP.x=(int)pretx;
				TP.y=(int)prety;
				return 1;
			}
		}
	}
	if(x*x+y*y<r*r){
		return 1;
	}
	return 0;
}

void ZikiTamaAtariHazikiSyori(){//自機の当たり判定、攻撃判定と玉の当たり判定の衝突時の処理
	if(ZP.atmode>0){
		if(TP.muteki==0){
			if(ZikiTamaHazikiJudge()){
				xzahyou=TP.x-ZP.x;
				yzahyou=TP.y-(ZP.y+17);
				TP.ang=(atan2(yzahyou,xzahyou))/PI;
				TP.muteki=1;
			}
		}
	}
	if(ZP.atmode==0){
		TP.muteki=0;
	}
	if(ZP.muteki==0){
		if(ZP.outmode==0){
			if(ZikiTamaAtariJudge()){
				ZikiOut();
			}
		}
	}
}

void ZikiMove(){//自機の動作(ポーズもここ)
	ZP.img=((ZP.imgcnt)%48)/12;
	if(Key[KEY_INPUT_RETURN]==1){//ポーズ
		if(Pause==0){
			TamaStop=1;
			ZikiStop=1;
			Pause=1;
		}
		else if(Pause==1){
			TamaStop=0;
			ZikiStop=0;
			Pause=0;
		}
	}
	if(ZikiStop==0){
		if(Key[KEY_INPUT_A]<=0 && Key[ KEY_INPUT_RIGHT ] >= 1 && Key[ KEY_INPUT_LEFT ] <= 0 && ZP.atmode==0 && ZP.outmode==0){//右移動
			if(ZP.x<(max_x-ZP.at)){
				ZP.x+=(int)ZP.sp;
			}
			ZP.img+=8;
		}
		else if(Key[KEY_INPUT_A]<=0 && Key[ KEY_INPUT_RIGHT ] <= 0 && Key[ KEY_INPUT_LEFT ] >= 1 && ZP.atmode==0 && ZP.outmode==0){//左移動
			if(ZP.x>(min_x+ZP.at)){
				ZP.x-=(int)ZP.sp;
			}
			ZP.img+=4;
		}
		else if(Key[KEY_INPUT_A]==1 && Key[ KEY_INPUT_RIGHT ] >= 1 && Key[ KEY_INPUT_LEFT ] <= 0 && ZP.atmode==0 && ZP.outmode==0){//右攻撃
			ZP.atmode=3;
			ZP.imgcnt=0;
		}
		else if(Key[KEY_INPUT_A]==1 && Key[ KEY_INPUT_RIGHT ] <= 0 && Key[ KEY_INPUT_LEFT ] >= 1 && ZP.atmode==0 && ZP.outmode==0){//左攻撃
			ZP.atmode=2;
			ZP.imgcnt=0;
		}
		else if(Key[KEY_INPUT_A]==1 && Key[ KEY_INPUT_RIGHT ] <= 0 && Key[ KEY_INPUT_LEFT ] <= 0 && ZP.atmode==0 && ZP.outmode==0){//その場攻撃
			ZP.atmode=1;
			ZP.imgcnt=0;
		}
		else if(Key[KEY_INPUT_A]==1 && Key[ KEY_INPUT_RIGHT ] >= 1 && Key[ KEY_INPUT_LEFT ] >= 1 && ZP.atmode==0 && ZP.outmode==0){//その場攻撃
			ZP.atmode=1;
			ZP.imgcnt=0;
		}
		else {}
		if(ZP.atmode>=1){/*攻撃中の処理*/
			ZP.img=((ZP.imgcnt)%48)/12;/*硬直時間*/
			ZP.img+=(2+ZP.atmode)*4;/*画像処理*/
			if(ZP.atmode==2){/*左攻撃中の移動*/
				if(ZP.x>(min_x+ZP.at)){
					ZP.x-=(int)ZP.sp;
				}
			}
			if(ZP.atmode==3){/*右攻撃中の移動*/
				if(ZP.x<(max_x-ZP.at)){
					ZP.x+=(int)ZP.sp;
				}
			}
			if(ZP.imgcnt==47){
				ZP.atmode=0;
			}
		}
		if(ZP.outmode>=1){//やられモーションの処理
			ZP.img=((ZP.imgcnt)%48)/12;/*硬直時間*/
			ZP.img+=24;/*画像処理*/
			if(ZP.imgcnt==47){
				ZP.outmode=0;
				//TP.x=Start_Tama_x;
				TP.y=Start_Tama_y;
				TP.ang=Start_Tama_ang;
				TamaStop=0;
			}
		}
		ZP.imgcnt++;
	}
}

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

	int i;//ループ用
	int img_waku;
	img_waku=LoadGraph("img/waku.png");
	int img_tama;
	img_tama=LoadGraph("img/tama_ver0.10.png");
	int img_block1;
	img_block1=LoadGraph("img/block1.png");
	int img_Ziki[28];
	LoadDivGraph("img/ziki[28]_ver0.26.png",28,4,7,53,35,img_Ziki);
	TP.x=Start_Tama_x;
	TP.y=Start_Tama_y;
	TP.muteki=0;
	TP.at=Tama_Atari_Hantei;
	TP.sp=4.000;
	TP.ang=Start_Tama_ang;

	ZP.at=8.000;
	ZP.haziki=17.000;
	ZP.x=(max_x+min_x)/2;
	ZP.y=max_y-18;
	ZP.sp=4.000;
	ZP.img=0;
	ZP.imgcnt=0;
	ZP.atmode=0;
	ZP.zanki=5;
	ZP.muteki=0;
	ZP.outmode=0;

    while(ScreenFlip()==0 &&ProcessMessage()==0 && ClearDrawScreen()==0 && GetHitKeyStateAll_2(Key)==0 && Key[KEY_INPUT_ESCAPE]==0){
                          //↑メッセージ処理          ↑画面をクリア           ↑入力状態を保存       ↑ESCが押されていない


		ZikiMove();
		TamaMove();
		ZikiTamaAtariHazikiSyori();
		GamenTamaAtariJudge();

		
		
		DrawRotaGraph(ZP.x,ZP.y,1.0,0.0,img_Ziki[ZP.img],TRUE);
		for(i=0;i<Block_Order_Max;i++){
			if(BO[i].flag==1){
				DrawRotaGraph(BO[i].x,BO[i].y,1.0,0.0,img_block1,TRUE);
			}
		}
		DrawRotaGraph(TP.x,TP.y,1.0,0.0,img_tama,TRUE);
		DrawGraph(0,0,img_waku,TRUE);
		DrawFormatString(  0,0,GetColor(255,255,255),"%f",TP.sp);
		DrawFormatString(  0,20,GetColor(255,255,255),"%d %d",TP.x,TP.y);
		DrawFormatString(  0,40,GetColor(255,255,255),"%f",TP.at+ZP.at);
		DrawFormatString(  0,60,GetColor(255,255,255),"%d %d",ZP.x-TP.x,ZP.y+9-TP.y);
		DrawFormatString(  0,80,GetColor(0,0,255),"%d %d %d",BO[0].x,BO[0].y,BO[0].flag);
		
    }

    DxLib_End();
    return 0;
}
int.h

コード:

#ifndef DEF_PLAYER_H //二重include防止

#define DEF_PLAYER_H

int Key[256];
int dgx=0,dgy=0;

int TamaStop=0,ZikiStop=0;//玉停止、自機停止
int Pause=0;//ポーズスイッチ

#endif
struct.h

コード:

#include "GV.h"

typedef struct{//玉のパラメータ
	int x,y,muteki;//x座標,y座標,玉無敵スイッチ
	double at,sp,ang;//当たり判定、スピード、投射角
}TamaPara_t;

typedef struct{//自機のパラメータ
	int x,y,img,imgcnt,zanki,muteki,atmode,outmode;//座標、画像の番号,画像カウンター,残機の数,無敵時間,攻撃スイッチ,やられスイッチ
	double sp,at,haziki;//自機の動く速さ,当たり判定の大きさ,はじき判定の大きさ
}ZikiPara_t;
define.h

コード:

#define PI 3.141592//円周率
#define max_y 432//ゲーム部分下端
#define min_y 79  //ゲーム部分上端
#define max_x 512 //ゲーム部分右端
#define min_x 63  //ゲーム部分左端

#define Start_Tama_x 502//玉の初期x座標
#define Start_Tama_y 404//玉の初期y座標
#define Start_Tama_ang 1.000//玉の初期角度

#define Tama_Atari_Hantei 10.000//玉の当たり判定

#define Block_Order_Max 3//敵情報の数
Interface.cpp

コード:

#include "../header/GV.h"

//int Key[256];

int GetHitKeyStateAll_2(int GetHitKeyStateAll_InputKey[]){
    char GetHitKeyStateAll_Key[256];
    GetHitKeyStateAll( GetHitKeyStateAll_Key );
    for(int i=0;i<256;i++){
        if(GetHitKeyStateAll_Key[i]==1) GetHitKeyStateAll_InputKey[i]++;
        else                            GetHitKeyStateAll_InputKey[i]=0;
    }
    return 0;
}
GV.h

コード:

#include "DxLib.h"
エラーコードには
1>AtariJudgeSyori.obj : error LNK2005: "int * Key" (?Key@@3PAHA) は既に main.obj で定義されています。
1>AtariJudgeSyori.obj : error LNK2005: "int dgx" (?dgx@@3HA) は既に main.obj で定義されています。
                       :

という風に書かれていたので「mainで定義されているならint.hをつなげなくてもいいだろう」と考えてmain.cppの4行目をコメントアウトしたら今度は「定義されていません」と出てしまいます。これは一体どういう事なのでしょうか。

YuO
記事: 947
登録日時: 14年前
住所: 東京都世田谷区

Re: 分割コンパイルの際の二重定義について

#2

投稿記事 by YuO » 13年前

インクルードガードは,同一の翻訳単位の中でのみ有効です。
翻訳単位というのは,正確さを犠牲に簡単に説明するなら.c/cppファイルひとつのことです。

ヘッダファイル中では

コード:

extern int dgx;
のように記述し,どこか一つの翻訳単位のみで

コード:

int dgx;
と書く必要があります。
# そもそもグローバル変数とする必要があるのか検証は必要ですが。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 分割コンパイルの際の二重定義について

#3

投稿記事 by softya(ソフト屋) » 13年前

とりあえず、悪い所を説明します。
・インクルードガードは全部のヘッダに。
・インクルードガードの名前はヘッダに合わせる。
・龍神録などのgv.hは悪い例ですので使わない方向で。
・cppと対になるヘッダを作ること。
・ヘッダに書いて良いのは、構造体の宣言、enum定義、#define、関数のプロトタイプ宣言、変数のextern参照です。
変数の初期値有りを書いてはいけません。インクルードした先のcpp側で全て変数の実体定義として処理されるので多重定義となります。
dast さんが書きました:という風に書かれていたので「mainで定義されているならint.hをつなげなくてもいいだろう」と考えてmain.cppの4行目をコメントアウトしたら今度は「定義されていません」と出てしまいます。これは一体どういう事なのでしょうか。
それはmainにとっては見えない変数だからです。実体定義かextern参照のどちらかはmainから見えていないといけません。

ヘッダ・インクルードはあくまでも毎回同じ事を書かなくて良い様に別にソースコードに書いた内容を組み込んでもらうための手段です。
だからinclude(…を包含する, 含む)なのですが、動作を理解して使いましょう。
コンパイラが毎回cppにhの内容をコピペしてると思ってもらったほうが良いかも知れません。

こちらも参考に。
「新・C言語 ~ゲームプログラミングの館~ [DXライブラリ]」
http://dixq.net/g/
d.1 メイン関数の作り方
d.2 複数のファイルにわけてコンパイルする
d.3 ゲームの設計と分割コンパイル(1)
d.4 ゲームの設計と分割コンパイル(2)
d.5 ゲームの設計と分割コンパイル(3)
d.6 管理部の作り方 (似た要素のまとめ方)
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

dast
記事: 41
登録日時: 13年前

Re: 分割コンパイルの際の二重定義について

#4

投稿記事 by dast » 13年前

ひとまず次のようにまとめたら動くようになりました。
main.cpp

コード:

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

#include "solution\header\define.h"
#include "solution\header\Interface.h"
#include "solution\header\struct.h"
#include "solution\header\AtariHaziki.h"





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

	int i;//ループ用

	Load_Graph();

	StructIni();

    while(ScreenFlip()==0 &&ProcessMessage()==0 && ClearDrawScreen()==0/* && Keyboard_Update()==0*/ && Keyboard_Get(KEY_INPUT_ESCAPE)==0){
                          //↑メッセージ処理          ↑画面をクリア            ↑入力状態を保存  ↑ESCが押されていない
		Keyboard_Update();


		ZikiMove();
		TamaMove();
		ZikiTamaAtariHazikiSyori();
		GamenTamaAtariJudge();

		
		DrawAll();

		
    }

    DxLib_End();
    return 0;
}
Interface.cpp

コード:

#include "DxLib.h"

int m_Key[256];
// キーの入力状態を更新する
void Keyboard_Update(){
        char tmpKey[256]; // 現在のキーの入力状態を格納する
        GetHitKeyStateAll( tmpKey ); // 全てのキーの入力状態を得る
        for( int i=0; i<256; i++ ){ 
                if( tmpKey[i] != 0 ){ // i番のキーコードに対応するキーが押されていたら
                        m_Key[i]++;     // 加算
                } else {              // 押されていなければ
                        m_Key[i] = 0;   // 0にする
                }
        }
}
int Keyboard_Get(int Key_Code){
	return m_Key[Key_Code];//Key_Codeの入力状態を返す
}
Interface.h

コード:

#ifndef DEF_INTERFACE_H //二重include防止
#define DEF_INTERFACE_H

void Keyboard_Update();
int Keyboard_Get(int Key_Code);

#endif
AtariHaziki.cpp

コード:

#include "DxLib.h"
#include <math.h>
#include "../header/define.h"
#include "../header/struct.h"
#include "../header/Interface.h"

double xzahyou,yzahyou;//(ZikiTamaAtariHazikiSyori())

int i;
int TamaStop=0;//玉停止(ZikiOut(),TamaMove(),ZikiMove(),)
int ZikiStop=0;//自機停止(ZikiMove(),)
int Pause=0;//ポーズスイッチ(ZikiMove(),)
int img_waku;int img_tama;int img_block1;int img_Ziki[28];

TamaPara_t TP;

ZikiPara_t ZP;

BlockDeta_t BD[Block_Order_Max]={
	/*中心のx,y座標,右端,左端,下端,上端,登場面,最大HP,HP,倒せるか,ノルマ,存在フラグ*/
	 {    273,  233, 259, 232, 247, 220,     1,     1, 1,       1,     1,         1},
	 {    245,  233, 259, 232, 247, 220,     1,     1, 1,       1,     1,         1},
	 {    217,  233, 229, 204, 247, 220,     1,     1, 1,       1,     1,         1}
};

BlockOrder_t BO[Block_Order_Max]={
	/*中心のx,y座標,右端,左端,下端,上端,登場面,最大HP,HP,倒せるか,ノルマ,存在フラグ*/
	 {    273,  233, 259, 232, 247, 220,     1,     1, 1,       1,     1,         1},
	 {    245,  233, 259, 232, 247, 220,     1,     1, 1,       1,     1,         1},
	 {    217,  233, 229, 204, 247, 220,     1,     1, 1,       1,     1,         1}
};

void ZikiOut(){//ミス時の処理
	ZP.outmode=1;ZP.atmode=0;TamaStop=1;ZP.imgcnt=0;
}

void TamaMove(){//玉の動作
	if(TamaStop==0){
		TP.x+=(int)(TP.sp*cos(TP.ang*PI));
		TP.y+=(int)(TP.sp*sin(TP.ang*PI));
	}
}


void GamenTamaAtariJudge(){//画面端と玉の当たり判定の衝突判定及び処理
	if(TP.y<=min_y+TP.at){//画面上
		TP.y=min_y+TP.at;
		TP.ang=2.000-TP.ang;
	}
	if(TP.y>=max_y-TP.at){//画面下
		if(ZP.outmode==0){
			ZikiOut();
		}
		/*TP.y=max_y-TP.at;
		TP.ang=2.000-TP.ang;*/
	}
	if(TP.x<=min_x+TP.at){//画面左
		TP.x=min_x+TP.at;
		TP.ang=3.000-TP.ang;
	}
	if(TP.x>=max_x-TP.at){//画面右
		TP.x=max_x-TP.at;
		TP.ang=3.000-TP.ang;
	}
}

int ZikiTamaHazikiJudge(){//自機のはじき判定と玉の当たり判定の衝突判定
	int i;
	double x,y,r;
	if(ZP.img==12||ZP.img==13||ZP.img==14||ZP.img==15){//その場攻撃
		x=(double)(ZP.x)-(double)(TP.x);//(自機の攻撃判定の中心のx座標)-玉のx座標
		y=(double)(ZP.y)-(double)(TP.y);//(自機の攻撃判定の中心のy座標)-玉のx座標
		r=(ZP.haziki)+(TP.at);
	}
	if(ZP.img==16||ZP.img==17||ZP.img==18||ZP.img==19){//左攻撃
		x=(double)(ZP.x-9)-(double)(TP.x);//(自機の攻撃判定の中心のx座標)-玉のx座標
		y=(double)(ZP.y)-(double)(TP.y);//(自機の攻撃判定の中心のy座標)-玉のx座標
		r=(ZP.haziki)+(TP.at);
	}
	if(ZP.img==20||ZP.img==21||ZP.img==22||ZP.img==23){//右攻撃
		x=(double)(ZP.x+9)-(double)(TP.x);//(自機の攻撃判定の中心のx座標)-玉のx座標
		y=(double)(ZP.y)-(double)(TP.y);//(自機の攻撃判定の中心のy座標)-玉のx座標
		r=(ZP.haziki)+(TP.at);
	}
	
	if(sqrt(TP.sp*TP.sp)>sqrt(r*r)){//移動した距離が(ZP.haziki)+(TP.at)より長ければ
		double prey = TP.y-TP.sp*sin(TP.ang*PI);//1フレーム前の表示y座標
		double prex = TP.x-TP.sp*cos(TP.ang*PI);//1フレーム前の表示x座標
		double imay = TP.y;//現在の表示y座標
		double imax = TP.x;//現在の表示x座標
		double px,py;
		for(i=0;i<sqrt(TP.sp*TP.sp)/sqrt(TP.at);i++){//進んだ分÷当たり判定分ループ
			if(ZP.img==12||ZP.img==13||ZP.img==14||ZP.img==15){
				px=prex-ZP.x;
				py=prey-ZP.y;
			}
			if(ZP.img==16||ZP.img==17||ZP.img==18||ZP.img==19){
				px=prex-(ZP.x-9);
				py=prey-ZP.y;
			}
			if(ZP.img==20||ZP.img==21||ZP.img==22||ZP.img==23){
				px=prex-(ZP.x+9);
				py=prey-ZP.y;
			}
			if(px*px+py*py<r*r){
				TP.x=(int)prex;
				TP.y=(int)prey;
				return 1;
			}
			prex+=TP.at*cos(TP.ang*PI);
			prey+=TP.at*sin(TP.ang*PI);
		}
	}
	if(x*x+y*y<r*r){//当たり判定内なら
		return 1;//当たり
	}
	return 0;
}

int ZikiTamaAtariJudge(){//自機の当たり判定と玉の当たり判定の衝突判定(要検証)
	int i;
	/*double x,y,r;*/
	double x=(double)(ZP.x)-(double)(TP.x);//自機の当たり判定の中心のx座標-玉のx座標
	double y=(double)(ZP.y+9)-(double)(TP.y);//自機の当たり判定の中心のy座標-玉のy座標
	double r=ZP.at+TP.at;//自機の当たり判定-玉の当たり判定
	if(sqrt(TP.sp*TP.sp)>sqrt(r*r)){//玉が移動した距離が(ZP.at)+(TP.at)より長ければ
		double pretx = TP.x-TP.sp*cos(TP.ang*PI);//1フレーム前の玉の表示x座標
		double prety = TP.y-TP.sp*sin(TP.ang*PI);//1フレーム前の玉の表示y座標
		double ptx,pty;
		for(i=0;i<sqrt(TP.sp*TP.sp)/sqrt(TP.at*TP.at);i++){//玉が進んだ分÷玉の当たり判定分ループ
			ptx=pretx-ZP.x;
			pty=prety-ZP.y+9;
			if(ptx*ptx+pty*pty<r*r){
				TP.x=(int)pretx;
				TP.y=(int)prety;
				return 1;
			}
		}
	}
	if(x*x+y*y<r*r){
		return 1;
	}
	return 0;
}

void ZikiTamaAtariHazikiSyori(){//自機の当たり判定、攻撃判定と玉の当たり判定の衝突時の処理
	if(ZP.atmode>0){
		if(TP.muteki==0){
			if(ZikiTamaHazikiJudge()){
				xzahyou=TP.x-ZP.x;
				yzahyou=TP.y-(ZP.y+17);
				TP.ang=(atan2(yzahyou,xzahyou))/PI;
				TP.muteki=1;
			}
		}
	}
	if(ZP.atmode==0){
		TP.muteki=0;
	}
	if(ZP.muteki==0){
		if(ZP.outmode==0){
			if(ZikiTamaAtariJudge()){
				ZikiOut();
			}
		}
	}
}


void ZikiMove(){//自機の動作(ポーズもここ)
	ZP.img=((ZP.imgcnt)%48)/12;
	if(Keyboard_Get(KEY_INPUT_RETURN)==1){//ポーズ
		if(Pause==0){
			TamaStop=1;
			ZikiStop=1;
			Pause=1;
		}
		else if(Pause==1){
			TamaStop=0;
			ZikiStop=0;
			Pause=0;
		}
	}
	if(ZikiStop==0){
		if(Keyboard_Get(KEY_INPUT_A)<=0 && Keyboard_Get( KEY_INPUT_RIGHT ) >= 1 && Keyboard_Get( KEY_INPUT_LEFT ) <= 0 && ZP.atmode==0 && ZP.outmode==0){//右移動
			if(ZP.x<(max_x-ZP.at)){
				ZP.x+=(int)ZP.sp;
			}
			ZP.img+=8;
		}
		else if(Keyboard_Get(KEY_INPUT_A)<=0 && Keyboard_Get( KEY_INPUT_RIGHT ) <= 0 && Keyboard_Get( KEY_INPUT_LEFT ) >= 1 && ZP.atmode==0 && ZP.outmode==0){//左移動
			if(ZP.x>(min_x+ZP.at)){
				ZP.x-=(int)ZP.sp;
			}
			ZP.img+=4;
		}
		else if(Keyboard_Get(KEY_INPUT_A)==1 && Keyboard_Get( KEY_INPUT_RIGHT ) >= 1 && Keyboard_Get( KEY_INPUT_LEFT ) <= 0 && ZP.atmode==0 && ZP.outmode==0){//右攻撃
			ZP.atmode=3;
			ZP.imgcnt=0;
		}
		else if(Keyboard_Get(KEY_INPUT_A)==1 && Keyboard_Get( KEY_INPUT_RIGHT ) <= 0 && Keyboard_Get( KEY_INPUT_LEFT ) >= 1 && ZP.atmode==0 && ZP.outmode==0){//左攻撃
			ZP.atmode=2;
			ZP.imgcnt=0;
		}
		else if(Keyboard_Get(KEY_INPUT_A)==1 && Keyboard_Get( KEY_INPUT_RIGHT ) <= 0 && Keyboard_Get( KEY_INPUT_LEFT ) <= 0 && ZP.atmode==0 && ZP.outmode==0){//その場攻撃
			ZP.atmode=1;
			ZP.imgcnt=0;
		}
		else if(Keyboard_Get(KEY_INPUT_A)==1 && Keyboard_Get( KEY_INPUT_RIGHT ) >= 1 && Keyboard_Get( KEY_INPUT_LEFT ) >= 1 && ZP.atmode==0 && ZP.outmode==0){//その場攻撃
			ZP.atmode=1;
			ZP.imgcnt=0;
		}
		else {}
		if(ZP.atmode>=1){/*攻撃中の処理*/
			ZP.img=((ZP.imgcnt)%48)/12;/*硬直時間*/
			ZP.img+=(2+ZP.atmode)*4;/*画像処理*/
			if(ZP.atmode==2){/*左攻撃中の移動*/
				if(ZP.x>(min_x+ZP.at)){
					ZP.x-=(int)ZP.sp;
				}
			}
			if(ZP.atmode==3){/*右攻撃中の移動*/
				if(ZP.x<(max_x-ZP.at)){
					ZP.x+=(int)ZP.sp;
				}
			}
			if(ZP.imgcnt==47){
				ZP.atmode=0;
			}
		}
		if(ZP.outmode>=1){//やられモーションの処理
			ZP.img=((ZP.imgcnt)%48)/12;/*硬直時間*/
			ZP.img+=24;/*画像処理*/
			if(ZP.imgcnt==47){
				ZP.outmode=0;
				//TP.x=Start_Tama_x;
				TP.y=Start_Tama_y;
				TP.ang=Start_Tama_ang;
				TamaStop=0;
			}
		}
		ZP.imgcnt++;
	}
}

void StructIni(){

	TP.x=Start_Tama_x;
	TP.y=Start_Tama_y;
	TP.muteki=0;
	TP.at=Tama_Atari_Hantei;
	TP.sp=4.000;
	TP.ang=Start_Tama_ang;

	ZP.at=8.000;
	ZP.haziki=17.000;
	ZP.x=(max_x+min_x)/2;
	ZP.y=max_y-18;
	ZP.sp=4.000;
	ZP.img=0;
	ZP.imgcnt=0;
	ZP.atmode=0;
	ZP.zanki=5;
	ZP.muteki=0;
	ZP.outmode=0;
}

void Load_Graph(){
	img_waku=LoadGraph("img/waku.png");
	img_tama=LoadGraph("img/tama_ver0.10.png");
	img_block1=LoadGraph("img/block1.png");
	LoadDivGraph("img/ziki[28]_ver0.26.png",28,4,7,53,35,img_Ziki);
}

void DrawAll(){
	DrawRotaGraph(ZP.x,ZP.y,1.0,0.0,img_Ziki[ZP.img],TRUE);
	for(i=0;i<Block_Order_Max;i++){if(BO[i].flag==1){DrawRotaGraph(BO[i].x,BO[i].y,1.0,0.0,img_block1,TRUE);}}
	DrawRotaGraph(TP.x,TP.y,1.0,0.0,img_tama,TRUE);
	DrawGraph(0,0,img_waku,TRUE);
	DrawFormatString(  0,0,GetColor(255,255,255),"%f",TP.sp);
	DrawFormatString(  0,20,GetColor(255,255,255),"%d %d",TP.x,TP.y);
	DrawFormatString(  0,40,GetColor(255,255,255),"%f",TP.at+ZP.at);
	DrawFormatString(  0,60,GetColor(255,255,255),"%d %d",ZP.x-TP.x,ZP.y+9-TP.y);
	DrawFormatString(  0,80,GetColor(0,0,255),"%d %d %d",BO[0].x,BO[0].y,BO[0].flag);
}
AtariHaziki.h

コード:

#ifndef DEF_ATARIHAZIKI_H //二重include防止
#define DEF_ATARIHAZIKI_H

void ZikiOut();
void TamaMove();
void GamenTamaAtariJudge();
int ZikiTamaHazikiJudge();
int ZikiTamaAtariJudge();
void ZikiTamaAtariHazikiSyori();
void ZikiMove();
void StructIni();
void Load_Graph();
void DrawAll();

#endif
define.h

コード:

#define PI 3.141592//円周率
#define max_y 432//ゲーム部分下端
#define min_y 79  //ゲーム部分上端
#define max_x 512 //ゲーム部分右端
#define min_x 63  //ゲーム部分左端

#define Start_Tama_x 502//玉の初期x座標
#define Start_Tama_y 404//玉の初期y座標
#define Start_Tama_ang 1.000//玉の初期角度

#define Tama_Atari_Hantei 10.000//玉の当たり判定

#define Block_Order_Max 3//敵情報の数
struct.h

コード:

#ifndef DEF_STRUCT_H //二重include防止
#define DEF_STRUCT_H

typedef struct{//玉のパラメータ
	int x,y,muteki;//x座標,y座標,玉無敵スイッチ
	double at,sp,ang;//当たり判定、スピード、投射角
}TamaPara_t;

typedef struct{//自機のパラメータ
	int x,y,img,imgcnt,zanki,muteki,atmode,outmode;//座標、画像の番号,画像カウンター,残機の数,無敵時間,攻撃スイッチ,やられスイッチ
	double sp,at,haziki;//自機の動く速さ,当たり判定の大きさ,はじき判定の大きさ
}ZikiPara_t;

typedef struct{
	int x,y,maxx,minx,maxy,miny,stage,maxhp,hp,canbreak,enemy,flag;
	//中心のx,y座標,右端のx座標,左端のx座標,下のy座標,上のy座標,登場ステージ,最大HP,HP,倒せるかどうか,敵かどうか,存在フラグ
}BlockDeta_t;

typedef struct{
	int x,y,maxx,minx,maxy,miny,stage,maxhp,hp,canbreak,enemy,flag;
	//中心のx,y座標,右端のx座標,左端のx座標,下のy座標,上のy座標,登場ステージ,最大HP,HP,倒せるかどうか,敵かどうか,存在フラグ
}BlockOrder_t;


#endif
ここから、AtariHaziki.cppの中身をさらに複数のファイルに分けたかったのですが、ここに入れた関数は全て構造体の変数を参照しているのでこのまま他のcppファイルを作ってそこに関数を移動させてそれに合わせたヘッダーファイルを作ってもZP.●●やTP.●●が参照できず、かといって

コード:

TamaPara_t TP;

ZikiPara_t ZP;

BlockDeta_t BD[Block_Order_Max]={
	/*中心のx,y座標,右端,左端,下端,上端,登場面,最大HP,HP,倒せるか,ノルマ,存在フラグ*/
	 {    273,  233, 259, 232, 247, 220,     1,     1, 1,       1,     1,         1},
	 {    245,  233, 259, 232, 247, 220,     1,     1, 1,       1,     1,         1},
	 {    217,  233, 229, 204, 247, 220,     1,     1, 1,       1,     1,         1}
};

BlockOrder_t BO[Block_Order_Max]={
	/*中心のx,y座標,右端,左端,下端,上端,登場面,最大HP,HP,倒せるか,ノルマ,存在フラグ*/
	 {    273,  233, 259, 232, 247, 220,     1,     1, 1,       1,     1,         1},
	 {    245,  233, 259, 232, 247, 220,     1,     1, 1,       1,     1,         1},
	 {    217,  233, 229, 204, 247, 220,     1,     1, 1,       1,     1,         1}
};
をstruct.hで宣言すると多重定義になってしまいます。この場合どうやって構造体の文字列を宣言すればいいでしょうか?

アバター
あたっしゅ
記事: 667
登録日時: 14年前
住所: 東京23区
連絡を取る:

Re: 分割コンパイルの際の二重定義について

#5

投稿記事 by あたっしゅ » 13年前

struct.h には、

コード:

extern BlockDeta_t BD[Block_Order_Max];
と宣言のみ。
.cpp には、

コード:

BlockDeta_t BD[Block_Order_Max]={
    /*中心のx,y座標,右端,左端,下端,上端,登場面,最大HP,HP,倒せるか,ノルマ,存在フラグ*/
     {    273,  233, 259, 232, 247, 220,     1,     1, 1,       1,     1,         1},
     {    245,  233, 259, 232, 247, 220,     1,     1, 1,       1,     1,         1},
     {    217,  233, 229, 204, 247, 220,     1,     1, 1,       1,     1,         1}
};
と実体を書く。


>をstruct.hで宣言すると多重定義になってしまいます。この場合どうやって構造体の文字列を宣言すればいいでしょうか?

C/C++ で文字列といったら "string" のこと。この場合は、文字列ではない。
VTuber:
[香車]東上☆Aho(暎帆)☆海美
http://atassyu.php.xdomain.jp/vtuber/index.html
レスがついていないものを優先して、レスするみみ。時々、見当外れなレスしみみ。

中の人:
手提鞄あたッしュ、[MrAtassyu] 手提鞄屋魚有店
http://ameblo.jp/mratassyu/
Pixiv: 666303
Windows, Mac, Linux, Haiku, Raspbery Pi, Jetson Nano, 電子ブロック 持ち。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 分割コンパイルの際の二重定義について

#6

投稿記事 by softya(ソフト屋) » 13年前

気をつけて欲しいこと
・グローバル公開しない変数や関数にはstaticを付けてファイルスコープにする。
・本当にグローバル公開すべき変数や関数か熟考する。
・TP/ZPなど極端に短い変数名は付けない。
・ファイル名と含まれる関数名の意味の統一性をよく考える。AtariHazikiにTamaMoveなどがある理由は無いはず。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

dast
記事: 41
登録日時: 13年前

Re: 分割コンパイルの際の二重定義について

#7

投稿記事 by dast » 13年前

あたっしゅさんのご指摘を受けて次のように分割したのですが、やはりTP.~とZP.~が多重定義になってしまいます。一体どのようにしたら初期値のある構造体の変数を複数のcppファイルで参照できるようになるのでしょうか?

main.cpp

コード:

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

#include "solution\header\define.h"
#include "solution\header\Interface.h"
#include "solution\header\AtariHaziki.h"
#include "solution\header\Draw.h"




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

	int i;//ループ用

	Load_Graph();

	StructIni();

    while(ScreenFlip()==0 &&ProcessMessage()==0 && ClearDrawScreen()==0/* && Keyboard_Update()==0*/ && Keyboard_Get(KEY_INPUT_ESCAPE)==0){
                          //↑メッセージ処理          ↑画面をクリア            ↑入力状態を保存  ↑ESCが押されていない
		Keyboard_Update();


		ZikiMove();
		TamaMove();
		ZikiTamaAtariHazikiSyori();
		GamenTamaAtariJudge();

		
		DrawAll();

		
    }

    DxLib_End();
    return 0;
}
AtariHaziki.cpp

コード:

#include "DxLib.h"
#include <math.h>
#include "../header/define.h"
#include "../header/struct.h"
#include "../header/Interface.h"

static double xzahyou,yzahyou;//(ZikiTamaAtariHazikiSyori())

static int i;
static int TamaStop=0;//玉停止(ZikiOut(),TamaMove(),ZikiMove(),)
static int ZikiStop=0;//自機停止(ZikiMove(),)
static int Pause=0;//ポーズスイッチ(ZikiMove(),)






BlockDeta_t BD[Block_Order_Max]={
	/*中心のx,y座標,右端,左端,下端,上端,登場面,最大HP,HP,倒せるか,ノルマ,存在フラグ*/
	 {    273,  233, 259, 232, 247, 220,     1,     1, 1,       1,     1,         1},
	 {    245,  233, 259, 232, 247, 220,     1,     1, 1,       1,     1,         1},
	 {    217,  233, 229, 204, 247, 220,     1,     1, 1,       1,     1,         1}
};

BlockOrder_t BO[Block_Order_Max]={
	/*中心のx,y座標,右端,左端,下端,上端,登場面,最大HP,HP,倒せるか,ノルマ,存在フラグ*/
	 {    273,  233, 259, 232, 247, 220,     1,     1, 1,       1,     1,         1},
	 {    245,  233, 259, 232, 247, 220,     1,     1, 1,       1,     1,         1},
	 {    217,  233, 229, 204, 247, 220,     1,     1, 1,       1,     1,         1}
};

void ZikiOut(){//ミス時の処理
	ZP.outmode=1;ZP.atmode=0;TamaStop=1;ZP.imgcnt=0;
}

void TamaMove(){//玉の動作
	if(TamaStop==0){
		TP.x+=(int)(TP.sp*cos(TP.ang*PI));
		TP.y+=(int)(TP.sp*sin(TP.ang*PI));
	}
}


void GamenTamaAtariJudge(){//画面端と玉の当たり判定の衝突判定及び処理
	if(TP.y<=min_y+TP.at){//画面上
		TP.y=min_y+TP.at;
		TP.ang=2.000-TP.ang;
	}
	if(TP.y>=max_y-TP.at){//画面下
		if(ZP.outmode==0){
			ZikiOut();
		}
		/*TP.y=max_y-TP.at;
		TP.ang=2.000-TP.ang;*/
	}
	if(TP.x<=min_x+TP.at){//画面左
		TP.x=min_x+TP.at;
		TP.ang=3.000-TP.ang;
	}
	if(TP.x>=max_x-TP.at){//画面右
		TP.x=max_x-TP.at;
		TP.ang=3.000-TP.ang;
	}
}

int ZikiTamaHazikiJudge(){//自機のはじき判定と玉の当たり判定の衝突判定
	int i;
	double x,y,r;
	if(ZP.img==12||ZP.img==13||ZP.img==14||ZP.img==15){//その場攻撃
		x=(double)(ZP.x)-(double)(TP.x);//(自機の攻撃判定の中心のx座標)-玉のx座標
		y=(double)(ZP.y)-(double)(TP.y);//(自機の攻撃判定の中心のy座標)-玉のx座標
		r=(ZP.haziki)+(TP.at);
	}
	if(ZP.img==16||ZP.img==17||ZP.img==18||ZP.img==19){//左攻撃
		x=(double)(ZP.x-9)-(double)(TP.x);//(自機の攻撃判定の中心のx座標)-玉のx座標
		y=(double)(ZP.y)-(double)(TP.y);//(自機の攻撃判定の中心のy座標)-玉のx座標
		r=(ZP.haziki)+(TP.at);
	}
	if(ZP.img==20||ZP.img==21||ZP.img==22||ZP.img==23){//右攻撃
		x=(double)(ZP.x+9)-(double)(TP.x);//(自機の攻撃判定の中心のx座標)-玉のx座標
		y=(double)(ZP.y)-(double)(TP.y);//(自機の攻撃判定の中心のy座標)-玉のx座標
		r=(ZP.haziki)+(TP.at);
	}
	
	if(sqrt(TP.sp*TP.sp)>sqrt(r*r)){//移動した距離が(ZP.haziki)+(TP.at)より長ければ
		double prey = TP.y-TP.sp*sin(TP.ang*PI);//1フレーム前の表示y座標
		double prex = TP.x-TP.sp*cos(TP.ang*PI);//1フレーム前の表示x座標
		double imay = TP.y;//現在の表示y座標
		double imax = TP.x;//現在の表示x座標
		double px,py;
		for(i=0;i<sqrt(TP.sp*TP.sp)/sqrt(TP.at);i++){//進んだ分÷当たり判定分ループ
			if(ZP.img==12||ZP.img==13||ZP.img==14||ZP.img==15){
				px=prex-ZP.x;
				py=prey-ZP.y;
			}
			if(ZP.img==16||ZP.img==17||ZP.img==18||ZP.img==19){
				px=prex-(ZP.x-9);
				py=prey-ZP.y;
			}
			if(ZP.img==20||ZP.img==21||ZP.img==22||ZP.img==23){
				px=prex-(ZP.x+9);
				py=prey-ZP.y;
			}
			if(px*px+py*py<r*r){
				TP.x=(int)prex;
				TP.y=(int)prey;
				return 1;
			}
			prex+=TP.at*cos(TP.ang*PI);
			prey+=TP.at*sin(TP.ang*PI);
		}
	}
	if(x*x+y*y<r*r){//当たり判定内なら
		return 1;//当たり
	}
	return 0;
}

int ZikiTamaAtariJudge(){//自機の当たり判定と玉の当たり判定の衝突判定(要検証)
	int i;
	/*double x,y,r;*/
	double x=(double)(ZP.x)-(double)(TP.x);//自機の当たり判定の中心のx座標-玉のx座標
	double y=(double)(ZP.y+9)-(double)(TP.y);//自機の当たり判定の中心のy座標-玉のy座標
	double r=ZP.at+TP.at;//自機の当たり判定-玉の当たり判定
	if(sqrt(TP.sp*TP.sp)>sqrt(r*r)){//玉が移動した距離が(ZP.at)+(TP.at)より長ければ
		double pretx = TP.x-TP.sp*cos(TP.ang*PI);//1フレーム前の玉の表示x座標
		double prety = TP.y-TP.sp*sin(TP.ang*PI);//1フレーム前の玉の表示y座標
		double ptx,pty;
		for(i=0;i<sqrt(TP.sp*TP.sp)/sqrt(TP.at*TP.at);i++){//玉が進んだ分÷玉の当たり判定分ループ
			ptx=pretx-ZP.x;
			pty=prety-ZP.y+9;
			if(ptx*ptx+pty*pty<r*r){
				TP.x=(int)pretx;
				TP.y=(int)prety;
				return 1;
			}
		}
	}
	if(x*x+y*y<r*r){
		return 1;
	}
	return 0;
}

void ZikiTamaAtariHazikiSyori(){//自機の当たり判定、攻撃判定と玉の当たり判定の衝突時の処理
	if(ZP.atmode>0){
		if(TP.muteki==0){
			if(ZikiTamaHazikiJudge()){
				xzahyou=TP.x-ZP.x;
				yzahyou=TP.y-(ZP.y+17);
				TP.ang=(atan2(yzahyou,xzahyou))/PI;
				TP.muteki=1;
			}
		}
	}
	if(ZP.atmode==0){
		TP.muteki=0;
	}
	if(ZP.muteki==0){
		if(ZP.outmode==0){
			if(ZikiTamaAtariJudge()){
				ZikiOut();
			}
		}
	}
}


void ZikiMove(){//自機の動作(ポーズもここ)
	ZP.img=((ZP.imgcnt)%48)/12;
	if(Keyboard_Get(KEY_INPUT_RETURN)==1){//ポーズ
		if(Pause==0){
			TamaStop=1;
			ZikiStop=1;
			Pause=1;
		}
		else if(Pause==1){
			TamaStop=0;
			ZikiStop=0;
			Pause=0;
		}
	}
	if(ZikiStop==0){
		if(Keyboard_Get(KEY_INPUT_A)<=0 && Keyboard_Get( KEY_INPUT_RIGHT ) >= 1 && Keyboard_Get( KEY_INPUT_LEFT ) <= 0 && ZP.atmode==0 && ZP.outmode==0){//右移動
			if(ZP.x<(max_x-ZP.at)){
				ZP.x+=(int)ZP.sp;
			}
			ZP.img+=8;
		}
		else if(Keyboard_Get(KEY_INPUT_A)<=0 && Keyboard_Get( KEY_INPUT_RIGHT ) <= 0 && Keyboard_Get( KEY_INPUT_LEFT ) >= 1 && ZP.atmode==0 && ZP.outmode==0){//左移動
			if(ZP.x>(min_x+ZP.at)){
				ZP.x-=(int)ZP.sp;
			}
			ZP.img+=4;
		}
		else if(Keyboard_Get(KEY_INPUT_A)==1 && Keyboard_Get( KEY_INPUT_RIGHT ) >= 1 && Keyboard_Get( KEY_INPUT_LEFT ) <= 0 && ZP.atmode==0 && ZP.outmode==0){//右攻撃
			ZP.atmode=3;
			ZP.imgcnt=0;
		}
		else if(Keyboard_Get(KEY_INPUT_A)==1 && Keyboard_Get( KEY_INPUT_RIGHT ) <= 0 && Keyboard_Get( KEY_INPUT_LEFT ) >= 1 && ZP.atmode==0 && ZP.outmode==0){//左攻撃
			ZP.atmode=2;
			ZP.imgcnt=0;
		}
		else if(Keyboard_Get(KEY_INPUT_A)==1 && Keyboard_Get( KEY_INPUT_RIGHT ) <= 0 && Keyboard_Get( KEY_INPUT_LEFT ) <= 0 && ZP.atmode==0 && ZP.outmode==0){//その場攻撃
			ZP.atmode=1;
			ZP.imgcnt=0;
		}
		else if(Keyboard_Get(KEY_INPUT_A)==1 && Keyboard_Get( KEY_INPUT_RIGHT ) >= 1 && Keyboard_Get( KEY_INPUT_LEFT ) >= 1 && ZP.atmode==0 && ZP.outmode==0){//その場攻撃
			ZP.atmode=1;
			ZP.imgcnt=0;
		}
		else {}
		if(ZP.atmode>=1){/*攻撃中の処理*/
			ZP.img=((ZP.imgcnt)%48)/12;/*硬直時間*/
			ZP.img+=(2+ZP.atmode)*4;/*画像処理*/
			if(ZP.atmode==2){/*左攻撃中の移動*/
				if(ZP.x>(min_x+ZP.at)){
					ZP.x-=(int)ZP.sp;
				}
			}
			if(ZP.atmode==3){/*右攻撃中の移動*/
				if(ZP.x<(max_x-ZP.at)){
					ZP.x+=(int)ZP.sp;
				}
			}
			if(ZP.imgcnt==47){
				ZP.atmode=0;
			}
		}
		if(ZP.outmode>=1){//やられモーションの処理
			ZP.img=((ZP.imgcnt)%48)/12;/*硬直時間*/
			ZP.img+=24;/*画像処理*/
			if(ZP.imgcnt==47){
				ZP.outmode=0;
				//TP.x=Start_Tama_x;
				TP.y=Start_Tama_y;
				TP.ang=Start_Tama_ang;
				TamaStop=0;
			}
		}
		ZP.imgcnt++;
	}
}

void StructIni(){

	TP.x=Start_Tama_x;
	TP.y=Start_Tama_y;
	TP.muteki=0;
	TP.at=Tama_Atari_Hantei;
	TP.sp=4.000;
	TP.ang=Start_Tama_ang;

	ZP.at=8.000;
	ZP.haziki=17.000;
	ZP.x=(max_x+min_x)/2;
	ZP.y=max_y-18;
	ZP.sp=4.000;
	ZP.img=0;
	ZP.imgcnt=0;
	ZP.atmode=0;
	ZP.zanki=5;
	ZP.muteki=0;
	ZP.outmode=0;
}
Draw.cpp

コード:

#include "DxLib.h"
#include "../header/define.h"
#include "../header/struct.h"

static int i;
static int img_waku;
static int img_tama;
static int img_block1;
static int img_Ziki[28];

BlockDeta_t BD[Block_Order_Max]={
	/*中心のx,y座標,右端,左端,下端,上端,登場面,最大HP,HP,倒せるか,ノルマ,存在フラグ*/
	 {    273,  233, 259, 232, 247, 220,     1,     1, 1,       1,     1,         1},
	 {    245,  233, 259, 232, 247, 220,     1,     1, 1,       1,     1,         1},
	 {    217,  233, 229, 204, 247, 220,     1,     1, 1,       1,     1,         1}
};

BlockOrder_t BO[Block_Order_Max]={
	/*中心のx,y座標,右端,左端,下端,上端,登場面,最大HP,HP,倒せるか,ノルマ,存在フラグ*/
	 {    273,  233, 259, 232, 247, 220,     1,     1, 1,       1,     1,         1},
	 {    245,  233, 259, 232, 247, 220,     1,     1, 1,       1,     1,         1},
	 {    217,  233, 229, 204, 247, 220,     1,     1, 1,       1,     1,         1}
};

void Load_Graph(){
	img_waku=LoadGraph("img/waku.png");
	img_tama=LoadGraph("img/tama_ver0.10.png");
	img_block1=LoadGraph("img/block1.png");
	LoadDivGraph("img/ziki[28]_ver0.26.png",28,4,7,53,35,img_Ziki);
}

void DrawAll(){
	DrawRotaGraph(ZP.x,ZP.y,1.0,0.0,img_Ziki[ZP.img],TRUE);
	for(i=0;i<Block_Order_Max;i++){if(BO[i].flag==1){DrawRotaGraph(BO[i].x,BO[i].y,1.0,0.0,img_block1,TRUE);}}
	DrawRotaGraph(TP.x,TP.y,1.0,0.0,img_tama,TRUE);
	DrawGraph(0,0,img_waku,TRUE);
	DrawFormatString(  0,0,GetColor(255,255,255),"%f",TP.sp);
	DrawFormatString(  0,20,GetColor(255,255,255),"%d %d",TP.x,TP.y);
	DrawFormatString(  0,40,GetColor(255,255,255),"%f",TP.at+ZP.at);
	DrawFormatString(  0,60,GetColor(255,255,255),"%d %d",ZP.x-TP.x,ZP.y+9-TP.y);
	DrawFormatString(  0,80,GetColor(0,0,255),"%d %d %d",BO[0].x,BO[0].y,BO[0].flag);
}
Interface.cpp

コード:

#include "DxLib.h"

int m_Key[256];
// キーの入力状態を更新する
void Keyboard_Update(){
        char tmpKey[256]; // 現在のキーの入力状態を格納する
        GetHitKeyStateAll( tmpKey ); // 全てのキーの入力状態を得る
        for( int i=0; i<256; i++ ){ 
                if( tmpKey[i] != 0 ){ // i番のキーコードに対応するキーが押されていたら
                        m_Key[i]++;     // 加算
                } else {              // 押されていなければ
                        m_Key[i] = 0;   // 0にする
                }
        }
        /*return 0;*/
}
int Keyboard_Get(int Key_Code){
	return m_Key[Key_Code];//Key_Codeの入力状態を返す
}
AtariHaziki.h

コード:

#ifndef DEF_ATARIHAZIKI_H //二重include防止
#define DEF_ATARIHAZIKI_H

void ZikiOut();
void TamaMove();
void GamenTamaAtariJudge();
int ZikiTamaHazikiJudge();
int ZikiTamaAtariJudge();
void ZikiTamaAtariHazikiSyori();
void ZikiMove();
void StructIni();


#endif
define.h

コード:

#define PI 3.141592//円周率
#define max_y 432//ゲーム部分下端
#define min_y 79  //ゲーム部分上端
#define max_x 512 //ゲーム部分右端
#define min_x 63  //ゲーム部分左端

#define Start_Tama_x 502//玉の初期x座標
#define Start_Tama_y 404//玉の初期y座標
#define Start_Tama_ang 1.000//玉の初期角度

#define Tama_Atari_Hantei 10.000//玉の当たり判定

#define Block_Order_Max 3//敵情報の
Draw.h

コード:

#ifndef DEF_DRAW_H //二重include防止
#define DEF_DRAW_H

void Load_Graph();
void DrawAll();

#endif
Interface.h

コード:

#ifndef DEF_INTERFACE_H //二重include防止
#define DEF_INTERFACE_H

void Keyboard_Update();
int Keyboard_Get(int Key_Code);

#endif
struct.h

コード:

#ifndef DEF_STRUCT_H //二重include防止
#define DEF_STRUCT_H

typedef struct{//玉のパラメータ
	int x,y,muteki;//x座標,y座標,玉無敵スイッチ
	double at,sp,ang;//当たり判定、スピード、投射角
}TamaPara_t;
TamaPara_t TP;

typedef struct{//自機のパラメータ
	int x,y,img,imgcnt,zanki,muteki,atmode,outmode;//座標、画像の番号,画像カウンター,残機の数,無敵時間,攻撃スイッチ,やられスイッチ
	double sp,at,haziki;//自機の動く速さ,当たり判定の大きさ,はじき判定の大きさ
}ZikiPara_t;
ZikiPara_t ZP;

typedef struct{
	int x,y,maxx,minx,maxy,miny,stage,maxhp,hp,canbreak,enemy,flag;
	//中心のx,y座標,右端のx座標,左端のx座標,下のy座標,上のy座標,登場ステージ,最大HP,HP,倒せるかどうか,敵かどうか,存在フラグ
}BlockDeta_t;
extern BlockDeta_t BD[Block_Order_Max];

typedef struct{
	int x,y,maxx,minx,maxy,miny,stage,maxhp,hp,canbreak,enemy,flag;
	//中心のx,y座標,右端のx座標,左端のx座標,下のy座標,上のy座標,登場ステージ,最大HP,HP,倒せるかどうか,敵かどうか,存在フラグ
}BlockOrder_t;
extern BlockOrder_t BO[Block_Order_Max];


#endif
>>softyaさん
とりあえずご指摘を受けて変数をstaticをつけてそのファイル限定の物にしてみました。ファイル名と含まれる関数名の意味の統一性のことは重々承知しておりますが、今のところ私の知識ではAtariHaziki.cppをこれ以上分割できないのでひとまずこの形で置いてあるだけです。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 分割コンパイルの際の二重定義について

#8

投稿記事 by softya(ソフト屋) » 13年前

ごめんなさい。
これだけファイルが多くなるとファイルをZIP等にまとめて添付してもらった方が調べやすいです。お願いできませんか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

dast
記事: 41
登録日時: 13年前

Re: 分割コンパイルの際の二重定義について

#9

投稿記事 by dast » 13年前

こちらになります。よろしくお願いします。
(どのファイルが個人情報に繋がるものなのかが判断がつかなかったので.cppと.hだけをまとめて圧縮しました。ミスを判断するのに足りなかったら言ってください)
添付ファイル
ブロック崩し.zip
(6.15 KiB) ダウンロード数: 107 回

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 分割コンパイルの際の二重定義について

#10

投稿記事 by softya(ソフト屋) » 13年前

都合でひとつのフォルダにまとめましたが多重定義やリンクエラーを解消したソースコードです。
ブロック崩し修正.zip
(5.44 KiB) ダウンロード数: 123 回
少なくとも2文字extern名は止めて欲しいですね。
extern TamaPara_t TP;
extern ZikiPara_t ZP;
extern BlockDeta_t BD[Block_Order_Max];
extern BlockOrder_t BO[Block_Order_Max];
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

閉鎖

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