シェルスクリプトマガジン

香川大学SLPからお届け!(Vol.93掲載)

著者:原口 莉奈

 私は最近、RPG(Role-Playing Game)の戦闘シーンをC++言語で作成しました。作成には、無償で利用できるゲーム開発用ライブラリ「DXライブラリ」(https://dxlib.xsrv.jp/)を用いています。今回は、その一部であるコマンド選択画面の実装について紹介します。

シェルスクリプトマガジン Vol.93は以下のリンク先でご購入できます。

図2 ビルド用のバッチファイル「build.bat」に記述する内容

g++ -c Main.cpp -DDX_GCC_COMPILE -I"DxLib"
g++ -o game.exe Main.o -L"DxLib" -lgcc -lDxLib -lDxUseCLib ^
 -lDxDrawFunc -ljpeg -lpng -lzlib -ltiff -ltheora_static ^
 -lvorbis_static -lvorbisfile_static -logg_static ^
 -lbulletdynamics -lbulletcollision -lbulletmath -lopusfile ^
 -lopus -lsilk_common -lcelt

図3 「Main.cpp」ファイルに記述するコード

#define WIN_X 256 
#define WIN_Y 224

#include <DxLib.h>

int WINAPI WinMain(
  _In_ HINSTANCE hInstance,
  _In_opt_ HINSTANCE hPrevInstance,
  _In_ LPSTR IpCmdLine,
  _In_ int nShowCmd)
{
  ChangeWindowMode(TRUE);
  DxLib_Init();

  // ウィンドウ初期化
  SetWindowText("game"); // タイトル
  SetGraphMode(WIN_X, WIN_Y, 32); // 解像度と色深度
  SetBackgroundColor(255, 255, 255); // 背景色

  WaitKey();
  DxLib_End();
  return 0;
}

図5 「Main.cpp」ファイルに記述するコード

#define WIN_X 256
#define WIN_Y 224

#include <DxLib.h>
#include "Status.h"
#include "Battle.h"

int WINAPI WinMain(
  _In_ HINSTANCE hInstance,
  _In_opt_ HINSTANCE hPrevInstance,
  _In_ LPSTR IpCmdLine,
  _In_ int nShowCmd)
{
  ChangeWindowMode(TRUE);
  DxLib_Init();

  SetWindowText("game");
  SetGraphMode(WIN_X, WIN_Y, 32);
  SetBackgroundColor(255, 255, 255);
  SetDrawScreen(DX_SCREEN_BACK); // 裏画面描画
  SetWindowSize(1024, 960); // ウィンドウサイズ

  Battle.materialLoad();
  while (ProcessMessage() == 0)
  {
    SetBackgroundColor(0, 0, 0);
    Battle.BattleDraw();
  }
  DxLib_End();
  return 0;
}

図6 「Status.h」ファイルに記述するコード

class BATTLE {
public:
  struct Status {
    char name[50];
    int HP, ATK, DEF; //体力、攻撃力、防御力
  };
  struct Status player = { "player",30, 10, 5 };
  struct Status villain = { "villain",30, 7, 5 };
  struct Status* Player = &player;
  const char* str[4] = { "たたかう", "まもる",
                         "どうぐ", "にげる" };
  const char* item[1] = { "回復" };
  int firstsym = 80;
  int sym = firstsym;
  int sym_limit = firstsym + (4 - 1) * 17;
  int symbol = -1, symnext = 0;
  int pattern = 1;
  int firstarrow = 80;
  int arrow = firstarrow;
  int limit; // firstarrow + (num - 1) * 17
  int a_posi = -1;
  int re = 0;
  int black, white, ms;
  void materialLoad();
  void BattleDraw();
  void one();
  void two();
  void Choices(int x, const char* str[], int n);
private:
};

図7 「Battle.h」ファイルに記述するコード

BATTLE Battle;
void BATTLE::materialLoad() {
  black = GetColor(0, 0, 0);
  white = GetColor(255, 255, 255);
  ms = CreateFontToHandle("MS ゴシック", 10, 6,
                          DX_FONTTYPE_ANTIALIASING_4X4);
}
void BATTLE::Choices(int x, const char* str[], int n) {
  int w = 0;
  for (int i = 0; i < n; i++) {
    DrawBox(x, firstarrow + w,
            x + 80, firstarrow + 16 + w, white, TRUE);
    DrawFormatStringToHandle(x + 5, firstarrow + 5 + w,
                             black, ms, str[i]);
    w += 17;
  }
}
// 初期表示
void BATTLE::one() {
  sym = firstsym;
  pattern = 2;
}
// 矢印の移動
void BATTLE::two() {
  if (symnext == 0) {
    switch (WaitKey()) {
      case KEY_INPUT_DOWN:
        if (sym != sym_limit) sym += 17;
        break;
      case KEY_INPUT_UP:
        if (sym != firstsym)  sym -= 17;
        break;
      case KEY_INPUT_ESCAPE:
        DxLib_End();
        break;	
    }
    if (symbol != -1) symnext++;
  }
}

void BATTLE::BattleDraw() {
  SetDrawScreen(DX_SCREEN_BACK);
  ClearDrawScreen();
  switch(pattern):
  if (pattern == 1) one();
  else if (pattern == 2) two();
  Choices(160, str, 4);
  DrawFormatStringToHandle(144, sym, white, ms, "→");
  ScreenFlip();
}

図9 「Status.h」ファイルにHpDraw()関数の記述を追加

(略)
  void HpDraw();
  void BattleDraw();
(略)

図10 「Battle.h」ファイルのBattleDraw()関数定義部分をこのように書き換える

(略)void BATTLE::HpDraw() {
  DrawBox(180, 160, 250, 184, white, FALSE);
  DrawBox(180, 186, 250, 210, white, FALSE);
  DrawFormatStringToHandle(182, 162, white, ms,
                           "villain\nHP: %d", villain.HP);
  DrawFormatStringToHandle(182, 188, white, ms,
                           "player\nHP:%d", player.HP);
}
void BATTLE::BattleDraw() {
  SetDrawScreen(DX_SCREEN_BACK);
  ClearDrawScreen();
  switch(pattern):
  if (pattern == 1) one();
  else if (pattern == 2) two();
  Choices(160, str, 4);
  DrawFormatStringToHandle(144, sym, white, ms, "→");
  HpDraw();
  ScreenFlip();
}