トップページ > 記事閲覧
文字の一部分だけに色を付ける方法について
名前:Nさん 日時: 2019/03/24 19:37

現在ローグライクゲームを作成中でDrawFormatStringToHandle等で描画しているアイテム残り使用回数等の文字の色を変えたくて、 ttp://volatile.hatenablog.com/entry/2019/03/16/135308 こちらのサイト様を参考に文章の途中で色を変える方法を試しているのですがfpsが半分以下になってしまいにっちもさっちもいかない状態になっています。 何かスマートな方法はあるのでしょうか?
メンテ

Page: 1 |

Re: 文字の一部分だけに色を付ける方法について ( No.1 )
名前:MOR 日時:2019/03/24 22:06

volatile.hatenablog.com/entry/2019/03/16/135308 のコードを使ってみましたが、確かに重いですね。 昨年 dxlib.xsrv.jp/cgi/patiobbs/patio.cgi?mode=view&no=4510 に書いたものを一部変更してみました。 ただし「Unicode専用版」なので注意して下さい。(マルチバイトだと表示されない) 元のサンプルでは25〜30fpsくらいでしたが、これだとだいたい60fpsくらいでているかと思います。 ただし、色の指定方法が大変なので、使いやすさでは遥かに劣りますが... #include "DxLib.h" #include <vector> #include <string> using namespace std; typedef std::basic_string<TCHAR> tstring; #define ALIGNMENT_LEFT 0 #define ALIGNMENT_CENTER 1 #define ALIGNMENT_RIGHT 2 // 文字ごとの色変更版DrawString (手抜きなのでUnicode専用版にしてあります) // // bApplyCRColor = TRUEなら、改行文字('\n')にもダミー色を割り当ててあるとして処理 // 位置寄せ指定は『改行後の文字』が対象なので、一行目は左寄せ固定。 // nLineInterval = 改行の際のドット数 (DrawStringの改行ドット数はWindowsとAndroidで挙動が違うが法則がわからなかったので手動にした) int DrawStringToHandleWithColorArray(int x, int y, const TCHAR* pStr, int FontHandle, unsigned int* pColorCodeArray, int bApplyCRColor, int nLineInterval, int nPosAlignment = ALIGNMENT_LEFT) { if (pStr == NULL) return -1; if (pColorCodeArray == NULL) return -1; const TCHAR *lpStr = pStr; vector<vector<TCHAR>> vct; vector<TCHAR> vct0; int SizeX, SizeY = 0, ColorBitDepth = 0; RECT rc; DxLib::GetDrawArea(&rc); SizeX = rc.right; int nFSize = DxLib::GetFontSize(), xs = x; size_t uiSize = DxLib::strlen2Dx(pStr); unsigned int uiCL = 0, ui2 = 0; int tt = 0; int CharBytes = 0; TCHAR c; TCHAR cc[10]; for (unsigned int ui = 0; ui < uiSize; ui++) { CharBytes = DxLib::GetCharBytes(DX_CHARCODEFORMAT_UTF16LE, lpStr + ui2) / 2; if (CharBytes == 1) { c = *(lpStr + ui2++); if (c == '\n') { vct.push_back(vct0); vct0.clear(); } else { vct0.push_back(c); } } else { for (int i = 0; i < CharBytes; i++) { c = *(lpStr + ui2++); vct0.push_back(c); } } } if (vct0.size() > 0) { vct.push_back(vct0); vct0.clear(); } for (unsigned int i = 0; i < vct.size(); i++) { vct0 = vct[i]; int xss = 0; if (nPosAlignment == ALIGNMENT_CENTER && i > 0) { for (unsigned int k = 0; k < vct0.size(); k++) { cc[0] = vct0[k]; CharBytes = DxLib::GetCharBytes(DX_CHARCODEFORMAT_UTF16LE, &cc[0]) / 2; for (int m = 1; m < CharBytes; m++) { cc[m] = vct0[++k]; } cc[CharBytes] = '\0'; xss += DxLib::GetDrawStringWidthToHandle(cc, CharBytes, FontHandle); } x = (SizeX - xss) / 2; } else if (nPosAlignment == ALIGNMENT_RIGHT && i > 0) { for (unsigned int k = 0; k < vct0.size(); k++) { cc[0] = vct0[k]; CharBytes = DxLib::GetCharBytes(DX_CHARCODEFORMAT_UTF16LE, &cc[0]) / 2; for (int m = 1; m < CharBytes; m++) { cc[m] = vct0[++k]; } cc[CharBytes] = '\0'; xss += DxLib::GetDrawStringWidthToHandle(cc, CharBytes, FontHandle); } x = SizeX - xss; } else { x = xs; } for (unsigned int j = 0; j < vct0.size(); j++) { cc[0] = vct0[j]; CharBytes = DxLib::GetCharBytes(DX_CHARCODEFORMAT_UTF16LE, &cc[0]) / 2; for (int m = 1; m < CharBytes; m++) { cc[m] = vct0[++j]; } cc[CharBytes] = '\0'; DxLib::DrawStringToHandle(x, y, cc, pColorCodeArray[uiCL++], FontHandle); x += DxLib::GetDrawStringWidthToHandle(cc, CharBytes, FontHandle); } if (bApplyCRColor) uiCL++; y += nLineInterval; } return 0; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { DxLib::ChangeWindowMode(TRUE); DxLib::SetGraphMode(1280, 720, 32); DxLib::SetAlwaysRunFlag(TRUE); if (DxLib::DxLib_Init() < 0) return -1; DxLib::SetDrawMode(DX_DRAWMODE_BILINEAR); DxLib::SetDrawScreen(DX_SCREEN_BACK); DxLib::SetBackgroundColor(192, 192, 192); DxLib::SetFontCacheCharNum(2048); int FontHandle = DxLib::CreateFontToHandle(NULL, 16, 3, DX_FONTTYPE_ANTIALIASING_EDGE_8X8); unsigned uiCounter = 0, uiCounter2 = 0; while (DxLib::ProcessMessage() == 0) { DxLib::ClearDrawScreen(); TCHAR string[1000]; // 文字列は volatile.hatenablog.com/entry/2019/03/16/135308 から拝借 DxLib::sprintfDx(string, TEXT("あのイーハトーヴォのすきとおった風、" "夏でも底に冷たさをもつ青いそら、\n" "うつくしい森で飾られたモリーオ市、" "郊外のぎらぎらひかる草の波。\n" "Lorem ipsum dolor sit amet, consectetur adipiscing elit,\n" "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n" "%d + %d = %d"), 30, 40, 30 + 40); size_t uiSize = DxLib::strlen2Dx(string); unsigned int *puiCArray = new unsigned int[uiSize]; for (unsigned int ui = 0; ui < uiSize; ui++) { puiCArray[ui] = DxLib::GetColor((uiCounter2 + ui & 2) ? 255 : 0, (uiCounter2 + ui & 4) ? 255 : 0, (uiCounter2 + ui & 1) ? 255 : 0); } if (uiCounter++ % 30 == 0) uiCounter2++; int nn = 20; // 改行のドット数 DrawStringToHandleWithColorArray(0, 100, string, FontHandle, puiCArray, TRUE, nn); // 改行でも色カウンターを進める・左寄せ DrawStringToHandleWithColorArray(0, 250, string, FontHandle, puiCArray, TRUE, nn); DrawStringToHandleWithColorArray(0, 400, string, FontHandle, puiCArray, TRUE, nn); delete[] puiCArray; DxLib::DrawFormatString(0, 0, GetColor(255, 255, 255), TEXT("%dFPS"), (int)DxLib::GetFPS()); if (DxLib::ScreenFlip() != 0) break; } DxLib::InitFontToHandle(); return DxLib::DxLib_End(); }
メンテ
Re: 文字の一部分だけに色を付ける方法について ( No.2 )
名前:yumetodo 日時:2019/03/24 23:25

