お久しぶりです。 第四回目を迎えることができました。だた
完全に行き詰ってます
設計が分からん...わからんぞー! というかそもそもゲーム自体の全体の流れを意識してから組むべきだったんだ!
ゲームのメイン即ち今回の場合実際にボールが跳ね返り、ブロックを崩していく場面から作っていったから画面転移とかの設計をどうすればいいのか分からなくなってきました。
小さなところから作り始めてあとからその周りの枠を後付けしていくって、わかりにくいに決まってんじゃないですか。 ミスったなぁ、
タイトル ⇒ ゲーム画面 ⇒ リザルト or ゲームオーバー画面
みたいな大まかな流れを最初から作っておいて、その中に処理を描くべきだったんだ...!なにを今更言っているのか。 何とかしないといかんなぁ
とりあえず、タイトル画面と終了画面 (ClearとGameOverを表示するの)を作って、それからどうやって画面転移、それと各シーンの情報を別のシーンに移すのか考えないと...
仕様としては(つか最初に仕様考えてからゲーム作れよ)
タイトル画面:
・マウスクリックでボタン選択、 ボタンの種類は GameStart GameExit Result Option ぐらいがあれば十分だろう。 各ボタンよりゲーム画面、ゲームの終了、リザルト画面、オプション画面への
転移を行う
ゲーム画面:
・8x8のブロックが存在していて、プレイヤーはマウスによってバーを操作しつつブロックを崩していく、マウスをクリックするとボールが移動し始める。
・コンティニューは3回、4回目のミスでゲームオーバー画面へと転移
・スコアの計算式は適当に クリア時間とコンティニュー回数でスコアを決定することにする。
・全部のブロックが消されたら、ゲームクリアー画面へ転移
ゲームクリアー画面:
・ゲームクリアー時のスコアを表示する。
・背景はゲーム画面を残しておきたい。
・スコアを記録するかの選択をする はい⇒スコアの書き込み後、タイトル画面へ転移 いいえ⇒タイトル画面へ転移
ゲームオーバー画面:
・ゲームオーバー時点の消せたブロック数とスコアを表示。
・リトライかどうかのボタンを設置 はい⇒ゲーム画面へ転移 いいえ⇒タイトルへ転移。
リザルト画面:
・今までのスコアの表示する。それだけ
・Backボタン設置、押すことによってタイトル画面へ転移。
オプション画面:
・なんらかのパラメータをいじれるようにする。 おそらくSE音量
・Backボタンの設置、押すことによってタイトル画面へ転移。
と、頭の悪い私はいちいちこう書かないと分からなくなるのです。 さらに加えてこのような画面転移を実際にどうやって実装すればいいのやら...
とりあえず私の左上にあるA4用紙にフローチャート的なものを書いてみる、つかそもそもフローチャートの記法すらまともに覚えてないな俺。
ここにきったないメモ残しときますね。
親クラスField_tを作ってソレを継承しつつ個々のシーンの処理を描いて、すべてのField_tを持つクラスをまた作って、そこで画面転移を処理するべきなのか。
でも個々のシーンに別のシーンの情報を渡さにゃならんし、それってどうやって書くの? 各シーンに対して情報の送受信を行うメンバ関数とか作ればいいの?
わ、わからん....もっと単純でスマートな考え方があるのかもしれませんが、思いつきません。
素直にゲームプログラミングの本を一冊買うかなぁ...
現時点でのソース(きったないしdeleteとか忘れてそう)
► スポイラーを表示
CODE:
#include "../DxLib/DxLib.h"
/******************全体で使う値*******************/
const int WINDOW_X = 640;
const int WINDOW_Y = 480;
/**********************クラス宣言***********************/
class Bar_t
{
private:
int x; //座標
int y;
int rect_x; //サイズ
int rect_y;
int color;
bool flag; //何かに使うかもしれない
public:
Bar_t();
~Bar_t(){}
int get_x(){ return x; }
int get_y(){ return y; }
int get_rect_x(){ return rect_x; }
int get_rect_y(){ return rect_y; }
void Init();
void Update();
void Draw();
};
class Ball_t
{
private:
//初期位置と現在位置用に二つ
float x[2]; //座標
float y[2];
float v_x[2]; //軸の速度
float v_y[2];
int r[2];
int color[2];
bool flag[2]; //何かに使うかもしれない
//ボールが矩形に対してどの面に当たっているかを示す変数
bool Horizon;
bool Stripe;
bool Lean;
public:
Ball_t();
~Ball_t(){}
//ボールの位置とか半径を返す
float get_x(){ return x[0]; }
float get_y(){ return y[0]; }
int get_r(){ return r[0]; }
//呼ぶと各フラグが有効になる
void isHitted_Horizon(){ Horizon = true; }
void isHitted_Stripe(){ Stripe = true; }
//void isHitted_Lean(){ Lean = true; }
//初期化 x座標、y座標、x方向への速度、y方向への速度、半径
void Init(float arg_x, float arg_y, float arg_v_x, float arg_v_y, int arg_r);
void Reset();
void Update();
void Draw();
};
class Blocks_t
{
private:
struct Block
{
int x;
int y;
int color;
bool isThere;
bool isHit;
};
static const int block_x = 8;
static const int block_y = 8;
static const int blocksize_x = (int)580 / block_x;
static const int blocksize_y = (int)256 / block_y;
static const int space = (int)64 / block_x;
Block block[block_x][block_y];
public:
Blocks_t();
~Blocks_t(){}
//x,y番目のブロックの座標とそれぞれのサイズを返す
int get_x(int num_x, int num_y){ return block[num_x][num_y].x; }
int get_y(int num_x, int num_y){ return block[num_x][num_y].y; }
int get_rect_x(){ return blocksize_x; }
int get_rect_y(){ return blocksize_y; }
//x,y番目のブロックの状態を取得する
bool get_flag(int num_x, int num_y){ return block[num_x][num_y].isThere; }
//x,y番目のブロックの有効化、無効化
void isthere(int num_x, int num_y){ block[num_x][num_y].isThere = true; }
void isnotthere(int num_x, int num_y){ block[num_x][num_y].isThere = false; }
void Init();
void Reset();
void Update();
void Draw();
};
class Field_t
{
private:
//ボールの状態
enum{
NO,
HORIZON,
STRIPE,
BOTH,
};
//とりあえずフィールド上のオブジェクトたち
Ball_t *ball;
Blocks_t *blocks;
Bar_t *bar;
//音関係
int se_bound;
//フィールドの状態
int state;
const int FIELD_X = 640;
const int FIELD_Y = 480;
public:
Field_t();
~Field_t(){ delete blocks, delete ball, delete bar; }
//あたり判定の関数、実装は現時点では適当(円 対 矩形)
//円のx座標、円のy座標、円の半径、矩形の各座標たち
int HitTest(int arg_cx, int arg_cy,int arg_cr, int arg_bx,int arg_by,int arg_bvx,int arg_bvy);
void Init();
void Update();
void Draw();
void Reset();
void Exit(){ delete blocks, delete ball, delete bar; }
};
/*************クラスの中身*************/
//バーに関して
//コンストラクタ、とりあえず初期化
Bar_t::Bar_t()
{
x = WINDOW_X / 2;
y = WINDOW_Y - 40;
rect_x = 96;
rect_y = 16;
color = GetColor(64, 255, 255);
}
//今のところ無し
void Bar_t::Init()
{
}
//更新はマウスの座標取得のみ
void Bar_t::Update()
{
GetMousePoint(&x, NULL);
}
//描画はマウスの座標に従いバーを描画
void Bar_t::Draw()
{
DrawBox(x, y, x + rect_x, y + rect_y, color, true);
}
//ボールに関して
//初期化
Ball_t::Ball_t()
{
x[0] = 0.0;
y[0] = 0.0;
v_x[0] = 0.0;
v_y[0] = 0.0;
r[0] = 0;
color[0] = GetColor(255, 64, 32);
}
//ゲームの初期化
void Ball_t::Init(float arg_x,float arg_y,float arg_v_x,float arg_v_y,int arg_r)
{
//初期状態ではどの面に対しても接触していない
Horizon = false;
Stripe = false;
Lean = false;
//値を代入
x[0] = arg_x;
y[0] = arg_y;
v_x[0] = arg_v_x;
v_y[0] = arg_v_y;
r[0] = arg_r;
//初期位置に代入
x[1] = x[0];
y[1] = y[0];
v_x[1] = v_x[0];
v_y[1] = v_y[0];
r[1] = r[0];
}
//初期状態にボールの位置、速度、方向、半径を戻す
void Ball_t::Reset()
{
//現在位置を初期位置に
x[0] = x[1];
y[0] = y[1];
v_x[0] = v_x[1];
v_y[0] = v_y[1];
r[0] = r[1];
}
//更新の関数、
void Ball_t::Update()
{
//壁際では跳ね返るよね
if (x[0] Init(320, 400,GetRand(3)+4, GetRand(3)+4, 8);
}
//フィールドのリセット
void Field_t::Reset()
{
ball->Init(320, 400, GetRand(3) + 4, GetRand(3) + 4, 8);
ball->Reset();
blocks->Reset();
}
//フィールドの更新
void Field_t::Update()
{
int ball_bar = NO,
ball_block[8][8];
int hit_ball = NO;
//各ブロックに対してあたり判定を行う
ball_bar = HitTest(ball->get_x(), ball->get_y(), ball->get_r(), bar->get_x(), bar->get_y(), bar->get_rect_x(), bar->get_rect_y());
for (int i = 0; i get_flag(i, k))
{
ball_block[i][k] = HitTest(ball->get_x(), ball->get_y(), ball->get_r(), blocks->get_x(i, k), blocks->get_y(i, k), blocks->get_rect_x(), blocks->get_rect_y());
if (ball_block[i][k]) blocks->isnotthere(i, k);
if (ball_bar == STRIPE || ball_block[i][k] == STRIPE) hit_ball = STRIPE;
if (ball_bar == HORIZON || ball_block[i][k] == HORIZON) hit_ball = HORIZON;
if (ball_bar == BOTH || ball_block[i][k] == BOTH) hit_ball = BOTH;
if (ball_block[i][k] != 0)break;
}
}
//ボールが何かにぶつかっていればボールをぶつかってるよと教える
if (hit_ball == STRIPE) ball->isHitted_Stripe();
if (hit_ball == HORIZON) ball->isHitted_Horizon();
//if (hit_ball == BOTH) ball->isHitted_Lean();
//デバッグ用
DrawFormatString(0, 420, GetColor(255, 0, 0), "State:%d", hit_ball);
//そして更新
ball->Update();
blocks->Update();
bar->Update();
}
//描画
void Field_t::Draw()
{
bar->Draw();
blocks->Draw();
ball->Draw();
}
//毎フレーム処理すべき必須の物
bool SystemUpdate()
{
if (
ScreenFlip() == 0 &&
ProcessMessage() == 0 &&
ClearDrawScreen() == 0 &&
CheckHitKey(KEY_INPUT_ESCAPE) == 0
) return true;
return false;
}
//メイン関数
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
ChangeWindowMode(TRUE);
DxLib_Init();
SetDrawScreen(DX_SCREEN_BACK);
//ゲーム画面作る
Field_t gamemain;
//ゲーム画面初期化
gamemain.Init();
while (SystemUpdate())
{
//Rキーが押されたらリセットする
if (CheckHitKey(KEY_INPUT_R)) gamemain.Reset();
//描画&更新
gamemain.Update();
gamemain.Draw();
}
//ゲーム終了
gamemain.Exit();
DxLib_End();
return 0;
}