C++どDXライブラリでのキー操作について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
sql

C++どDXライブラリでのキー操作について

#1

投稿記事 by sql » 11年前

現在、DXライブラリを使ったプログラミングの練習で、独学でキー操作を学習しているのですが、C++での操作の仕方がわかりません。
こちらの龍神録C++版をDLしてソースコードを見て、自分のやりたい操作が書いていったのですが、わからないところもありましたので質問させてください、DLするのは大変だとおもうのでDLしたソースコードの中から載せます。
key

コード:

#ifndef DEF_KEY_H
#define DEF_KEY_H

#define KEY_CODE_NUM 256

#include "Singleton.h"

class CKey : public CSingleton<CKey>{

	int m_nKey[ KEY_CODE_NUM ];

public:
	CKey();
	void Update();
	int Get( int sKeyCode );

};

#endif
//--------------------------------------------------------------------------------------------------

#include <DxLib.h>

#include "Macro.h"
#include "Key.h"

/*
@brief コンストラクタ
*/
CKey::CKey(){
	memset( m_nKey, 0, sizeof( m_nKey ) );
}

/*
	@brief キーが押されているフレーム数の更新
*/
void CKey::Update(){
	char tmpKey[KEY_CODE_NUM];		//現在のキーの入力状態を格納する
	GetHitKeyStateAll( tmpKey );	//全てのキーの入力状態を得る
	for( int i=0; i<KEY_CODE_NUM; i++ ){ 
		if( tmpKey[i] != 0 ){	//i番のキーコードに対応するキーが押されていたら
			if( m_nKey[i] < 0 ){//前フレームで離されていたら
				m_nKey[i] = 1;	//入力して1フレーム目にする
			} else {			//前フレームで押されていたら
				m_nKey[i]++;    //入力フレーム数を加算
			}
		} else {				//押されていなければ
			if( m_nKey[i] > 0 ){//前フレームで押されていたら
				m_nKey[i] = -1;	//離されて1フレーム目にする
			} else {			//前フレームで離されていたら
				m_nKey[i]--;	//離されているフレーム数を加算(減算)
			}
		}
	}
}

/*
	@brief	KeyCodeのキーが押されてるフレーム数を返す

	@param[in]	sKeyCode	キーコード(KEY_INPUT_Zとか)
*/
int CKey::Get( int sKeyCode ){
	if( !( 0<= sKeyCode && sKeyCode < KEY_CODE_NUM ) ){
		eprintfDx("KeyCodeが範囲外です。 %d", sKeyCode );
		return -1;
	}
	return m_nKey[ sKeyCode ];
}

player

コード:

#ifndef DEF_PLAYER_H
#define DEF_PLAYER_H

#include "BaseChara.h"
#include "PlyrShot.h"

namespace nsPlayer{
	static const int   sBodySize = 50;
	static const float fHitRange = 2.1f;
};

class CPlayer : public CBaseChara{
	
	unsigned int m_uPow;
	CPlyrShot *m_pPlyrShot;

	bool Process_Hit();

public:
	CPlayer(ScrPrm_t* Prm);
	~CPlayer();
	bool Initialize() override;
	bool Process() override;
	void Draw() override;
	bool Hit( int nPow ) override;
	void StartBossBattle() override;

	bool Process_Ctrl();
	void LoadModel();
	void SetType(){ m_eType = nsChara::ePlyr; }
	void SetBodySize(){ m_fBodyH = 17.f; m_fBodyD = -5.f; m_nBodySize = 0; }
	void SetHitRange(){ m_fHitRange = nsPlayer::fHitRange; }
	void DeleteAllShot(){ m_pPlyrShot->Delete(); }
	std::list<CBullet*>* GetBulList(){ return m_pPlyrShot->GetBulList(); }

	const VECTOR GetTalkPrevPos();
	const VECTOR GetTalkNextPos();
};

#endif
//--------------------------------------------------------------------------------------------------------------
#include <math.h>
#include "Player.h"
#include "Key.h"
#include "GameDefine.h"
#include "CommonDefine.h"
#include "Model.h"
#include "Facade.h"
#include "Util.h"
#include "EffMgr.h"
#include "Eff_HitBom.h"
#include "SndGame.h"

using namespace std;

static const float csMoveSpd = 3.0f;
static const int csHitBomTime = 10;
static const int csReturningTime = 10;

const static VECTOR vNextPos={ FWO/2, FHO*4/5,      0 };

