DXライブラリで指定範囲の英語文字列を表示したい

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
でぶの極み重め
記事: 6
登録日時: 1年前

DXライブラリで指定範囲の英語文字列を表示したい

#1

投稿記事 by でぶの極み重め » 1年前

http://www.usamimi.info/~guiprog/game_p ... amming.pdf
上記のサイト54枚目の「指定範囲の英字文字列を表示」を参考にDXライブラリ、C言語でプログラムを作成しているのですが、printfをDrawFormatStringで代用しようとするとエラーが出てしまいます。
const char*型とconst TCHAR*型の互換性がないことが原因のようですが、どのようにすれば解決できるのかわかりません。最終的にはノベルゲームのように1文字ずつ時間差で表示できるようにしたいです。

コード:

void WriteString(int x, int y, const char* message, int start, int len) {
	int MaxLen = strlen(message);
	if (start >= MaxLen)	return;							//出力終わり

	for (int i = 0; i < len && message[start + 1] != '\0'; i++) {		//出力長さまで出力 or 終端文字で終了
		DrawFormatString(x, y + FONTSIZE, white, message[start + i]);
	}
}
}

アバター
あたっしゅ
記事: 665
登録日時: 14年前
住所: 東京23区
連絡を取る:

Re: DXライブラリで指定範囲の英語文字列を表示したい

#2

投稿記事 by あたっしゅ » 1年前

[香車]東上☆あらし☆海美「

> DrawFormatString(x, y + FONTSIZE, white, message[start + i]);

message に [start + i] を付けたことで、エラーが出ています。


> 最終的にはノベルゲームのように1文字ずつ時間差で表示できるようにしたいです。

https://dxlib.xsrv.jp/dxprogram.html
DxLib 本家の『DXライブラリ サンプルプログ』(ja)

の『サンプルプログラム実行用プロジェクト』をクリックして、ダウンロードされたものが、
ノベルゲームのサンプルになっているので、参考にしてくださいみみ。

VTuber:
東上☆海美☆(とうじょう・うみみ)
http://atassyu.php.xdomain.jp/vtuber/index.html
レスがついていないものを優先して、レスするみみ。時々、見当外れなレスしみみ。

中の人:
手提鞄あたッしュ、[MrAtassyu] 手提鞄屋魚有店
http://ameblo.jp/mratassyu/
Pixiv: 666303
Windows, Mac, Linux, Haiku, Raspbery Pi, Jetson Nano, 電子ブロック 持ち。

dic
記事: 657
登録日時: 14年前
住所: 宮崎県
連絡を取る:

Re: DXライブラリで指定範囲の英語文字列を表示したい

#3

投稿記事 by dic » 1年前

こういうことでしょうか?

コード:


#include <DxLib.h>




#define FONTSIZE 20
int white = GetColor(255, 255, 255);



void WriteString(int x, int y, const char* message, int start, int len)
{
	int MaxLen = strlen(message);
	if (start >= MaxLen)	return;							//出力終わり

	// 日本語だったら i=i+2
	// 英語だったら i++
	for (int i = 0; i < len && message[start + 1] != '\0'; i=i+2) {		//出力長さまで出力 or 終端文字で終了

		DrawFormatString(x+i*10, y + FONTSIZE+i*20, white, &message[start+i]);
	}
}



//ループで必ず行う3大処理
int ProcessLoop(){
    if(ProcessMessage()!=0)return -1;//プロセス処理がエラーなら-1を返す
    if(ClearDrawScreen()!=0)return -1;//画面クリア処理がエラーなら-1を返す
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
	ChangeWindowMode( TRUE );//ウィンドウモード

	if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化

	while(ProcessLoop()==0){//メインループ

		// 呼び出し
		char mes[80];
		memset(mes, 0, sizeof(mes));
		sprintf_s(mes, "テストメッセージです。");
		WriteString(0, 0, mes, 0, strlen(mes));


		if(CheckHitKey(KEY_INPUT_ESCAPE)==1)break;//エスケープが入力されたらブレイク1
		ScreenFlip();//裏画面反映
	}
	
	DxLib_End();//DXライブラリ終了処理
	return 0;

}

でぶの極み重め
記事: 6
登録日時: 1年前

Re: DXライブラリで指定範囲の英語文字列を表示したい

#4

投稿記事 by でぶの極み重め » 1年前

