Skin:
[NORMAL]
[BLUE] [DOS] [LIGHT]  / コピーするための表示 / 実行
このファイル: /home/web6047/www/cgi-bin/prj/20200515-RPG/基本的/20200620-ウィンドウ入力/20200621-1/simple.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 /*
7 ウィンドウを表示して、選択を行い、選択結果をデータとして保存する。
8
9 流れ:
10 1. プレイヤーがある座標に乗るとイベントが起動する
11 2. イベントの中で2択のウィンドウを表示する。
12 キー入力対象を変更する。
13 2択ウィンドウを描画対象に入れる。
14 3. ウィンドウで選択されたら、選択結果データを保存する。
15
16 要点:
17 JavaScriptによる「シナリオイベント」の実現
18 戦闘ロジックの実現
19 マップ移動、ウィンドウ入力など場面ごとにキー入力を分別
20
21
22 関数:
23 関数は6つある。
24
25 onloadx
26 frame
27 battle
28 eve1
29 question
30 draw
31
32 プログラムはonloadxから開始する。
33 onkeydownでキー押下ごとにキーを処理を行う。
34 ただし、map, win1_question, battle といった場面ごとに分別している。
35 setIntervalで80msごとにframeを呼び出す。
36
37 frameに書かれたアニメ処理はおまけプログラムである。
38
39 キャラクター(赤い四角)が5,5の位置に来ると、イベントスクリプトとしてeve1が呼ばれる。
40 eve1はquestionを呼ぶ。
41 questionは2択の画面を表示して選択結果を返す。
42 questionが終了すると、eve1の続く命令(おまけアニメ)が実行される。
43 なお、eve1がquestionが終了するまで待つ動きは、Promiseによって実現されている。
44 また、questionは通常イベントでも、戦闘イベントでもどちらでも利用可能になるように汎用的に書かれている。
45
46 キャラクター(赤い四角)が10,5の位置に来ると、イベントスクリプトとしてbattleが呼ばれる。
47 battleはイベントスクリプトで戦闘ロジックを表現するサンプルである。
48
49 */
50 function onloadx() {
51 cc = document.getElementsByTagName( "canvas" )[ 0 ].getContext( "2d" );
52 cc.font = "16px ''";
53 x = 0;
54 y = 0;
55 test = new Array();
56 doAnimate = false;
57 win1 = {
58 title : "どちらが好きか?",
59 items : [
60 { title:"海が好き", func:function() { return "blue" }, },
61 { title:"山が好き", func:function() { return "rgb(255,196,0)" }, },
62 ],
63 cursorY : 0,
64 }
65 slime = {
66 hp : 30,
67 }
68 win2 = {
69 title : "スライムがあらわれた!",
70 items : [
71 { title:"こうげき", func:function() { return "こうげき" }, },
72 { title:"にげる", func:function() { return "にげる" }, },
73 ],
74 cursorY : 0,
75 }
76 tellOK2 = null;
77
78 drawingList = { map : true, }
79 stack = new Array();
80 keyTarget = "map";
81
82 onkeydown = function( e ) {
83 switch( keyTarget ) {
84 case "map": //キー入力のターゲット マップ
85 switch( e.which ) {
86 case 37: x -= 1; break;
87 case 38: y -= 1; break;
88 case 39: x += 1; break;
89 case 40: y += 1; break;
90 }
91 //1. プレイヤーがある座標に乗るとイベントが起動する
92 if( x == 5 && y == 5 ) {
93 eve1();
94 } else if( x == 10 && y == 5 ) {
95 battle();
96 }
97 break;
98 //キー入力のターゲット ウィンドウ
99 case "win1_question":
100 case "battle":
101 let win;
102 if( keyTarget == "win1_question" ) win = win1;
103 else if( keyTarget == "battle" ) win = win2;
104 switch( e.which ) {
105 case 38: if( win.cursorY > 0 ) win.cursorY --; break;
106 case 40: if( win.cursorY < win.items.length - 1 ) win.cursorY ++; break;
107 case 32:
108 //3. ウィンドウで選択されたら、選択結果データを保存する。
109 let res = win.items[ win.cursorY ].func();
110 tellOK2( res );
111 break;
112 }
113 break;
114 }
115 }
116 setInterval( frame, 80 );
117 }
118 function frame() {
119 if( doAnimate ) {
120 //ぐるぐる塗りつぶすアニメの1コマ
121 anm.ax += ( anm.dir == 39 ) - ( anm.dir == 37 );
122 anm.ay += ( anm.dir == 40 ) - ( anm.dir == 38 );
123
124 test.push( {
125 x : anm.ax,
126 y : anm.ay,
127 c : anm.color,
128 } );
129
130 anm.val ++;
131 //check. アニメ終了
132 if( anm.val == anm.max ) {
133 doAnimate = false;
134 }
135
136 if( anm.val % anm.len == 0 ) {
137 anm.dir += 1;
138 //check.
139 if( anm.dir > 40 ) {
140 anm.dir = 37;
141 anm.len ++;
142 }
143 if( anm.dir == 38 ) {
144 anm.len ++;
145 }
146 }
147 }
148
149 draw();
150 }
151 async function battle() {
152 //戦闘ロジック
153 let endFlg = false;
154 do {
155 res = await question( "battle" );
156 console.log( res );
157 //そのコマンドの結果を作成
158 let mess = new Array();
159 switch( res ) {
160 case "こうげき":
161 mess.push( "こうげきした!" );
162 slime.hp -= 10;
163 mess.push( "スライムに 10 のダメージをあたえた!" );
164 mess.push( "(ちなみに、スライムのHPは今 " + slime.hp + " です)" );
165
166 //check.
167 if( slime.hp <= 0 ) {
168 endFlg = true;
169 slime.hp = 30;
170 mess.push( "スライムを倒した!" );
171 endFlg = true;
172 break;
173 }
174 mess.push( "スライムのこうげき!" );
175 mess.push( "ミス!" );
176 break;
177 case "にげる":
178 mess.push( "あなたはにげだした!" );
179 endFlg = true;
180 break;
181 }
182
183 //結果を表示
184 alert( mess.join( "\n" ) );
185
186 } while( ! endFlg );
187 }
188 async function eve1() {
189 //2. イベントの中で2択のウィンドウを表示する。
190 res = await question( "win1_question" );
191
192 //アニメ初期化
193 anm = new Object();
194 anm.dir = 39;
195 anm.len = 1;
196 anm.max = 48;
197 anm.val = 0;
198 anm.ax = x;
199 anm.ay = y;
200 anm.color = res;
201 doAnimate = true;
202 }
203 function question( winname ) {
204 //2.1. キー入力対象を変更する。
205 stack.push( keyTarget );
206 keyTarget = winname;
207 //2.2. 2択ウィンドウを描画対象に入れる。
208 drawingList[ winname ] = true;
209
210 return ( new Promise( function( tellOK ) {
211 tellOK2 = tellOK;
212 } ) ).then( function( argmentReceivedByTellOK ) {
213 keyTarget = stack.pop();
214 delete drawingList[ winname ];
215 return argmentReceivedByTellOK;
216 } );
217 }
218 function draw() {
219 cc.clearRect( 0,0, cc.canvas.width, cc.canvas.height );
220
221 if( drawingList.map ) {
222 cc.fillStyle = "lightgreen";
223 cc.fillRect(0,0, cc.canvas.width, cc.canvas.height);
224
225 //test
226 for( let i = 0; i < test.length; i++ ) {
227 let o = test[ i ];
228 cc.fillStyle = o.c;
229 cc.fillRect( o.x * 32, o.y * 32, 32, 32 );
230 }
231
232 cc.fillStyle = "red";
233 cc.fillRect( x * 32, y * 32, 32, 32 );
234 cc.fillStyle = "black";
235 cc.fillText( x + ", " + y, 16,16 );
236 }
237
238 if( drawingList[ "win1_question" ] || drawingList.battle ) {
239 let win;
240 if( drawingList[ "win1_question" ] ) win = win1;
241 else if( drawingList.battle ) win = win2;
242 cc.save();
243 cc.translate( 100, 100 );
244 cc.fillStyle = "black";
245 cc.fillRect( 0, 0, 200, 100 );
246 cc.lineWidth = 3;
247 cc.strokeStyle = "white";
248 cc.strokeRect( 0, 0, 200, 100 );
249 cc.translate( 4, 4 );
250 for( let i = 0; i < win.items.length; i++ ) {
251 let item = win.items[ i ];
252 let gy = 16 + i * 16;
253 if( win.cursorY == i ) {
254 cc.fillStyle = "white";
255 cc.fillRect( 0, gy+2, 100, 16 );
256 cc.fillStyle = "black";
257 } else {
258 cc.fillStyle = "white";
259 }
260 cc.fillText( item.title, 16, 16 + gy );
261 }
262 cc.fillStyle = "lightblue";
263 cc.fillText( win.title, 0, 16-1 );
264 cc.restore();
265 }
266
267 }
268 </script>
269 <style>
270 </style>
271 </head>
272 <body onload="onloadx()">
273 <canvas width="640" height="480" style="
274 border : solid 1px black;
275 float:left;
276 ">
277 </canvas>
278 <div style="float:left; width:512px; padding-left:1em;">
279 移動:カーソルキー、決定:スペースキー
280
281 5,5 の位置に移動すると、2択のウィンドウが表示されます。
282 10,5 の位置に移動すると、戦闘のウィンドウが表示されます。
283 </div>
284 <script>
285 div = document.getElementsByTagName( "div" )[ 0 ];
286 div.innerHTML = div.innerHTML.replace( /\n/g, "<BR>" );
287 </script>
288 </body>
289 </html>