> nLineInterval GetFontLineSpaceToHandleで取ってこれるものとはまた違うんでしょうか ref: ttps: //qiita.com/yumetodo/items/8180d48b6fca18d78a90
メンテ
Re: 文字の一部分だけに色を付ける方法について ( No.3 )
名前:MOR 日時:2019/03/25 19:58

> GetFontLineSpaceToHandleで取ってこれるものとはまた違うんでしょうか 例えば int FontHandle = DxLib::CreateFontToHandle(NULL, 16, 3, DX_FONTTYPE_ANTIALIASING_EDGE_8X8); int n = DxLib::GetFontLineSpaceToHandle(FontHandle); とやってみると、戻り値 n は Windows 10 ... 20 Android実機 ... 28 iOSシミュレーター ... 26 のようにバラバラなので、現状ではY方向の位置を強制指定しないと見た目がそろいません。 (…と書きかけて DxLib::SetFontLineSpaceToHandle(20); とやっておけばいいと気が付きました)
メンテ
Re: 文字の一部分だけに色を付ける方法について ( No.4 )
名前:管理人 日時:2019/03/26 00:45

Debug版の std が非常に重いのが fps が半分以下になる原因みたいです なので、Releaseビルドでは fpsが半分以下になることはないと思いますが 開発中も常に Releaseビルドだとデバッグ作業に支障をきたしそうですね… MORさんが既に解決のアイディアをご提案されていますが、私もNさんがご紹介 されたサイト( ttp://volatile.hatenablog.com/entry/2019/03/16/135308 )と 同じ書式で色が付けられる std を使用しないプログラムを組んでみましたので よろしければご覧ください m(_ _)m ( 因みに私のサンプルは MORさんのプログラムとは逆にマルチバイト専用です… ) #include <DxLib.h> #include <string.h> // 16進数の2桁の数字を数値に変換する int GetNum16( const char *NumStr ) { int Num = 0 ; if( NumStr[ 0 ] >= 'a' && NumStr[ 0 ] <= 'f' ) { Num += ( NumStr[ 0 ] - 'a' + 10 ) * 16 ; } else { Num += ( NumStr[ 0 ] - '0' ) * 16 ; } if( NumStr[ 1 ] >= 'a' && NumStr[ 1 ] <= 'f' ) { Num += NumStr[ 1 ] - 'a' + 10 ; } else { Num += NumStr[ 1 ] - '0' ; } return Num ; } void DrawFormatStringToHandleColor(const int x, const int y, const unsigned int Color, const int FontHandle, const char *FormatString, ... ) { va_list VaList ; char String[ 4096 ]; char TempString[ 4096 ] ; const char *StringP ; int DrawX, DrawY ; int LineHeight ; int TempStringBytes ; int CharCodeFormat ; int NowColor ; int CharBytes ; // 書式文字列から文字列を作成する va_start( VaList, FormatString ) ; vsnprintfDx( String, sizeof( String ) - 1, FormatString, VaList ) ; va_end( VaList ) ; // 使用している文字コード形式を取得 CharCodeFormat = GetUseCharCodeFormat() ; // フォントの高さを取得しておく LineHeight = GetFontLineSpaceToHandle( FontHandle ) ; // 描画位置の初期化 DrawX = x ; DrawY = y ; // 色をセット NowColor = Color ; // 描画する文字列の長さを初期化 TempStringBytes = 0 ; // 文字列のアドレスをセット StringP = String ; // 文字列の終端に到達するまでループ while( *StringP != '\0' ) { // 1文字のバイト数を取得 CharBytes = GetCharBytes( CharCodeFormat, StringP ) ; // 1文字が1バイト以上の場合は全角文字として判断 if( CharBytes > 1 ) { // 描画する文字列に1文字分コピー memcpy( &TempString[ TempStringBytes ], StringP, CharBytes ) ; TempStringBytes += CharBytes ; TempString[ TempStringBytes ] = '\0' ; // 文字列のアドレスを1文字分進める StringP += CharBytes ; } else // [ だったら色変更関係として処理 if( StringP[ 0 ] == '[' ) { // 描画する文字列があったらここで描画する if( TempStringBytes > 0 ) { DrawStringToHandle( DrawX, DrawY, TempString, NowColor, FontHandle ) ; // 描画 x 座標を描画文字列の幅分だけ右側に移動する DrawX += GetDrawStringWidthToHandle( TempString, -1, FontHandle ) ; // 描画文字列の長さを初期化 TempStringBytes = 0 ; } // 2文字目が - の場合は色を元に戻す if( StringP[ 1 ] == '-' ) { NowColor = Color ; // [-] の 3文字分アドレスを進める StringP += 3 ; } else { // それ以外の場合は文字の色を読み取る NowColor = GetColor( GetNum16( &StringP[ 1 ] ), GetNum16( &StringP[ 3 ] ), GetNum16( &StringP[ 5 ] ) ) ; // [RRGGBB] の 8文字分アドレスを進める StringP += 8 ; } } else // 改行文字の場合は描画文字位置を改行する if( StringP[ 0 ] == '\n' ) { // 描画する文字列があったらここで描画する if( TempStringBytes > 0 ) { DrawStringToHandle( DrawX, DrawY, TempString, NowColor, FontHandle ) ; // 描画文字列の長さを初期化 TempStringBytes = 0 ; } // 描画 x 座標を最初の位置に戻す DrawX = x ; // 描画 y 座標を1行分下にずらす DrawY += LineHeight ; // 改行文字の 1文字分アドレスを進める StringP++ ; } else // 上記以外の場合は 1バイトの 1文字 { // 描画文字列に 1文字加える TempString[ TempStringBytes ] = *StringP ; TempStringBytes++ ; TempString[ TempStringBytes ] = '\0' ; // アドレスを 1文字分進める StringP++ ; } } // 描画する文字列があったらここで描画する if( TempStringBytes > 0 ) { DrawStringToHandle( DrawX, DrawY, TempString, NowColor, FontHandle ) ; } } int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { // ウインドウモードで起動 ChangeWindowMode( TRUE ) ; // 画面モードをセット SetGraphMode( 1024, 480, 32 ) ; // DXライブラリの初期化 if( DxLib_Init() < 0 ) return -1 ; // 描画先を裏画面にする SetDrawScreen( DX_SCREEN_BACK ) ; const char *string = "あの[fc585a]イーハトーヴォ[-]の[49b21f]すきとおった風[-]、" "[eb8900]夏[-]でも[2ed2fd]底に冷たさをもつ青いそら[-]、\n" "[49b21f]うつくしい森[-]で飾られた[fc585a]モリーオ市[-]、" "[fc585a]郊外[-]の[fdbf2d]ぎらぎらひかる[49b21f]草の波[-]。\n" "[ff0000]Lorem ipsum dolor sit amet, [00ff00]consectetur adipiscing elit,\n" "[0000ff]sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.[-]\n" "%d + %d = [abcdef]%d"; // フォントハンドルの作成 int FontHandle = CreateFontToHandle( NULL, 20, 4, DX_FONTTYPE_NORMAL ) ; // 背景の色を灰色にする SetBackgroundColor( 128,128,128 ) ; // メインループ while( ProcessMessage() == 0 ) { // 画面のクリア ClearDrawScreen() ; DrawFormatStringToHandleColor(0, 100, 0xffffff, FontHandle, string, 30, 40, 30 + 40); // 裏画面の内容を表画面に反映 ScreenFlip() ; } // DXライブラリの後始末 DxLib_End() ; // ソフトの終了 return 0 ; } あと、このサンプルでは今回新たに追加した関数 GetUseCharCodeFormat を 使用していますので、お手数で申し訳ありませんが関数を追加したこちらの バージョンを使用してください m(_ _;m https://dxlib.xsrv.jp/temp/DxLibVCTest.zip // Windows版 VisualC++ 用 https://dxlib.xsrv.jp/temp/DxLibBCCTest.zip // Windows版 BorlandC++ 用 https://dxlib.xsrv.jp/temp/DxLibBCC2Test.zip // Windows版 C++ Builder 10.2 用 https://dxlib.xsrv.jp/temp/DxLibGCC_MinGWTest.zip // Windows版 MinGW 用 https://dxlib.xsrv.jp/temp/DxLibDotNet.zip // Windows版 .NET用 https://dxlib.xsrv.jp/temp/DxLibAndroidTest_ARM.zip // Android版 ARM用 https://dxlib.xsrv.jp/temp/DxLibAndroidTest_ARM64.zip // Android版 ARM64用 https://dxlib.xsrv.jp/temp/DxLibAndroidTest_x86.zip // Android版 x86用 https://dxlib.xsrv.jp/temp/DxLibAndroidTest_x64.zip // Android版 x64用 https://dxlib.xsrv.jp/temp/DxLibiOSTest.zip // iOS版 https://dxlib.xsrv.jp/temp/DxLibMakeTest.zip // ソース (中身を既存のライブラリのファイルに上書きして『リビルド』をして下さい)
メンテ
Re: 文字の一部分だけに色を付ける方法について ( No.5 )
名前:Nさん 日時:2019/03/26 12:55

MORさん、管理人さんありがとうございます。試してみたいと思います
メンテ

Page: 1 |

題名
名前
コメント
パスワード (記事メンテ時に使用)

   クッキー保存