回答ありがとうございます。添付のサイトを参考に自作関数を作成することができました。次に、引数に表示したいメッセージを指定して表示するように改良しようと考え、作ってみたのですが表示したいメッセージを表示した後に文字化けしたメッセージが表示されてしまいます。おそらく引数のconst char String[][256]に問題があるのだと思いますが、何が問題なのかわかりません。

ソースファイル

コード:

void WriteString(const char String[][256]) {
	char OneMojiBuf[3];	// 1文字分一時記憶配列
	int i = 0, j = 0;
	int EndFlag = 0;							//終了判定フラグ
	int KeyWaitFlag = 0;						//ボタン押し待ちフラグ

	//描画位置セット
	static int CursorX = 0;
	static int CursorY = 0;

	//参照位置セット
	static int SP = 0;
	static int CP = 0;

	//フレームカウンタ初期化
	static int count = 0;

	// ループ
	// サウンドノベル風文字列描画処理を行う
		// ただし終了フラグが1だった場合は処理をしない
	if (EndFlag == 0)
	{
		char  Moji;
		while (ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0) {
			// ボタン押し待ちフラグがたっていた場合はボタンが押されるまでここで終了
			if (KeyWaitFlag == 1)
			{
				if (ProcessMessage() == 0 && CheckHitKeyAll() != 0)
				{
					// ボタンが押されていたら解除
					KeyWaitFlag = 0;
				}
			}
			else
			{
				// 文字の描画
				Moji = String[SP][CP];
				switch (Moji)
				{
				case '@':	// 改行文字

					// 改行処理および参照文字位置を一つ進める
					CursorY++;		//描画行を1つ下げる
					CursorX = 0;	//描画列を初期化

					//縦にはみ出した時の処理は一旦なし

					CP++;
					break;

				case 'B':	// ボタン押し待ち文字
					// ボタンが離されるまで待つ
					while (ProcessMessage() == 0 && CheckHitKeyAll() != 0) {}

					// ボタン押し待ちフラグをたてる
					KeyWaitFlag = 1;
					CP++;
					break;

				case 'E':	// 終了文字
					// 終了フラグを立てるおよび参照文字位置を一つ進める
					EndFlag = 1;
					CP++;
					break;

				case 'C':	// クリア文字
					// 仮想テキストバッファを初期化して描画文字位置を初期位置に戻すおよび参照文字位置を一つ進める
					for (i = 0; i < STRBUF_HEIGHT; i++)
					{
						for (j = 0; j < STRBUF_WIDTH * 2; j++)
						{
							StringBuf[i][j] = 0;
						}
					}

					CursorY = 0;
					CursorX = 0;
					CP++;
					break;

				default:	// その他の文字
					// 1文字分抜き出す
					OneMojiBuf[0] = String[SP][CP];
					OneMojiBuf[1] = String[SP][CP + 1];
					OneMojiBuf[2] = '\0';

					// 1文字テキストバッファに代入
					StringBuf[CursorY][CursorX * 2] = OneMojiBuf[0];
					StringBuf[CursorY][CursorX * 2 + 1] = OneMojiBuf[1];

					// 参照文字位置を2バイト勧める
					CP += 2;

					// カーソルを一文字文進める
					CursorX++;

					// テキストバッファ横幅からはみ出たら改行する
					if (CursorX >= STRBUF_WIDTH) {
						CursorY++;		//描画行を1つ下げる
						CursorX = 0;	//描画列を初期化
					}
					break;
				}

				// 参照文字列の終端まで行っていたら参照文字列を進める
				if (String[SP][CP] == '\0')
				{
					SP++;
					CP = 0;
				}
			}
			// 画面のクリア
			ClsDrawScreen();

			// テキストバッファの描画
			for (i = 0; i < STRBUF_HEIGHT; i++)
			{
				DrawString(8, i * FONTSIZE, StringBuf[i], GetColor(255, 255, 255));
			}

			// 裏画面の内容を表画面に反映させる
			ScreenFlip();
		}
	}
}
ヘッダーファイル

コード:

//WriteString用
// 仮想テキストバッファの横サイズ縦サイズ
#define STRBUF_WIDTH	24
#define STRBUF_HEIGHT	20