CPlayer::CPlayer(ScrPrm_t* Prm):CBaseChara(Prm){
	m_uPow = 0;
	m_vPos.x = FWO / 2;
	m_vPos.y = FWO * 3 / 4;
	m_pPlyrShot = new CPlyrShot( &m_vPos, &m_uPow );
	m_bReady = true;
}

CPlayer::~CPlayer(){
	delete m_pPlyrShot; m_pPlyrShot = nullptr;
}

void CPlayer::LoadModel(){
	m_nMdl = CModel::Inst()->Get( eMDL_Reimu );
}

bool CPlayer::Initialize(){
	CBaseChara::Initialize();
	MV1SetRotationXYZ( m_nMdl, VGet( DEF_MDLROTA_X, PI, 0.0f ) ) ;
	return true;
}

// キー入力による自機の移動計算
bool CPlayer::Process_Ctrl(){
	float x=0, y=0;
//-----------------------------------------------------------------------------------------※このような書き方をしたい!
	if( CKey::Inst()->Get( KEY_INPUT_LEFT  ) > 0 ){	x = -csMoveSpd;	}
	if( CKey::Inst()->Get( KEY_INPUT_RIGHT ) > 0 ){	x = +csMoveSpd;	}
	if( CKey::Inst()->Get( KEY_INPUT_UP    ) > 0 ){	y = -csMoveSpd;	}
	if( CKey::Inst()->Get( KEY_INPUT_DOWN  ) > 0 ){	y = +csMoveSpd;	}
//------------------------------------------------------------------------------------------------------------------------
	if( x && y ){	//斜めに移動中なら
		x /= sqrt(2.0f);	//√2で割る
		y /= sqrt(2.0f);
	}
	if( CKey::Inst()->Get( KEY_INPUT_LSHIFT ) > 0 ){	//低速移動中なら
		x /= 3.0f;	//速度を1/3にする
		y /= 3.0f;
	}
	m_vPos.x += x;	m_vPos.y += y;
	if( m_vPos.x < FX      ){ m_vPos.x = FX;    }	//画面外にはみ出すなら、再端に設定
	if( FX+FW   < m_vPos.x ){ m_vPos.x = FX+FW; }
	if( m_vPos.y < FY      ){ m_vPos.y = FY;    }
	if( FY+FH   < m_vPos.y ){ m_vPos.y = FY+FH; }
	return true;
}

bool CPlayer::Process(){
	if( m_bNowTalking ){
		return true;
	}
	switch( m_eState ){
	case eRETURNING:	//浮上中
		m_vPos.y-=2;
		if( m_nCnt == 60 ){
			m_nCnt=0;
			m_eState = eNORMAL;
		}
		break;
	case eNORMAL:		//通常
		Process_Ctrl();
		break;
	case eHITTING:		//喰らいボム受付中
		if( m_nCnt == csHitBomTime ){
			m_eState = eRETURNING;
			m_nCnt = 0;
			m_vPos.x = FWO/2;
			m_vPos.y = FHO + nsPlayer::sBodySize;
//			CEff_Base *p = CEffMgr::Inst()->Get( eEFFTYPE_HITBOM, 0 );
//			if( p ){
//				p->SetDelFlag();
//			}
		}
		break;
	default:
		break;
	}
	Process_Hit();
	m_pPlyrShot->Process();
	return CBaseChara::Process();
}

void CPlayer::Draw(){
	m_pPlyrShot->Draw();
	CBaseChara::Draw();
}

void CPlayer::StartBossBattle(){
	m_vPos = vNextPos;
	m_pMotion->Attach( eMdlAnim_Normal );
}

//被弾時処理
bool CPlayer::Hit( int nPow ){
	m_eState = eHITTING;
	m_nCnt = 0;
	CEffMgr::Inst()->Register( new CEff_HitBom(csHitBomTime) );
	CSndGame::Inst()->SetPlay( eSNDGM_PlyrHit );
	return false;	//死亡するならfalseを返す。自機にはHPが無いので必ずfalse
}

