ページ 1 / 1
ゲームの画面切り替えについて
Posted: 2021年1月20日(水) 09:52
by souta
ゲーム制作をしているのですか、タイトル画面とゲーム画面とスコア画面の切り替えの仕方がわかりません。メニュー選択してEnterを押すと次の画面に切り替えれるようにしたいです(クリック入力でも可)
環境はWindowsで、Visual Studio 2019とDXライブラリで作っています。C言語は習っている最中で完璧には理解できていないレベルです。
<タイトル画面のコード>
コード:
#include "DxLib.h"
int Key[256]; // キーが押されているフレーム数を格納する
// キーの入力状態を更新する
int gpUpdateKey() {
char tmpKey[256]; // 現在のキーの入力状態を格納する
GetHitKeyStateAll(tmpKey); // 全てのキーの入力状態を得る
for (int i = 0; i < 256; i++) {
if (tmpKey[i] != 0) { // i番のキーコードに対応するキーが押されていたら
Key[i]++; // 加算
}
else { // 押されていなければ
Key[i] = 0; // 0にする
}
}
return 0;
}
// メニュー項目の表示に必要な構造体を用意する
typedef struct {
int x, y; // 座標格納用変数
char name[128]; // 項目名格納用変数
} MenuElement_t;
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen(DX_SCREEN_BACK); //ウィンドウモード変更と初期化と裏画面設定
SetGraphMode(800, 800, 32); //画面の解像度指定
// メニュー項目要素を2つ作る
MenuElement_t MenuElement[2] = {
{ 350, 300, "ゲームスタート" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
{ 380, 400, "ゲーム終了" },
};
int SelectNum = 0; // 現在の選択番号
// while(裏画面を表画面に反映, メッセージ処理, 画面クリア, キー更新)
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
// 計算フェーズ
if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理
SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)
for (int i = 0; i < 2; i++) { // メニュー項目数である2個ループ処理
if (i == SelectNum) { // 今処理しているのが、選択番号と同じ要素なら
MenuElement[i].x = 350; // 座標を320にする
}
else { // 今処理しているのが、選択番号以外なら
MenuElement[i].x = 380;// 座標を350にする
}
}
}
// 描画フェーズ
LoadGraphScreen(0, 0, "gahag-0073412840-1.png", TRUE); //背景
LoadGraphScreen(220, 75, "cooltext373677233987331.png", TRUE); //タイトルロゴ
for (int i = 0; i < 5; i++) { // メニュー項目を描画
DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
SetFontSize(32);
SetFontThickness(4);
ChangeFontType(DX_FONTTYPE_ANTIALIASING);
}
}
DxLib_End(); // DXライブラリ終了処理
return 0;
}
<ゲーム画面のコード>
コード:
#include "DxLib.h"
#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅
#define LANE_SIZE 1 //レーンの数
#define BAR_SIZE 40 //1レーンあたりの最大bar数
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
char buf[256]; //キー押下状態格納用配列
int key[LANE_SIZE] = {
KEY_INPUT_A
};
bool bar_f[LANE_SIZE][BAR_SIZE]; //barの存在フラグ
float bar_y[LANE_SIZE][BAR_SIZE]; //barのY座標
for (int j = 0; j < BAR_SIZE; j++) {
for (int i = 0; i < LANE_SIZE; i++) {
bar_f[i][j] = false; //全てにfalseを代入
}
}
LONGLONG start_time; //開始した時刻
LONGLONG now_time; //現在のフレームの時刻
int currentTime; //開始してからの経過時間
int counter = 0;
const int bpm = 120;
SetMainWindowText("リズムの達人"); //ウインドウのタイトルを設定
ChangeWindowMode(TRUE); //ウィンドウモードで起動
SetGraphMode(WIN_W, WIN_H, 32); //画面の解像度指定
SetWindowSizeChangeEnableFlag(FALSE); //画面サイズ変更不可
if (DxLib_Init() == -1) { return -1; } //DxLib初期化処理
SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定
enum judge_value {
NONE, GOOD, MISS
};
const int JUDGE_DISPLAY_TIME = 30; // 判定を表示する時間 (フレーム数)
judge_value judge = NONE; // 表示中の判定
int judge_time = 10; // 判定を表示する残り時間 (フレーム数)
//while(裏画面を表画面に反映, メッセージ処理, 画面クリア)
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0) {
LoadGraphScreen(1, 1, "a0.png", TRUE);
if (buf[KEY_INPUT_ESCAPE] == 1) {
break; // 終了
}
//時間関係
if (counter == 0) {
start_time = GetNowHiPerformanceCount();
}
now_time = GetNowHiPerformanceCount();
currentTime = (int)((now_time - start_time) / 1000); // ms
//bar生成
if (currentTime >= 550000 / bpm * counter) {
for (int i = 0; i < LANE_SIZE; i++) {
bar_f[i][counter % BAR_SIZE] = true;
bar_y[i][counter % BAR_SIZE] = -100.f;
}
counter++;
}
//DrawFormatString(100, 100, GetColor(255, 255, 255), "currentTime---%d", currentTime);
//bar座標更新
for (int i = 0; i < LANE_SIZE; i++) {
for (int j = 0; j < BAR_SIZE; j++) {
if (bar_f[i][j]) {
bar_y[i][j] += 4.f;
//DrawFormatString(100, 120, GetColor(255, 255, 0), "bar_y[i][j]---%f", bar_y[i][j]);
if (bar_y[i][j] > WIN_H + 10) {
bar_f[i][j] = false; //画面外に出たらfalse
// MISSを表示させる
judge = MISS;
DrawFormatString(10, 10, GetColor(0, 0, 255), "MISS");
judge_time = JUDGE_DISPLAY_TIME;
}
}
}
}
// 判定
GetHitKeyStateAll(buf);
for (int i = 0; i < LANE_SIZE; i++) {
for (int j = 0; j < BAR_SIZE; j++) {
if (bar_f[i][j]) {
if (WIN_H / 5 * 4 - 30 < bar_y[i][j] && bar_y[i][j] < WIN_H / 5 * 4 + 30) {
if (buf[key[i]] == 1) {
bar_f[i][j] = false;
// GOODを表示させる
judge = GOOD;
DrawFormatString(10, 10, GetColor(255, 0, 0), "GOOD");
judge_time = JUDGE_DISPLAY_TIME;
}
}
}
}
}
if (judge != NONE) {
if (judge == GOOD) {
DrawFormatString(10, 10, GetColor(255, 0, 0), "GOOD");
// GOODを描画する (テキスト・画像など)
}
else if (judge == MISS) {
DrawFormatString(10, 10, GetColor(0, 0, 255), "MISS");
// MISSを描画する (テキスト・画像など)
}
judge_time--;
if (judge_time <= 0) judge = NONE; // 指定の時間が経過したら、判定を消す
}
//判定ライン描画
DrawLine(0, WIN_H / 5 * 4, WIN_W, WIN_H / 5 * 4, GetColor(255, 255, 255));
DrawCircleAA(400.f, 480.f, 45.f, 60.f, GetColor(255, 255, 255), FALSE);
//bar描画
for (int i = 0; i < LANE_SIZE; i++) {
for (int j = 0; j < BAR_SIZE; j++) {
if (bar_f[i][j]) {
DrawCircleAA(400.f + i * 1.f, bar_y[i][j] - 10.f,
30.f + 1.f + i * 1.f, bar_y[i][j] + 10.f, GetColor(0, 255, 0), TRUE);
}
}
}
}
DxLib_End(); //DxLibの終了処理
return 0; //正常終了
}
<スコア画面のコード>
コード:
#include "DxLib.h"
int Key[256]; // キーが押されているフレーム数を格納する
// キーの入力状態を更新する
int gpUpdateKey() {
char tmpKey[256]; // 現在のキーの入力状態を格納する
GetHitKeyStateAll(tmpKey); // 全てのキーの入力状態を得る
for (int i = 0; i < 256; i++) {
if (tmpKey[i] != 0) { // i番のキーコードに対応するキーが押されていたら
Key[i]++; // 加算
}
else { // 押されていなければ
Key[i] = 0; // 0にする
}
}
return 0;
}
// メニュー項目の表示に必要な構造体を用意する
typedef struct {
int x, y; // 座標格納用変数
char name[128]; // 項目名格納用変数
} MenuElement_t;
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
SetBackgroundColor(255, 255, 255);
ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen(DX_SCREEN_BACK); //ウィンドウモード変更と初期化と裏画面設定
SetMainWindowText("スコア画面"); //ウインドウのタイトルを設定
SetGraphMode(800, 600, 32); //画面の解像度指定
// メニュー項目要素を2つ作る
MenuElement_t MenuElement[2] = {
{ 270, 400, "もう一度プレイする" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
{ 300, 450, "タイトルへ戻る" },
};
int SelectNum = 0; // 現在の選択番号
// while(裏画面を表画面に反映, メッセージ処理, 画面クリア, キー更新)
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
// 計算フェーズ
if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理
SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)
for (int i = 0; i < 2; i++) { // メニュー項目数である2個ループ処理
if (i == SelectNum) { // 今処理しているのが、選択番号と同じ要素なら
MenuElement[i].x = 270; // 座標を270にする
}
else { // 今処理しているのが、選択番号以外なら
MenuElement[i].x = 300;// 座標を300にする
}
}
}
// 描画フェーズ
LoadGraphScreen(0, 0, "hanakazari_waku_ao.png", TRUE); //背景
LoadGraphScreen(270, 75, "cooltext373678716545718.png", TRUE); //スコアロゴ
for (int i = 0; i < 5; i++) { // メニュー項目を描画
DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
SetFontSize(32);
SetFontThickness(4);
ChangeFontType(DX_FONTTYPE_ANTIALIASING);
}
}
DxLib_End(); // DXライブラリ終了処理
return 0;
}
Re: ゲームの画面切り替えについて
Posted: 2021年1月20日(水) 19:36
by 参照魚
まずは各画面をサブルーチン化するところから始めてください。例えばタイトル画面なら、int WINAPI WinMain を int SceneTitle(void) に変更します。そして、そのサブルーチンからDxLibのシステムの初期化と後始末に関連する部分を削除します。タイトル画面なら、ChangeWindowMode, DxLib_Init,SetDrawScreen,DxLinEnd です。次に While ループを外します。これでビルドが通るところまで行ってみてください。最後のリンクでWinMainが無いというエラーがでますが、それは次の段階になります。
Re: ゲームの画面切り替えについて
Posted: 2021年1月21日(木) 09:11
by souta
このような感じですか?
コード:
#include "DxLib.h"
#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅
#define LANE_SIZE 1 //レーンの数
#define BAR_SIZE 40 //1レーンあたりの最大bar数
int Key[256]; // キーが押されているフレーム数を格納する
// キーの入力状態を更新する
int gpUpdateKey() {
char tmpKey[256]; // 現在のキーの入力状態を格納する
GetHitKeyStateAll(tmpKey); // 全てのキーの入力状態を得る
for (int i = 0; i < 256; i++) {
if (tmpKey[i] != 0) { // i番のキーコードに対応するキーが押されていたら
Key[i]++; // 加算
}
else { // 押されていなければ
Key[i] = 0; // 0にする
}
}
return 0;
}
// メニュー項目の表示に必要な構造体を用意する
typedef struct {
int x, y; // 座標格納用変数
char name[128]; // 項目名格納用変数
} MenuElement_t;
int SceneTitle(void) {
SetGraphMode(800, 600, 32); //画面の解像度指定
// メニュー項目要素を2つ作る
MenuElement_t MenuElement[2] = {
{ 350, 300, "ゲームスタート" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
{ 380, 400, "ゲーム終了" },
};
int SelectNum = 0; // 現在の選択番号
// while(裏画面を表画面に反映, メッセージ処理, 画面クリア, キー更新)
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
// 計算フェーズ
if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理
SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)
for (int i = 0; i < 2; i++) { // メニュー項目数である2個ループ処理
if (i == SelectNum) { // 今処理しているのが、選択番号と同じ要素なら
MenuElement[i].x = 350; // 座標を320にする
}
else { // 今処理しているのが、選択番号以外なら
MenuElement[i].x = 380;// 座標を350にする
}
}
}
// 描画フェーズ
LoadGraphScreen(0, 0, "gahag-0073412840-1.png", TRUE); //背景
LoadGraphScreen(220, 75, "cooltext373677233987331.png", TRUE); //タイトルロゴ
for (int i = 0; i < 5; i++) { // メニュー項目を描画
DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
SetFontSize(32);
SetFontThickness(4);
ChangeFontType(DX_FONTTYPE_ANTIALIASING);
}
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
char buf[256]; //キー押下状態格納用配列
int key[LANE_SIZE] = {
KEY_INPUT_A
};
bool bar_f[LANE_SIZE][BAR_SIZE]; //barの存在フラグ
float bar_y[LANE_SIZE][BAR_SIZE]; //barのY座標
for (int j = 0; j < BAR_SIZE; j++) {
for (int i = 0; i < LANE_SIZE; i++) {
bar_f[i][j] = false; //全てにfalseを代入
}
}
LONGLONG start_time; //開始した時刻
LONGLONG now_time; //現在のフレームの時刻
int currentTime; //開始してからの経過時間
int counter = 0;
const int bpm = 120;
SetMainWindowText("リズムの達人"); //ウインドウのタイトルを設定
ChangeWindowMode(TRUE); //ウィンドウモードで起動
SetGraphMode(WIN_W, WIN_H, 32); //画面の解像度指定
SetWindowSizeChangeEnableFlag(FALSE); //画面サイズ変更不可
if (DxLib_Init() == -1) { return -1; } //DxLib初期化処理
SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定
enum judge_value {
NONE, GOOD, MISS
};
const int JUDGE_DISPLAY_TIME = 30; // 判定を表示する時間 (フレーム数)
judge_value judge = NONE; // 表示中の判定
int judge_time = 10; // 判定を表示する残り時間 (フレーム数)
//while(裏画面を表画面に反映, メッセージ処理, 画面クリア)
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0) {
LoadGraphScreen(1, 1, "a0.png", TRUE);
if (buf[KEY_INPUT_ESCAPE] == 1) {
break; // 終了
}
//時間関係
if (counter == 0) {
start_time = GetNowHiPerformanceCount();
}
now_time = GetNowHiPerformanceCount();
currentTime = (int)((now_time - start_time) / 1000); // ms
//bar生成
if (currentTime >= 550000 / bpm * counter) {
for (int i = 0; i < LANE_SIZE; i++) {
bar_f[i][counter % BAR_SIZE] = true;
bar_y[i][counter % BAR_SIZE] = -100.f;
}
counter++;
}
//DrawFormatString(100, 100, GetColor(255, 255, 255), "currentTime---%d", currentTime);
//bar座標更新
for (int i = 0; i < LANE_SIZE; i++) {
for (int j = 0; j < BAR_SIZE; j++) {
if (bar_f[i][j]) {
bar_y[i][j] += 4.f;
//DrawFormatString(100, 120, GetColor(255, 255, 0), "bar_y[i][j]---%f", bar_y[i][j]);
if (bar_y[i][j] > WIN_H + 10) {
bar_f[i][j] = false; //画面外に出たらfalse
// MISSを表示させる
judge = MISS;
DrawFormatString(10, 10, GetColor(0, 0, 255), "MISS");
judge_time = JUDGE_DISPLAY_TIME;
}
}
}
}
// 判定
GetHitKeyStateAll(buf);
for (int i = 0; i < LANE_SIZE; i++) {
for (int j = 0; j < BAR_SIZE; j++) {
if (bar_f[i][j]) {
if (WIN_H / 5 * 4 - 30 < bar_y[i][j] && bar_y[i][j] < WIN_H / 5 * 4 + 30) {
if (buf[key[i]] == 1) {
bar_f[i][j] = false;
// GOODを表示させる
judge = GOOD;
DrawFormatString(10, 10, GetColor(255, 0, 0), "GOOD");
judge_time = JUDGE_DISPLAY_TIME;
}
}
}
}
}
if (judge != NONE) {
if (judge == GOOD) {
DrawFormatString(10, 10, GetColor(255, 0, 0), "GOOD");
// GOODを描画する (テキスト・画像など)
}
else if (judge == MISS) {
DrawFormatString(10, 10, GetColor(0, 0, 255), "MISS");
// MISSを描画する (テキスト・画像など)
}
judge_time--;
if (judge_time <= 0) judge = NONE; // 指定の時間が経過したら、判定を消す
}
//判定ライン描画
DrawLine(0, WIN_H / 5 * 4, WIN_W, WIN_H / 5 * 4, GetColor(255, 255, 255));
DrawCircleAA(400.f, 480.f, 45.f, 60.f, GetColor(255, 255, 255), FALSE);
//bar描画
for (int i = 0; i < LANE_SIZE; i++) {
for (int j = 0; j < BAR_SIZE; j++) {
if (bar_f[i][j]) {
DrawCircleAA(400.f + i * 1.f, bar_y[i][j] - 10.f,
30.f + 1.f + i * 1.f, bar_y[i][j] + 10.f, GetColor(0, 255, 0), TRUE);
}
}
}
}
DxLib_End(); //DxLibの終了処理
return 0; //正常終了
}
int Key[256]; // キーが押されているフレーム数を格納する
// キーの入力状態を更新する
int gpUpdateKey() {
char tmpKey[256]; // 現在のキーの入力状態を格納する
GetHitKeyStateAll(tmpKey); // 全てのキーの入力状態を得る
for (int i = 0; i < 256; i++) {
if (tmpKey[i] != 0) { // i番のキーコードに対応するキーが押されていたら
Key[i]++; // 加算
}
else { // 押されていなければ
Key[i] = 0; // 0にする
}
}
return 0;
}
// メニュー項目の表示に必要な構造体を用意する
typedef struct {
int x, y; // 座標格納用変数
char name[128]; // 項目名格納用変数
} MenuElement_t;
int SceneScore(void) {
SetBackgroundColor(255, 255, 255);
ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen(DX_SCREEN_BACK); //ウィンドウモード変更と初期化と裏画面設定
SetMainWindowText("スコア画面"); //ウインドウのタイトルを設定
SetGraphMode(800, 600, 32); //画面の解像度指定
// メニュー項目要素を2つ作る
MenuElement_t MenuElement[2] = {
{ 270, 400, "もう一度プレイする" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
{ 300, 450, "タイトルへ戻る" },
};
int SelectNum = 0; // 現在の選択番号
// while(裏画面を表画面に反映, メッセージ処理, 画面クリア, キー更新)
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
// 計算フェーズ
if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理
SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)
for (int i = 0; i < 2; i++) { // メニュー項目数である2個ループ処理
if (i == SelectNum) { // 今処理しているのが、選択番号と同じ要素なら
MenuElement[i].x = 270; // 座標を270にする
}
else { // 今処理しているのが、選択番号以外なら
MenuElement[i].x = 300;// 座標を300にする
}
}
}
// 描画フェーズ
LoadGraphScreen(0, 0, "hanakazari_waku_ao.png", TRUE); //背景
LoadGraphScreen(270, 75, "cooltext373678716545718.png", TRUE); //スコアロゴ
for (int i = 0; i < 5; i++) { // メニュー項目を描画
DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
SetFontSize(32);
SetFontThickness(4);
ChangeFontType(DX_FONTTYPE_ANTIALIASING);
}
}
return 0;
}
Re: ゲームの画面切り替えについて
Posted: 2021年1月21日(木) 18:16
by 参照魚
SceneTitle,SceneScoreの中にあるwhile (ScreenFlip() == 0...){ コード }の部分は、whileループを外して、中のコードを剥き出しにします。あと、ゲーム画面のコードもSceneGameにします。WinMain部分はその次に考えます。
Re: ゲームの画面切り替えについて
Posted: 2021年1月21日(木) 20:10
by souta
こうですか?
コード:
#include "DxLib.h"
#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅
#define LANE_SIZE 1 //レーンの数
#define BAR_SIZE 40 //1レーンあたりの最大bar数
int Key[256]; // キーが押されているフレーム数を格納する
// キーの入力状態を更新する
int gpUpdateKey() {
char tmpKey[256]; // 現在のキーの入力状態を格納する
GetHitKeyStateAll(tmpKey); // 全てのキーの入力状態を得る
for (int i = 0; i < 256; i++) {
if (tmpKey[i] != 0) { // i番のキーコードに対応するキーが押されていたら
Key[i]++; // 加算
}
else { // 押されていなければ
Key[i] = 0; // 0にする
}
}
return 0;
}
// メニュー項目の表示に必要な構造体を用意する
typedef struct {
int x, y; // 座標格納用変数
char name[128]; // 項目名格納用変数
} MenuElement_t;
int SceneTitle(void) {
SetGraphMode(800, 600, 32); //画面の解像度指定
// メニュー項目要素を2つ作る
MenuElement_t MenuElement[2] = {
{ 350, 300, "ゲームスタート" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
{ 380, 400, "ゲーム終了" },
};
int SelectNum = 0; // 現在の選択番号
// while(裏画面を表画面に反映, メッセージ処理, 画面クリア, キー更新)
// 計算フェーズ
if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理
SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)
for (int i = 0; i < 2; i++) { // メニュー項目数である2個ループ処理
if (i == SelectNum) { // 今処理しているのが、選択番号と同じ要素なら
MenuElement[i].x = 350; // 座標を320にする
}
else { // 今処理しているのが、選択番号以外なら
MenuElement[i].x = 380;// 座標を350にする
}
}
}
// 描画フェーズ
LoadGraphScreen(0, 0, "gahag-0073412840-1.png", TRUE); //背景
LoadGraphScreen(220, 75, "cooltext373677233987331.png", TRUE); //タイトルロゴ
for (int i = 0; i < 5; i++) { // メニュー項目を描画
DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
SetFontSize(32);
SetFontThickness(4);
ChangeFontType(DX_FONTTYPE_ANTIALIASING);
}
}
return 0;
int SceneGame{
char buf[256]; //キー押下状態格納用配列
int key[LANE_SIZE] = {
KEY_INPUT_A
};
bool bar_f[LANE_SIZE][BAR_SIZE]; //barの存在フラグ
float bar_y[LANE_SIZE][BAR_SIZE]; //barのY座標
for (int j = 0; j < BAR_SIZE; j++) {
for (int i = 0; i < LANE_SIZE; i++) {
bar_f[i][j] = false; //全てにfalseを代入
}
}
LONGLONG start_time; //開始した時刻
LONGLONG now_time; //現在のフレームの時刻
int currentTime; //開始してからの経過時間
int counter = 0;
const int bpm = 120;
SetMainWindowText("リズムの達人"); //ウインドウのタイトルを設定
ChangeWindowMode(TRUE); //ウィンドウモードで起動
SetGraphMode(WIN_W, WIN_H, 32); //画面の解像度指定
SetWindowSizeChangeEnableFlag(FALSE); //画面サイズ変更不可
if (DxLib_Init() == -1) { return -1; } //DxLib初期化処理
SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定
enum judge_value {
NONE, GOOD, MISS
};
const int JUDGE_DISPLAY_TIME = 30; // 判定を表示する時間 (フレーム数)
judge_value judge = NONE; // 表示中の判定
int judge_time = 10; // 判定を表示する残り時間 (フレーム数)
//while(裏画面を表画面に反映, メッセージ処理, 画面クリア)
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0) {
LoadGraphScreen(1, 1, "a0.png", TRUE);
if (buf[KEY_INPUT_ESCAPE] == 1) {
break; // 終了
}
//時間関係
if (counter == 0) {
start_time = GetNowHiPerformanceCount();
}
now_time = GetNowHiPerformanceCount();
currentTime = (int)((now_time - start_time) / 1000); // ms
//bar生成
if (currentTime >= 550000 / bpm * counter) {
for (int i = 0; i < LANE_SIZE; i++) {
bar_f[i][counter % BAR_SIZE] = true;
bar_y[i][counter % BAR_SIZE] = -100.f;
}
counter++;
}
//DrawFormatString(100, 100, GetColor(255, 255, 255), "currentTime---%d", currentTime);
//bar座標更新
for (int i = 0; i < LANE_SIZE; i++) {
for (int j = 0; j < BAR_SIZE; j++) {
if (bar_f[i][j]) {
bar_y[i][j] += 4.f;
//DrawFormatString(100, 120, GetColor(255, 255, 0), "bar_y[i][j]---%f", bar_y[i][j]);
if (bar_y[i][j] > WIN_H + 10) {
bar_f[i][j] = false; //画面外に出たらfalse
// MISSを表示させる
judge = MISS;
DrawFormatString(10, 10, GetColor(0, 0, 255), "MISS");
judge_time = JUDGE_DISPLAY_TIME;
}
}
}
}
// 判定
GetHitKeyStateAll(buf);
for (int i = 0; i < LANE_SIZE; i++) {
for (int j = 0; j < BAR_SIZE; j++) {
if (bar_f[i][j]) {
if (WIN_H / 5 * 4 - 30 < bar_y[i][j] && bar_y[i][j] < WIN_H / 5 * 4 + 30) {
if (buf[key[i]] == 1) {
bar_f[i][j] = false;
// GOODを表示させる
judge = GOOD;
DrawFormatString(10, 10, GetColor(255, 0, 0), "GOOD");
judge_time = JUDGE_DISPLAY_TIME;
}
}
}
}
}
if (judge != NONE) {
if (judge == GOOD) {
DrawFormatString(10, 10, GetColor(255, 0, 0), "GOOD");
// GOODを描画する (テキスト・画像など)
}
else if (judge == MISS) {
DrawFormatString(10, 10, GetColor(0, 0, 255), "MISS");
// MISSを描画する (テキスト・画像など)
}
judge_time--;
if (judge_time <= 0) judge = NONE; // 指定の時間が経過したら、判定を消す
}
//判定ライン描画
DrawLine(0, WIN_H / 5 * 4, WIN_W, WIN_H / 5 * 4, GetColor(255, 255, 255));
DrawCircleAA(400.f, 480.f, 45.f, 60.f, GetColor(255, 255, 255), FALSE);
//bar描画
for (int i = 0; i < LANE_SIZE; i++) {
for (int j = 0; j < BAR_SIZE; j++) {
if (bar_f[i][j]) {
DrawCircleAA(400.f + i * 1.f, bar_y[i][j] - 10.f,
30.f + 1.f + i * 1.f, bar_y[i][j] + 10.f, GetColor(0, 255, 0), TRUE);
}
}
}
}
DxLib_End(); //DxLibの終了処理
return 0; //正常終了
}
int Key[256]; // キーが押されているフレーム数を格納する
// キーの入力状態を更新する
int gpUpdateKey() {
char tmpKey[256]; // 現在のキーの入力状態を格納する
GetHitKeyStateAll(tmpKey); // 全てのキーの入力状態を得る
for (int i = 0; i < 256; i++) {
if (tmpKey[i] != 0) { // i番のキーコードに対応するキーが押されていたら
Key[i]++; // 加算
}
else { // 押されていなければ
Key[i] = 0; // 0にする
}
}
return 0;
}
// メニュー項目の表示に必要な構造体を用意する
typedef struct {
int x, y; // 座標格納用変数
char name[128]; // 項目名格納用変数
} MenuElement_t;
int SceneScore(void) {
SetBackgroundColor(255, 255, 255);
ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen(DX_SCREEN_BACK); //ウィンドウモード変更と初期化と裏画面設定
SetMainWindowText("スコア画面"); //ウインドウのタイトルを設定
SetGraphMode(800, 600, 32); //画面の解像度指定
// メニュー項目要素を2つ作る
MenuElement_t MenuElement[2] = {
{ 270, 400, "もう一度プレイする" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
{ 300, 450, "タイトルへ戻る" },
};
int SelectNum = 0; // 現在の選択番号
// while(裏画面を表画面に反映, メッセージ処理, 画面クリア, キー更新)
// 計算フェーズ
if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理
SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)
for (int i = 0; i < 2; i++) { // メニュー項目数である2個ループ処理
if (i == SelectNum) { // 今処理しているのが、選択番号と同じ要素なら
MenuElement[i].x = 270; // 座標を270にする
}
else { // 今処理しているのが、選択番号以外なら
MenuElement[i].x = 300;// 座標を300にする
}
}
}
// 描画フェーズ
LoadGraphScreen(0, 0, "hanakazari_waku_ao.png", TRUE); //背景
LoadGraphScreen(270, 75, "cooltext373678716545718.png", TRUE); //スコアロゴ
for (int i = 0; i < 5; i++) { // メニュー項目を描画
DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
SetFontSize(32);
SetFontThickness(4);
ChangeFontType(DX_FONTTYPE_ANTIALIASING);
}
}
return 0;
Re: ゲームの画面切り替えについて
Posted: 2021年1月21日(木) 20:55
by 参照魚
SceneGameについてもSceneTitle,SceneScoreと同様にDxLibのシステムの初期化と後始末に関連する部分を削除して、whileループを外します。各画面のコードはファイルを分けた方が管理しやすいので、それぞれSceneGame.c SceneTitle.c SceneScore.cに記述してください。
Re: ゲームの画面切り替えについて
Posted: 2021年1月22日(金) 09:57
by souta
直しました
<タイトルのコード>
コード:
int Key[256]; // キーが押されているフレーム数を格納する
// キーの入力状態を更新する
int gpUpdateKey() {
char tmpKey[256]; // 現在のキーの入力状態を格納する
GetHitKeyStateAll(tmpKey); // 全てのキーの入力状態を得る
for (int i = 0; i < 256; i++) {
if (tmpKey[i] != 0) { // i番のキーコードに対応するキーが押されていたら
Key[i]++; // 加算
}
else { // 押されていなければ
Key[i] = 0; // 0にする
}
}
return 0;
}
// メニュー項目の表示に必要な構造体を用意する
typedef struct {
int x, y; // 座標格納用変数
char name[128]; // 項目名格納用変数
} MenuElement_t;
int SceneTitle(void) {
SetGraphMode(800, 600, 32); //画面の解像度指定
// メニュー項目要素を2つ作る
MenuElement_t MenuElement[2] = {
{ 350, 300, "ゲームスタート" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
{ 380, 400, "ゲーム終了" },
};
int SelectNum = 0; // 現在の選択番号
// 計算フェーズ
if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理
SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)
for (int i = 0; i < 2; i++) { // メニュー項目数である2個ループ処理
if (i == SelectNum) { // 今処理しているのが、選択番号と同じ要素なら
MenuElement[i].x = 350; // 座標を320にする
}
else { // 今処理しているのが、選択番号以外なら
MenuElement[i].x = 380;// 座標を350にする
}
}
}
// 描画フェーズ
LoadGraphScreen(0, 0, "gahag-0073412840-1.png", TRUE); //背景
LoadGraphScreen(220, 75, "cooltext373677233987331.png", TRUE); //タイトルロゴ
for (int i = 0; i < 5; i++) { // メニュー項目を描画
DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
SetFontSize(32);
SetFontThickness(4);
ChangeFontType(DX_FONTTYPE_ANTIALIASING);
}
}
return 0;
<ゲームのコード>
コード:
#include "DxLib.h"
#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅
#define LANE_SIZE 1 //レーンの数
#define BAR_SIZE 40 //1レーンあたりの最大bar数
int SceneGame{
char buf[256]; //キー押下状態格納用配列
int key[LANE_SIZE] = {
KEY_INPUT_A
};
bool bar_f[LANE_SIZE][BAR_SIZE]; //barの存在フラグ
float bar_y[LANE_SIZE][BAR_SIZE]; //barのY座標
for (int j = 0; j < BAR_SIZE; j++) {
for (int i = 0; i < LANE_SIZE; i++) {
bar_f[i][j] = false; //全てにfalseを代入
}
}
LONGLONG start_time; //開始した時刻
LONGLONG now_time; //現在のフレームの時刻
int currentTime; //開始してからの経過時間
int counter = 0;
const int bpm = 120;
SetMainWindowText("リズムの達人"); //ウインドウのタイトルを設定
ChangeWindowMode(TRUE); //ウィンドウモードで起動
SetGraphMode(WIN_W, WIN_H, 32); //画面の解像度指定
SetWindowSizeChangeEnableFlag(FALSE); //画面サイズ変更不可
SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定
enum judge_value {
NONE, GOOD, MISS
};
const int JUDGE_DISPLAY_TIME = 30; // 判定を表示する時間 (フレーム数)
judge_value judge = NONE; // 表示中の判定
int judge_time = 10; // 判定を表示する残り時間 (フレーム数)
LoadGraphScreen(1, 1, "a0.png", TRUE);
if (buf[KEY_INPUT_ESCAPE] == 1) {
break; // 終了
}
//時間関係
if (counter == 0) {
start_time = GetNowHiPerformanceCount();
}
now_time = GetNowHiPerformanceCount();
currentTime = (int)((now_time - start_time) / 1000); // ms
//bar生成
if (currentTime >= 550000 / bpm * counter) {
for (int i = 0; i < LANE_SIZE; i++) {
bar_f[i][counter % BAR_SIZE] = true;
bar_y[i][counter % BAR_SIZE] = -100.f;
}
counter++;
}
//bar座標更新
for (int i = 0; i < LANE_SIZE; i++) {
for (int j = 0; j < BAR_SIZE; j++) {
if (bar_f[i][j]) {
bar_y[i][j] += 4.f;
if (bar_y[i][j] > WIN_H + 10) {
bar_f[i][j] = false; //画面外に出たらfalse
// MISSを表示させる
judge = MISS;
DrawFormatString(10, 10, GetColor(0, 0, 255), "MISS");
judge_time = JUDGE_DISPLAY_TIME;
}
}
}
}
// 判定
GetHitKeyStateAll(buf);
for (int i = 0; i < LANE_SIZE; i++) {
for (int j = 0; j < BAR_SIZE; j++) {
if (bar_f[i][j]) {
if (WIN_H / 5 * 4 - 30 < bar_y[i][j] && bar_y[i][j] < WIN_H / 5 * 4 + 30) {
if (buf[key[i]] == 1) {
bar_f[i][j] = false;
// GOODを表示させる
judge = GOOD;
DrawFormatString(10, 10, GetColor(255, 0, 0), "GOOD");
judge_time = JUDGE_DISPLAY_TIME;
}
}
}
}
}
if (judge != NONE) {
if (judge == GOOD) {
DrawFormatString(10, 10, GetColor(255, 0, 0), "GOOD");
// GOODを描画する (テキスト・画像など)
}
else if (judge == MISS) {
DrawFormatString(10, 10, GetColor(0, 0, 255), "MISS");
// MISSを描画する (テキスト・画像など)
}
judge_time--;
if (judge_time <= 0) judge = NONE; // 指定の時間が経過したら、判定を消す
}
//判定ライン描画
DrawLine(0, WIN_H / 5 * 4, WIN_W, WIN_H / 5 * 4, GetColor(255, 255, 255));
DrawCircleAA(400.f, 480.f, 45.f, 60.f, GetColor(255, 255, 255), FALSE);
//bar描画
for (int i = 0; i < LANE_SIZE; i++) {
for (int j = 0; j < BAR_SIZE; j++) {
if (bar_f[i][j]) {
DrawCircleAA(400.f + i * 1.f, bar_y[i][j] - 10.f,
30.f + 1.f + i * 1.f, bar_y[i][j] + 10.f, GetColor(0, 255, 0), TRUE);
}
}
}
}
return 0; //正常終了
<スコアのコード>
コード:
int Key[256]; // キーが押されているフレーム数を格納する
// キーの入力状態を更新する
int gpUpdateKey() {
char tmpKey[256]; // 現在のキーの入力状態を格納する
GetHitKeyStateAll(tmpKey); // 全てのキーの入力状態を得る
for (int i = 0; i < 256; i++) {
if (tmpKey[i] != 0) { // i番のキーコードに対応するキーが押されていたら
Key[i]++; // 加算
}
else { // 押されていなければ
Key[i] = 0; // 0にする
}
}
return 0;
}
// メニュー項目の表示に必要な構造体を用意する
typedef struct {
int x, y; // 座標格納用変数
char name[128]; // 項目名格納用変数
} MenuElement_t;
int SceneScore(void) {
SetBackgroundColor(255, 255, 255);
ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen(DX_SCREEN_BACK); //ウィンドウモード変更と初期化と裏画面設定
SetMainWindowText("スコア画面"); //ウインドウのタイトルを設定
SetGraphMode(800, 600, 32); //画面の解像度指定
// メニュー項目要素を2つ作る
MenuElement_t MenuElement[2] = {
{ 270, 400, "もう一度プレイする" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
{ 300, 450, "タイトルへ戻る" },
};
int SelectNum = 0; // 現在の選択番号
// 計算フェーズ
if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理
SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)
for (int i = 0; i < 2; i++) { // メニュー項目数である2個ループ処理
if (i == SelectNum) { // 今処理しているのが、選択番号と同じ要素なら
MenuElement[i].x = 270; // 座標を270にする
}
else { // 今処理しているのが、選択番号以外なら
MenuElement[i].x = 300;// 座標を300にする
}
}
}
// 描画フェーズ
LoadGraphScreen(0, 0, "hanakazari_waku_ao.png", TRUE); //背景
LoadGraphScreen(270, 75, "cooltext373678716545718.png", TRUE); //スコアロゴ
for (int i = 0; i < 5; i++) { // メニュー項目を描画
DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
SetFontSize(32);
SetFontThickness(4);
ChangeFontType(DX_FONTTYPE_ANTIALIASING);
}
}
return 0;
Re: ゲームの画面切り替えについて
Posted: 2021年1月22日(金) 22:02
by 参照魚
・いずれも最後の return の位置がおかしいです
・int SceneGameの書式がおかしいです
・while ループを外したことに伴い、while から抜け出す break; は return 0; に変更する必要があります。
編集するごとにビルドが通るかこまめに確認しないとあとが大変になるので注意が必要です。
Re: ゲームの画面切り替えについて
Posted: 2021年1月22日(金) 23:39
by souta
一応通るようになりました!
<タイトルのコード>
コード:
#include "DxLib.h"
int Key[256]; // キーが押されているフレーム数を格納する
// キーの入力状態を更新する
int gpUpdateKey() {
char tmpKey[256]; // 現在のキーの入力状態を格納する
GetHitKeyStateAll(tmpKey); // 全てのキーの入力状態を得る
for (int i = 0; i < 256; i++) {
if (tmpKey[i] != 0) { // i番のキーコードに対応するキーが押されていたら
Key[i]++; // 加算
}
else { // 押されていなければ
Key[i] = 0; // 0にする
}
}
return 0;
}
// メニュー項目の表示に必要な構造体を用意する
typedef struct {
int x, y; // 座標格納用変数
char name[128]; // 項目名格納用変数
} MenuElement_t;
int SceneTitle(void) {
SetGraphMode(800, 600, 32); //画面の解像度指定
// メニュー項目要素を2つ作る
MenuElement_t MenuElement[2] = {
{ 350, 300, "ゲームスタート" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
{ 380, 400, "ゲーム終了" },
};
int SelectNum = 0; // 現在の選択番号
// 計算フェーズ
if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理
SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)
for (int i = 0; i < 2; i++) { // メニュー項目数である2個ループ処理
if (i == SelectNum) { // 今処理しているのが、選択番号と同じ要素なら
MenuElement[i].x = 350; // 座標を320にする
}
else { // 今処理しているのが、選択番号以外なら
MenuElement[i].x = 380;// 座標を350にする
}
}
}
// 描画フェーズ
LoadGraphScreen(0, 0, "gahag-0073412840-1.png", TRUE); //背景
LoadGraphScreen(220, 75, "cooltext373677233987331.png", TRUE); //タイトルロゴ
for (int i = 0; i < 5; i++) { // メニュー項目を描画
DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
SetFontSize(32);
SetFontThickness(4);
ChangeFontType(DX_FONTTYPE_ANTIALIASING);
}
}
<ゲームのコード>
コード:
#include "DxLib.h"
#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅
#define LANE_SIZE 1 //レーンの数
#define BAR_SIZE 40 //1レーンあたりの最大bar数
int SceneGame(void) {
char buf[256]; //キー押下状態格納用配列
int key[LANE_SIZE] = {
KEY_INPUT_A
};
bool bar_f[LANE_SIZE][BAR_SIZE]; //barの存在フラグ
float bar_y[LANE_SIZE][BAR_SIZE]; //barのY座標
for (int j = 0; j < BAR_SIZE; j++) {
for (int i = 0; i < LANE_SIZE; i++) {
bar_f[i][j] = false; //全てにfalseを代入
}
}
LONGLONG start_time; //開始した時刻
LONGLONG now_time; //現在のフレームの時刻
int currentTime; //開始してからの経過時間
int counter = 0;
const int bpm = 120;
SetMainWindowText("リズムの達人"); //ウインドウのタイトルを設定
ChangeWindowMode(TRUE); //ウィンドウモードで起動
SetGraphMode(WIN_W, WIN_H, 32); //画面の解像度指定
SetWindowSizeChangeEnableFlag(FALSE); //画面サイズ変更不可
SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定
enum judge_value {
NONE, GOOD, MISS
};
const int JUDGE_DISPLAY_TIME = 30; // 判定を表示する時間 (フレーム数)
judge_value judge = NONE; // 表示中の判定
int judge_time = 10; // 判定を表示する残り時間 (フレーム数)
LoadGraphScreen(1, 1, "a0.png", TRUE);
if (buf[KEY_INPUT_ESCAPE] == 1) {
return 0; // 終了
}
//時間関係
if (counter == 0) {
start_time = GetNowHiPerformanceCount();
}
now_time = GetNowHiPerformanceCount();
currentTime = (int)((now_time - start_time) / 1000); // ms
//bar生成
if (currentTime >= 550000 / bpm * counter) {
for (int i = 0; i < LANE_SIZE; i++) {
bar_f[i][counter % BAR_SIZE] = true;
bar_y[i][counter % BAR_SIZE] = -100.f;
}
counter++;
}
//bar座標更新
for (int i = 0; i < LANE_SIZE; i++) {
for (int j = 0; j < BAR_SIZE; j++) {
if (bar_f[i][j]) {
bar_y[i][j] += 4.f;
if (bar_y[i][j] > WIN_H + 10) {
bar_f[i][j] = false; //画面外に出たらfalse
// MISSを表示させる
judge = MISS;
DrawFormatString(10, 10, GetColor(0, 0, 255), "MISS");
judge_time = JUDGE_DISPLAY_TIME;
}
}
}
}
// 判定
GetHitKeyStateAll(buf);
for (int i = 0; i < LANE_SIZE; i++) {
for (int j = 0; j < BAR_SIZE; j++) {
if (bar_f[i][j]) {
if (WIN_H / 5 * 4 - 30 < bar_y[i][j] && bar_y[i][j] < WIN_H / 5 * 4 + 30) {
if (buf[key[i]] == 1) {
bar_f[i][j] = false;
// GOODを表示させる
judge = GOOD;
DrawFormatString(10, 10, GetColor(255, 0, 0), "GOOD");
judge_time = JUDGE_DISPLAY_TIME;
}
}
}
}
}
if (judge != NONE) {
if (judge == GOOD) {
DrawFormatString(10, 10, GetColor(255, 0, 0), "GOOD");
// GOODを描画する (テキスト・画像など)
}
else if (judge == MISS) {
DrawFormatString(10, 10, GetColor(0, 0, 255), "MISS");
// MISSを描画する (テキスト・画像など)
}
judge_time--;
if (judge_time <= 0) judge = NONE; // 指定の時間が経過したら、判定を消す
}
//判定ライン描画
DrawLine(0, WIN_H / 5 * 4, WIN_W, WIN_H / 5 * 4, GetColor(255, 255, 255));
DrawCircleAA(400.f, 480.f, 45.f, 60.f, GetColor(255, 255, 255), FALSE);
//bar描画
for (int i = 0; i < LANE_SIZE; i++) {
for (int j = 0; j < BAR_SIZE; j++) {
if (bar_f[i][j]) {
DrawCircleAA(400.f + i * 1.f, bar_y[i][j] - 10.f,
30.f + 1.f + i * 1.f, bar_y[i][j] + 10.f, GetColor(0, 255, 0), TRUE);
}
}
}
}
<スコアのコード>
コード:
#include "DxLib.h"
int Key[256]; // キーが押されているフレーム数を格納する
// キーの入力状態を更新する
int gpUpdateKey() {
char tmpKey[256]; // 現在のキーの入力状態を格納する
GetHitKeyStateAll(tmpKey); // 全てのキーの入力状態を得る
for (int i = 0; i < 256; i++) {
if (tmpKey[i] != 0) { // i番のキーコードに対応するキーが押されていたら
Key[i]++; // 加算
}
else { // 押されていなければ
Key[i] = 0; // 0にする
}
}
return 0;
}
// メニュー項目の表示に必要な構造体を用意する
typedef struct {
int x, y; // 座標格納用変数
char name[128]; // 項目名格納用変数
} MenuElement_t;
int SceneScore(void) {
SetBackgroundColor(255, 255, 255);
SetMainWindowText("スコア画面"); //ウインドウのタイトルを設定
SetGraphMode(800, 600, 32); //画面の解像度指定
// メニュー項目要素を2つ作る
MenuElement_t MenuElement[2] = {
{ 270, 400, "もう一度プレイする" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
{ 300, 450, "タイトルへ戻る" },
};
int SelectNum = 0; // 現在の選択番号
// 計算フェーズ
if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理
SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)
for (int i = 0; i < 2; i++) { // メニュー項目数である2個ループ処理
if (i == SelectNum) { // 今処理しているのが、選択番号と同じ要素なら
MenuElement[i].x = 270; // 座標を270にする
}
else { // 今処理しているのが、選択番号以外なら
MenuElement[i].x = 300;// 座標を300にする
}
}
}
// 描画フェーズ
LoadGraphScreen(0, 0, "hanakazari_waku_ao.png", TRUE); //背景
LoadGraphScreen(270, 75, "cooltext373678716545718.png", TRUE); //スコアロゴ
for (int i = 0; i < 5; i++) { // メニュー項目を描画
DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
SetFontSize(32);
SetFontThickness(4);
ChangeFontType(DX_FONTTYPE_ANTIALIASING);
}
}
Re: ゲームの画面切り替えについて
Posted: 2021年1月23日(土) 00:05
by 参照魚
各画面のSceneXXXX関数内で定義している変数を関数の外に出してstaticを付けてください。
SceneTitle と SceneScore の int Key[256]だけはexternにします。また、int gpUpdateKey()関数はでは使用されていないので削除します。
<タイトルのコード>
コード:
#include "DxLib.h"
extern int Key[256]; // キーが押されているフレーム数を格納する
// メニュー項目の表示に必要な構造体を用意する
typedef struct {
int x, y; // 座標格納用変数
char name[128]; // 項目名格納用変数
} MenuElement_t;
static MenuElement_t MenuElement[2] = {
{ 350, 300, "ゲームスタート" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
{ 380, 400, "ゲーム終了" },
};
static int SelectNum = 0; // 現在の選択番号
int SceneTitle(void) {
// 計算フェーズ
if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理
SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)
for (int i = 0; i < 2; i++) { // メニュー項目数である2個ループ処理
if (i == SelectNum) { // 今処理しているのが、選択番号と同じ要素なら
MenuElement[i].x = 350; // 座標を320にする
}
else { // 今処理しているのが、選択番号以外なら
MenuElement[i].x = 380;// 座標を350にする
}
}
}
// 描画フェーズ
LoadGraphScreen(0, 0, "gahag-0073412840-1.png", TRUE); //背景
LoadGraphScreen(220, 75, "cooltext373677233987331.png", TRUE); //タイトルロゴ
for (int i = 0; i < 5; i++) { // メニュー項目を描画
DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
SetFontSize(32);
SetFontThickness(4);
ChangeFontType(DX_FONTTYPE_ANTIALIASING);
}
return 0;
}
<ゲームのコード>
コード:
#include "DxLib.h"
#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅
#define LANE_SIZE 1 //レーンの数
#define BAR_SIZE 40 //1レーンあたりの最大bar数
static char buf[256]; //キー押下状態格納用配列
static int key[LANE_SIZE] = {
KEY_INPUT_A
};
static bool bar_f[LANE_SIZE][BAR_SIZE] = {}; //barの存在フラグ
static float bar_y[LANE_SIZE][BAR_SIZE]; //barのY座標
static LONGLONG start_time; //開始した時刻
static LONGLONG now_time; //現在のフレームの時刻
static int currentTime; //開始してからの経過時間
static int counter = 0;
static const int bpm = 120;
enum judge_value {
NONE, GOOD, MISS
};
static const int JUDGE_DISPLAY_TIME = 30; // 判定を表示する時間 (フレーム数)
static judge_value judge = NONE; // 表示中の判定
static int judge_time = 10; // 判定を表示する残り時間 (フレーム数)
int SceneGame( void ){
LoadGraphScreen(1, 1, "a0.png", TRUE);
if (buf[KEY_INPUT_ESCAPE] == 1) {
return 0; // 終了
}
//時間関係
if (counter == 0) {
start_time = GetNowHiPerformanceCount();
}
now_time = GetNowHiPerformanceCount();
currentTime = (int)((now_time - start_time) / 1000); // ms
//bar生成
if (currentTime >= 550000 / bpm * counter) {
for (int i = 0; i < LANE_SIZE; i++) {
bar_f[i][counter % BAR_SIZE] = true;
bar_y[i][counter % BAR_SIZE] = -100.f;
}
counter++;
}
//bar座標更新
for (int i = 0; i < LANE_SIZE; i++) {
for (int j = 0; j < BAR_SIZE; j++) {
if (bar_f[i][j]) {
bar_y[i][j] += 4.f;
if (bar_y[i][j] > WIN_H + 10) {
bar_f[i][j] = false; //画面外に出たらfalse
// MISSを表示させる
judge = MISS;
DrawFormatString(10, 10, GetColor(0, 0, 255), "MISS");
judge_time = JUDGE_DISPLAY_TIME;
}
}
}
}
// 判定
GetHitKeyStateAll(buf);
for (int i = 0; i < LANE_SIZE; i++) {
for (int j = 0; j < BAR_SIZE; j++) {
if (bar_f[i][j]) {
if (WIN_H / 5 * 4 - 30 < bar_y[i][j] && bar_y[i][j] < WIN_H / 5 * 4 + 30) {
if (buf[key[i]] == 1) {
bar_f[i][j] = false;
// GOODを表示させる
judge = GOOD;
DrawFormatString(10, 10, GetColor(255, 0, 0), "GOOD");
judge_time = JUDGE_DISPLAY_TIME;
}
}
}
}
}
if (judge != NONE) {
if (judge == GOOD) {
DrawFormatString(10, 10, GetColor(255, 0, 0), "GOOD");
// GOODを描画する (テキスト・画像など)
}
else if (judge == MISS) {
DrawFormatString(10, 10, GetColor(0, 0, 255), "MISS");
// MISSを描画する (テキスト・画像など)
}
judge_time--;
if (judge_time <= 0) judge = NONE; // 指定の時間が経過したら、判定を消す
}
//判定ライン描画
DrawLine(0, WIN_H / 5 * 4, WIN_W, WIN_H / 5 * 4, GetColor(255, 255, 255));
DrawCircleAA(400.f, 480.f, 45.f, 60.f, GetColor(255, 255, 255), FALSE);
//bar描画
for (int i = 0; i < LANE_SIZE; i++) {
for (int j = 0; j < BAR_SIZE; j++) {
if (bar_f[i][j]) {
DrawCircleAA(400.f + i * 1.f, bar_y[i][j] - 10.f, 30.f + 1.f + i * 1.f, bar_y[i][j] + 10.f, GetColor(0, 255, 0), TRUE);
}
}
}
return 0; //正常終了
}
<スコアのコード>
コード:
#include "DxLib.h"
extern int Key[256]; // キーが押されているフレーム数を格納する
// メニュー項目の表示に必要な構造体を用意する
typedef struct {
int x, y; // 座標格納用変数
char name[128]; // 項目名格納用変数
} MenuElement_t;
static MenuElement_t MenuElement[2] = {
{ 270, 400, "もう一度プレイする" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
{ 300, 450, "タイトルへ戻る" },
};
static int SelectNum = 0; // 現在の選択番号
int SceneScore(void) {
// 計算フェーズ
if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理
SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)
for (int i = 0; i < 2; i++) { // メニュー項目数である2個ループ処理
if (i == SelectNum) { // 今処理しているのが、選択番号と同じ要素なら
MenuElement[i].x = 270; // 座標を270にする
}
else { // 今処理しているのが、選択番号以外なら
MenuElement[i].x = 300;// 座標を300にする
}
}
}
// 描画フェーズ
LoadGraphScreen(0, 0, "hanakazari_waku_ao.png", TRUE); //背景
LoadGraphScreen(270, 75, "cooltext373678716545718.png", TRUE); //スコアロゴ
for (int i = 0; i < 5; i++) { // メニュー項目を描画
DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
SetFontSize(32);
SetFontThickness(4);
ChangeFontType(DX_FONTTYPE_ANTIALIASING);
}
return 0;
}
Re: ゲームの画面切り替えについて
Posted: 2021年1月23日(土) 00:39
by 参照魚
WinMainはmain.cに作成してください。これまで各画面で行っていたDxLibの設定やWhileループはここで行います。while ループの中でここまでに作成したSceneTitle/SceneGame/SceneScoreを呼び出すことになります。どれを呼び出すかは変数(int SceneMode)を用意して切り替えます。タイトル画面が表示されるか確認してください。これでとりあえず画面切り替えの骨格は完成です。
コード:
#include "DxLib.h"
#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅
extern int gpUpdateKey();
static int SceneMode = 0;
extern SceneTitle( void );
extern SceneGame( void );
extern SceneScore( void );
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
ChangeWindowMode(TRUE); //ウィンドウモードで起動
SetGraphMode(WIN_W, WIN_H, 32); //画面の解像度指定
SetMainWindowText("リズムの達人"); //ウインドウのタイトルを設定
SetBackgroundColor(255, 255, 255);
if (DxLib_Init() == -1) { return -1; } //DxLib初期化処理
SetWindowSizeChangeEnableFlag(FALSE); //画面サイズ変更不可
SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
switch ( SceneMode ) {
case 0: SceneTitle(); break;
case 1: SceneGame(); break;
case 2: SceneScore(); break;
}
}
DxLib_End(); // DxLib終了処理
return 0;
}
int Key[256]; // キーが押されているフレーム数を格納する
// キーの入力状態を更新する
int gpUpdateKey() {
char tmpKey[256]; // 現在のキーの入力状態を格納する
GetHitKeyStateAll(tmpKey); // 全てのキーの入力状態を得る
for (int i = 0; i < 256; i++) {
if (tmpKey[i] != 0) { // i番のキーコードに対応するキーが押されていたら
Key[i]++; // 加算
}
else { // 押されていなければ
Key[i] = 0; // 0にする
}
}
return 0;
}
Re: ゲームの画面切り替えについて
Posted: 2021年1月23日(土) 00:51
by souta
アドバイスされたコードにしたらこのようなエラーが出ました。
・エラー LNK2001 外部シンボル "int * Key" (?Key@@3PAHA) は未解決です リズムゲーム 1行目
・エラー LNK2001 外部シンボル "int * Key" (?Key@@3PAHA) は未解決です リズムゲーム 1行目
・エラー LNK2019 未解決の外部シンボル _WinMain@16 が
関数 "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ) で参照されました リズムゲーム 1行目
・エラー LNK1120 2 件の未解決の外部参照 リズムゲーム 1行目
Re: ゲームの画面切り替えについて
Posted: 2021年1月23日(土) 00:55
by souta
すいません、追加のアドバイス試してみます!
Re: ゲームの画面切り替えについて
Posted: 2021年1月23日(土) 01:05
by souta
Main.cppを教えていただいた通り作成したのですが10行目11行目12行目のコードにエラーが出ます。
明示的な型がありません ('int' が想定されます) と表示されています。
Re: ゲームの画面切り替えについて
Posted: 2021年1月23日(土) 01:12
by 参照魚
戻り値の型が抜けていました。
extern SceneTitle( void );
extern SceneGame( void );
extern SceneScore( void );
↓
extern int SceneTitle( void );
extern int SceneGame( void );
extern int SceneScore( void );
Re: ゲームの画面切り替えについて
Posted: 2021年1月23日(土) 01:23
by souta
無事タイトル画面表示されました!!
Re: ゲームの画面切り替えについて
Posted: 2021年1月23日(土) 01:35
by 参照魚
キー入力でSceneModeを変更できるようにして各画面が出るか確認してください。
コード:
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
if (Key[KEY_INPUT_Z] == 1) { SceneMode = 0; }
if (Key[KEY_INPUT_X] == 1) { SceneMode = 1; }
if (Key[KEY_INPUT_C] == 1) { SceneMode = 2; }
switch ( SceneMode ) {
case 0: SceneTitle(); break;
case 1: SceneGame(); break;
case 2: SceneScore(); break;
}
}
なお、各画面は1回だけしか正常に実行されない可能性があります。例えばタイトル→ゲーム→タイトルと遷移した場合、2回目のタイトルで挙動が変になったり、最悪はハングするかもしれません。それへの対処は次の段階になります。
Re: ゲームの画面切り替えについて
Posted: 2021年1月23日(土) 15:32
by souta
27行目28行目29行目に 'Key': 定義されていない識別子です。とエラーが出ます。
<Main.p>
コード:
#include "DxLib.h"
#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅
extern int gpUpdateKey();
static int SceneMode = 0;
extern int SceneTitle(void);
extern int SceneGame(void);
extern int SceneScore(void);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
ChangeWindowMode(TRUE); //ウィンドウモードで起動
SetGraphMode(WIN_W, WIN_H, 32); //画面の解像度指定
SetMainWindowText("リズムの達人"); //ウインドウのタイトルを設定
SetBackgroundColor(255, 255, 255);
if (DxLib_Init() == -1) { return -1; } //DxLib初期化処理
SetWindowSizeChangeEnableFlag(FALSE); //画面サイズ変更不可
SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
if (Key[KEY_INPUT_Z] == 1) { SceneMode = 0; }
if (Key[KEY_INPUT_X] == 1) { SceneMode = 1; }
if (Key[KEY_INPUT_C] == 1) { SceneMode = 2; }
switch (SceneMode) {
case 0: SceneTitle(); break;
case 1: SceneGame(); break;
case 2: SceneScore(); break;
}
}
DxLib_End(); // DxLib終了処理
return 0;
}
int Key[256]; // キーが押されているフレーム数を格納する
// キーの入力状態を更新する
int gpUpdateKey() {
char tmpKey[256]; // 現在のキーの入力状態を格納する
GetHitKeyStateAll(tmpKey); // 全てのキーの入力状態を得る
for (int i = 0; i < 256; i++) {
if (tmpKey[i] != 0) { // i番のキーコードに対応するキーが押されていたら
Key[i]++; // 加算
}
else { // 押されていなければ
Key[i] = 0; // 0にする
}
}
return 0;
}
Re: ゲームの画面切り替えについて
Posted: 2021年1月23日(土) 19:18
by 参照魚
Keyは43行目に定義されています。使用する場所より前の適切な位置でextern 宣言をしてKeyを参照できるようにしてください。
Re: ゲームの画面切り替えについて
Posted: 2021年1月24日(日) 11:26
by souta
無事に切り替えできました。
Re: ゲームの画面切り替えについて
Posted: 2021年1月24日(日) 11:31
by souta
タイトル画面でゲームスタートとゲーム終了を選べるようにしたいのですが、ゲーム終了を入力したらウインドウを閉じるコードもよければ教えてほしいです!
Re: ゲームの画面切り替えについて
Posted: 2021年1月24日(日) 13:15
by 参照魚
実際に画面選択する前にもう少し準備が必要です。menu.hを作成して、main.c/SceneTitle.c/SceneGame.c/SceneScore.cのそれぞれでインクルードしてください。
<menu.h>
コード:
#pragma once
enum {
SCENE_GAMEOVER= -1,
SCENE_TITLE,
SCENE_GAME,
SCENE_SCORE,
};
画面切り替え用の変数SceneNextを追加する。
コード:
static int SceneMode = SCENE_TITLE;
static int SceneNext;
これまで数値で直接書いていた画面の番号をenumで置き換える。
コード:
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
switch (SceneMode) {
case SCENE_TITLE: SceneNext = SceneTitle(); break;
case SCENE_GAME: SceneNext = SceneGame(); break;
case SCENE_SCORE: SceneNext = SceneScore(); break;
}
if ( SceneNext == SCENE_GAMEOVER ) {
break;
}
}
Re: ゲームの画面切り替えについて
Posted: 2021年1月24日(日) 13:47
by souta
menu.hの3行目に ’}’が必要です とエラーが出ます。
main.pに識別子 "SCENE_GAMEOVER" が定義されていません 識別子 "SCENE_SCORE" が定義されていません
識別子 "SCENE_GAME" が定義されていません 識別子 "SCENE_TITLE" が定義されていません
識別子 "SCENE_TITLE" が定義されていません とエラーが出ます。
Re: ゲームの画面切り替えについて
Posted: 2021年1月24日(日) 14:15
by 参照魚
SCENE_GAMEOVER= -1, =が全角になってました。半角に修正してください。
Re: ゲームの画面切り替えについて
Posted: 2021年1月24日(日) 14:22
by 参照魚
ここまでの流れに直接関係ないですが、SceneTitle.c/SceneScore.cでMenuElement_tという同じ構造体をそれぞれのファイル内で宣言されています。複数のファイルで共通に使用される#defineや構造体はヘッダファイルに集約すると後々の管理/修正が容易になります。
<menu.h>
コード:
#pragma once
enum {
SCENE_GAMEOVER = -1,
SCENE_TITLE,
SCENE_GAME,
SCENE_SCORE,
};
// メニュー項目の表示に必要な構造体を用意する
typedef struct {
int x, y; // 座標格納用変数
char name[128]; // 項目名格納用変数
} MenuElement_t;
menu.hで宣言したら、SceneTitle.c/SceneScore.cからは削除します。
Re: ゲームの画面切り替えについて
Posted: 2021年1月24日(日) 14:42
by souta
main.pのエラーはどうやって直しますか?
"SCENE_GAMEOVER"と"SCENE_SCORE"と"SCENE_GAME"と"SCENE_TITLE"と"SCENE_TITLE" が定義されていませんとでます。
Re: ゲームの画面切り替えについて
Posted: 2021年1月24日(日) 15:10
by 参照魚
>main.c/SceneTitle.c/SceneGame.c/SceneScore.cのそれぞれでインクルードしてください。
main.cに#include "menu.h"するのを忘れていませんか?
Re: ゲームの画面切り替えについて
Posted: 2021年1月24日(日) 15:26
by souta
'SceneMode': 再定義されています。2 回以上初期化されています。とエラーが出ます。
コード:
#include "DxLib.h"
#include "menu.h"
#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅
extern int gpUpdateKey();
static int SceneMode = 0;
static int SceneMode = SCENE_TITLE;
static int SceneNext;
extern int SceneTitle(void);
extern int SceneGame(void);
extern int SceneScore(void);
extern int Key[256]; // キーが押されているフレーム数を格納する
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
ChangeWindowMode(TRUE); //ウィンドウモードで起動
SetGraphMode(WIN_W, WIN_H, 32); //画面の解像度指定
SetMainWindowText("リズムの達人"); //ウインドウのタイトルを設定
SetBackgroundColor(255, 255, 255);
if (DxLib_Init() == -1) { return -1; } //DxLib初期化処理
SetWindowSizeChangeEnableFlag(FALSE); //画面サイズ変更不可
SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
switch (SceneMode) {
case SCENE_TITLE: SceneNext = SceneTitle(); break;
case SCENE_GAME: SceneNext = SceneGame(); break;
case SCENE_SCORE: SceneNext = SceneScore(); break;
}
if (SceneNext == SCENE_GAMEOVER) {
break;
}
}
DxLib_End(); // DxLib終了処理
return 0;
}
int Key[256]; // キーが押されているフレーム数を格納する
// キーの入力状態を更新する
int gpUpdateKey() {
char tmpKey[256]; // 現在のキーの入力状態を格納する
GetHitKeyStateAll(tmpKey); // 全てのキーの入力状態を得る
for (int i = 0; i < 256; i++) {
if (tmpKey[i] != 0) { // i番のキーコードに対応するキーが押されていたら
Key[i]++; // 加算
}
else { // 押されていなければ
Key[i] = 0; // 0にする
}
}
return 0;
}
Re: ゲームの画面切り替えについて
Posted: 2021年1月24日(日) 17:36
by 参照魚
9行目の方のSceneMode = 0 は削除してください。
Re: ゲームの画面切り替えについて
Posted: 2021年1月25日(月) 09:05
by souta
ビルド通りました!
Re: ゲームの画面切り替えについて
Posted: 2021年1月25日(月) 20:20
by souta
切り替えの仕方はどうやってするのでしょうか?前のコードではキーボード入力で切り替えできていたのですが。
Re: ゲームの画面切り替えについて
Posted: 2021年1月25日(月) 22:43
by 参照魚
SceneTitle/SceneGame/SceneScoreの各関数は返り値にシーン番号を返すように修正してください。main.cの下記のswitch文は実行された各画面の返り値で次に実行する画面を受け取ります。
コード:
switch (SceneMode) {
case SCENE_TITLE: SceneNext = SceneTitle(); break;
case SCENE_GAME: SceneNext = SceneGame(); break;
case SCENE_SCORE: SceneNext = SceneScore(); break;
}
例えばSceneTitleであれば、概念的に下記のとおりとなります。
コード:
int SceneTitle( void )
:
省略
:
return SCENE_TITLE;
}
このままであればタイトル画面が実行されつづけます。キーボードの入力で切り替える場合は下記のようになります。
コード:
int SceneTitle( void )
:
省略
:
if ( Key[KEY_INPUT_A] == 1 ) { // キーの種類は適当
switch ( SelectNum ) {
case 0: return SCENE_GAME;
case 1: return SCENE_GAMEOVER;
}
}
return SCENE_TITLE;
}
Re: ゲームの画面切り替えについて
Posted: 2021年1月25日(月) 22:45
by 参照魚
main.cではSceneNextを受け取ってSceneModeを切り替えます。
コード:
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
switch (SceneMode) {
case SCENE_TITLE: SceneNext = SceneTitle(); break;
case SCENE_GAME: SceneNext = SceneGame(); break;
case SCENE_SCORE: SceneNext = SceneScore(); break;
}
if (SceneNext == SCENE_GAMEOVER) {
break;
}
if ( SceneNext != SceneMode ) {
SceneMode = SceneNext;
}
Re: ゲームの画面切り替えについて
Posted: 2021年1月25日(月) 23:25
by souta
タイトル画面の46行目47行目50行目に 識別子 "SCENE_TITLE" が定義されていません 識別子 "SCENE_GAME" が定義されていません 識別子 "SCENE_GAMEOVER" が定義されていません とそれぞれエラーが出ます。
<タイトル画面のコード>
コード:
#include "DxLib.h"
extern int Key[256]; // キーが押されているフレーム数を格納する
// メニュー項目の表示に必要な構造体を用意する
typedef struct {
int x, y; // 座標格納用変数
char name[128]; // 項目名格納用変数
} MenuElement_t;
static MenuElement_t MenuElement[2] = {
{ 300, 300, "ゲームスタート" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
{ 330, 400, "ゲーム終了" },
};
static int SelectNum = 0; // 現在の選択番号
int SceneTitle(void) {
LoadGraphScreen(0, 0, "001.png", TRUE); //背景
LoadGraphScreen(180, 120, "002.png", TRUE); //タイトルロゴ
// 計算フェーズ
if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理
SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)
for (int i = 0; i < 2; i++) { // メニュー項目数である2個ループ処理
if (i == SelectNum) { // 今処理しているのが、選択番号と同じ要素なら
MenuElement[i].x = 300; // 座標を320にする
}
else { // 今処理しているのが、選択番号以外なら
MenuElement[i].x = 330;// 座標を350にする
}
}
}
for (int i = 0; i < 5; i++) { // メニュー項目を描画
DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
SetFontSize(32);
SetFontThickness(4);
ChangeFontType(DX_FONTTYPE_ANTIALIASING);
}
if (Key[KEY_INPUT_Z] == 1) { // キーの種類は適当
switch (SelectNum) {
case 0: return SCENE_GAME;
case 1: return SCENE_GAMEOVER;
}
}
return SCENE_TITLE;
}
<Main.c>
コード:
#include "DxLib.h"
#include "menu.h"
#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅
extern int gpUpdateKey();
static int SceneMode = SCENE_TITLE;
static int SceneNext;
extern int SceneTitle(void);
extern int SceneGame(void);
extern int SceneScore(void);
extern int Key[256]; // キーが押されているフレーム数を格納する
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
ChangeWindowMode(TRUE); //ウィンドウモードで起動
SetGraphMode(WIN_W, WIN_H, 32); //画面の解像度指定
SetMainWindowText("リズムの達人"); //ウインドウのタイトルを設定
SetBackgroundColor(255, 255, 255);
if (DxLib_Init() == -1) { return -1; } //DxLib初期化処理
SetWindowSizeChangeEnableFlag(FALSE); //画面サイズ変更不可
SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
switch (SceneMode) {
case SCENE_TITLE: SceneNext = SceneTitle(); break;
case SCENE_GAME: SceneNext = SceneGame(); break;
case SCENE_SCORE: SceneNext = SceneScore(); break;
}
if (SceneNext == SCENE_GAMEOVER) {
break;
}
if (SceneNext != SceneMode) {
SceneMode = SceneNext;
}
DxLib_End(); // DxLib終了処理
return 0;
}
int Key[256]; // キーが押されているフレーム数を格納する
// キーの入力状態を更新する
int gpUpdateKey() {
char tmpKey[256]; // 現在のキーの入力状態を格納する
GetHitKeyStateAll(tmpKey); // 全てのキーの入力状態を得る
for (int i = 0; i < 256; i++) {
if (tmpKey[i] != 0) { // i番のキーコードに対応するキーが押されていたら
Key[i]++; // 加算
}
else { // 押されていなければ
Key[i] = 0; // 0にする
}
}
return 0;
}
Re: ゲームの画面切り替えについて
Posted: 2021年1月25日(月) 23:32
by souta
あと、Main.cの54行目に ';' が必要です 'gpUpdateKey': ローカル関数の定義が正しくありません。とエラーが出ます。
Re: ゲームの画面切り替えについて
Posted: 2021年1月25日(月) 23:35
by souta
このように直したらエラー出なくなりました。大丈夫でしょうか?
Re: ゲームの画面切り替えについて
Posted: 2021年1月26日(火) 10:58
by souta
また自分で直してみたのですが、今度はタイトルとスコアのコードの10行目に 'MenuElement_t': 再定義されています。異なる基本型です。 とエラーが出ます。
<タイトル>
コード:
#include "DxLib.h"
#include "menu.h"
extern int Key[256]; // キーが押されているフレーム数を格納する
// メニュー項目の表示に必要な構造体を用意する
typedef struct {
int x, y; // 座標格納用変数
char name[128]; // 項目名格納用変数
} MenuElement_t;
static MenuElement_t MenuElement[2] = {
{ 300, 300, "ゲームスタート" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
{ 330, 400, "ゲーム終了" },
};
static int SelectNum = 0; // 現在の選択番号
int SceneTitle(void) {
LoadGraphScreen(0, 0, "001.png", TRUE); //背景
LoadGraphScreen(180, 120, "002.png", TRUE); //タイトルロゴ
// 計算フェーズ
if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理
SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)
for (int i = 0; i < 2; i++) { // メニュー項目数である2個ループ処理
if (i == SelectNum) { // 今処理しているのが、選択番号と同じ要素なら
MenuElement[i].x = 300; // 座標を320にする
}
else { // 今処理しているのが、選択番号以外なら
MenuElement[i].x = 330;// 座標を350にする
}
}
}
for (int i = 0; i < 5; i++) { // メニュー項目を描画
DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
SetFontSize(32);
SetFontThickness(4);
ChangeFontType(DX_FONTTYPE_ANTIALIASING);
}
if (Key[KEY_INPUT_Z] == 1) { // キーの種類は適当
switch (SelectNum) {
case 0: return SCENE_GAME;
case 1: return SCENE_GAMEOVER;
}
}
return SCENE_TITLE;
}
<スコア>
コード:
#include "DxLib.h"
#include "menu.h"
extern int Key[256]; // キーが押されているフレーム数を格納する
// メニュー項目の表示に必要な構造体を用意する
typedef struct {
int x, y; // 座標格納用変数
char name[128]; // 項目名格納用変数
} MenuElement_t;
static MenuElement_t MenuElement[2] = {
{ 270, 400, "もう一度プレイする" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
{ 300, 450, "タイトルへ戻る" },
};
static int SelectNum = 0; // 現在の選択番号
int SceneScore(void) {
// 計算フェーズ
if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理
SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)
for (int i = 0; i < 2; i++) { // メニュー項目数である2個ループ処理
if (i == SelectNum) { // 今処理しているのが、選択番号と同じ要素なら
MenuElement[i].x = 270; // 座標を270にする
}
else { // 今処理しているのが、選択番号以外なら
MenuElement[i].x = 300; // 座標を300にする
}
}
}
// 描画フェーズ
LoadGraphScreen(0, 0, "004.png", TRUE); //背景
LoadGraphScreen(270, 75, "003.png", TRUE); //スコアロゴ
for (int i = 0; i < 5; i++) { // メニュー項目を描画
DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
SetFontSize(32);
SetFontThickness(4);
ChangeFontType(DX_FONTTYPE_ANTIALIASING);
}
if (Key[KEY_INPUT_C] == 1) { // キーの種類は適当
switch (SelectNum) {
case 0: return SCENE_TITLE;
case 1: return SCENE_GAMEOVER;
}
}
return SCENE_SCORE;
}
<menu.h>
コード:
#pragma once
enum {
SCENE_GAMEOVER = -1,
SCENE_TITLE,
SCENE_GAME,
SCENE_SCORE,
};
// メニュー項目の表示に必要な構造体を用意する
typedef struct {
int x, y; // 座標格納用変数
char name[128]; // 項目名格納用変数
} MenuElement_t;
Re: ゲームの画面切り替えについて
Posted: 2021年1月26日(火) 12:24
by 参照魚
タイトルとスコアのMenuElement_tの宣言は、menu.hをインクルードしているので必要ありません。
Re: ゲームの画面切り替えについて
Posted: 2021年1月26日(火) 12:35
by souta
消したのですが、また別のエラーが出ます。
LNK2001 外部シンボル "int * Key" (?Key@@3PAHA) は未解決です C:\ckadai\リズムゲーム\リズムゲーム.obj
LNK2001 外部シンボル "int * Key" (?Key@@3PAHA) は未解決です C:\ckadai\リズムゲーム\タイトル.obj
LNK2001 外部シンボル "int * Key" (?Key@@3PAHA) は未解決です C:\ckadai\リズムゲーム\スコア.obj
LNK2019 未解決の外部シンボル "int __cdecl gpUpdateKey(void)" (?gpUpdateKey@@YAHXZ) が関数 _WinMain@16 で参照されました C:\ckadai\リズムゲーム\Main.obj
とでます。
Re: ゲームの画面切り替えについて
Posted: 2021年1月26日(火) 19:22
by 参照魚
main.cからint Key[256]とint gpUpdateKey(void)をコメントアウトかなにかしましたか?
Re: ゲームの画面切り替えについて
Posted: 2021年1月26日(火) 19:36
by souta
コード送ります。変なところありますか?
<main.c>
コード:
#include "DxLib.h"
#include "menu.h"
#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅
extern int gpUpdateKey();
static int SceneMode = SCENE_TITLE;
static int SceneNext;
extern int SceneTitle(void);
extern int SceneGame(void);
extern int SceneScore(void);
extern int Key[256]; // キーが押されているフレーム数を格納する
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
ChangeWindowMode(TRUE); //ウィンドウモードで起動
SetGraphMode(WIN_W, WIN_H, 32); //画面の解像度指定
SetMainWindowText("リズムの達人"); //ウインドウのタイトルを設定
SetBackgroundColor(255, 255, 255);
if (DxLib_Init() == -1) { return -1; } //DxLib初期化処理
SetWindowSizeChangeEnableFlag(FALSE); //画面サイズ変更不可
SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
switch (SceneMode) {
case SCENE_TITLE: SceneNext = SceneTitle(); break;
case SCENE_GAME: SceneNext = SceneGame(); break;
case SCENE_SCORE: SceneNext = SceneScore(); break;
}
if (SceneNext == SCENE_GAMEOVER) {
break;
}
if (SceneNext != SceneMode) {
SceneMode = SceneNext;
}
DxLib_End(); // DxLib終了処理
return 0;
}
int Key[256]; // キーが押されているフレーム数を格納する
// キーの入力状態を更新する
int gpUpdateKey();
char tmpKey[256]; // 現在のキーの入力状態を格納する
GetHitKeyStateAll(tmpKey); // 全てのキーの入力状態を得る
for (int i = 0; i < 256; i++) {
if (tmpKey[i] != 0) { // i番のキーコードに対応するキーが押されていたら
Key[i]++; // 加算
}
else { // 押されていなければ
Key[i] = 0; // 0にする
}
}
return 0;
}
Re: ゲームの画面切り替えについて
Posted: 2021年1月26日(火) 19:51
by 参照魚
①②のところがコードの意味として間違っています
コード:
DxLib_End(); // DxLib終了処理
return 0;
}
} //①
int Key[256]; // キーが押されているフレーム数を格納する
// キーの入力状態を更新する
int gpUpdateKey(){ // ②
char tmpKey[256];
Re: ゲームの画面切り替えについて
Posted: 2021年1月26日(火) 20:06
by souta
正直、理解が浅くてどうすればいいか良く分かりません。すみません。
18行目に '{': 一致するトークンが見つかりませんでした。とでます。
コード:
#include "DxLib.h"
#include "menu.h"
#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅
extern int gpUpdateKey();
static int SceneMode = SCENE_TITLE;
static int SceneNext;
extern int SceneTitle(void);
extern int SceneGame(void);
extern int SceneScore(void);
extern int Key[256]; // キーが押されているフレーム数を格納する
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
ChangeWindowMode(TRUE); //ウィンドウモードで起動
SetGraphMode(WIN_W, WIN_H, 32); //画面の解像度指定
SetMainWindowText("リズムの達人"); //ウインドウのタイトルを設定
SetBackgroundColor(255, 255, 255);
if (DxLib_Init() == -1) { return -1; } //DxLib初期化処理
SetWindowSizeChangeEnableFlag(FALSE); //画面サイズ変更不可
SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
switch (SceneMode) {
case SCENE_TITLE: SceneNext = SceneTitle(); break;
case SCENE_GAME: SceneNext = SceneGame(); break;
case SCENE_SCORE: SceneNext = SceneScore(); break;
}
if (SceneNext == SCENE_GAMEOVER) {
break;
}
if (SceneNext != SceneMode) {
SceneMode = SceneNext;
}
DxLib_End(); // DxLib終了処理
return 0;
}
int Key[256]; // キーが押されているフレーム数を格納する
// キーの入力状態を更新する
int gpUpdateKey();{
char tmpKey[256]; // 現在のキーの入力状態を格納する
GetHitKeyStateAll(tmpKey); // 全てのキーの入力状態を得る
for (int i = 0; i < 256; i++) {
if (tmpKey[i] != 0) { // i番のキーコードに対応するキーが押されていたら
Key[i]++; // 加算
}
else { // 押されていなければ
Key[i] = 0; // 0にする
}
}
return 0;
}
Re: ゲームの画面切り替えについて
Posted: 2021年1月26日(火) 20:19
by 参照魚
これでまだエラーになるようなら、menu.hのコードをお知らせください。
コード:
#include "DxLib.h"
#include "menu.h"
#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅
extern int gpUpdateKey();
static int SceneMode = SCENE_TITLE;
static int SceneNext;
extern int SceneTitle(void);
extern int SceneGame(void);
extern int SceneScore(void);
extern int Key[256]; // キーが押されているフレーム数を格納する
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
ChangeWindowMode(TRUE); //ウィンドウモードで起動
SetGraphMode(WIN_W, WIN_H, 32); //画面の解像度指定
SetMainWindowText("リズムの達人"); //ウインドウのタイトルを設定
SetBackgroundColor(255, 255, 255);
if (DxLib_Init() == -1) { return -1; } //DxLib初期化処理
SetWindowSizeChangeEnableFlag(FALSE); //画面サイズ変更不可
SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
switch (SceneMode) {
case SCENE_TITLE: SceneNext = SceneTitle(); break;
case SCENE_GAME: SceneNext = SceneGame(); break;
case SCENE_SCORE: SceneNext = SceneScore(); break;
}
if (SceneNext == SCENE_GAMEOVER) {
break;
}
if (SceneNext != SceneMode) {
SceneMode = SceneNext;
}
DxLib_End(); // DxLib終了処理
return 0;
}
}
int Key[256]; // キーが押されているフレーム数を格納する
// キーの入力状態を更新する
int gpUpdateKey(){
char tmpKey[256]; // 現在のキーの入力状態を格納する
GetHitKeyStateAll(tmpKey); // 全てのキーの入力状態を得る
for (int i = 0; i < 256; i++) {
if (tmpKey[i] != 0) { // i番のキーコードに対応するキーが押されていたら
Key[i]++; // 加算
}
else { // 押されていなければ
Key[i] = 0; // 0にする
}
}
return 0;
}
Re: ゲームの画面切り替えについて
Posted: 2021年1月26日(火) 20:43
by souta
エラーは出なくなりましたがデバックすると勝手にウインドウが閉じてしまいます。よければ全部のコードを送るのでチェックしてもらってもいいですか?丸投げとなってしまって申し訳ないです。
<main.c>
コード:
#include "DxLib.h"
#include "menu.h"
#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅
extern int gpUpdateKey();
static int SceneMode = SCENE_TITLE;
static int SceneNext;
extern int SceneTitle(void);
extern int SceneGame(void);
extern int SceneScore(void);
extern int Key[256]; // キーが押されているフレーム数を格納する
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
ChangeWindowMode(TRUE); //ウィンドウモードで起動
SetGraphMode(WIN_W, WIN_H, 32); //画面の解像度指定
SetMainWindowText("リズムの達人"); //ウインドウのタイトルを設定
SetBackgroundColor(255, 255, 255);
if (DxLib_Init() == -1) { return -1; } //DxLib初期化処理
SetWindowSizeChangeEnableFlag(FALSE); //画面サイズ変更不可
SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
switch (SceneMode) {
case SCENE_TITLE: SceneNext = SceneTitle(); break;
case SCENE_GAME: SceneNext = SceneGame(); break;
case SCENE_SCORE: SceneNext = SceneScore(); break;
}
if (SceneNext == SCENE_GAMEOVER) {
break;
}
if (SceneNext != SceneMode) {
SceneMode = SceneNext;
}
DxLib_End(); // DxLib終了処理
return 0;
}
}
int Key[256]; // キーが押されているフレーム数を格納する
// キーの入力状態を更新する
int gpUpdateKey() {
char tmpKey[256]; // 現在のキーの入力状態を格納する
GetHitKeyStateAll(tmpKey); // 全てのキーの入力状態を得る
for (int i = 0; i < 256; i++) {
if (tmpKey[i] != 0) { // i番のキーコードに対応するキーが押されていたら
Key[i]++; // 加算
}
else { // 押されていなければ
Key[i] = 0; // 0にする
}
}
return 0;
}
<タイトル>
コード:
#include "DxLib.h"
#include "menu.h"
extern int Key[256]; // キーが押されているフレーム数を格納する
static MenuElement_t MenuElement[2] = {
{ 300, 300, "ゲームスタート" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
{ 330, 400, "ゲーム終了" },
};
static int SelectNum = 0; // 現在の選択番号
int SceneTitle(void) {
LoadGraphScreen(0, 0, "001.png", TRUE); //背景
LoadGraphScreen(180, 120, "002.png", TRUE); //タイトルロゴ
// 計算フェーズ
if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理
SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)
for (int i = 0; i < 2; i++) { // メニュー項目数である2個ループ処理
if (i == SelectNum) { // 今処理しているのが、選択番号と同じ要素なら
MenuElement[i].x = 300; // 座標を320にする
}
else { // 今処理しているのが、選択番号以外なら
MenuElement[i].x = 330;// 座標を350にする
}
}
}
for (int i = 0; i < 5; i++) { // メニュー項目を描画
DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
SetFontSize(32);
SetFontThickness(4);
ChangeFontType(DX_FONTTYPE_ANTIALIASING);
}
if (Key[KEY_INPUT_Z] == 1) { // キーの種類は適当
switch (SelectNum) {
case 0: return SCENE_GAME;
case 1: return SCENE_GAMEOVER;
}
}
return SCENE_TITLE;
}
<ゲーム>
コード:
#include "DxLib.h"
#include "menu.h"
#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅
#define LANE_SIZE 1 //レーンの数
#define BAR_SIZE 40 //1レーンあたりの最大bar数
extern int Key[256]; // キーが押されているフレーム数を格納する
static int SelectNum = 0; // 現在の選択番号
static char buf[256]; //キー押下状態格納用配列
static int key[LANE_SIZE] = {
KEY_INPUT_A
};
static bool bar_f[LANE_SIZE][BAR_SIZE] = {}; //barの存在フラグ
static float bar_y[LANE_SIZE][BAR_SIZE]; //barのY座標
static LONGLONG start_time; //開始した時刻
static LONGLONG now_time; //現在のフレームの時刻
static int currentTime; //開始してからの経過時間
static int counter = 0;
static const int bpm = 120;
enum judge_value {
NONE, GOOD, MISS
};
static const int JUDGE_DISPLAY_TIME = 30; // 判定を表示する時間 (フレーム数)
static judge_value judge = NONE; // 表示中の判定
static int judge_time = 10; // 判定を表示する残り時間 (フレーム数)
static int state = 0;
static int SHandle;
static int good;
static int miss;
int SceneGame(void) {
int score;
LoadGraphScreen(1, 1, "a0.png", TRUE);
if (buf[KEY_INPUT_ESCAPE] == 1) {
return 0; // 終了
}
SHandle = LoadSoundMem("ゆかいな日常.mp3");
switch (state) {
case 0:
PlaySoundMem(SHandle, DX_PLAYTYPE_BACK);
state = 1;
break;
case 1:
if (CheckSoundMem(SHandle) == 0)
state = 2;
break;
case 2:
StopSoundMem(SHandle);
DeleteSoundMem(SHandle);
}
//時間関係
if (counter == 0) {
start_time = GetNowHiPerformanceCount();
}
now_time = GetNowHiPerformanceCount();
currentTime = (int)((now_time - start_time) / 1000); // ms
//bar生成
if (currentTime >= 550000 / bpm * counter) {
for (int i = 0; i < LANE_SIZE; i++) {
bar_f[i][counter % BAR_SIZE] = true;
bar_y[i][counter % BAR_SIZE] = -100.f;
}
counter++;
}
//bar座標更新
for (int i = 0; i < LANE_SIZE; i++) {
for (int j = 0; j < BAR_SIZE; j++) {
if (bar_f[i][j]) {
bar_y[i][j] += 4.f;
if (bar_y[i][j] > WIN_H + 10) {
bar_f[i][j] = false; //画面外に出たらfalse
// MISSを表示させる
judge = MISS;
DrawFormatString(115, 300, GetColor(0, 0, 255), "MISS");
judge_time = JUDGE_DISPLAY_TIME;
PlaySoundMem(miss, DX_PLAYTYPE_BACK);
}
}
}
}
// 判定
GetHitKeyStateAll(buf);
for (int i = 0; i < LANE_SIZE; i++) {
for (int j = 0; j < BAR_SIZE; j++) {
if (bar_f[i][j]) {
if (WIN_H / 5 * 4 - 30 < bar_y[i][j] && bar_y[i][j] < WIN_H / 5 * 4 + 30) {
if (buf[key[i]] == 1) {
bar_f[i][j] = false;
// GOODを表示させる
judge = GOOD;
DrawFormatString(115, 300, GetColor(255, 0, 0), "GOOD");
judge_time = JUDGE_DISPLAY_TIME;
PlaySoundMem(good, DX_PLAYTYPE_BACK);
}
}
}
}
}
if (judge != NONE) {
if (judge == GOOD) {
DrawFormatString(115, 300, GetColor(255, 0, 0), "GOOD");
// GOODを描画する (テキスト・画像など)
}
else if (judge == MISS) {
DrawFormatString(115, 300, GetColor(0, 0, 255), "MISS");
// MISSを描画する (テキスト・画像など)
}
judge_time--;
if (judge_time <= 0) judge = NONE; // 指定の時間が経過したら、判定を消す
}
//判定ライン描画
DrawLine(0, WIN_H / 5 * 4, WIN_W, WIN_H / 5 * 4, GetColor(255, 255, 255));
DrawCircleAA(400.f, 480.f, 45.f, 60.f, GetColor(255, 255, 255), FALSE);
//bar描画
for (int i = 0; i < LANE_SIZE; i++) {
for (int j = 0; j < BAR_SIZE; j++) {
if (bar_f[i][j]) {
DrawCircleAA(400.f + i * 1.f, bar_y[i][j] - 10.f, 30.f + 1.f + i * 1.f, bar_y[i][j] + 10.f, GetColor(0, 255, 0), TRUE);
}
}
}
if (Key[KEY_INPUT_X] == 1) { // キーの種類は適当
switch (SelectNum) {
case 2: return SCENE_SCORE;
}
}
return SCENE_GAME;
}
<スコア>
コード:
#include "DxLib.h"
#include "menu.h"
extern int Key[256]; // キーが押されているフレーム数を格納する
static MenuElement_t MenuElement[2] = {
{ 270, 400, "もう一度プレイする" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
{ 300, 450, "タイトルへ戻る" },
};
static int SelectNum = 0; // 現在の選択番号
int SceneScore(void) {
// 計算フェーズ
if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理
SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)
for (int i = 0; i < 2; i++) { // メニュー項目数である2個ループ処理
if (i == SelectNum) { // 今処理しているのが、選択番号と同じ要素なら
MenuElement[i].x = 270; // 座標を270にする
}
else { // 今処理しているのが、選択番号以外なら
MenuElement[i].x = 300; // 座標を300にする
}
}
}
// 描画フェーズ
LoadGraphScreen(0, 0, "004.png", TRUE); //背景
LoadGraphScreen(270, 75, "003.png", TRUE); //スコアロゴ
for (int i = 0; i < 5; i++) { // メニュー項目を描画
DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
SetFontSize(32);
SetFontThickness(4);
ChangeFontType(DX_FONTTYPE_ANTIALIASING);
}
if (Key[KEY_INPUT_C] == 1) { // キーの種類は適当
switch (SelectNum) {
case 1: return SCENE_TITLE;
case 2: return SCENE_GAMEOVER;
}
}
return SCENE_SCORE;
}
<mune.h>
コード:
#pragma once
enum {
SCENE_GAMEOVER = -1,
SCENE_TITLE,
SCENE_GAME,
SCENE_SCORE,
};
// メニュー項目の表示に必要な構造体を用意する
typedef struct {
int x, y; // 座標格納用変数
char name[128]; // 項目名格納用変数
}MenuElement_t;
Re: ゲームの画面切り替えについて
Posted: 2021年1月26日(火) 22:08
by 参照魚
DxLib_EndがWhileループの中に入っていました。
コード:
#include "DxLib.h"
#include "menu.h"
#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅
extern int gpUpdateKey();
static int SceneMode = SCENE_TITLE;
static int SceneNext;
extern int SceneTitle(void);
extern int SceneGame(void);
extern int SceneScore(void);
extern int Key[256]; // キーが押されているフレーム数を格納する
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
ChangeWindowMode(TRUE); //ウィンドウモードで起動
SetGraphMode(WIN_W, WIN_H, 32); //画面の解像度指定
SetMainWindowText("リズムの達人"); //ウインドウのタイトルを設定
SetBackgroundColor(255, 255, 255);
if (DxLib_Init() == -1) { return -1; } //DxLib初期化処理
SetWindowSizeChangeEnableFlag(FALSE); //画面サイズ変更不可
SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
switch (SceneMode) {
case SCENE_TITLE: SceneNext = SceneTitle(); break;
case SCENE_GAME: SceneNext = SceneGame(); break;
case SCENE_SCORE: SceneNext = SceneScore(); break;
}
if (SceneNext == SCENE_GAMEOVER) {
break;
}
if (SceneNext != SceneMode) {
SceneMode = SceneNext;
}
}
DxLib_End(); // DxLib終了処理
return 0;
}
int Key[256]; // キーが押されているフレーム数を格納する
// キーの入力状態を更新する
int gpUpdateKey() {
char tmpKey[256]; // 現在のキーの入力状態を格納する
GetHitKeyStateAll(tmpKey); // 全てのキーの入力状態を得る
for (int i = 0; i < 256; i++) {
if (tmpKey[i] != 0) { // i番のキーコードに対応するキーが押されていたら
Key[i]++; // 加算
}
else { // 押されていなければ
Key[i] = 0; // 0にする
}
}
return 0;
}
Re: ゲームの画面切り替えについて
Posted: 2021年1月26日(火) 22:41
by souta
無事切り替えができるようになったみたいです。長々とありがとうございました。丸投げのような感じになってしまい本当にすみませんでした。助言感謝します!!
Re: ゲームの画面切り替えについて
Posted: 2021年1月27日(水) 08:16
by 参照魚
ここまでで当初の質問の内容は達成できたと思います。ただこのままだと繰り返し切り替えをしていると挙動がおかしくなる可能性が残っています。最後にそれを解消するコードを提示します。
main.c
コード:
#include "DxLib.h"
#include "menu.h"
#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅
static int SceneMode = SCENE_GAMESTART;
static int SceneNext = SCENE_TITLE;
extern void InitSceneTitle(void);
extern void InitSceneGame(void);
extern void InitSceneScore(void);
extern int SceneTitle(void);
extern int SceneGame(void);
extern int SceneScore(void);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
ChangeWindowMode(TRUE); //ウィンドウモードで起動
SetGraphMode(WIN_W, WIN_H, 32); //画面の解像度指定
SetMainWindowText("リズムの達人"); //ウインドウのタイトルを設定
SetBackgroundColor(255, 255, 255);
if (DxLib_Init() == -1) { return -1; } //DxLib初期化処理
SetWindowSizeChangeEnableFlag(FALSE); //画面サイズ変更不可
SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
if (SceneNext != SceneMode) {
switch (SceneMode) {
case SCENE_TITLE: InitSceneTitle(); break;
case SCENE_GAME : InitSceneGame(); break;
case SCENE_SCORE: InitSceneScore(); break;
}
SceneMode = SceneNext;
}
switch (SceneMode) {
case SCENE_TITLE: SceneNext = SceneTitle(); break;
case SCENE_GAME : SceneNext = SceneGame(); break;
case SCENE_SCORE: SceneNext = SceneScore(); break;
}
if (SceneNext == SCENE_GAMEOVER) {
break;
}
}
DxLib_End(); // DxLib終了処理
return 0;
}
int Key[256]; // キーが押されているフレーム数を格納する
// キーの入力状態を更新する
int gpUpdateKey() {
char tmpKey[256]; // 現在のキーの入力状態を格納する
GetHitKeyStateAll(tmpKey); // 全てのキーの入力状態を得る
for (int i = 0; i < 256; i++) {
if (tmpKey[i] != 0) { // i番のキーコードに対応するキーが押されていたら
Key[i]++; // 加算
}
else { // 押されていなければ
Key[i] = 0; // 0にする
}
}
return 0;
}
menu.h
コード:
#pragma once
enum {
SCENE_GAMESTART= -2,
SCENE_GAMEOVER = -1,
SCENE_TITLE,
SCENE_GAME,
SCENE_SCORE,
};
// メニュー項目の表示に必要な構造体を用意する
typedef struct {
int x, y; // 座標格納用変数
char name[128]; // 項目名格納用変数
}MenuElement_t;
extern int Key[256]; // キーが押されているフレーム数を格納する
extern int gpUpdateKey();
SceneTitle.c
SceneGame.c/SceneScore.cも同様に変更します。
コード:
#include "DxLib.h"
#include "menu.h"
static MenuElement_t MenuElement[2] = {
{ 300, 300, "ゲームスタート" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
{ 330, 400, "ゲーム終了" },
};
static int SelectNum = 0; // 現在の選択番号
static int background;
static int titlelogo;
void InitSceneTitle(void) {
background = LoadGraph( "001.png" ); //背景
titlelogo = LoadGraph( "002.png" ); //タイトルロゴ
SetFontSize(32);
SetFontThickness(4);
ChangeFontType(DX_FONTTYPE_ANTIALIASING);
}
int SceneTitle(void) {
DrawGraphScreen( 0, 0, background, TRUE); //背景
DrawGraphScreen(180, 120, titlelogo, TRUE); //タイトルロゴ
// 計算フェーズ
if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理
SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)
for (int i = 0; i < 2; i++) { // メニュー項目数である2個ループ処理
if (i == SelectNum) { // 今処理しているのが、選択番号と同じ要素なら
MenuElement[i].x = 300; // 座標を320にする
}
else { // 今処理しているのが、選択番号以外なら
MenuElement[i].x = 330;// 座標を350にする
}
}
}
for (int i = 0; i < 5; i++) { // メニュー項目を描画
DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
}
if (Key[KEY_INPUT_Z] == 1) { // キーの種類は適当
switch (SelectNum) {
case 0: return SCENE_GAME;
case 1: return SCENE_GAMEOVER;
}
}
return SCENE_TITLE;
}
なお、こちらではビルド確認や動作確認はしていないので、やる場合はここまでの動作するコードはバックアップしておいてからにしてください。
Re: ゲームの画面切り替えについて
Posted: 2021年2月02日(火) 09:38
by souta
返信遅くなりました。すいません。最後までありがとうございました!!