static char StringBuf[STRBUF_HEIGHT][STRBUF_WIDTH * 2 + 1];	// 仮想テキストバッファ
const char String1[][256] =
{
	" ゲームプログラムを習得するための一番の近道はとにかく沢山プログラムを組む",
	"ことである。B" ,
	"@ プログラムの参考書にはゲームのプログラムの方法なんて何も書かれていない、B",
	"変数、B配列、B関数、Bループ、B条件分岐…Bこれらすべての説明はゲームで何に使うか",
	"なんてどこにも書いていない、Bせいぜい住所録を題材にした例がある程度である。B" ,
	"C プログラムは習うより慣れろなのでプログラムを組むに当たって少しでも知識が",
	"つけば後はそこからは掘り下げ、広げていけば良いわけで、Bプログラムの参考書を",
	"読んでいて少しでも何か出来るような気がしたらそこでとにかくプログラム",
	"を打ってみることが大事である。E",
};

でぶの極み重め
記事: 6
登録日時: 1年前

Re: DXライブラリで指定範囲の英語文字列を表示したい

#5

投稿記事 by でぶの極み重め » 1年前

dic様も回答ありがとうございます。実行してみたところ少し思っていた挙動とは違いましたが、プログラムを見たところ、const char*型の引数に&message[start + i]で指定できるようなので、この先は自分で一度組んでみようと思います。

dic
記事: 657
登録日時: 14年前
住所: 宮崎県
連絡を取る:

Re: DXライブラリで指定範囲の英語文字列を表示したい

#6

投稿記事 by dic » 1年前

文字化けは TCHAR を使えばいいといいたい、
だけど、TCHAR は時代遅れだそうな、
また、DxLibは TCHAR型を使うから
UNICODE を使おうとするとコンパイルエラーがでた
解決方法は俺にはわからない。

dic
記事: 657
登録日時: 14年前
住所: 宮崎県
連絡を取る:

Re: DXライブラリで指定範囲の英語文字列を表示したい

#7

投稿記事 by dic » 1年前

UNICODE (2バイト文字列)の場合のサンプル

コード:

// 2023_05_06_TCHAR.cpp : アプリケーションのエントリ ポイントを定義します。
//

#include "framework.h"
#include "2023_05_06_TCHAR.h"

//  これがいる
#include <iostream>
#include <wchar.h>



#define MAX_LOADSTRING 100

// グローバル変数:
HINSTANCE hInst;                                // 現在のインターフェイス
WCHAR szTitle[MAX_LOADSTRING];                  // タイトル バーのテキスト
WCHAR szWindowClass[MAX_LOADSTRING];            // メイン ウィンドウ クラス名

// このコード モジュールに含まれる関数の宣言を転送します:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: ここにコードを挿入してください。

    // グローバル文字列を初期化する
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_MY20230506TCHAR, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // アプリケーション初期化の実行:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MY20230506TCHAR));

    MSG msg;

    // メイン メッセージ ループ:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}



//
//  関数: MyRegisterClass()
//
//  目的: ウィンドウ クラスを登録します。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MY20230506TCHAR));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_MY20230506TCHAR);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

//
//   関数: InitInstance(HINSTANCE, int)
//
//   目的: インスタンス ハンドルを保存して、メイン ウィンドウを作成します
//
//   コメント:
//
//        この関数で、グローバル変数でインスタンス ハンドルを保存し、
//        メイン プログラム ウィンドウを作成および表示します。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // グローバル変数にインスタンス ハンドルを格納する

   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  関数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的: メイン ウィンドウのメッセージを処理します。
//
//  WM_COMMAND  - アプリケーション メニューの処理
//  WM_PAINT    - メイン ウィンドウを描画する
//  WM_DESTROY  - 中止メッセージを表示して戻る
//
//

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    TCHAR   mes[80];
    swprintf_s(mes, 80, L"テストメッセージです。");
    TCHAR   szSize[8];
    swprintf_s(szSize, 8, L"SIZE:%d", sizeof(szSize[0]) );

    switch (message)
    {
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // 選択されたメニューの解析:
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: HDC を使用する描画コードをここに追加してください...
            TextOut(hdc, 0, 0, mes, lstrlen(mes));
            TextOut(hdc, 200, 0, szSize, lstrlen(szSize));
            for (int i = 0; i < lstrlen(mes); i++) {
                TextOut(hdc, i*20, 20 + i * 20, &mes[i], 1);
            }
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

// バージョン情報ボックスのメッセージ ハンドラーです。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}

返信

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