複数のソースコードファイルにプログラムを書く
Posted: 2014年11月04日(火) 12:26
タイトルとゲームオーバ画面を表示するプログラムという記事は覚えていますでしょうか?あの続きです。
あれから本の内容を見ながら進めていたのですが、またまた躓いてしまいました。
(いつもの事ながら申し訳ありません)
サンプルファイルありますけど、すでに完成版で見てもさっぱりわかりません。
今回、何がしたいのかという概要を下に書いておきます。
(前)
(前)で作ったプログラムを使って、ゲームを作成するというもの。
・複製の作業
(前)プロジェクトをコピーし、複製されたファイルの名前を変える(
プロジェクト内のプロパティの名前、ルート名前空間の変更、
前の<Debug>、.sdf、.vcxproj.userファイルを削除、
.vcxprojと.vcxproj.filtersファイルの名前を変える)
ゲーム作成のために、
Gamemain.hのプログラム
Main.hのプログラム
Main.cppのプログラム
Gamemain.cppのプログラム
※プログラムファイル名はサンプルと区別するために最初の文字を大文字にしてあります。
エラー
1 error LNK2005: "int g_lasttime" (?g_lasttime@@3HA) は既に Gamemain.obj で定義されています。
2 error LNK2005: "float g_fremetime" (?g_fremetime@@3MA) は既に Gamemain.obj で定義されています。
3 error LNK2005: "float g_hx" (?g_hx@@3MA) は既に Gamemain.obj で定義されています。
4 error LNK2005: "float g_hy" (?g_hy@@3MA) は既に Gamemain.obj で定義されています。
5 error LNK1169: 1 つ以上の複数回定義されているシンボルが見つかりました。
元のMain.cppにあったコードをGamemainにペーストし、Main.hにインクルードと列挙体、関数プロトタイプを持ってくる。
(前にexternをつける)Main.cppでMain.hに書いた部分を削除し、代わりにMain.hをインクルード。
インクルードの繰り返しを防ぐために#ifndefと#endifをヘッダファイル内に書く。
・・・で、コンパイルをしてみたら上のエラーが出てしまいました。
本に従ってプログラムしたのに、なぜエラーになるのでしょうか?(本にはこのエラーの対処は載っていません)
いつもの様な一文字だけ間違ってるっていうのは無いですよね?それとも、消すところを間違えているのでしょうか?
あれから本の内容を見ながら進めていたのですが、またまた躓いてしまいました。
(いつもの事ながら申し訳ありません)
サンプルファイルありますけど、すでに完成版で見てもさっぱりわかりません。
今回、何がしたいのかという概要を下に書いておきます。
(前)
- 読み込んだ画像を動かしてみたり、リアルタイムでプログラムを進行させてみる
- タイトル、ゲームオーバー画面を表示してみる(ここが前の質問)
(前)で作ったプログラムを使って、ゲームを作成するというもの。
・複製の作業
(前)プロジェクトをコピーし、複製されたファイルの名前を変える(
プロジェクト内のプロパティの名前、ルート名前空間の変更、
前の<Debug>、.sdf、.vcxproj.userファイルを削除、
.vcxprojと.vcxproj.filtersファイルの名前を変える)
ゲーム作成のために、
- cppファイルを新たに作成し、その中に関数の定義を書く。
- ヘッダファイルを作成し、その中に関数のプロトタイプ宣言を書く。
- 後はヘッダファイルをインクルードして関数を呼び出す。
Gamemain.hのプログラム
#ifndef __GAMEMAIN_H__
#define __GAMEMAIN_H__
#include <DxLib.h>
#include "Main.h"
void GameMain();
#endif
#ifndef __MAIN_H__
#define __MAIN_H__
#include <DxLib.h>
#include "Gamemain.h"
//グローバル変数
//時間計測用変数
extern int g_lasttime = 0; //直前の計測時間
extern float g_fremetime = 0; //1ループにかかった時間
extern int g_timerstart; //タイマー用変数
enum GameState{ //ゲーム状態
GAME_TITLE, GAME_MAIN,
GAME_CLEAR, GAME_OVER
};
extern GameState g_gamestate;
extern int g_gametitleimg; //タイトルイメージ
extern int g_heroimg; //画像
extern float g_hx = 0, g_hy = 0; //座標
//ボタン
extern BOOL g_akey_prev; //直前のAボタンの状態
//フォント
extern int g_middlefont; //中サイズのフォントハンドル
extern int g_largefont; //大サイズのフォントハンドル
//関数プロトタイプ宣言
void DrawGameTitle();
void DrawGameMain();
void DrawGameClear();
void DrawGameOver();
BOOL IsAkeyTrigger(int key);
#endif
#include "Main.h"
//グローバル変数
//時間計測用変数
int g_timerstart; //タイマー用変数
GameState g_gamestate = GAME_TITLE;
int g_gametitleimg; //タイトルイメージ
int g_heroimg; //画像
//ボタン
BOOL g_akey_prev; //直前のAボタンの状態
//フォント
int g_middlefont; //中サイズのフォントハンドル
int g_largefont; //大サイズのフォントハンドル
int WINAPI WinMain(HINSTANCE h1, HINSTANCE hP, LPSTR lPC, int nC){
//ウィンドウモードにする
ChangeWindowMode(TRUE);
//ウィンドウサイズを変更する
SetGraphMode(800, 600, 32);
//DXライブラリ初期化
if (DxLib_Init() == -1) return -1;
//画像を読み込み
g_gametitleimg = LoadGraph("media\\smp1_title.png");
g_heroimg = LoadGraph("media\\smp1_chara01.png");
g_middlefont = CreateFontToHandle("メイリオ", 42, -1, DX_FONTTYPE_ANTIALIASING);
g_largefont = CreateFontToHandle("メイリオ", 90, -1, DX_FONTTYPE_ANTIALIASING);
SetDrawScreen(DX_SCREEN_BACK);
g_lasttime = GetNowCount(); //現在時刻の記録
while (ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0){
//1ループにかかった時間を計測
int curtime = GetNowCount();
g_fremetime = (float)(curtime - g_lasttime) / 1000.0f;
g_lasttime = curtime;
ClearDrawScreen();
//画面描画関数に切り替え
switch (g_gamestate)
{
case GAME_TITLE:
DrawGameTitle();
break;
case GAME_MAIN:
DrawGameMain();
break;
case GAME_CLEAR:
DrawGameClear();
break;
case GAME_OVER:
DrawGameOver();
break;
default:
break;
}
ScreenFlip();
}
//待機
WaitKey();
//DXライブラリの終了処理
DxLib_End();
return 0;
}
//タイトル画面描画
void DrawGameTitle(){
DrawBox(0, 0, 800, 600, GetColor(255, 255, 255), TRUE);
DrawGraph(0, 0, g_gametitleimg, TRUE);
//テキスト表示
DrawStringToHandle(100, 400, "Zキーでゲームスタート",
GetColor(255, 0, 255), g_middlefont);
DrawStringToHandle(100, 460, "カーソルキーで上下左右に移動",
GetColor(0, 0, 0), g_middlefont);
//キーをチェックして画面を切り替え
int key = GetJoypadInputState(DX_INPUT_KEY_PAD1);
if (IsAkeyTrigger(key) == TRUE) g_gamestate = GAME_MAIN;
}
//ゲーム本編描画
void DrawGameMain(){
GameMain();
}
//ゲームクリア画面描画
void DrawGameClear(){
}
//ゲームオーバー画面描画
void DrawGameOver(){
//テキスト表示
DrawStringToHandle(100, 200, "ゲームオーバー",
GetColor(255, 0, 0), g_largefont);
//5秒経ったらタイトル画面へ
if (g_lasttime - g_timerstart > 5000) g_gamestate = GAME_TITLE;
}
//キートリガー処理
BOOL IsAkeyTrigger(int key){
if (key & PAD_INPUT_A){
if (g_akey_prev == FALSE){
g_akey_prev = TRUE;
return TRUE;
}
}
else{
g_akey_prev = FALSE;
}
return FALSE;
}
#include "Gamemain.h"
void GameMain(){
//自キャラ移動
int Key = GetJoypadInputState(DX_INPUT_KEY_PAD1);
float mv = 80.0f * g_fremetime; //移動量計算
if (Key & PAD_INPUT_UP) g_hy -= mv;
if (Key & PAD_INPUT_DOWN) g_hy += mv;
if (Key & PAD_INPUT_LEFT) g_hx -= mv;
if (Key & PAD_INPUT_RIGHT) g_hx += mv;
DrawGraph(g_hx, g_hy, g_heroimg, TRUE);
//Zキーをチェックして画面を切り替え
if (IsAkeyTrigger(Key) == TRUE){
g_gamestate = GAME_OVER;
g_timerstart = g_lasttime; //タイマーセット
}
}
エラー
1 error LNK2005: "int g_lasttime" (?g_lasttime@@3HA) は既に Gamemain.obj で定義されています。
2 error LNK2005: "float g_fremetime" (?g_fremetime@@3MA) は既に Gamemain.obj で定義されています。
3 error LNK2005: "float g_hx" (?g_hx@@3MA) は既に Gamemain.obj で定義されています。
4 error LNK2005: "float g_hy" (?g_hy@@3MA) は既に Gamemain.obj で定義されています。
5 error LNK1169: 1 つ以上の複数回定義されているシンボルが見つかりました。
元のMain.cppにあったコードをGamemainにペーストし、Main.hにインクルードと列挙体、関数プロトタイプを持ってくる。
(前にexternをつける)Main.cppでMain.hに書いた部分を削除し、代わりにMain.hをインクルード。
インクルードの繰り返しを防ぐために#ifndefと#endifをヘッダファイル内に書く。
・・・で、コンパイルをしてみたら上のエラーが出てしまいました。
本に従ってプログラムしたのに、なぜエラーになるのでしょうか?(本にはこのエラーの対処は載っていません)
いつもの様な一文字だけ間違ってるっていうのは無いですよね?それとも、消すところを間違えているのでしょうか?