神代クロ のすべての投稿

ゲーム開発8:入力処理1

予告どおり入力の処理です。

入力はDirectInputを使います。なんかクラス見たらDirectX8のまま変わってなかったんで楽勝、と思ったらやっぱり微妙に違う(汗) まぁほぼ手直し無しで済んだけどね。

今回もDirectXに依存する部分をCInputBaseクラス、入力を処理する部分をCInputクラスに分けます。使うデバイスはキーボードゲームパッドです。使うボタンはキーボードはテンキーと十字キー、あとZとXとCのボタンにします。ゲームパッドの方は十字キーと0と1と2のボタンです。

キーボードは簡単に初期化出来るんだけど、ゲームパッドはモノによってボタンや十字キー(もしくはアナログスティック)の数が違うので、コールバックで再帰的に設定します。まあ定型処理だし、最低限のボタンしか使わないから、関係ないけどね。

今回はCInputBaseだけ組んで、次回CInputで実際に入力キーを取り出します。

//---------------------------------------------------------
// 初期化
BOOL CInputBase::Init(HWND hWnd)
{
 HRESULT hr;

 // DirectInputオブジェクトを作成する
 hr=DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&DInput, NULL);
 if FAILED(hr) {
  MessageBox(NULL, "DirectInputオブジェクトの生成に失敗しました", "CInputBase::Init", MB_OK);
  return E_FAIL;
 }

 // キーボードの初期化
 hr=InitKeyboard(hWnd);
 if FAILED(hr) {
  return E_FAIL;
 }

 // ジョイスティックの初期化
 hr=InitJoystick(hWnd);
 if FAILED(hr) {
  return E_FAIL;
 }

 return S_OK;
}

//---------------------------------------------------------
// キーボードの初期化
BOOL CInputBase::InitKeyboard(HWND hWnd)
{
 HRESULT hr;

 // キーボードデバイスを取得する
 hr=DInput->CreateDevice(GUID_SysKeyboard, &DIKeyboard, NULL);
 if FAILED(hr) { 
  MessageBox(NULL, "DirectInputキーボードデバイスの生成に失敗しました", "CInputBase::InitKeyboard", MB_OK);
  TermDInput();
  return E_FAIL;
 }

 // キーボードのデータ形式を設定する
 hr=DIKeyboard->SetDataFormat(&c_dfDIKeyboard);
 if FAILED(hr) {
  MessageBox(NULL, "DirectInputキーボードのデータ形式の取得に失敗しました", "CInputBase::InitKeyboard", MB_OK);
  TermDInput();
  return E_FAIL;
 }

 // キーボードの協調レベルを設定する
 hr=DIKeyboard->SetCooperativeLevel(hWnd, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE);
 if FAILED(hr) {
  MessageBox(NULL, "DirectInputキーボードの強調レベルの取得に失敗しました", "CInputBase::InitKeyboard", MB_OK);
  TermDInput();
  return E_FAIL;
 }

 // キーボードの入力デバイスにアクセスする
 hr=DIKeyboard->Acquire();
 if FAILED(hr) {
  MessageBox(NULL, "DirectInputキーボードへのアクセスに失敗しました", "CInputBase::InitKeyboard", MB_OK);
  TermDInput();
  return E_FAIL;
 }

 return S_OK;
}

