開発環境:DXライブラリ、 VisualStudio Express 2013、 言語はC++
で、デモンズソウルのようなステージ間ワープを作りました。
2Dの横スクロールアクションゲームです。
具体的にどのような感じかというと、まずワープには
ワープ先を選べる「拠点からのワープ」と、拠点へただ帰る「各ステージからのワープ」の二つあり、
「拠点からのワープ」
①ワープポイントでメニューを開いて、ワープしたいステージを選択。
②エフェクトとかアニメーションしながら、画面がフェードアウト。
③ステージロード。
④フェードインして、エフェクトとかアニメーションしながら、ステージに到着。
⑤アクション
「各ステージからのワープ」
①ワープポイントでメニューを開いて、「拠点に帰る」項目を選択。
②エフェクトとかアニメーションしながら、画面がフェードアウト。
③ステージロード。
④フェードインして、エフェクトとかアニメーションしながら、拠点に到着。
⑤アクション
まあ大体こんな感じです。
で、その処理をコードに書き表したのがこちら。
※以下のコードは簡単にまとめた疑似コードです。ありのままのコードを書くと、とんでもない量になってしまうので、そうしました。
GameMng.h(ゲームメインの管理クラスの宣言が書かれたヘッダ)
#pragma once
#include "Singleton.h"
#include "StateMng.h"
#include "Stage.h"
#include "WarpPoint.h"
#include "Player.h"
//ゲームメインの管理クラスのシングルトンクラス(これを介してプレイヤーのあたり判定やら敵のデータやらをやり取りする)
class GameMng : public Singleton<GameMng>{
friend Singleton<GameMng>;
public:
//ゲームの状態
enum{
GAMESTATE_STAGEWARP_OUT, //ステージワープ移動
GAMESTATE_STAGEWARP_IN, //ステージワープ到着
GAMESTATE_STAGELOAD, //ステージロード処理
GAMESTATE_ACTION, //アクション
GAMESTATE_WARPMENU, //ワープメニューオープン
GAMESTATE_MAX, //ゲーム本編の状態の数
};
//ステージの種類
enum{
STAGE_BASE, //拠点
STAGE_1,
STAGE_2,
STAGETYPE_MAX, //ステージの数
};
private:
//=========
//各クラス(ここに敵とかもある感じ)
//=========
Stage *stage; //ステージ
WarpPoint *warp;//ワープポイント
Player *player; //プレイヤー
private:
//=========
//各状態
//=========
StateMng *GameState;//ゲーム本体の状態
StateMng *NowStage; //今いるステージ
StateMng *NextStage;//次のステージ
private:
//===========================
//画面効果
//===========================
//暗転
int Black_Alpha; //フェード用の黒画面の透明度
bool FadeIn_Flag; //フェードインするよー
bool FadeOut_Flag;//フェードアウトするよーフラグ
void DisplayEffect_FadeInBlack(); //実際の処理
void DisplayEffect_FadeOutBlack();
public:
void Set_FadeInFlag(); //フェードイン
void Set_FadeOutFlag();//フェードアウト
private:
GameMng(); //初期化
~GameMng();
void GameMng_StageLoad(); //ステージロードパート
void GameMng_StageWarp_Out();//ワープ開始
void GameMng_StageWarp_In(); //ワープ到着
void GameMng_Action(); //アクションパート(プレイヤーがステージ攻略とか)
void GameMng_WarpMenuOpen(); //ワープポイントでのメニューオープンパート(メニュー項目のワープでステージ間ワープ)
public:
//===========================
//ステージのゲッター
//===========================
bool StageHitX(int state, Rect rx, bool way);//あたり判定
bool StageHitY(int state, Rect ry);
bool SlopeHitY_RDOWN(int sx, int sy); //坂とのあたり判定
bool SlopeHitY_LDOWN(int sx, int sy);
double Get_SlopeNowY(int x); //乗ってる坂のY座標
public:
//===========================
//ワープポイントのゲッター
//===========================
int WarpPointGetPos(int type);//ワープポイントの位置
public:
//===========================
//プレイヤーのゲッター
//===========================
int Player_GetState(); //プレイヤーの状態
int Player_GetPos(int type); //プレイヤーの位置
int Player_GetHPFuel(); //HP残量
Rect Player_GetHit(int type); //あたり判定
//===========================
//プレイヤーのセッター
//===========================
void Player_SetHPPlus(int point); //HP足します
void Player_SetHPMinus(int point);//HP引きます
public:
//===========================
//ゲームメインのゲッター
//===========================
int Get_StageType();//現在のステージ
//===========================
//ゲームメインのセッター
//===========================
void Set_Change_GAMEMAIN_STATE(int sstate);//ゲームの状態
void Set_Change_GAMEMAIN_NOWSTAGE(int sstate);//今のステージ
void Set_Change_GAMEMAIN_NEXTSTAGE(int sstate);//次のステージ
void Main();//メイン
};
GameMng.cpp(ゲームメインの管理クラスの処理が書かれたcpp)
#include <DxLib.h>
#include "Camera.h"
#include "SystemMng.h"
#include "GameMng.h"
//==================
//コンストラクタ
//==================
GameMng::GameMng(){
//ゲームの状態初期化
GameState = DEBUG_NEW StateMng(GAMESTATE_MAX);
//今のステージがどこか初期化
NowStage = DEBUG_NEW StateMng(STAGETYPE_MAX);
//次のステージがどこか初期化
NextStage = DEBUG_NEW StateMng(STAGETYPE_MAX);
//ステージ初期化
stage = DEBUG_NEW Stage(STAGE_BASE);/*DEBUG_NEWはnewです。メモリリーク確認のためこうしてます。*/
//ワープポイント初期化
warp = DEBUG_NEW WarpPoint("data/StageData/WarpPoint/BaseStage.csv");
//今現在のステージを拠点に
NowStage->ChangeState(STAGE_BASE);
NextStage->ChangeState(STAGE_BASE);
//プレイヤー初期化(ワープポイントの位置を初期位置に)
player = DEBUG_NEW Player(warp->GetPos(Light::X) - 38, warp->GetPos(Light::Y, i));
//フェードインとか
Black_Alpha = 0;
FadeIn_Flag = false;
FadeOut_Flag = false;
//ゲームの状態を"アクションパート"に
GameState->ChangeState(GAMESTATE_ACTION);
}
//==================
//デストラクタ
//==================
GameMng::~GameMng(){
if (GameState != nullptr){
delete GameState;
GameState = nullptr;
}
if (NowStage != nullptr){
delete NowStage;
NowStage = nullptr;
}
if (NextStage != nullptr){
delete NextStage;
NextStage = nullptr;
}
if (stage != nullptr){
delete stage;
stage = nullptr;
}
if (warp != nullptr){
delete warp;
warp = nullptr;
}
if (player != nullptr){
delete player;
player = nullptr;
}
}
//==================
//状態セッター
//==================
//ゲームの状態
void GameMng::Set_Change_GAMEMAIN_STATE(int sstate){
GameState->ChangeState(sstate);
}
//現在のステージ
void GameMng::Set_Change_GAMEMAIN_NOWSTAGE(int sstate){
NowStage->ChangeState(sstate);
}
//次のステージ
void GameMng::Set_Change_GAMEMAIN_NEXTSTAGE(int sstate){
NextStage->ChangeState(sstate);
}
//==================
//ステージロード中
//==================
void GameMng::GameMng_StageLoad(){
//ステージ破棄
delete stage;
stage = nullptr;
//ワープポイント破棄
delete warp;
warp = nullptr;
//ワープ先、次のステージに合わせて各オブジェクトを確保
switch (NextStage->GetNowState()){
case STAGE_BASE://拠点
//拠点ステージロード
stage = new Stage(STAGE_BASE);
//ワープポイントロード
warp = new WarpPoint("data/StageData/WarpPoint/BaseStage.csv");
//プレイヤーの位置変更(ワープポイントの位置を初期位置に)
player->Reload(warp->GetPos(Warp::X) - 38, warp->GetPos(Warp::Y) + 96);
//フェードイン開始
FadeIn_Flag = true;
//ワープ到着に
GameState->ChangeState(GAMESTATE_STAGEWARP_IN);
break;
case STAGE_1:
//---省略(上とおんなじ---
break;
case STAGE_2:
//---省略---
break;
}
//===================
//フェードイン描画
//===================
SetDrawBlendMode(DX_BLENDMODE_ALPHA, Black_Alpha);
DrawBox(0, 0, SCREEN_W, SCREEN_H, GetColor(0, 0, 0), TRUE);
SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0);
}
//================================================
//フェードイン/フェードアウトの開始フラグセット
//================================================
void GameMng::Set_FadeInFlag(){
FadeIn_Flag = true;
}
void GameMng::Set_FadeOutFlag(){
FadeOut_Flag = true;
}
//================================
//フェードイン/フェードアウト動作
//================================
//フェードイン
void GameMng::DisplayEffect_FadeInBlack(){
if (FadeIn_Flag){
if (Black_Alpha > 0){
Black_Alpha -= 10;
}
if (Black_Alpha < 0 || Black_Alpha == 0){
FadeIn_Flag = false;
Black_Alpha = 0;
}
}
}
//フェードアウト
void GameMng::DisplayEffect_FadeOutBlack(){
if (FadeOut_Flag){
if (Black_Alpha < 255){
Black_Alpha += 10;
}
if (Black_Alpha > 255 || Black_Alpha == 255){
FadeIn_Flag = false;
Black_Alpha = 255;
}
}
}
void GameMng::GameMng_Respawn(){
}
//===================
//ワープ開始
//===================
void GameMng::GameMng_StageWarp_Out(){
//================================
//フェードイン/フェードアウト動作
//================================
DisplayEffect_FadeInBlack();
DisplayEffect_FadeOutBlack();
//=================
//各動作
//=================
warp->Update();
player->Warp_Out();
//=================
//ステージ切り替え
//=================
if (Black_Alpha == 255){//画面が真っ黒になったら
FadeOut_Flag = false;//フェードアウト終わったよ
switch (NextStage->GetNowState()){//次のステージを
//今現在いるステージにする
case STAGE_BASE:
Set_Change_GAMEMAIN_NOWSTAGE(STAGE_BASE);
break;
case STAGE_1:
Set_Change_GAMEMAIN_NOWSTAGE(STAGE_1);
break;
case STAGE_2:
Set_Change_GAMEMAIN_NOWSTAGE(STAGE_2);
break;
}
//ゲームの状態をステージロード中に
GameState->ChangeState(GAMESTATE_STAGELOAD);
}
//=================
//各描画
//=================
stage->Draw();
warp->Draw();
player->Draw();
stage->PlayerFrontDraw();
//===================
//フェードアウト描画
//===================
SetDrawBlendMode(DX_BLENDMODE_ALPHA, Black_Alpha);
DrawBox(0, 0, SCREEN_W, SCREEN_H, GetColor(0, 0, 0), TRUE);
SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0);
}
//===================
//ワープ到着
//===================
void GameMng::GameMng_StageWarp_In(){
//================================
//フェードイン/フェードアウト動作
//================================
DisplayEffect_FadeInBlack();
DisplayEffect_FadeOutBlack();
//=================
//各動作
//=================
warp->Update();
player->WarpIn_Move();
//=================
//フェードイン動作
//=================
if (Black_Alpha == 0){
FadeIn_Flag = false;
player->Warp_In();
}
//===========
//ゲーム描画
//===========
stage->Draw();
warp->Draw();
player->Draw();
stage->PlayerFrontDraw();
//=================
//フェードイン描画
//=================
SetDrawBlendMode(DX_BLENDMODE_ALPHA, Black_Alpha);
DrawBox(0, 0, SCREEN_W, SCREEN_H, GetColor(0, 0, 0), TRUE);
SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0);
}
//===================
//アクションパート
//===================
void GameMng::GameMng_Action(){
//===========
//動作
//===========
warp->Update();
player->Move();
//===========
//ゲーム描画
//===========
stage->Draw();
warp->Draw();
player->Draw();
stage->PlayerFrontDraw();
//==========================================
//HPゲージやメニューなどインタ―フェース描画
//==========================================
player->GaugeDraw();
}
//===================
//ワープメニューオープン(プレイヤーキャラはこの時動かないので描画だけ)
//===================
//基盤
void GameMng::GameMng_WarpMenuOpen(){
//ワープポイント更新
warp->Update();
//===========
//ゲーム描画
//===========
stage->Draw();
warp->Draw();
player->Draw();/*描画だけする。キャラは動かない*/
stage->PlayerFrontDraw();
//メニュー描画
warp->MenuMove();/*ここでワープ先を決める処理(Set_Change_GAMEMAIN_NEXTSTAGE(int sstate)とかを使ってる)*/
warp->MenuDraw();
}
//===================
//メイン
//===================
void GameMng::Main(){
//=============
//状態の更新
//=============
GameState->UpdateState();
NowStage->UpdateState();
NextStage->UpdateState();
//===============
//各状態での動作
//===============
switch (GameState->GetNowState()){
case GAMESTATE_STAGEWARP_OUT://ワープ開始
GameMng_StageWarp_Out();
DrawFormatString(0, 15, GetColor(255, 255, 255), "STAGEWARP_OUT");
break;
case GAMESTATE_STAGEWARP_IN://ワープ到着
GameMng_StageWarp_In();
DrawFormatString(0, 15, GetColor(255, 255, 255), "STAGEWARP_In");
break;
case GAMESTATE_STAGELOAD://ステージロード
GameMng_StageLoad();
DrawFormatString(0, 15, GetColor(255, 255, 255), "STAGELOAD");
break;
case GAMESTATE_ACTION://アクション
GameMng_Action();
DrawFormatString(0, 15, GetColor(255, 255, 255), "GAMESTATE_ACTION");
break;
case GAMESTATE_WARPMENU://ワープメニューオープン時
GameMng_WarpMenuOpen();
DrawFormatString(0, 15, GetColor(255, 255, 255), "GAMESTATE_WARPMENU");
break;
}
}
/*ゲッター*/
//===========================
//ステージ
//===========================
int GameMng::Get_StageType(){
return NowStage->GetNowState();
}
bool GameMng::StageHitX(int state, Rect rx, bool way){
return stage->StageHitX(state, rx, way);
}
bool GameMng::StageHitY(int state, Rect ry){
return stage->StageHitY(state, ry);
}
bool GameMng::SlopeHitY_RDOWN(int sx, int sy){
return stage->SlopeHitY_RDOWN(sx, sy);
}
bool GameMng::SlopeHitY_LDOWN(int sx, int sy){
return stage->SlopeHitY_LDOWN(sx, sy);
}
double GameMng::Get_SlopeNowY(int x){
return stage->Get_SlopeNowY(x);
}
//===========================
//ワープポイント
//===========================
int GameMng::WarpPointGetPos(int type, int i){
return warp->GetPos(type, i);
}
//===========================
//プレイヤー
//===========================
int GameMng::Player_GetState(int type){
return player->GetState(type);
}
int GameMng::Player_GetPos(int type){
return player->GetPos(type);
}
int GameMng::Player_GetHPFuel(){
return player->Get_HPFuel();
}
Rect GameMng::Player_GetHit(int type){
return player->GetHit(type);
}
void GameMng::Player_SetHPMinus(int point){
player->Set_HPMinus(point);
}
void GameMng::Player_SetHPPlus(int point){
player->Set_HPPlus(point);
}
ざっとこんな感じなのですが、どうでしょうか?
ステージファイル読み込み部分(C++なのにfopenでtxtファイルを読み込んでる)だとか、見てほしい場所はまだあるのですが、
一気に張るのもあれなので、ひとまず全てのベースとなるこれから。
一番気になるというか自信のない部位が
//==================
//ステージロード中
//==================
GameMng_StageLoad()
の部分で、このステージロード方法がほんとうにこれでいいのかいまいち自信が持てません。
今のところ問題なく動作はしてはいますが、
これからステージを追加していく前に、一度本当に問題ないかを確認したいと思い、質問しに来ました。
全部追加してから問題に気づいた、となったら地獄を見る羽目になると思うので……
俺ならこうするとか、これじゃロード長くなるぞとか、なんでもいいので、気軽に書き込んでください。
よろしくお願いします。