bool CPlayer::Process_Hit(){
	// 敵が持つ弾リストのリストを取得
	list< list<CBullet* >* > ListOfBulList;
	// 敵が持つレーザーリストのリストを取得
	list< list<CLaser * >* > ListOfLasList;

	CFacade::Inst()->GetListOfBulList( ListOfBulList, ListOfLasList );

	//弾リストのリスト分ループ
	for(list< list<CBullet* >* >::iterator it=ListOfBulList.begin();it!=ListOfBulList.end();it++){
		//弾リスト分ループ
		for(list< CBullet* >::iterator bl=(*it)->begin();bl!=(*it)->end();bl++){
			if( Util_IsHit( (*bl)->GetPos(), (*bl)->GetSpd(), (*bl)->GetAng(), (*bl)->GetHitR(), 
							m_vPos,	m_fHitRange ) ){
				if( m_eState == eNORMAL ){
					Hit( 0 );	//自機の場合、ダメージ量を表す引数0に意味は無い
				}
				(*bl)->SetDelFlag();
				return true;
			}
		}
	}
	return false;
}

const VECTOR CPlayer::GetTalkPrevPos(){
	return Get3DPos();
}

const VECTOR CPlayer::GetTalkNextPos(){
	return Util_Get3DPos( vNextPos, m_fBodyD, m_fBodyH, DEF_MDLROTA_X );
}

player87行目にあるように、このような書き方にしたいです。
順を追って説明します。Key関係は、幸いコードに説明(コメント)もついていましたし、理解できました。
(Getの返り値が0以上ということは、update(押下されるとGetの返り値と同じ値が加算される)であるように押下状態を示し、player.cppにあるif( CKey::Inst()->Get( KEY_INPUT_LEFT ) > 0 )は左が押されている時・・・というのは理解できました。また、ループでkeyのupdateを呼べばいいことも分かります)

しかし、if( CKey::Inst()->Get( KEY_INPUT_LEFT ) > 0 )にある「Inst()」の意味がイマイチわかりません。シングルトンと調べたのですが例が少なくて理解に苦しんでいるのが現状です。(テンプレートに関しては、少ししか勉強していません・・・)
Inst()の存在理由がわからないので、もしif( CKey::Inst()->Get( KEY_INPUT_LEFT ) > 0 )からInstを取るとどうなってしまうのかなどわかりません。(コメント(説明がなかったため理解できませんでした・・・))

自分なりにまとめた結果、Key.hにもSingleton.hがインクルードされていますし、Singleton.hさえ理解すればこの問題は解決されると思っているので、どうか仕組みとソースの意味を教えてください。(Singleton.hは下に貼っておきます。)
Singleton.h

コード:

#ifndef DEF_SINGLETON_H
#define DEF_SINGLETON_H

template <typename _T>
class CSingleton {
protected:
	CSingleton() {
	}

	virtual ~CSingleton() {
//		m_pInst = nullptr;
	}

//	static _T* m_pInst;

public:
	static _T* Inst() {
		static _T inst;
		return &inst;
//		if ( m_pInst == nullptr ){
//			m_pInst = new _T;
//		}
//		return m_pInst;
	};
};

//template<typename _T>
//_T* CSingleton<_T>::m_pInst = nullptr;

#endif

kiuri
記事: 20
登録日時: 12年前

Re: C++どDXライブラリでのキー操作について

#2

投稿記事 by kiuri » 11年前

シングルトンとはインスタンスが一つしか生成されないと保証されるデザインパターンの一つです。

今回の例に上がっているようなキー入力のクラスはゲームを通して一つしか必要ないですよね?
勿論普通のクラスにしてインスタンスを一つしか生成しないという方法もありますが、人間は間違いの生き物ですので
どこかで二つ目、三つ目のインスタンスを作ってしまうかもしれません。
もしそうなれば、各インスタンスでキー入力情報がごちゃごちゃになり思ったように動作しなくなります。
しかも、ソースの上ではちゃんとキークラスを使っているので間違いがわかりにくいです。
そういったことを防ぐためにシングルトンパターンはあります。

仕組みに関しては下記URLの”静的ローカル変数を使う方法”が参考になると思います。
http://www.geocities.jp/ky_webid/design ... n/009.html

今回のSingleton.hはお約束のコードを継承することで省こうとしているのだと思います。
それに伴ってテンプレートが必要になっています。(ベースクラスでサブクラスの型を知るために)

しかし、protectedにしているためサブクラスのインスタンスが複数作成できるような・・・?
というより、シングルトンって継承するようなものではない気も・・・。

sql

Re: C++どDXライブラリでのキー操作について

#3

投稿記事 by sql » 11年前

返信ありがとうございます。
おかげで理解することができました!自分なりにですが・
これで作業が進められます!

閉鎖

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