//---------------------------------------------------------
// ジョイスティックの初期化
BOOL CInputBase::InitJoystick(HWND hWnd)
{
 HRESULT  hr;
 DIDEVCAPS g_DevCaps;

 //ジョイスティックのコールバック設定
 hr=DInput->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, NULL, DIEDFL_ATTACHEDONLY);
 if FAILED(hr) {
  MessageBox(NULL, "DirectInputジョイスティックコールバックの生成に失敗しました", "CInputBase::InitJoystick", MB_OK);
  TermDInput();
  return E_FAIL;
 }

 // ジョイスティックが存在しているか?
 if (DIJoystick==NULL) {
  return S_OK;
 }

 // ジョイスティックのデータ形式を設定する
 hr=DIJoystick->SetDataFormat(&c_dfDIJoystick);
 if FAILED(hr) {
  MessageBox(NULL, "DirectInputジョイスティックのデータ形式の取得に失敗しました", "CInputBase::InitJoystick", MB_OK);
  TermDInput();
  return E_FAIL;
 }

 // ジョイスティックの協調レベルを設定する
 hr=DIJoystick->SetCooperativeLevel(hWnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE);
 if FAILED(hr) {
  MessageBox(NULL, "DirectInputジョイスティックの強調レベルの取得に失敗しました", "CInputBase::InitJoystick", MB_OK);
  TermDInput();
  return E_FAIL;
 }

 // ジョイスティックの能力を取得する
 g_DevCaps.dwSize = sizeof(DIDEVCAPS);
 hr=DIJoystick->GetCapabilities(&g_DevCaps);
 if FAILED(hr) {
  MessageBox(NULL, "DirectInputジョイスティックの能力の取得に失敗しました", "CInputBase::InitJoystick", MB_OK);
  TermDInput();
  return E_FAIL;
 }

 // 全ての軸を列挙する
 hr=DIJoystick->EnumObjects(EnumAxesCallback, (void*)hWnd, DIDFT_AXIS);
 if FAILED(hr) {
  MessageBox(NULL, "DirectInputジョイスティックの軸の列挙に失敗しました", "CInputBase::InitJoystick", MB_OK);
  TermDInput();
  return E_FAIL;
 }

 // ジョイスティックの入力デバイスにアクセスする
 hr=DIJoystick->Acquire();
 if FAILED(hr) {
  MessageBox(NULL, "DirectInputジョイスティックへのアクセスに失敗しました", "CInputBase::InitJoystick", MB_OK);
  TermDInput();
  return E_FAIL;
 }

 return S_OK;
}

//---------------------------------------------------------
// ジョイスティック列挙コールバック
BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE* pdidInstance, VOID* pContext)
{
 HRESULT hr;

 // ジョイスティックデバイスを取得する
 hr=System->Input->DInput->CreateDevice(pdidInstance->guidInstance, &System->Input->DIJoystick, NULL );
 if FAILED(hr) {
  return DIENUM_CONTINUE;
 }

 // ジョイスティックが取得できたらこの関数は呼び出されなくなる
 return DIENUM_STOP;
}

//---------------------------------------------------------
// ジョイスティック軸列挙コールバック
BOOL CALLBACK EnumAxesCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* pContext)
{
 HWND hDlg=(HWND)pContext;

 DIPROPRANGE diprg;
 diprg.diph.dwSize  = sizeof(DIPROPRANGE);
 diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
 diprg.diph.dwHow  = DIPH_BYID;
 diprg.diph.dwObj  = pdidoi->dwType; // Specify the enumerated axis
 diprg.lMin    = -1000;
 diprg.lMax    = +1000;

 // ジョイスティックデバイスを設定する
 if (FAILED(System->Input->DIJoystick->SetProperty(DIPROP_RANGE, &diprg.diph))) {
  return DIENUM_STOP;
 }

 return DIENUM_CONTINUE;
}

//---------------------------------------------------------
// DirectInput解放
void CInputBase::TermDInput()
{ 
 if (DInput) {
  if (DIKeyboard) {
   // Release()を呼び出す前は常にデバイスを解放する
   DIKeyboard->Unacquire();
   DIKeyboard->Release();
   DIKeyboard=NULL;
  }
  if (DIJoystick) {
   // Release()を呼び出す前は常にデバイスを解放する
   DIJoystick->Unacquire();
   DIJoystick->Release();
   DIJoystick=NULL;
  }
  DInput->Release();
  DInput=NULL;
 }
}

//---------------------------------------------------------
// キーボード入力取得
BOOL CInputBase::ProcessKeyboard(char *buffer)
{
 HRESULT hr;

 if (DIKeyboard==NULL) {
  return E_FAIL;
 }

 // キーボードステータス取得
 hr=DIKeyboard->GetDeviceState(256/*sizeof(buffer)*/,(LPVOID)buffer);
 if FAILED(hr) {
  return E_FAIL;
 }

 return S_OK;
}

