Skin: [NORMAL]
[BLUE]
[DOS] [LIGHT]  / コピーするための表示 / 実行
このファイル: /home/web6047/www/cgi-bin/prj/20180701-3DCG迷路/20180916-試作/canvas.html
1 <!DOCTYPE html><!--ESCAPEPROCESS-->
2 <head>
3 <meta content="text/html; charset=UTF-8" http-equiv="content-type">
4 <title>スムーズに動く3D迷路プログラム</title>
5 <script>
6
7 console.clear();
8 console.log( "=============== script ==============" );
9 function con() { console.log( Array.prototype.join.call( arguments, " " ) ); }
10 function $( id ) { return document.getElementById( id ); }
11 var HereDocument = /\/\*\s*([^]*?)\s*\*\//;
12 // usage: var txt = ( function() { /*multiTXT*/ } ).toString().match( HereDocument )[ 1 ];
13
14 /*
15 「スムーズに動く3D迷路プログラム」
16
17 最初に2Dの迷路上を動き回るプログラムを作り、その後に3D化するという手順で作成しました。
18 そのため、2Dの状況を見て、3Dの景観を作るような形になっています。
19
20
21 2Dの状況を見て、3Dの景観を作る:
22
23 Mapクラスが2Dの状況を作っています。
24 まず、ユーザーからキー入力されると
25 (cfg.animateがtrueの場合は)
26 onkeydown()→setInterval()→run()→map.keyexec()→
27 map.walk()またはmap.turn()→map.calc()
28 (cfg.animateがfalseの場合は)
29 onkeydown()→map.keyexec()→map.walk()またはmap.turn()→map.calc()
30 の順に関数が呼ばれ、最後のcalc()の中で、3Dの景観を作るための壁の位置を示したデータである、
31 map.data3Dsという配列を作っています。
32 run()のなかのmap.keyexec()を呼んだ後に、setWalls3D()を呼んでいます。
33 setWalls3D()は更新されたmap.data3Dsから3Dオブジェクト(壁)を新たに作成しています(3Dの景観)。
34
35
36 スムーズに動く:
37
38 ユーザーからキー入力されると、onkeydown()にて
39 cfg.animateがfalseの場合は、
40 アニメせず、ウィザードリィみたいにパタパタとした動きになりますが、
41 cfg.animateがtrueの場合は、
42 押されたキーによって左右回転アニメや、前後移動アニメが設定されます。
43
44 その設定の中でsetInterval()が実行され、60msごとにrun()が実行されます。
45 run()の中で、アニメの設定(anm)のとおり、カメラの角度が左右に動いたり、
46 カメラの位置が前後に移動したりします。
47 カメラの角度が左右に動く:
48 cam.kaiten.yを0.1ずつ増やしたり減らしたりします。
49 カメラの位置が前後に移動:
50 cam.pos.zを5ずつ増やしたり減らしたりします。
51
52 cam.kaiten.yや、cam.pos.zは3次元計算を行っている部分で使われます。
53
54
55 3次元計算:
56
57 3次元計算はdraw()の中ですべて行っています。
58 ここで行っている3次元計算は、行列や視錐台など難解な計算をいっさい行わない
59 比較的わかりやすい計算方法となっています。そのなかで一番難しい計算はsin, cosですが、
60 それもsin, cosとしてはごく基本的な計算にとどまっています。
61 しかし、出てくる計算は簡単なものばかりでも、3次元のりくつはとても難しいもので、
62 一朝一夕で理解するのは難しいと思います。
63
64
65 その他:
66
67 u,jキーを押すとリアルタイムで視界の深度を変更できます。
68 たいまつがだんだん弱くなる表現とかできそうです。
69 eキーを押して天井がちょっと見える程度にカメラを上昇させ、
70 rキーを押してカメラを下に回転させるとちょっと変わった感じになって面白いです。
71
72
73 このプログラムの著作権は特にきびしく主張しないので、
74 コピーしたり好きに改造したりと自由に遊んでください。
75
76 d_kawakawa(homepage6047) 18/09/17(月) 23:41:08
77 */
78
79
80 var cfg;
81 switch( 0 ) { //0,1,2から選ぶ
82 case 0:
83 //simple
84 cfg = {
85 wallcolor : "lightgray",
86 backgroundcolor : "white",
87 wirecolor : "black",
88 map2dcolorwallF : "rgba(0,0,0,.5)",
89 map2dcolorwallS : "rgba(0,0,0,.25)",
90 map2dcoloryukaF : "rgba(0,0,0,.25)",
91 animate : true,
92 };
93 break;
94 case 1:
95 //blue
96 cfg = {
97 wallcolor : "rgb(32,48,192)",
98 backgroundcolor : "rgb(32,32,96)",
99 wirecolor : "blue",
100 map2dcolorwallF : "rgba(0,0,0,.5)",
101 map2dcolorwallS : "rgba(0,0,0,.25)",
102 map2dcoloryukaF : "rgba(0,0,0,.25)",
103 animate : true,
104 };
105 break;
106 case 2:
107 //wiz
108 cfg = {
109 wallcolor : "black",
110 backgroundcolor : "black",
111 wirecolor : "white",
112 map2dcolorwallF : "rgba(255,255,255,.25)",
113 map2dcolorwallS : "rgba(255,255,255,.15)",
114 map2dcoloryukaF : "rgba(255,255,255,.15)",
115 animate : false,
116 };
117 break;
118 }
119
120 //正六面体
121 var cubeMaster = {
122 //正六面体の頂点
123 tens : [
124 { x : -1, y : 1, z : -1 }, //手前 左上
125 { x : 1, y : 1, z : -1 }, //手前 右上
126 { x : 1, y : -1, z : -1 }, //手前 右下
127 { x : -1, y : -1, z : -1 }, //手前 左下
128 { x : -1, y : 1, z : 1 }, //奥 左上
129 { x : 1, y : 1, z : 1 }, //奥 右上
130 { x : 1, y : -1, z : 1 }, //奥 右下
131 { x : -1, y : -1, z : 1 }, //奥 左下
132 ],
133 //正六面体の面
134 mens : [
135 [ 0, 1, 2, 3 ], //正面
136 [ 0, 3, 7, 4 ], //向かって左側
137 [ 5, 6, 2, 1 ], //向かって右側
138 [ 1, 0, 4, 5 ], //天面
139 [ 2, 6, 7, 3 ], //底面
140 [ 5, 4, 7, 6 ], //背面
141 ],
142 pos : new XYZ( 0, 0, 300 ),
143 scale : new XYZ( 20, 15, 20 ),
144 color : cfg.wallcolor,
145 };
146
147 //3Dオブジェクト
148 var objects = null;
149
150 //カメラ
151 var cam = {
152 s : 32,
153 pos : new XYZ( 0,0,0 ),
154 zoom : 22.15,
155 shift : new XYZ( 0,0,-45 ),
156 kaiten : new XYZ( 0,0,0 ),
157 };
158
159 //スムーズアニメ
160 var anm = null;
161
162 //オブジェクトのメンバをconsole.log出力
163 function memb( o ) {
164 var res = "";
165 for( var name in o ) {
166 res += name + " : " + o[ name ] + ", ";
167 }
168 return res;
169 }
170 function onloadx() {
171
172 var HereDocument = /[^]*\/\*([^]*)\*\/\}$/;
173
174 touchlay = ( function() {/*
175 □↑□|□□□
176 ←□→|z□x
177 □↓□|□□□
178 */} ).toString().match( HereDocument, "m" )[ 1 ];
179
180
181 canvasEL = $( "canvasELID" );
182 canvas = canvasEL.getContext( '2d' );
183 screenW = canvas.canvas.width;
184 screenH = canvas.canvas.height;
185
186 //(canvas Special resize low crisp / )
187
188 //2Dマップ
189 map = new Map();
190
191 setWalls3D(); //マップデータから必要な3Dオブジェクトを作成
192 draw( canvas );
193
194 //キー入力について キーセンス型とキータイプ型の区別がある
195 if( cfg.animate ) {
196
197 keys = new Array();
198 timerID = setInterval( keyRun, 50 );
199 onkeydown = function( e ) {
200 keytype( e.which ); //キータイプ型の処理
201 if( keys.indexOf( e.which ) == -1 ) keys.push( e.which );
202 };
203 onkeyup = function( e ) {
204 if( keys.indexOf( e.which ) != -1 ) keys.splice( keys.indexOf( e.which ), 1 );
205 };
206
207 } else {
208
209 //アニメしない場合はすべてキータイプ型
210 onkeydown = function( e ) {
211 keytype( e.which );
212 keysence( e.which );
213 };
214 }
215
216 }//onloadx
217
218 function keyRun() {
219 //キーセンス型の処理
220 for( var i = 0; i < keys.length; i++ ) {
221 var key = keys[ i ];
222 keysence( key );
223 }
224 }
225
226 //---key
227
228 function keytype( key ) {
229 var doResetWalls = false;
230
231 //機能
232 switch( key ) {
233 //焦点距離(画角)
234 case 81: cam.s++; break; //q
235 case 65: cam.s--; break; //a
236 //前後シフト
237 case 87: cam.shift.z++; break; //w
238 case 83: cam.shift.z--; break; //s
239 //上下シフト
240 case 69: cam.shift.y++; break; //e
241 case 68: cam.shift.y--; break; //d
242 //上下回転
243 case 82: cam.kaiten.x -= .05; break; //r
244 case 70: cam.kaiten.x += .05; break; //f
245 //上下伸長
246 case 84: cubeMaster.scale.y++; break; //t
247 case 71: cubeMaster.scale.y--; break; //g
248 //画面拡縮
249 case 89: cam.zoom += .1; break; //y
250 case 72: cam.zoom -= .1; break; //h
251 //視界拡縮
252 case 85: map.scopeW += 2; map.calc(); doResetWalls = true; break; //u
253 case 74: if( map.scopeW > 1 )
254 map.scopeW -= 2; map.calc(); doResetWalls = true; break; //j
255 //設定値console.log出力
256 case 90:
257 console.log( "cam.s", cam.s );
258 console.log( "cam.shift", memb( cam.shift ) );
259 console.log( "cam.kaiten", memb( cam.kaiten ) );
260 console.log( "cam.zoom", cam.zoom );
261 console.log( "cubeMaster.scale", memb( cubeMaster.scale ) );
262 console.log( "map.scopeW", map.scopeW );
263 break;
264 }
265
266 if( doResetWalls ) setWalls3D();
267 draw( canvas );
268 }
269 function keysence( key ) {
270 var doResetWalls = false;
271
272 //移動
273 if( cfg.animate ) {
274 if( anm == null ) {
275 switch( key ) {
276 case 37:
277 case 39:
278 //左右回転
279 anm = {
280 object : cam.kaiten,
281 member : "y",
282 value : 0,
283 maxvalue : 3.14 / 2,
284 addvalue : .1,
285 dir : ( key == 37 ) - ( key == 39 ),
286 timerID : setInterval( run, 60 ),
287 key : key,
288 };
289 break;
290 case 38:
291 case 40:
292 //前後移動
293 //check. 壁があるなら進まない
294 if( map.chk2( ( key == 38 ) - ( key == 40 ) ) == false ) break;
295
296 anm = {
297 object : cam.pos,
298 member : "z",
299 value : 0,
300 maxvalue : objects[ 0 ].scale.x * 2,
301 addvalue : 5,
302 dir : ( key == 38 ) - ( key == 40 ),
303 timerID : setInterval( run, 60 ),
304 key : key,
305 }
306 break;
307 }//switch
308 }
309 } else {
310 //アニメしないで移動する場合
311 map.keyexec( key );
312 doResetWalls = true;
313 }
314 if( doResetWalls ) setWalls3D();
315
316 draw( canvas );
317 }//
318
319
320 function run() {
321 //アニメの一コマ
322 anm.value += anm.addvalue;
323 anm.object[ anm.member ] += anm.addvalue * anm.dir;
324
325 //check. アニメの終了
326 if( anm.value >= anm.maxvalue ) {
327 anm.object[ anm.member ] = 0; //対象変数は初期値に
328 clearInterval( anm.timerID ); //タイマ終了
329 map.keyexec( anm.key ); //マップの実際の移動
330 setWalls3D(); //マップから3Dオブジェクトをセット
331 anm = null;
332 }
333
334 draw( canvas );
335 }
336 function setWalls3D() {
337 //マップから3Dオブジェクトをセット
338
339 objects = new Array();
340
341 //雑用関数
342 var makeLink = function( master ) {
343 return {
344 tens : master.tens, //参照
345 mens : master.mens, //参照
346 pos : { x : master.pos.x, y : master.pos.y, z : master.pos.z }, //コピー
347 scale : master.scale,
348 color : master.color,
349 };
350 };
351
352 //mapのデータから3Dオブジェクト(壁)を作成。
353 for( var i = 0; i < map.data3Ds.length; i++ ) {
354 var data3D = map.data3Ds[ i ];
355 var object = makeLink( cubeMaster );
356 object.pos.x = data3D.x * cubeMaster.scale.x * 2;
357 object.pos.z = data3D.y * cubeMaster.scale.z * 2;
358 objects.push( object );
359 }
360 }
361 function draw( cc ) {
362 cc.fillStyle = cfg.backgroundcolor;
363 cc.fillRect( 0, 0, screenW, screenH );
364
365 //画面の中心を0,0とする
366 cc.save();
367 cc.translate( screenW / 2, screenH / 2 );
368
369 //3次元計算
370
371 //頂点の位置を計算
372 for( var j = 0; j < objects.length; j++ ) {
373 var object = objects[ j ];
374 object.tensC = new Array();
375 for( var i = 0; i < object.tens.length; i++ ) {
376 var ten = object.tens[ i ];
377
378 var x = ten.x;
379 var y = ten.y;
380 var z = ten.z;
381
382 //大きさの設定の反映
383 x *= object.scale.x;
384 y *= object.scale.y;
385 z *= object.scale.z;
386
387 //位置
388 x += object.pos.x;
389 y += object.pos.y;
390 z += object.pos.z;
391
392 //カメラの移動。カメラの移動は、景色の逆移動で表現される
393 x -= cam.pos.x;
394 y -= cam.pos.y;
395 z -= cam.pos.z;
396
397 //カメラをy軸を中心に回転。同様に景色の逆回転で表現される
398 var k = kaiten( x, z, -cam.kaiten.y );
399 x = k.X;
400 z = k.Y;
401
402 //カメラをx軸を中心に回転。〃
403 var k = kaiten( z, y, -cam.kaiten.x );
404 z = k.X;
405 y = k.Y;
406
407 //カメラを少し後方に下げるために
408 //(迷路の回転特有、というかファンタシースター1に近づけるために)
409 x -= cam.shift.x;
410 y -= cam.shift.y;
411 z -= cam.shift.z;
412
413 //3次元座標を2次元座標へ変換
414 var h = x * ( cam.s / z ) * cam.zoom;
415 var v = -y * ( cam.s / z ) * cam.zoom;
416
417 //頂点の計算結果
418 var tenC = {
419 x : x,
420 y : y,
421 z : z,
422 h : h,
423 v : v,
424 };
425 object.tensC[ i ] = tenC;
426 }
427 }
428
429 //面の集合を得る(「オブジェクトが持つ面」ではなく、「3次元空間にある面」という扱いに直す)
430 var allmens = new Array();
431 for( var k = 0; k < objects.length; k++ ) {
432 var object = objects[ k ];
433
434 for( var i = 0; i < object.mens.length; i++ ) {
435 var men = object.mens[ i ];
436 var jusin = new XYZ( 0, 0, 0 );
437 var tensC = new Array();
438 var overZ = false;
439 for( var j = 0; j < men.length; j++ ) {
440 var tenIdx = men[ j ];
441 var tenC = object.tensC[ tenIdx ];
442
443 //check. 視点の後方に入ったら描かない
444 if( tenC.z <= 0 ) {
445 overZ = true;
446 break;
447 }
448
449 tensC.push( tenC );
450
451 jusin.x += tenC.x;
452 jusin.y += tenC.y;
453 jusin.z += tenC.z;
454 }
455
456 //重心はあとで使う
457 jusin.x /= men.length;
458 jusin.y /= men.length;
459 jusin.z /= men.length;
460
461 //check. 視点の後方に入ったら描かない
462 if( overZ ) continue;
463
464 var housen = getHousen( tensC );
465 //check. 法線ベクトル法(陰面消去2) 向こうを向いた面は描かない
466 if( getNaiseki( housen, getHanten( jusin ) ) < 0 ) continue;
467
468 allmens.push( {
469 tensC : tensC,
470 object : object,
471 jusin : jusin,
472 housen : housen,
473 } );
474 }
475 }
476
477 //画家のアルゴリズムでソート(陰面消去1) z座標が奥の面ほど、手前の面で上書きされるように
478 allmens.sort( function( a, b ) {
479 if( a.jusin.z < b.jusin.z ) return 1;
480 else if( a.jusin.z > b.jusin.z ) return -1;
481 else return 0;
482 } );
483
484 //面の集合を描画
485 for( var i = 0; i < allmens.length; i++ ) {
486 var amen = allmens[ i ];
487
488 cc.beginPath();
489 for( var j = 0; j < amen.tensC.length; j++ ) {
490 var tenC = amen.tensC[ j ];
491
492 if( j == 0 )
493 cc.moveTo( tenC.h, tenC.v );
494 else
495 cc.lineTo( tenC.h, tenC.v );
496 }
497 cc.closePath();
498
499 cc.fillStyle = amen.object.color;
500 cc.strokeStyle = cfg.wirecolor;
501 cc.fill();
502 cc.stroke();
503 }
504
505 cc.restore();
506
507 //主に2Dマップの描画
508 map.draw( cc );
509 }
510
511 function XYZ( x, y, z ) {
512 this.x = x;
513 this.y = y;
514 this.z = z;
515 }
516
517 function getHousen( p ) {
518 /*
519 数学分野の汎用関数
520 法線を得る
521 */
522 var x1 = p[ 0 ].x, y1 = p[ 0 ].y, z1 = p[ 0 ].z;
523 var x2 = p[ 1 ].x, y2 = p[ 1 ].y, z2 = p[ 1 ].z;
524 var x3 = p[ 2 ].x, y3 = p[ 2 ].y, z3 = p[ 2 ].z;
525
526 //法線
527 return getNorm( {
528 x : (y2-y1)*(z3-z2)-(z2-z1)*(y3-y2),
529 y : (z2-z1)*(x3-x2)-(x2-x1)*(z3-z2),
530 z : (x2-x1)*(y3-y2)-(y2-y1)*(x3-x2),
531 } );
532 }
533 function getNaiseki( v1, v2 ) {
534 return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
535 }
536 function getHanten( v ) {
537 return {
538 x : -v.x,
539 y : -v.y,
540 z : -v.z,
541 };
542 }
543 function getNorm( v ) {
544 /*
545 数学分野の汎用関数
546 原点から座標vまでの距離を1にした座標を返す(単位ベクトル化)
547 */
548 var len = Math.sqrt( v.x * v.x + v.y * v.y + v.z * v.z );
549 return {
550 x : v.x / len,
551 y : v.y / len,
552 z : v.z / len,
553 };
554 }
555 function kaiten( x, y, theta2 ) {
556 /*
557 数学分野の汎用関数
558 原点を中心にして、回転する
559 */
560 var theta1 = Math.atan2( y, x );
561 var hankei = Math.sqrt( x * x + y * y );
562 var kaitenX = Math.cos( theta1 + theta2 ) * hankei;
563 var kaitenY = Math.sin( theta1 + theta2 ) * hankei;
564 return { X : kaitenX, Y : kaitenY };
565 }
566
567 //---map
568
569 function Map() {
570 //このデータのサイズは可変(自由に広げてよい。きちんとした長方形であること)
571 this.data = [
572 "■■■■■■■■■■",
573 "■ ■      ■",
574 "■ ■ ■■ ■ ■",
575 "■ ■■ ■ ■ ■",
576 "■    ■ ■ ■",
577 "■ ■■■■ ■ ■",
578 "■ ■  ■ ■ ■",
579 "■ ■ ■■ ■ ■",
580 "■      ■ ■",
581 "■■■■■■■■■■",
582 ];
583
584 this.sx = 1; //スタート位置
585 this.sy = 1;
586 this.width = this.data[ 0 ].length;
587 this.height = this.data.length;
588 this.px = this.sx; //プレイヤーの位置
589 this.py = this.sy;
590 this.playerDirection = 1; //プレイヤーの方向
591 this.viewmap = null;
592
593 this.scopeW = 9; //視界の広さ 9x9など奇数であること
594 this.calc();
595
596 };
597 Map.prototype.keyexec = function( key ) {
598 switch( key ) {
599 case 37: this.turn( -1 ); break;
600 case 38: this.walk( 1 ); break;
601 case 39: this.turn( 1 ); break;
602 case 40: this.walk( -1 ); break;
603 }
604 };
605 Map.prototype.walk = function( step ) {
606 //前進または後退する
607 switch( this.playerDirection ) {
608 case 0: if( this.chk( this.px + step, this.py ) ) { this.px += step; this.calc(); } break;
609 case 1: if( this.chk( this.px, this.py + step ) ) { this.py += step; this.calc(); } break;
610 case 2: if( this.chk( this.px - step, this.py ) ) { this.px -= step; this.calc(); } break;
611 case 3: if( this.chk( this.px, this.py - step ) ) { this.py -= step; this.calc(); } break;
612 }
613 };
614 Map.prototype.chk = function( x, y ) {
615 //指定位置の壁チェック
616 return this.data[ y ].substr( x, 1 ) == " ";
617 };
618 Map.prototype.chk2 = function( step ) {
619 //行く先の壁チェック
620 switch( this.playerDirection ) {
621 case 0: return this.chk( this.px + step, this.py ); break;
622 case 1: return this.chk( this.px, this.py + step ); break;
623 case 2: return this.chk( this.px - step, this.py ); break;
624 case 3: return this.chk( this.px, this.py - step ); break;
625 }
626 };
627 Map.prototype.turn = function( side ) {
628 //左右にターンする
629 this.playerDirection = ( this.playerDirection + side + 4 ) % 4;
630 this.calc();
631 };
632 Map.prototype.calc = function() {
633
634 /*
635 this.playerDirection の数値が示す方向
636
637  3 
638 2●0
639  1 
640 */
641
642 //視界の半分のサイズ、少数切り捨て
643 this.half = Math.floor( this.scopeW / 2 );
644
645 //viewmapを作成
646 /*
647 viewmapはこの関数内で使われるほかに、
648 2Dマップ(視界)の表示で使われる。
649 元はマップを回転しやすくするために用意したもの。
650 このviewmapを作らなくても、sin,cosを使えば、回転の問題は解決するが、
651 sin,cosを使うとその時点で数学のレベルが上がるので使わないことを考えた。
652 訪問者の方は難しい計算のないサンプルを欲しがると考えた。
653 ただ、3次元計算のほうでちょっとsin,cosを使っている。
654 */
655 this.viewmap = new Array();
656 for( var y = 0; y < this.scopeW; y++ ) {
657 var array = new Array();
658 for( var x = 0; x < this.scopeW; x++ ) {
659 //方向によって回転
660 var kaitenX, kaitenY;
661 switch( this.playerDirection ) {
662 //行と列を入れ替えるようなことをすると、90度回転となる
663 case 0: kaitenX = this.scopeW - y - 1; kaitenY = x; break;
664 case 1: kaitenX = this.scopeW - x - 1; kaitenY = this.scopeW - y - 1; break;
665 case 2: kaitenX = y; kaitenY = this.scopeW - x - 1; break;
666 case 3: kaitenX = x; kaitenY = y; break;
667 }
668 var mx = this.px - this.half + kaitenX;
669 var my = this.py - this.half + kaitenY;
670 var mapchip;
671 if( mx < 0 || mx >= this.width || my < 0 || my >= this.height )
672 mapchip = " "; //範囲外時
673 else
674 mapchip = this.data[ my ].substr( mx, 1 );
675 array.push( mapchip );
676 }
677 this.viewmap[ y ] = array;
678 }
679
680 //3次元処理系向けにデータを作成しておく
681 this.data3Ds = new Array();
682 for( var y = 0; y < this.viewmap.length; y++ ) {
683 for( var x = 0; x < this.viewmap[ y ].length; x++ ) {
684 var mapchip = this.viewmap[ y ][ x ];
685 if( mapchip == "■" ) {
686 var data3D = {
687 x : x - this.half,
688 y : this.viewmap.length - y - this.half - 1,
689 };
690 this.data3Ds.push( data3D );
691 }
692 }
693 }
694 };//Map.calc
695 Map.prototype.draw = function( cc ) {
696
697 //プレイヤーマークを描く臨時関数
698 var drawPlayerMark = function( x, y, d ) {
699 cc.fillStyle = "rgba(255,0,0,.5)";
700 cc.strokeStyle = "rgba(255,0,0,.25)";
701 cc.beginPath();
702 cc.arc( x, y, 4, 0, 6.28, false );
703 cc.closePath();
704 cc.fill();
705 cc.stroke();
706 var ax = [4,0,-4,0][ d ];
707 var ay = [0,4,0,-4][ d ];
708 cc.beginPath();
709 cc.arc( x + ax, y + ay, 2, 0, 6.28, false );
710 cc.closePath();
711 cc.fill();
712 cc.stroke();
713 };
714
715
716 //視界マップ
717 if( 1 ) {
718 cc.save();
719 cc.translate( 200, 0 );
720 for( var y = 0; y < this.viewmap.length; y++ ) {
721 for( var x = 0; x < this.viewmap[ y ].length; x++ ) {
722 var mapchip = this.viewmap[ y ][ x ];
723 if( mapchip == "■" ) {
724 cc.fillStyle = cfg.map2dcolorwallF;
725 cc.strokeStyle = cfg.map2dcolorwallS;
726 cc.fillRect( x * 16, y * 16, 16, 16 );
727 cc.strokeRect( x * 16, y * 16, 16, 16 );
728 } else {
729 cc.fillStyle = cfg.map2dcoloryukaF;
730 cc.fillRect( x * 16, y * 16, 16, 16 );
731 }
732 }
733 }
734 drawPlayerMark( this.half * 16 + 8, this.half * 16 + 8, 3 );
735 cc.restore();
736 }
737
738 //全体マップ
739 if( 1 ) {
740 for( var y = 0; y < this.height; y++ ) {
741 for( var x = 0; x < this.width; x++ ) {
742 var mapchip = this.data[ y ].substr( x, 1 );
743 if( mapchip == "■" ) {
744 cc.fillStyle = cfg.map2dcolorwallF;
745 cc.strokeStyle = cfg.map2dcolorwallS;
746 cc.fillRect( x * 16, y * 16, 16, 16 );
747 cc.strokeRect( x * 16, y * 16, 16, 16 );
748 } else {
749 cc.fillStyle = cfg.map2dcoloryukaF;
750 cc.fillRect( x * 16, y * 16, 16, 16 );
751 }
752 }
753 }
754 drawPlayerMark( this.px * 16 + 8, this.py * 16 + 8, this.playerDirection );
755 }
756 };//Map.draw
757
758 </script>
759 <style>
760 </style>
761 </head>
762 <body onload="onloadx();" style="
763 background-color : lightgray;
764 ">
765 <canvas id="canvasELID" width="512" height="448" style="
766 display : block;
767 margin : auto;
768 background-color : white;
769 border : solid 1px black;
770 ">There is no canvas.</canvas><BR>
771 <div style="
772 position : absolute;
773 padding : 2em;
774 left : 0px;
775 top : 0px;
776 ">
777 [移動]<BR>
778 ↑↓:前後<br>
779 ←→左右<br>
780 <BR>
781 [見た目の調整]<BR>
782 q,a:画角<br>
783 w,s:前後シフト<br>
784 e,d:上下シフト<br>
785 r,f:上下回転<br>
786 t,g:上下伸長<br>
787 y,h:画面拡縮<br>
788 u,j:視界<br>
789 z:con.log<br>
790 </div>
791
792 </body>
793 <script src="a.js"></script>
794 </html>