ノベルゲームのテキストエンジン[C/C++]
Posted: 2014年10月21日(火) 19:02
開発環境
OS:Windows7 Ultimate(Mac OS X Mavericks上のVirtual Box 4.3.12で動かしています)
Microsoft Visual C++ 2010 で DxLibraryを使用
現在ノベルゲームのテキストエンジンを作成していて、
・1行の長さを文字数で制限
・メッセージボックスに収まる行数の表示
はできているのですが、
・1行の長さを幅で制限する方法(全角/半角が混ざることが考えられるため。等幅フォントを使用)
・メッセージボックスに収まらないメッセージの時のメッセージボックスの更新の仕方
(例えばメッセージボックスが三行しか表示できず、メッセージは4行以上の場合)
この二つの実装の仕方について悩んでいます
メッセージボックスにつきましては
①表示されているメッセージの二行目、三行目を変数に格納
②表示されているメッセージを消去
③変数に格納したものをまとめて描画
④新しい行を一文字ずつ表示
という形にしたいと思っています
以下、ソースコード
コンパイルエラーは出ていません
下記のページを参考にしながら開発を行っております
http://karetta.jp/book-node/game-programming/235056
OS:Windows7 Ultimate(Mac OS X Mavericks上のVirtual Box 4.3.12で動かしています)
Microsoft Visual C++ 2010 で DxLibraryを使用
現在ノベルゲームのテキストエンジンを作成していて、
・1行の長さを文字数で制限
・メッセージボックスに収まる行数の表示
はできているのですが、
・1行の長さを幅で制限する方法(全角/半角が混ざることが考えられるため。等幅フォントを使用)
・メッセージボックスに収まらないメッセージの時のメッセージボックスの更新の仕方
(例えばメッセージボックスが三行しか表示できず、メッセージは4行以上の場合)
この二つの実装の仕方について悩んでいます
メッセージボックスにつきましては
①表示されているメッセージの二行目、三行目を変数に格納
②表示されているメッセージを消去
③変数に格納したものをまとめて描画
④新しい行を一文字ずつ表示
という形にしたいと思っています
以下、ソースコード
コンパイルエラーは出ていません
#include "DxLib.h"
// 関数プロトタイプ宣言
int DiscriminateChar(unsigned char);
void OutString(char*, int, int, int, int, int, int);
void drawMsg();
void initGame();
// #define
// メッセージのフォントの大きさ
#define MESSAGE_FONT_SIZE 17
// 仮想バッファの最大文字数(半角60字==全角30字)
#define MESSAGE_MAX_LENGTH 60
// 仮想バッファの最大行数
#define MESSAGE_MAX_LINE 5
// メッセージボックスのX座標
#define MESSAGE_BOX_X_POS 40
// メッセージボックスのY座標
#define MESSAGE_BOX_Y_POS 340
// メッセージボックスの画像ファイル
#define MESSAGE_BOX_GRAPHIC_FILENAME "./img/msg_box.png"
// グローバル変数
// 表示したいメッセージ
char g_msg[MESSAGE_MAX_LENGTH * MESSAGE_MAX_LINE] ="HELLO WORLD!あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわをん1234567890";
// 画面にメッセージを表示する際に使用する仮想テキストバッファ
char g_msgBuf[MESSAGE_MAX_LINE][MESSAGE_MAX_LENGTH];
// フォントハンドル
int g_FontHandle;
// 現在何文字目までを表示しているか
static int g_curCursor = 0;
// 何行目の文字を表示しているか
static int g_curLineCursor = 0;
// 色
static int g_whiteColor;
static int g_blackColor;
//メッセージボックスの画像
static int g_msgBoxGraphHandle;
// WinMain
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
//ウィンドウモードで起動
ChangeWindowMode(TRUE);
//画面の大きさは640 * 480
SetGraphMode(640, 480, 16) ;
//DxLib初期化
if(DxLib_Init() == -1)
return -1;
// 描画先を裏画面にセット
SetDrawScreen(DX_SCREEN_BACK) ;
// グローバル変数をセット
initGame();
// メインループ
while(ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0){
// 画面初期化
ClearDrawScreen();
// メッセージ描画
drawMsg();
// 300msec.待機
Sleep(300);
// 描画を表画面に
ScreenFlip();
}
// フォントハンドル破棄
DeleteFontToHandle(g_FontHandle);
// DxLib終了処理
DxLib_End();
return 0;
}
// Codeが全角であるか判定する
// 戻り値 1:全角 0:全角ではない
int DiscriminateChar(unsigned char Code){
if((Code >= 0x81 && Code <= 0x9F) || (Code >= 0xE0 && Code <= 0xFC))
return 1;
return 0;
}
// msgで指定した文章をstartの位置からlen文字分表示する
void OutString(char* msg, int start, int len, int posX, int posY, int color, int bufLine){
// ループカウンタ
int i;
//文字数
int maxLen = strlen(msg);
//startの位置を変更する
//startの位置までに全角がでてきていたら,1を足していく
for(i = 0; i < start && msg[i] != '\0';){
if(DiscriminateChar(msg[i])) {
//日本語の場合,2バイト分すすめる
++i;
//startに1バイト分足す
++start;
}
//半角の場合,1バイト分進める
++i;
}
//startの位置が表示したい最大文字数より大きい場合
if(start >= maxLen)
return;
//指定した位置からlen文字分表示する
for(i = 0; i < len && msg[start + i] != '\0';){
g_msgBuf[bufLine][i] = msg[start + i];
if(DiscriminateChar(msg[start + i ])){
//日本語の場合,2文字分bufferにセット
g_msgBuf[bufLine ][i + 1] = msg[start + i + 1];
//lenは日本語なので,1バイト分追加する
++len;
//2バイト分進める
++i;
}
//1バイト分進める
++i;
}
// 配列の最後に'\0'を代入
g_msgBuf[bufLine][i] = '\0';
//メッセージ描画
DrawStringToHandle(posX, posY, g_msgBuf[bufLine], color, g_FontHandle);
}
// メッセージ描画
void drawMsg(){
// ループカウンタ
int i;
// メッセージボックス描画
DrawGraph(MESSAGE_BOX_X_POS, MESSAGE_BOX_Y_POS, g_msgBoxGraphHandle, FALSE);
if(g_msg[g_curCursor] != '\0'){
// 全角なら2文字分、半角なら一文字分カーソルを進める
if(DiscriminateChar(g_msg[g_curCursor]))
++g_curCursor;
++g_curCursor;
}
// 半角60字分に到達->次の行へ
// 半角で59字分、次の文字が全角の場合も次の行へ
if(g_msg[g_curCursor] != '\0' &&
(g_curCursor % MESSAGE_MAX_LENGTH == 0 ||
(g_curCursor % MESSAGE_MAX_LENGTH == MESSAGE_MAX_LENGTH - 1 && DiscriminateChar(g_msg[g_curCursor + 1]))))
++g_curLineCursor;
// draw msg
for(i = 0; i < MESSAGE_MAX_LINE; i++){
if(i==g_curLineCursor){
OutString(g_msg, i * MESSAGE_MAX_LENGTH, g_curCursor - MESSAGE_MAX_LENGTH * i,
MESSAGE_BOX_X_POS + 8, MESSAGE_BOX_Y_POS + MESSAGE_FONT_SIZE * i + 15, g_blackColor, i);
break;
}else
OutString(g_msg, i * MESSAGE_MAX_LENGTH, MESSAGE_MAX_LENGTH,
MESSAGE_BOX_X_POS + 8, MESSAGE_BOX_Y_POS + MESSAGE_FONT_SIZE * i + 15, g_blackColor, i);
}
}
// グローバル変数初期化
void initGame(){
// 白
g_whiteColor = GetColor(255, 255, 255);
// 黒
g_blackColor = GetColor(0, 0, 0);
// メッセージボックスの画像
g_msgBoxGraphHandle = LoadGraph(MESSAGE_BOX_GRAPHIC_FILENAME);
// フォント指定(等幅フォントのMS ゴシックを使用)
g_FontHandle = CreateFontToHandle("MS ゴシック" , MESSAGE_FONT_SIZE, 2 , DX_FONTTYPE_ANTIALIASING);
}
http://karetta.jp/book-node/game-programming/235056