//---------------------------------------------------------
// ジョイスティック入力取得
BOOL CInputBase::ProcessJoystick(DIJOYSTATE *js)
{
 HRESULT  hr;

 if (DIJoystick==NULL) {
  return E_FAIL;
 }

 // ジョイスティックポーリング
 hr=DIJoystick->Poll();
 if FAILED(hr) {
  hr=DIJoystick->Acquire();
  while(hr==DIERR_INPUTLOST) 
  hr=DIJoystick->Acquire();
  return E_FAIL;
 }

 // ジョイスティックステータス取得
 hr=DIJoystick->GetDeviceState(sizeof(DIJOYSTATE), js);
 if FAILED(hr) {
  return E_FAIL;
 }

 return S_OK;
}

ゲーム開発7:スプライト処理

ba1523d5.gifグラフィックまわりをやる事にしました。

まずスプライト描画処理を修正しました。DrawSpriteBase()です。スプライトに拡大縮小回転と色味の引数を渡して、それを計算しています。

次にスプライトそのもののデータ管理ですが、スプライト管理構造体SPRITE_MANAGEMENTテクスチャ管理構造体TEXTURE_MANAGEMENTの2つに分けてみました。なぜかというと、1枚の画像(テクスチャ)から複数のスプライトを取り出すため、別々に扱った方がよさそうだからです。

まずテクスチャの生成CreateTexture()ですが、上に書いた通り1枚のテクスチャを複数のスプライトが参照するため、既に生成しているテクスチャなのかをTEXTURE_MANAGEMENTのファイル名で確認し、その参照している数をreferenceでカウントします。参照数のカウントは、テクスチャを破棄する際に、誰も参照していない事を確認するためです。誰かが参照してるのに破棄したら困るからね。

次にスプライトの生成CreateSprite()は、どのテクスチャを使うか、またテクスチャのどの領域から切り取って使うかをSPRITE_MANAGEMENTに格納します。

これで生成されたスプライトは、最低限スプライト番号spr_noと座標x,yだけで画面に表示できます。ちなみにDrawSprite()には引数がたくさんあるけど、spr_no,x,y以外はディフォルト引数にしているため、未入力でもOKです。

グラフィックに関しては、画面スクロールを実現するため、ワールド座標系ビューポート座標系の導入が必要になりますが、とりあえず置いといて、次回は入力まわりです。

//---------------------------------------------------------
// スプライト描画

void CGraphicsBase::DrawSpriteBase(int tex_no, RECT drawRect, float x, float y, float z, DWORD color, float angle, float scale_x, float scale_y)
{
 D3DXMATRIX mat, mat1, mat2, mat3;
 float  center_x, center_y;
 D3DXVECTOR3 Center;

 // マトリクス初期化
 D3DXMatrixIdentity(&mat1);
 D3DXMatrixIdentity(&mat2);
 D3DXMatrixIdentity(&mat3);

 // マトリクスで拡大縮小回転移動
 D3DXMatrixScaling(&mat1, scale_x, scale_y, 1);
 D3DXMatrixRotationZ(&mat2, D3DXToRadian(angle));
 D3DXMatrixTranslation(&mat3, x, y, z);
 mat=mat1*mat2*mat3;
 D3Sprite->SetTransform(&mat);

 // 画像の中心
 center_x=(float)(drawRect.right-drawRect.left)/2;
 center_y=(float)(drawRect.bottom-drawRect.top)/2;
 Center=D3DXVECTOR3(center_x, center_y, 0);

 // 描画
 D3Sprite->Draw(Texture[tex_no]->Tex, &drawRect, &Center, NULL, color);
}

//---------------------------------------------------------
// テクスチャ生成
int CGraphics::CreateTexture(char *filename)
{
 int  i, tex_no;

 // テクスチャが既に登録されていないか判断
 tex_no=-1;
 i=0;
 for (i=0; i<max_TEX; i++) {
  if (Texture[i]!=NULL) {
   if (strcmp(Texture[i]->filename, filename)==0) {
    tex_no=i;
   }
  }
 }
 if (tex_no!=-1) {
  Texture[tex_no]->reference++;
  return tex_no;
 }

 // 空いているテクスチャを探す
 tex_no=0;
 while (Texture[tex_no]!=NULL || tex_no>=MAX_TEX) {
  tex_no++;
 }
 if (tex_no>=MAX_TEX) {
  return -1;
 }

 // テクスチャ生成
 Texture[tex_no]= new TEXTURE_MANAGEMENT;
 Texture[tex_no]->filename= new char[strlen(filename)+1];
 Texture[tex_no]->reference=1;
 strcpy_s(Texture[tex_no]->filename, (strlen(filename)+1), filename);

 // テクスチャ読み込み
 CreateTextureBase(Texture[tex_no]->filename, &Texture[tex_no]->Tex);

 return tex_no;
}

