1 //  ここにサンプルプログラムをペーストしてください
2 // 初期状態ではサウンドノベル風文字列描画サンプルが入力されています。
3 //  べつのサンプルプログラムを実行する場合は以下のプログラムをすべて
4 // 削除して、新たにコピー&ペーストしてください。
5 module windows_sample.app;
6 
7 
8 version (Windows):
9 
10 import core.stdc.math;
11 import dxlib_d.DxDataType;
12 import dxlib_d.DxFunctionWin;
13 import dxlib_d.DxLib;
14 
15 // サウンドノベル風文字列描画、テキストバッファ使用バージョン
16 
17 // 文字のサイズ
18 enum MOJI_SIZE = 24;
19 
20 //画面の幅と高さ
21 enum WIDTH = 640;
22 enum HEIGTH = 480;
23 
24 // 仮想テキストバッファの横サイズ縦サイズ
25 enum STRBUF_WIDTH = 24;
26 enum STRBUF_HEIGHT = 20;
27 
28 // 仮想テキストバッファ
29 dxlib_d.DxDataType.TCHAR[(.STRBUF_WIDTH * 4) + 1][.STRBUF_HEIGHT] StringBuf;
30 
31 // 仮想画面上での文字表示カーソルの位置
32 int CursorX;
33 int CursorY;
34 
35 // 参照する文字列番号と文字列中の文字ポインタ
36 int SP;
37 int CP;
38 int CursorX_CP;
39 
40 // 終了フラグ
41 bool EndFlag;
42 
43 // ボタン押し待ちフラグ
44 bool KeyWaitFlag;
45 
46 // フレームカウンタ
47 int Count;
48 
49 //Dxlibの関数に渡される文字列の終端は'\0'でなければならないことに気をつける。
50 version (Unicode) {
51 	//正常に動作するかは未確認
52 	static assert(false);
53 
54 	//UTF-16 文字列
55 	static immutable wchar[256][] String =
56 	[
57 		" ゲームプログラムを習得するための一番の近道はとにかく沢山プログラムを組む",
58 		"ことである。B",
59 		"@ プログラムの参考書にはゲームのプログラムの方法なんて何も書かれていない、B",
60 		"変数、B配列、B関数、Bループ、B条件分岐…Bこれらすべての説明はゲームで何に使うか",
61 		"なんてどこにも書いていない、Bせいぜい住所録を題材にした例がある程度である。B",
62 		"C プログラムは習うより慣れろなのでプログラムを組むに当たって少しでも知識が",
63 		"つけば後はそこからは掘り下げ、広げていけば良いわけで、Bプログラムの参考書を",
64 		"読んでいて少しでも何か出来るような気がしたらそこでとにかくプログラム",
65 		"を打ってみることが大事である。E",
66 	];
67 } else {
68 	version (all) {
69 		//UTF-8文字列
70 		//Dxlibの関数に文字列を渡す場合、DxLib_Initの前にSetUseCharCodeFormat(DX_CHARCODEFORMAT_UTF8)としないと、UTF-8ではなくSHIFT-JIS文字列と認識されてしまう
71 		static immutable char[256][] String =
72 		[
73 			" ゲームプログラムを習得するための一番の近道はとにかく沢山プログラムを組む",
74 			"ことである。B",
75 			"@ プログラムの参考書にはゲームのプログラムの方法なんて何も書かれていない、B",
76 			"変数、B配列、B関数、Bループ、B条件分岐…Bこれらすべての説明はゲームで何に使うか",
77 			"なんてどこにも書いていない、Bせいぜい住所録を題材にした例がある程度である。B",
78 			"C プログラムは習うより慣れろなのでプログラムを組むに当たって少しでも知識が",
79 			"つけば後はそこからは掘り下げ、広げていけば良いわけで、Bプログラムの参考書を",
80 			"読んでいて少しでも何か出来るような気がしたらそこでとにかくプログラム",
81 			"を打ってみることが大事である。E",
82 		];
83 	} else {
84 		//SHIFT-JIS 文字列
85 		static immutable char[256][] String =
86 		[
87 			"\x81\x40\x83\x51\x81\x5B\x83\x80\x83\x76\x83\x8D\x83\x4F\x83\x89\x83\x80\x82\xF0\x8F\x4B\x93\xBE\x82\xB7\x82\xE9\x82\xBD\x82\xDF\x82\xCC\x88\xEA\x94\xD4\x82\xCC\x8B\xDF\x93\xB9\x82\xCD\x82\xC6\x82\xC9\x82\xA9\x82\xAD\x91\xF2\x8E\x52\x83\x76\x83\x8D\x83\x4F\x83\x89\x83\x80\x82\xF0\x91\x67\x82\xDE",
88 			"\x82\xB1\x82\xC6\x82\xC5\x82\xA0\x82\xE9\x81\x42\x42",
89 			"\x40\x81\x40\x83\x76\x83\x8D\x83\x4F\x83\x89\x83\x80\x82\xCC\x8E\x51\x8D\x6C\x8F\x91\x82\xC9\x82\xCD\x83\x51\x81\x5B\x83\x80\x82\xCC\x83\x76\x83\x8D\x83\x4F\x83\x89\x83\x80\x82\xCC\x95\xFB\x96\x40\x82\xC8\x82\xF1\x82\xC4\x89\xBD\x82\xE0\x8F\x91\x82\xA9\x82\xEA\x82\xC4\x82\xA2\x82\xC8\x82\xA2\x81\x41\x42",
90 			"\x95\xCF\x90\x94\x81\x41\x42\x94\x7A\x97\xF1\x81\x41\x42\x8A\xD6\x90\x94\x81\x41\x42\x83\x8B\x81\x5B\x83\x76\x81\x41\x42\x8F\xF0\x8C\x8F\x95\xAA\x8A\xF2\x81\x63\x42\x82\xB1\x82\xEA\x82\xE7\x82\xB7\x82\xD7\x82\xC4\x82\xCC\x90\xE0\x96\xBE\x82\xCD\x83\x51\x81\x5B\x83\x80\x82\xC5\x89\xBD\x82\xC9\x8E\x67\x82\xA4\x82\xA9",
91 			"\x82\xC8\x82\xF1\x82\xC4\x82\xC7\x82\xB1\x82\xC9\x82\xE0\x8F\x91\x82\xA2\x82\xC4\x82\xA2\x82\xC8\x82\xA2\x81\x41\x42\x82\xB9\x82\xA2\x82\xBA\x82\xA2\x8F\x5A\x8F\x8A\x98\x5E\x82\xF0\x91\xE8\x8D\xDE\x82\xC9\x82\xB5\x82\xBD\x97\xE1\x82\xAA\x82\xA0\x82\xE9\x92\xF6\x93\x78\x82\xC5\x82\xA0\x82\xE9\x81\x42\x42",
92 			"\x43\x81\x40\x83\x76\x83\x8D\x83\x4F\x83\x89\x83\x80\x82\xCD\x8F\x4B\x82\xA4\x82\xE6\x82\xE8\x8A\xB5\x82\xEA\x82\xEB\x82\xC8\x82\xCC\x82\xC5\x83\x76\x83\x8D\x83\x4F\x83\x89\x83\x80\x82\xF0\x91\x67\x82\xDE\x82\xC9\x93\x96\x82\xBD\x82\xC1\x82\xC4\x8F\xAD\x82\xB5\x82\xC5\x82\xE0\x92\x6D\x8E\xAF\x82\xAA",
93 			"\x82\xC2\x82\xAF\x82\xCE\x8C\xE3\x82\xCD\x82\xBB\x82\xB1\x82\xA9\x82\xE7\x82\xCD\x8C\x40\x82\xE8\x89\xBA\x82\xB0\x81\x41\x8D\x4C\x82\xB0\x82\xC4\x82\xA2\x82\xAF\x82\xCE\x97\xC7\x82\xA2\x82\xED\x82\xAF\x82\xC5\x81\x41\x42\x83\x76\x83\x8D\x83\x4F\x83\x89\x83\x80\x82\xCC\x8E\x51\x8D\x6C\x8F\x91\x82\xF0",
94 			"\x93\xC7\x82\xF1\x82\xC5\x82\xA2\x82\xC4\x8F\xAD\x82\xB5\x82\xC5\x82\xE0\x89\xBD\x82\xA9\x8F\x6F\x97\x88\x82\xE9\x82\xE6\x82\xA4\x82\xC8\x8B\x43\x82\xAA\x82\xB5\x82\xBD\x82\xE7\x82\xBB\x82\xB1\x82\xC5\x82\xC6\x82\xC9\x82\xA9\x82\xAD\x83\x76\x83\x8D\x83\x4F\x83\x89\x83\x80",
95 			"\x82\xF0\x91\xC5\x82\xC1\x82\xC4\x82\xDD\x82\xE9\x82\xB1\x82\xC6\x82\xAA\x91\xE5\x8E\x96\x82\xC5\x82\xA0\x82\xE9\x81\x42\x45",
96 		];
97 	}
98 }
99 
100 extern (Windows)
101 nothrow @nogc
102 int WinMain(dxlib_d.DxDataType.HINSTANCE hInstance, dxlib_d.DxDataType.HINSTANCE hPrevInstance, dxlib_d.DxDataType.LPSTR lpCmdLine, int nCmdShow)
103 
104 	do
105 	{
106 		//WIDTH × HEIGTH, 色ビット深度 32
107 		dxlib_d.DxLib.SetGraphMode(WIDTH, HEIGTH, 32);
108 
109 		//全画面表示にしない
110 		dxlib_d.DxFunctionWin.ChangeWindowMode(dxlib_d.DxDataType.TRUE);
111 
112 		version (ANSI) {
113 			version (all) {
114 				//UTF-8にする
115 				dxlib_d.DxLib.SetUseCharCodeFormat(dxlib_d.DxLib.DX_CHARCODEFORMAT_UTF8);
116 			}
117 		}
118 
119 		//ウィンドウが非アクティブ時にも動作させる
120 		dxlib_d.DxLib.SetAlwaysRunFlag(dxlib_d.DxDataType.TRUE);
121 
122 		// DXライブラリ初期化処理
123 		if (dxlib_d.DxLib.DxLib_Init() == -1) {
124 			// エラーが起きたら直ちに終了
125 			return -1;
126 		}
127 
128 		scope (exit) {
129 			// DXライブラリ使用の終了処理
130 			dxlib_d.DxLib.DxLib_End();
131 		}
132 
133 		// 描画位置の初期位置セット
134 		.CursorX = 0;
135 		.CursorX_CP = 0;
136 		.CursorY = 0;
137 
138 		// 参照文字位置をセット
139 
140 		// 1行目の
141 		.SP = 0;
142 
143 		// 0文字
144 		.CP = 0;
145 
146 		// フォントのサイズセット
147 		dxlib_d.DxLib.SetFontSize(.MOJI_SIZE);
148 
149 		// フォントの太さを変更
150 		dxlib_d.DxLib.SetFontThickness(1);
151 
152 		// フォントのタイプをアンチエイリアスフォントに変更
153 		dxlib_d.DxLib.ChangeFontType(dxlib_d.DxLib.DX_FONTTYPE_ANTIALIASING_EDGE_8X8);
154 
155 		// 描画先を裏画面にセット
156 		dxlib_d.DxLib.SetDrawScreen(dxlib_d.DxLib.DX_SCREEN_BACK);
157 
158 		// フレームカウンタ初期化
159 		.Count = 0;
160 
161 		//文字コード形式の取得
162 		version (Unicode) {
163 			immutable int code = dxlib_d.DxLib.Get_wchar_t_CharCodeFormat();
164 		} else {
165 			immutable int code = dxlib_d.DxLib.GetUseCharCodeFormat();
166 		}
167 
168 		// ループ
169 		while ((dxlib_d.DxLib.ProcessMessage() == 0) && (dxlib_d.DxLib.CheckHitKey(dxlib_d.DxLib.KEY_INPUT_ESCAPE) == 0)) {
170 			// サウンドノベル風文字列描画処理を行う
171 			// ただし終了フラグが1だった場合は処理をしない
172 			if (!.EndFlag) {
173 				// ボタン押し待ちフラグがたっていた場合はボタンが押されるまでここで終了
174 				if (.KeyWaitFlag) {
175 					if ((dxlib_d.DxLib.ProcessMessage() == 0) && (dxlib_d.DxLib.CheckHitKeyAll() != 0)) {
176 						// ボタンが押されていたら解除
177 						.KeyWaitFlag = false;
178 					}
179 				} else {
180 					// 文字の描画
181 					dxlib_d.DxDataType.TCHAR Moji = String[.SP][.CP];
182 
183 					switch (Moji) {
184 						// 改行文字
185 						case '@':
186 							// 改行処理および参照文字位置を1つ進める
187 							.Kaigyou();
188 							.CP++;
189 
190 							break;
191 
192 
193 						// ボタン押し待ち文字
194 						case 'B':
195 							// ボタンが離されるまで待つ
196 							while ((dxlib_d.DxLib.ProcessMessage() == 0) && (dxlib_d.DxLib.CheckHitKeyAll() != 0)) {
197 							}
198 
199 							// ボタン押し待ちフラグをたてる
200 							.KeyWaitFlag = true;
201 							.CP++;
202 
203 							break;
204 
205 						// 終了文字
206 						case 'E':
207 							// 終了フラグを立てるおよび参照文字位置を1つ進める
208 							.EndFlag = true;
209 							.CP++;
210 
211 							break;
212 
213 						// クリア文字
214 						case 'C':
215 							// 仮想テキストバッファを初期化して描画文字位置を初期位置に戻すおよび参照文字位置を1つ進める
216 							for (size_t i = 0; i < .StringBuf.length; i++) {
217 								for (size_t j = 0; j < (StringBuf[i - 1].length - 1); j++) {
218 									.StringBuf[i][j] = 0;
219 								}
220 							}
221 
222 							.CursorY = 0;
223 							.CursorX = 0;
224 							.CursorX_CP = 0;
225 							.CP++;
226 
227 							break;
228 
229 						// その他の文字
230 						default:
231 							int code_length = GetCharBytes(code, &(String[.SP][.CP]));
232 							assert(code_length != -1);
233 
234 							version (Unicode) {
235 								code_length = cast(int)(code_length / dxlib_d.DxDataType.TCHAR.sizeof);
236 							}
237 
238 							// 1文字テキストバッファに代入
239 							for (size_t i = 0; i < code_length; i++) {
240 								.StringBuf[.CursorY][.CursorX_CP + i] = String[.SP][.CP + i];
241 							}
242 
243 							// 参照文字位置を1文字分進める
244 							.CP += code_length;
245 							.CursorX_CP += code_length;
246 
247 							// カーソルを1文字分進める
248 							.CursorX++;
249 
250 							// テキストバッファ横幅からはみ出たら改行する
251 							if (.CursorX >= .STRBUF_WIDTH) {
252 								.Kaigyou();
253 							}
254 
255 							break;
256 					}
257 
258 					// 参照文字列の終端まで行っていたら参照文字列を進める
259 					if (String[.SP][.CP] == '\0') {
260 						.SP++;
261 						.CP = 0;
262 					}
263 				}
264 			}
265 
266 			// 画面のクリア
267 			dxlib_d.DxLib.ClsDrawScreen();
268 
269 			// 背景エフェクトの描画
270 			{
271 				int Color = cast(int)(core.stdc.math.sin((.Count / 100.0) * 80.0) + 125.0);
272 				dxlib_d.DxLib.DrawBox(0, 0, WIDTH, HEIGTH, dxlib_d.DxLib.GetColor(Color, 0, 0), dxlib_d.DxDataType.TRUE);
273 				.Count++;
274 			}
275 
276 			// テキストバッファの描画
277 			for (size_t i = 0; i < .StringBuf.length; i++) {
278 				dxlib_d.DxLib.DrawString(8, cast(int)(i * .MOJI_SIZE), &(.StringBuf[i][0]), dxlib_d.DxLib.GetColor(255, 255, 255));
279 			}
280 
281 			// 裏画面の内容を表画面に反映させる
282 			dxlib_d.DxLib.ScreenFlip();
283 		}
284 
285 		// ソフトの終了
286 		return 0;
287 	}
288 
289 // テキストバッファの改行処理関数
290 nothrow @nogc
291 void Kaigyou()
292 
293 	do
294 	{
295 		// 描画行位置を1つ下げる
296 		.CursorY++;
297 
298 		// 描画列を最初に戻す
299 		.CursorX = 0;
300 		.CursorX_CP = 0;
301 
302 		// もしテキストバッファ縦幅からはみ出るならテキストバッファを縦スクロールさせる
303 		if (.CursorY >= .StringBuf.length) {
304 			for (size_t i = 1; i < .StringBuf.length; i++) {
305 				for (size_t j = 0; j < (StringBuf[i - 1].length - 1); j++) {
306 					.StringBuf[i - 1][j] = .StringBuf[i][j];
307 				}
308 			}
309 
310 			// 描画行位置を1つあげる
311 			.CursorY--;
312 		}
313 	}