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