//---------------------------------------------------------
// テクスチャ解放
void CGraphics::ReleaseTexture(int tex_no)
{
 // 解放済み?
 if (Texture[tex_no]==NULL) {
  return;
 }

 // どのオブジェクトからも参照されていなければ解放
 Texture[tex_no]->reference--;
 if (Texture[tex_no]->reference<=0) {
  delete[] Texture[tex_no]->filename;
  Texture[tex_no]->Tex->Release();
  delete Texture[tex_no];
  Texture[tex_no]=NULL;
 }
}

//---------------------------------------------------------
// スプライト生成
int CGraphics::CreateSprite(char *filename, RECT Range)
{
 int  i, tex_no, spr_no;

 // 空いているスプライトを探す
 spr_no=-1;
 for (i=0; i<max_SPR; i++) {
  if (Sprite[i]==NULL) {
   spr_no=i;
  }
 }
 if (spr_no==-1) {
  return -1;
 }

 // テクスチャ生成
 tex_no=CreateTexture(filename);

 // スプライト生成
 Sprite[spr_no]= new SPRITE_MANAGEMENT;
 Sprite[spr_no]->tex_no=tex_no;
 Sprite[spr_no]->Range=Range;

 return spr_no;
}

//---------------------------------------------------------
// スプライト解放
void CGraphics::ReleaseSprite(int spr_no)
{
 // 解放済み?
 if (Sprite[spr_no]==NULL) {
  return;
 }

 // テクスチャ解放
 ReleaseTexture(Sprite[spr_no]->tex_no);

 // 解放
 delete Sprite[spr_no];
 Sprite[spr_no]=NULL;
}

//---------------------------------------------------------
// スプライト描画
void CGraphics::DrawSprite(int spr_no, float x, float y, float z, DWORD color, float angle, float scale_x, float scale_y)
{
 DrawSpriteBase(Sprite[spr_no]->tex_no, Sprite[spr_no]->Range, x, y, z, color, angle, scale_x, scale_y);
}

ゲーム開発6:文字と画像を表示する

36e2abd7.gif引き続きDirect3Dでグラフィックスします。

まず文字ですが、前回LPD3DXFONT(D3DebugFont)に必要なパラメータを入れて初期化してるので、あとはDrawTextA()で表示するだけです。ちなみにこの関数、DirectX8と同名で別物だったんで、ちょっと苦労した(汗) ネットで検索しても、新旧両方のバージョンが入り混じってるからなぁ。

次はスプライト(画像)を表示させます。DirectX8以降、スプライトは3Dテクスチャとして扱われてるので、テクスチャ関連のクラスを使います。ファイルからD3DXCreateTextureFromFile()でテクスチャとして読み込み、オブジェクトLPDIRECT3DTEXTURE9に格納します。そしてDraw()で描画します。今回のスプライトまわりは直打ちで汚いので、後ほど作り直します。

それらを画面に出力します。背景をClear()で青に塗りつぶし、描画部分をBeginScene()EndScene()で囲います。最後にPresent()で出力。

ようやく画面が表示されました。そういえばフレームレートは何となく50FPSにしてみた。次回はグラフィックまわりを突き詰めるか、入力系のどちらかにします。

//---------------------------------------------------------
//  テクスチャ読み込み
BOOL CGraphicsBase::CreateTextureBase(LPCTSTR filename, LPDIRECT3DTEXTURE9 *tex)
{
 if(D3DXCreateTextureFromFile(D3Device, filename, tex)!=S_OK) {
  MessageBox(NULL, "テクスチャの読み込みに失敗しました", "CGraphicsBase::CreateTextureBase", MB_OK);
  return E_FAIL;
 }

 return S_OK;
}

//---------------------------------------------------------
// スプライト描画
void CGraphicsBase::DrawSpriteBase(int tex_no, RECT drawRect, int x, int y, int damage)
{
 RECT srcRect;
 SetRect(&srcRect, 0, 0, 128, 128); // テクスチャ切り出し
 D3DXVECTOR3 Center=D3DXVECTOR3(0, 0, 0); // センター
 D3DXVECTOR3 Position=D3DXVECTOR3(100, 100, 0); // 位置

 // 描画
 D3Sprite->Draw(Texture[tex_no]->Tex, &srcRect, &Center, &Position, D3DXCOLOR(1,1,1,1));
}

