このファイル: /home/web6047/www/cgi-bin/prj/20180701-3DCG迷路/20180916-試作/canvas.html
1
<!DOCTYPE html>
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
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
var cfg;
81
switch( 0 ) {
82
case 0:
83
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
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
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
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
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
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
187
188
189
map = new Map();
190
191
setWalls3D();
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
}
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
227
228
function keytype( key ) {
229
var doResetWalls = false;
230
231
232
switch( key ) {
233
234
case 81: cam.s++; break;
235
case 65: cam.s--; break;
236
237
case 87: cam.shift.z++; break;
238
case 83: cam.shift.z--; break;
239
240
case 69: cam.shift.y++; break;
241
case 68: cam.shift.y--; break;
242
243
case 82: cam.kaiten.x -= .05; break;
244
case 70: cam.kaiten.x += .05; break;
245
246
case 84: cubeMaster.scale.y++; break;
247
case 71: cubeMaster.scale.y--; break;
248
249
case 89: cam.zoom += .1; break;
250
case 72: cam.zoom -= .1; break;
251
252
case 85: map.scopeW += 2; map.calc(); doResetWalls = true; break;
253
case 74: if( map.scopeW > 1 )
254
map.scopeW -= 2; map.calc(); doResetWalls = true; break;
255
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
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
}
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
326
if( anm.value >= anm.maxvalue ) {
327
anm.object[ anm.member ] = 0;
328
clearInterval( anm.timerID );
329
map.keyexec( anm.key );
330
setWalls3D();
331
anm = null;
332
}
333
334
draw( canvas );
335
}
336
function setWalls3D() {
337
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
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
366
cc.save();
367
cc.translate( screenW / 2, screenH / 2 );
368
369
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
398
var k = kaiten( x, z, -cam.kaiten.y );
399
x = k.X;
400
z = k.Y;
401
402
403
var k = kaiten( z, y, -cam.kaiten.x );
404
z = k.X;
405
y = k.Y;
406
407
408
409
x -= cam.shift.x;
410
y -= cam.shift.y;
411
z -= cam.shift.z;
412
413
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
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
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
462
if( overZ ) continue;
463
464
var housen = getHousen( tensC );
465
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
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
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
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
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;
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
636
637
638
639
640
641
642
643
this.half = Math.floor( this.scopeW / 2 );
644
645
646
647
648
649
650
651
652
653
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
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
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
};
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
};
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>