Skin:
[NORMAL]
[BLUE] [DOS] [LIGHT]  / コピーするための表示 / 実行
このファイル: /home/web6047/www/cgi-bin/prj/20200515-RPG/基本的/20200620-ウィンドウ入力/20200629-メモにまとめたものをもとにして/simple4.html
1 <html><!--ESCAPEPROCESS-->
2 <head>
3 <meta content="text/html; charset=UTF-8" http-equiv="content-type">
4 <script>console.clear();</script>
5 <script>
6 function onloadx() {
7 app = new App();
8 }
9 let cc;
10
11 //---App
12
13 class App {
14 constructor() {
15 this.cc = cc = document.getElementById( "test" ).getContext( "2d" );
16
17 this.chars = new Array();
18
19 //道具
20
21 this.douguMaster = {
22 "やくそう" : { title : "やくそう",
23 subMenu : {
24 title : "どうする",
25 items : [
26 { title : "つかう", subMenu : { title : "だれに", items : this.chars } },
27 { title : "わたす", subMenu : { title : "だれに", items : this.chars } },
28 { title : "すてる" },
29 ],
30 },
31 }//やくそう
32 }//douguMaster
33
34 //キャラクタデータを作成し、
35
36 this.chars.push( {
37 title : "c1",
38 dougus : [
39 this.douguMaster[ "やくそう" ],
40 { title : "dougu2" },
41 { title : "dougu3" },
42 ],
43 } );
44 this.chars.push( {
45 title : "c2",
46 dougus : [
47 { title : "dougu4" },
48 { title : "dougu5" },
49 { title : "dougu6" },
50 ],
51 jumons : [
52 { title : "jumon1" },
53 { title : "jumon2" },
54 { title : "jumon3" },
55 ],
56 } );
57 this.chars.push( {
58 title : "c3",
59 dougus : [
60 { title : "dougu7" },
61 { title : "dougu8" },
62 { title : "dougu9" },
63 ],
64 jumons : [
65 { title : "jumon4" },
66 { title : "jumon5" },
67 { title : "jumon6" },
68 ],
69 } );
70
71 //各キャラに戦闘コマンドを作成。
72 this.chars[ 0 ].batcom = [
73 { title : "たたかう1" },
74 { title : "にげる" },
75 { title : "ぼうぎょ" },
76 { title : "どうぐ", items : this.chars[ 0 ].dougus },
77 ];
78 this.chars[ 1 ].batcom = [
79 { title : "たたかう2" },
80 { title : "じゅもん", items : this.chars[ 1 ].jumons },
81 { title : "ぼうぎょ" },
82 { title : "どうぐ", items : this.chars[ 1 ].dougus },
83 ];
84 this.chars[ 2 ].batcom = [
85 { title : "たたかう3" },
86 { title : "じゅもん", items : this.chars[ 2 ].jumons },
87 { title : "ぼうぎょ" },
88 { title : "どうぐ", items : this.chars[ 2 ].dougus },
89 ];
90
91 this.camp = [
92 { title : "はなす" },
93 { title : "つよさ" },
94 { title : "そうび" },
95 { title : "じゅもん", },
96 { title : "どうぐ",
97 subMenu : {
98 title : "だれの?",
99 items : { items1 : this.chars, items2 : "dougus" },
100 },
101 },
102 { title : "しらべる" },
103 ];
104
105 this.drawingElements = new Array();
106
107 this.field = new Field( this );
108 this.drawingElements.push( this.field );
109 this.field.activate();
110
111 this.timerId = setInterval( this.frame.bind( this ), 100 );
112
113 this.battleEvent();
114
115 }//constructor
116
117 //---EO constructor
118
119 //---campEvent
120 async campEvent() {
121 let onkeydownBak = window.onkeydown;
122 let onkeyupBak = window.onkeyup;
123
124 let wizard = new Wizard();
125 wizard.isAbleToCancel = true;
126 let menu = new Menu( "コマンド?", this.camp, 5, 1, null, null, 2 );
127 wizard.add( menu );
128
129 this.drawingElements.push( wizard );
130
131 let results = await wizard.execute();
132
133 alert( results.map( result => result.map( item => item.title ).join( ", " ) ).join( "\n" ) );
134
135 //かたづけ
136 this.drawingElements.splice( this.drawingElements.indexOf( wizard ), 1 );
137 window.onkeydown = onkeydownBak;
138 window.onkeyup = onkeyupBak;
139 }
140 //---battleEvent
141 async battleEvent() {
142 let wizard = new Wizard();
143 wizard.isAbleToCancel = false;
144 wizard.add( new Menu( "test1", this.chars[ 0 ].batcom, 0, 15, 10, 10 ) );
145 wizard.add( new Menu( "test2", this.chars[ 1 ].batcom, 0, 15, 10, 10 ) );
146 wizard.add( new Menu( "test3", this.chars[ 2 ].batcom, 0, 15, 10, 10 ) );
147 this.drawingElements.push( wizard );
148 let results = await wizard.execute();
149 alert( results.map( result => result.map( item => item.title ).join( ", " ) ).join( "\n" ) );
150 //かたづけ
151 this.drawingElements.splice( this.drawingElements.indexOf( wizard ), 1 );
152
153 this.field.activate();
154 }
155 frame() {
156 this.draw( this.cc );
157 }
158 draw( cc ) {
159 cc.clearRect( 0,0,cc.canvas.width, cc.canvas.height );
160 for( let i = 0; i < this.drawingElements.length; i++ ) {
161 this.drawingElements[ i ].draw( cc );
162 }
163 }
164 }//App
165
166 //---Ctrl
167
168 class Ctrl {
169 constructor() {
170 this.keys = new Object();
171 this.tellOk = function() {};
172 }
173 activate( tellOk ) {
174 this.tellOk = tellOk;
175 window.onkeydown = this.onkeydown.bind( this );
176 window.onkeyup = this.onkeyup.bind( this );
177 }
178 onkeydown( e ) {
179 this.keys[ e.which ] = true;
180 this.keytype( String( e.which ) );
181 }
182 onkeyup( e ) {
183 this.keys[ e.which ] = false;
184 }
185 keytype( key ) {
186 }
187 keyexec( key ) {
188 }
189 }
190
191 //---Win
192
193 class Win extends Ctrl {
194 constructor( title, cx, cy, cw, ch ) {
195 super();//Ctrl
196 this.cx = cx;
197 this.cy = cy;
198 this.cw = cw;
199 this.ch = ch;
200 this.title = title;
201 }
202 draw( cc ) {
203
204 let gx = this.cx * 16;
205 let gy = this.cy * 16;
206 let gw = this.cw * 16;
207 let gh = this.ch * 16;
208
209 //枠
210 cc.fillStyle = "white";
211 cc.fillRect( gx, gy, gw, gh );
212 cc.strokeStyle = "black";
213 cc.strokeRect( gx, gy, gw, gh );
214
215 //タイトル
216 cc.fillStyle = "black";
217 cc.fillText( this.title, gx, gy + 16 );
218 cc.fillText( this.title, gx + 1, gy + 16 );
219 }
220 }
221
222 //---Menu
223
224 class Menu extends Win {
225 constructor( title, items, cx, cy, cw, ch, dankumi ) {
226 super( title, cx, cy, cw, ch );//Win
227
228 this.dankumi = ! dankumi ? 1 : dankumi;
229 this.maxY = Math.ceil( items.length / this.dankumi );
230
231 this.items = new Array();
232 for( let y = 0; y < this.maxY; y ++ ) {
233 this.items[ y ] = new Array();
234 for( let x = 0; x < this.dankumi; x ++ ) {
235 this.items[ y ][ x ] = items[ this.maxY * x + y ];
236 }
237 }
238 this.itemCw = Math.max( ...items.map( item => item.title.length ) );
239
240 //check.
241 if( cw == null ) {
242 this.cw = this.itemCw * this.dankumi + 2 + this.dankumi - 1;
243 }
244 if( ch == null ) {
245 this.ch = this.items.length;
246 this.ch += 2; //padding
247 this.ch += this.title == "" ? 0 : 1;
248 }
249 this.cursorX = 0;
250 this.cursorY = 0;
251 this.parentMenu = null;
252 this.childMenu = null;
253 }
254 //Menu
255 openChild( title, items, cx, cy, cw, ch ) {
256 this.childMenu = new Menu( title, items, cx, cy, cw, ch );
257 this.childMenu.parentMenu = this;
258 this.childMenu.activate( this.tellOk );
259 }
260 //Menu
261 keytype( key ) {
262 switch( key ) {
263 case "37": if( this.cursorX > 0 ) this.cursorX --; break;
264 case "38": if( this.cursorY > 0 ) this.cursorY --; break;
265 case "39": if( this.cursorX < this.dankumi - 1 ) this.cursorX ++; break;
266 case "40": if( this.cursorY < this.maxY - 1 ) this.cursorY ++; break;
267 case "32":
268 //項目決定
269 let selectedItem = this.items[ this.cursorY ][ this.cursorX ];
270 if( selectedItem.subMenu ) {
271 //サブメニューある場合
272 let subMenu = selectedItem.subMenu;
273 let cx = this.cx + this.cw;
274 let cy = this.cy;
275 let cw = null;
276 let ch = null;
277 let title = subMenu.title ? subMenu.title : "";
278
279 let items;
280 if( subMenu.items instanceof Array ) {
281 items = subMenu.items;
282 } else {
283 //itemsの特殊書式
284 let array = subMenu.items.items1; //this.chars
285 let memb = subMenu.items.items2; //"dougus"
286
287 items = array.map(
288 function( item ) {
289 return { title : item.title, //char
290 subMenu : {
291 items : item[ memb ], //char.dougus
292 },
293 };
294 /*
295 キャラクターを選ぶメニューの各項目(キャラクター)には
296 さらにサブメニューとして道具のメニューが準備されている。
297 */
298 }
299 );
300
301 }
302 this.openChild( title, items, cx, cy, cw, ch );
303 } else {
304 //サブメニューない場合
305 let res = new Array();
306 let tmp = this;
307 while( tmp ) {
308 res.unshift( tmp.items[ tmp.cursorY ][ tmp.cursorX ] );
309 tmp = tmp.parentMenu;
310 }
311 this.tellOk( res );
312 }
313 break;
314 case "88": //x
315 //メニューキャンセル
316 if( this.parentMenu ) {
317 //サブメニューのとき
318 this.parentMenu.childMenu = null;
319 this.parentMenu.activate( this.tellOk );
320 } else {
321 //トップメニューのとき
322 this.tellOk( null );
323 }
324 break;
325 }
326 this.draw( cc );
327 }//keytype
328 //Menu
329 draw( cc ) {
330
331 let gx = this.cx * 16;
332 let gy = this.cy * 16;
333 let gw = this.cw * 16;
334 let gh = this.ch * 16;
335
336 cc.font = "16px ''";
337
338 //枠
339 cc.fillStyle = "white";
340 cc.fillRect( gx, gy, gw, gh );
341 cc.strokeStyle = "black";
342 cc.strokeRect( gx, gy, gw, gh );
343
344 //タイトル
345 if( this.title ) {
346 cc.fillStyle = "black";
347 cc.fillText( this.title, gx, gy + 16 );
348 cc.fillText( this.title, gx + 1, gy + 16 );
349 }
350 //項目
351 cc.save();
352 cc.translate( gx + 16, gy + 16 + ( this.title ? 16 : 0 ) );
353 let itemGw = this.itemCw * 16;
354 for( let y = 0; y < this.items.length; y++ ) {
355 for( let x = 0; x < this.items[ y ].length; x++ ) {
356 let item = this.items[ y ][ x ];
357 gx = ( itemGw + 16 ) * x;
358 gy = y * 16;
359
360 if( x == this.cursorX && y == this.cursorY ) {
361 cc.fillStyle = "black";
362 cc.fillRect( gx, gy + 2, itemGw, 16 );
363 cc.fillStyle = "white";
364 } else {
365 cc.fillStyle = "black";
366 }
367 if( item ) cc.fillText( item.title, gx, gy + 16 );
368 }
369 }
370 cc.restore();
371
372 if( this.childMenu ) this.childMenu.draw( cc );
373 }//draw
374 }//Menu
375
376 //---Wizard
377
378 class Wizard {
379 constructor( isAbleToCancel ) {
380 this.menus = new Array();
381 this.isAbleToCancel = isAbleToCancel; //Wizardのキャンセルはできないという意
382 //Wizardの途中で前に戻るというキャンセルは可
383 }
384 add( menu ) {
385 this.menus.push( menu );
386 }
387 //Wizard
388 execute() {
389 return new Promise(
390 async function( tellOk ) {
391 let results = new Array();
392 //Wizardの進行
393 for( let i =0; i < this.menus.length; i++ ) {
394 let result = await this.executeOne( i ); //Wizardの1コマ
395 //check. キャンセルされた?
396 if( ! result ) {
397 if( i == 0 ) {
398 if( this.isAbleToCancel ) {
399 //Wizardをキャンセルする
400 tellOk( null );
401 return;
402 } else
403 i -= 1; //Wizardのキャンセルはできない
404 } else {
405 i -= 2; //Wizardの途中で前に戻る
406 }
407 continue;
408 }//if
409
410 results[ i ] = result;
411 }//for
412 //Wizard終了
413 tellOk( results );
414 }.bind( this )//function
415 );//Promise
416 }//execute()
417 //Wizard
418 executeOne( idx ) {
419 return new Promise(
420 function( tellOk ) {
421 this.currentMenu = this.menus[ idx ];
422 this.currentMenu.activate( tellOk );
423 }.bind( this )
424 );
425 }
426 //Wizard
427 draw( cc ) {
428 this.currentMenu.draw( cc );
429 }
430 }//Wizard
431
432
433 //---Field
434
435 class Field extends Ctrl {
436 constructor( app ) {
437 super();
438 this.app = app;
439 }
440 keytype( key ) {
441 switch( key ) {
442 case "32":
443 this.app.campEvent();
444 break;
445 }
446 }
447 draw( cc ) {
448 let gx, gy;
449 cc.fillStyle = "lightgreen";
450 cc.fillRect( 0, 0, cc.canvas.width, cc.canvas.height );
451 cc.strokeStyle = "green";
452 for( let y = 0; y < 15; y++ ) {
453 gy = y * 32;
454 for( let x = 0; x < 20; x++ ) {
455 gx = x * 32;
456 cc.strokeRect( gx, gy, 32, 32 );
457 }
458
459 }
460 }
461 }//Field
462
463 </script>
464 <style>
465 </style>
466 </head>
467 <body onload="onloadx()">
468 <canvas id="test" width="640" height="480" style="
469 border : solid 1px black;
470 float:left;
471 " onclick="location.reload()">
472 </canvas>
473 <div style="float:left; width:512px; padding-left:1em;">
474 <B>最初にバトルイベントが始まります</B>
475 上下:↑↓キー、決定:スペースキー、キャンセル:xキー
476 3人分のコマンドを入力すると、入力内容を表示します。
477
478 <B>フィールドではスペースキーを押すとコマンドメニューを表示します。</B>
479 (キャラ移動はありません)
480 「どうぐ」、「C1」、「やくそう」、「つかう」でサブメニューの動きを確認できます。
481 それだけです。
482 </div>
483 <script>
484 div = document.getElementsByTagName( "div" )[ 0 ];
485 div.innerHTML = div.innerHTML.replace( /\n/g, "<BR>" );
486 </script>
487 </body>
488 </html>