//---------------------------------------------------------
// レンダリング
void CGraphicsBase::Render()
{
 RECT drawRect;
 char text[100];

 if (D3Device==NULL) {
  return;
 }

 // バックバッファを青でクリアする
 D3Device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0);

 // シーン開始
 D3Device->BeginScene();

 // スプライト描画
 D3Sprite->Begin(D3DXSPRITE_ALPHABLEND);
 SetRect(&drawRect, 0, 0, 128, 128);
 DrawSpriteBase(0, drawRect, 100, 100);
 D3Sprite->End();

 // デバッグ文字表示
 if (System->DebugFlag==1) {
  SetRect(&drawRect, 0, 0, strlen(text)*32, 32);
  System->GetFPS(text);
  D3DebugFont->DrawTextA(NULL, (char *)text, -1, &drawRect, (DT_SINGLELINE | DT_LEFT | DT_TOP | DT_NOCLIP), 0xFFFFFFFF);
 }

 // シーン終了
 D3Device->EndScene();

 // シーンを表示する
 D3Device->Present(NULL, NULL, NULL, NULL);
}

ゲーム開発5:DirectX Graphics(Direct3D)を初期化する

ちょっと間が空いたけど、今回はDirect3Dの初期化と解放です。ここも定型処理だね。今回使うのはDirect3Dのデバイスとオブジェクト、Direct3DXのスプライトとフォントです。ちなみにDirect3DXはDirect3Dのラッパーです。

将来的にDirectXのバージョンが変わる可能性を考慮して(もう新しいの出てるけど)、クラスは2つに分けます。CGraphicisBaseとCGraphicsです。CGraphicisBaseにはDirectXに依存する処理を入れておき、CGraphicisに継承させます。いざ環境が変わったらCGraphicisBaseだけ差し替えれば動く、という感じにします。クラス名はCGraphicisBase90cみたいにバージョン入れた方がわかりやすいかもね。

しかし今回もDirectX8時代のソースを基に組んでるけど、細かい所が色々変わってるね。同じ名前なのにクラスがオーバーロードする訳でもなく、別物になってたりするし。ゲイツめ…

//---------------------------------------------------------
// 初期化

BOOL CGraphicsBase::Init(HWND hWnd)
{
 // 表示系初期化
 if (InitD3D(hWnd)==E_FAIL) {
  MessageBox(NULL, "Direct3Dの初期化に失敗しました", "CGraphicsBase::Init", MB_OK);
  return E_FAIL;
 }

 // スプライトオブジェクトの作成
 D3DXCreateSprite(D3Device, &D3Sprite);

 // フォント初期化
 InitFont(&D3DebugFont);

 return S_OK;
}

//---------------------------------------------------------
// Direct3D初期化

BOOL CGraphicsBase::InitD3D(HWND hWnd)
{
 D3DPRESENT_PARAMETERS d3dpp; 
 D3DDISPLAYMODE   d3ddm;

 // Direct3Dオブジェクトの作成
 if (NULL==(D3D=Direct3DCreate9(D3D_SDK_VERSION))) {
  MessageBox(NULL, "Direct3Dオブジェクトの生成に失敗しました", "CGraphicsBase::InitD3D", MB_OK);
  return E_FAIL;
 }

 // 現在のディスプレイモードを検出する
 if (FAILED(D3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm))) {
  MessageBox(NULL, "ディスプレイモードの検出に失敗しました", "CGraphicsBase::InitD3D", MB_OK);
  return E_FAIL;
 }

 // 3Dアプリケーションの動作を指定する
 ZeroMemory(&d3dpp, sizeof(d3dpp));
 d3dpp.BackBufferWidth=640;
 d3dpp.BackBufferHeight=480;
 d3dpp.Windowed=System->ScreenMode; // フルスクリーン:FALSE
 d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;
 d3dpp.BackBufferFormat=d3ddm.Format;

 // Direct3Dデバイスの作成
 if (FAILED(D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
         D3DCREATE_SOFTWARE_VERTEXPROCESSING,
         &d3dpp, &D3Device))) {
  MessageBox(NULL, "Direct3Dデバイスの生成に失敗しました", "CGraphicsBase::InitD3D", MB_OK);
  return E_FAIL;
 }

 return S_OK;
}

//---------------------------------------------------------
// フォント初期化

void CGraphicsBase::InitFont(LPD3DXFONT *D3Font)
{
 // テキスト設定
 D3DXFONT_DESCA FontDesc={
  32,     // 高さ
  0,     // 幅
  0,     // 太さ
  0,     // ミップレベル
  FALSE,    // イタリック
  SHIFTJIS_CHARSET,
  OUT_DEFAULT_PRECIS,
  DEFAULT_QUALITY,
  DEFAULT_PITCH | FF_DONTCARE,
  NULL,
 };

 // フォントオブジェクト作成
 D3DXCreateFontIndirect(D3Device, &FontDesc, D3Font);
}

//---------------------------------------------------------
// Direct3D解放

void CGraphicsBase::TermD3D()
{
 // フォント解放
 if (D3DebugFont!=NULL) {
  D3DebugFont->Release();
 }

 // スプライト解放
 if (D3Sprite!=NULL) {
  D3Sprite->Release();
 }

 // Direct3Dデバイス解放
 if (D3Device!=NULL) {
  D3Device->Release();
 }

 // Direct3Dオブジェクト解放
 if (D3D!=NULL) {
  D3D->Release();
 }
}

ぐるみんプレイ中

秋葉原に行ったらぐるみんというゲームが500円(ワゴン)で売ってましたw なのでプレイしてみます。

ゲーム自体は4年位前に出たもので、ファルコム3Dアクションです。主人公の女の子がドリルで敵を倒すというのが、ちょっと懐かしいですね。最初オープニングムービーの音が出なかったので、あれこれ試してたんだけど、ffdshowをアップデートしたら音が鳴ったよ。

とりあえず1時間くらいプレイしましたが、なかなか面白いです。子供向けなファンタジックなストーリーと雰囲気のお陰で、気楽にプレイできます。PCよりコンシューマ向けじゃないかと思ったら、やっぱりPSPでも発売されてるね。

のんびりプレイしますか。

六本木で外人さん達と飲む

今更サイトにアイコンを付けてみた>挨拶
---

今日は六本木で打ち合わせしました。その後、そこの会社の人達+αで飲む事に。

面子はイギリス人、フランス人、オーストラリア人、ロシア系日本人、ハワイに住んでる日本人、あとは生粋の日本人が3人です。生粋と言っても俺以外は海外に行って商品の買い付けとかしてる人達なんだけどね。

でもその場でのメインの言語は日本語だったので助かりましたw 横に座ったフランス人は明日からはじまる東京ゲームショウに作品を出展すると言うので、しばしゲーム話をしましたよ。昔俺が開発に関わったゲームとか知ってて、ちょっと嬉しかったり。

ちなみに料理は鍋でした。肉が速攻で無くなって野菜鍋になってたけど。あと日本酒を薦められ飲んでたのですが、大量に薦められて久しぶりに酔っ払ったよ。

日本語が通じにくかったりしたけど、みんなテンション高くてなかなか面白かったです。

秋葉原の焼肉屋に行く

秋葉原の焼肉屋に行きました。面子は前回参加のうちの3人。秋葉原にある焼肉屋は値段が高い所が多いので、安い所を探そう、とか言って歩き回ったけど見つからず。昔は食べ放題の鉄板焼き屋とかあったのにね。

もう焼き鳥屋でいいか、という雰囲気になったけど、最後のあがきでケータイでgoogle検索してみる。そしたらちょうど近くに焼肉屋があるって出たので行ってみました。

そこは…風俗ビルでしたよ(汗) 風俗ばかりが入る雑居ビルの1フロアが焼肉屋になってます。でも入ってみたら普通っぽい雰囲気だったので入店。

食べ放題メニューを選択してしばし肉を食べてました。意外に普通の店だな。値段は安いし、特に問題なく腹が膨れるまで食べれました。

まぁたまにはこんな店もいいか。

ゲーム開発4:システムクラス作成

ちょっと間が空いてしまいましたが、システムクラスCSystemを作成しています。もともと58.8fpsで動くように作ってあったのをそのまま流用です。そのうちちゃんと60fpsにしよう。

ProcessNextFrame()メインルーチンWndProc()から呼び出して、システムをフレーム単位で動くようにしています。ProcessNextFrame()内にあるWaitTime()で、動作が一定になるようにウェイトを入れてます。

昔作ったシステムでは場合分けやエラー処理をたくさん入れてたけど、最近はPCの性能も上がったし、OSもWindowsXP以上で動かすこと前提で組んでいるので、ばっさり切ってます。

いつまでも画面が表示されないと寂しいので、次はグラフィックスクラスCGraphicsを作って何か表示させようかね。

//---------------------------------------------------------
#define SPF 17 // 58.8フレーム

//---------------------------------------------------------
// 生成
CSystem::CSystem(HWND hWnd)
{
 // パラメータ設定
 MyhWnd=hWnd;

 // 乱数初期化
 srand((unsigned)timeGetTime());

 // タイマの高精度化開始
 timeBeginPeriod(1); 
}

//---------------------------------------------------------
// 解放
CSystem::~CSystem()
{
 // タイマの高精度化終了
 timeEndPeriod(1);
}

//---------------------------------------------------------
// Name: フレーム処理
HRESULT CSystem::ProcessNextFrame()
{
 // 計算

 // 時間待ち
 WaitTime();

 // レンダリング

 return S_OK;
}

//---------------------------------------------------------
// 時間待ち
void CSystem::WaitTime()
{
 static DWORD dwLastTick=0;
 static LONG  lErrTick=0;
 DWORD   dwCurrTick, dwNowTick;
 LONG   lWaitTick;

 // 待ち時間を計算
 dwCurrTick=timeGetTime();
 lWaitTick=SPF-(dwCurrTick-dwLastTick)+lErrTick;
 lErrTick=0;

 // 処理落ちしている?
 if (lWaitTick<0) {
  lErrTick=lWaitTick;     // lErrTickはマイナスになる
  if ((SPF+lErrTick)<0) lErrTick=0;
  dwLastTick=dwCurrTick;
  return;
 }

 // 処理が早ければスリープする
 if (lWaitTick>=4) {
  Sleep(lWaitTick-3);
 }

 // ループで細かい時間待ち
 while (SPF>((dwNowTick=timeGetTime())-dwLastTick)) {
  ;
 }

 dwLastTick=dwNowTick;
}

豚肉料理専門店に行く

ジョニーから豚肉料理専門店に行こうと連絡がありました。またジョニーか! とか思ったけど、学生時代の人間が東京に来ているとの事だったので、参加です。

面子は俺を含めて5人。みんな学生時代の連中です。肉を食いながら投資の話やセミナーの話が出たり。そういえば最近はセミナーとか行ってないなぁ。最後に行ったのはコールドリーディングの人のだったかな。最近ちょっと気になってるフォトリーディングのセミナーの話やマインドマップなんかの話が聞けてなかなか面白かったです。

そういえば知人の何人かが、「そろそろセミナービジネスやりたいなぁ」とか言ってたっけ。トークに自信のある人達は良いね。まあ俺は彼らと協力して、そのセミナーで収録したCDやDVDをネットで販売して儲ける、とw

たまにはこういう話題を肴に飲むのも良いね。

しゃぶしゃぶ食べ放題

今日はジョニーが「肉が食いたい気分でごわすゲマ」とか言うのでしゃぶしゃぶ食べ放題に行きました。いい加減このネタも古いな…

季節的にちょっと寒くなってきていたので、しゃぶしゃぶは良いですね。牛と豚を交互に、そしてたまに野菜を含めて食べてたよ。

ジョニーはオタクで情報系の学校に行っていたにもかかわらずネットに疎く、持ってるテレビはなぜかVHFしか映らない、さらにビデオデッキやHDDレコーダーも持っていない情報弱者なので、最近の(番組改編で終了してるけど)アニメなんかを教えてみました。どうやら幾つかは興味を持ったみたいで、DVDを買うとか言ってたよ。

食べ放題の店でジョニーがやらかす事は、食べきれない程の料理を持って来て余らせてしまうです。今回も余らせてたけど、迷惑な客だね。