summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Buland <Mike.Buland@mjfirm.com>2016-10-21 10:45:54 -0600
committerMike Buland <Mike.Buland@mjfirm.com>2016-10-21 10:45:54 -0600
commite3a6b64a9dcae8e4d1d02969e28779be1337af7e (patch)
tree03cb5856ef91ce29c4da24d46f1b3009ddbc884a
parent9fb42f1e2e1361a07f0fca213dfb914d71763781 (diff)
downloadlost-e3a6b64a9dcae8e4d1d02969e28779be1337af7e.tar.gz
lost-e3a6b64a9dcae8e4d1d02969e28779be1337af7e.tar.bz2
lost-e3a6b64a9dcae8e4d1d02969e28779be1337af7e.tar.xz
lost-e3a6b64a9dcae8e4d1d02969e28779be1337af7e.zip
Hey! It's interactive!
-rw-r--r--js/lost.js453
1 files changed, 358 insertions, 95 deletions
diff --git a/js/lost.js b/js/lost.js
index b2b908c..58a7840 100644
--- a/js/lost.js
+++ b/js/lost.js
@@ -20,6 +20,27 @@ function oppositeDir( iDir )
20} 20}
21 21
22// 22//
23// Class: Signal
24//
25function Signal()
26{
27 this.aSlot = new Array();
28}
29
30Signal.prototype.connect = function connect( fSlot )
31{
32 this.aSlot.push( fSlot );
33}
34
35Signal.prototype.call = function call()
36{
37 for( let j = 0; j < this.aSlot.length; j++ )
38 {
39 (this.aSlot[j])();
40 }
41}
42
43//
23// Class: Cell 44// Class: Cell
24// 45//
25function Cell() 46function Cell()
@@ -99,6 +120,21 @@ Position.prototype.copy = function translate()
99 return new Position( this.iDims, ...this.aiValues.slice() ); 120 return new Position( this.iDims, ...this.aiValues.slice() );
100} 121}
101 122
123Position.prototype.equals = function equals( rhs )
124{
125 if( this.iDims != rhs.iDims &&
126 this.aiValues.length != rhs.aiValues.length )
127 return false;
128
129 for( let j = 0; j < this.aiValues.length; j++ )
130 {
131 if( this.aiValues[j] != rhs.aiValues[j] )
132 return false;
133 }
134
135 return true;
136}
137
102// 138//
103// Class: Map 139// Class: Map
104// 140//
@@ -106,6 +142,9 @@ function Map( Dimensions )
106{ 142{
107 // Store dimensional data 143 // Store dimensional data
108 this.Dimensions = Dimensions; 144 this.Dimensions = Dimensions;
145 this.aWorms = new Array();
146 this.pPlayer = null;
147 this.ePlayerMoved = new Signal();
109 148
110 // Compute the total number of cells 149 // Compute the total number of cells
111 let iTotalSize = 1; 150 let iTotalSize = 1;
@@ -132,6 +171,36 @@ Map.prototype.getSize = function getSize( iDim )
132 return this.Dimensions.get( iDim ); 171 return this.Dimensions.get( iDim );
133} 172}
134 173
174Map.prototype.getPlayerPos = function getPlayerPos()
175{
176 return this.pPlayer;
177}
178
179Map.prototype.setPlayerPos = function setPlayerPos( pNewPos )
180{
181 this.pPlayer = pNewPos;
182 this.ePlayerMoved.call();
183}
184
185Map.prototype.movePlayer = function movePlayer( iDim, iDelta )
186{
187 let cCur = this.get( this.pPlayer );
188
189 let iBit = iDim*2;
190 if( iDelta > 0 )
191 iBit++;
192
193 if( (cCur.iWalls&(1<<iBit)) === 0 )
194 return;
195
196 let iNewX = this.pPlayer.get( iDim ) + iDelta;
197 if( iNewX < 0 || iNewX >= this.getSize( iDim ) )
198 return;
199
200 this.pPlayer.add( iDim, iDelta );
201 this.ePlayerMoved.call();
202}
203
135Map.prototype.isInside = function isInside( Position ) 204Map.prototype.isInside = function isInside( Position )
136{ 205{
137 if( Position.getDims() != this.Dimensions.getDims() ) 206 if( Position.getDims() != this.Dimensions.getDims() )
@@ -174,6 +243,39 @@ Map.prototype.get = function get( Position )
174 return this.aCell[this.getIndex( Position )]; 243 return this.aCell[this.getIndex( Position )];
175} 244}
176 245
246Map.prototype.addWorm = function addWorm( pStart )
247{
248 if( this.aWorms.length === 0 )
249 {
250 this.pPlayer = pStart;
251 }
252 let iNewId = this.aWorms.length+1;
253 this.aWorms.push(
254 new Worm(
255 iNewId,
256 pStart,
257 this
258 )
259 );
260 return iNewId;
261}
262
263Map.prototype.buildMaze = function buildMaze()
264{
265 do
266 {
267 for( let j = 0; j < this.aWorms.length; j++ )
268 {
269 if( !this.aWorms[j].timestep() )
270 {
271 this.aWorms.splice( j, 1 );
272 j--;
273 }
274 }
275 } while( this.aWorms.length > 0 );
276 this.connect( 1, 2 );
277}
278
177Map.prototype.connect = function connect( iWormId1, iWormId2 ) 279Map.prototype.connect = function connect( iWormId1, iWormId2 )
178{ 280{
179 let p = new Position( this.getDims() ); 281 let p = new Position( this.getDims() );
@@ -376,12 +478,41 @@ Render.prototype.render = function render()
376{ 478{
377} 479}
378 480
481function createMoveButton( rMap, iDim, iDir, sLabel )
482{
483 let btn = document.createElement('button');
484 btn.addEventListener(
485 'click',
486 Map.prototype.movePlayer.bind(
487 rMap,
488 iDim,
489 iDir
490 )
491 );
492 if( sLabel === null || sLabel === '' )
493 {
494 btn.appendChild(
495 document.createTextNode('Dim ' + (j+1) + ': -')
496 );
497 }
498 else
499 {
500 btn.appendChild(
501 document.createTextNode( sLabel )
502 );
503 }
504 return btn;
505}
506
379// 507//
380// Class: RenderCanvas2D 508// Class: RenderCanvas2D
381// 509//
382function RenderCanvas2D( rMap, eParent ) 510function RenderCanvas2D( rMap, eParent )
383{ 511{
384 Render.call( this, rMap, eParent ); 512 Render.call( this, rMap, eParent );
513 this.rMap.ePlayerMoved.connect(
514 RenderCanvas2D.prototype.render.bind( this )
515 );
385 516
386 this.eCanvas = null; 517 this.eCanvas = null;
387 this.ctx = null; 518 this.ctx = null;
@@ -390,9 +521,13 @@ function RenderCanvas2D( rMap, eParent )
390 521
391 this.iIconSize = 11; 522 this.iIconSize = 11;
392 this.iBorder = 3; 523 this.iBorder = 3;
524 this.iIconSquare = Math.ceil(
525 Math.sqrt((this.rMap.getDims()-2)*2 + 1)
526 );
527
393 this.iCellSize = 528 this.iCellSize =
394 this.iBorder + 529 this.iBorder +
395 (this.rMap.getDims()-2)*2*(this.iIconSize+this.iBorder); 530 this.iIconSquare*(this.iIconSize+this.iBorder);
396 531
397 this.eCanvas = document.createElement('canvas'); 532 this.eCanvas = document.createElement('canvas');
398 this.eCanvas.width = this.iCellSize*this.rMap.getSize( 0 ); 533 this.eCanvas.width = this.iCellSize*this.rMap.getSize( 0 );
@@ -408,24 +543,88 @@ function RenderCanvas2D( rMap, eParent )
408 eParent.appendChild( document.createElement('br') ); 543 eParent.appendChild( document.createElement('br') );
409 eParent.appendChild( btnBox ); 544 eParent.appendChild( btnBox );
410 545
411 for( let j = 2; j < this.rMap.getDims(); j++ ) 546 let cardTbl;
547 let cardRow;
548 let cardTd;
549
550 cardTbl = document.createElement('table');
551 cardRow = document.createElement('tr');
552 cardTbl.appendChild( cardRow );
553 cardRow.appendChild( document.createElement('td') );
554 cardTd = document.createElement('td');
555 cardTd.appendChild( createMoveButton( this.rMap, 1, -1, "North" ) );
556 cardRow.appendChild( cardTd );
557 cardRow.appendChild( document.createElement('td') );
558 if( this.rMap.getDims() >= 3 )
412 { 559 {
413 for( let k = 0; k < this.rMap.getSize( j ); k++ ) 560 cardTd = document.createElement('td');
414 { 561 cardTd.appendChild( createMoveButton( this.rMap, 2, -1, "Up" ) );
415 let btn = document.createElement('button'); 562 cardRow.appendChild( cardTd );
416 btn.addEventListener( 563 }
417 'click', 564
418 RenderCanvas2D.prototype.setFloor.bind( 565 cardRow = document.createElement('tr');
419 this, 566 cardTbl.appendChild( cardRow );
420 [k] 567 cardTd = document.createElement('td');
421 ) 568 cardTd.appendChild( createMoveButton( this.rMap, 0, -1, "West" ) );
422 ); 569 cardRow.appendChild( cardTd );
423 btn.appendChild( 570 cardRow.appendChild( document.createElement('td') );
424 document.createTextNode('Floor ' + (k+1) ) 571 cardTd = document.createElement('td');
425 ); 572 cardTd.appendChild( createMoveButton( this.rMap, 0, 1, "East" ) );
426 btnBox.appendChild( btn ); 573 cardRow.appendChild( cardTd );
427 } 574 if( this.rMap.getDims() >= 3 )
575 {
576 cardRow.appendChild( document.createElement('td') );
577 }
578
579 cardRow = document.createElement('tr');
580 cardTbl.appendChild( cardRow );
581 cardRow.appendChild( document.createElement('td') );
582 cardTd = document.createElement('td');
583 cardTd.appendChild( createMoveButton( this.rMap, 1, 1, "South" ) );
584 cardRow.appendChild( cardTd );
585 cardRow.appendChild( document.createElement('td') );
586 if( this.rMap.getDims() >= 3 )
587 {
588 cardTd = document.createElement('td');
589 cardTd.appendChild( createMoveButton( this.rMap, 2, 1, "Down" ) );
590 cardRow.appendChild( cardTd );
428 } 591 }
592
593 btnBox.appendChild( cardTbl );
594
595 let names = [];
596 names[6] = 'In';
597 names[7] = 'Out';
598 names[8] = 'Through';
599 names[9] = 'Around';
600
601 cardTbl = document.createElement('table');
602 for( let j = 3; j < this.rMap.getDims(); j++ )
603 {
604 cardRow = document.createElement('tr');
605 cardTbl.appendChild( cardRow );
606
607 let label;
608
609 if( typeof names[j*2] === 'undefined' )
610 label = 'Dim ' + (j+1) + ': -';
611 else
612 label = names[j*2];
613
614 cardTd = document.createElement('td');
615 cardTd.appendChild( createMoveButton( this.rMap, j, -1, label ) );
616 cardRow.appendChild( cardTd );
617
618 if( typeof names[j*2+1] === 'undefined' )
619 label = 'Dim ' + (j+1) + ': +';
620 else
621 label = names[j*2+1];
622
623 cardTd = document.createElement('td');
624 cardTd.appendChild( createMoveButton( this.rMap, j, 1, label ) );
625 cardRow.appendChild( cardTd );
626 }
627 btnBox.appendChild( cardTbl );
429} 628}
430 629
431RenderCanvas2D.prototype = Object.create(Render.prototype); 630RenderCanvas2D.prototype = Object.create(Render.prototype);
@@ -437,76 +636,156 @@ RenderCanvas2D.prototype.render = function render()
437 this.ctx.clearRect( 0, 0, this.eCanvas.width, this.eCanvas.height ); 636 this.ctx.clearRect( 0, 0, this.eCanvas.width, this.eCanvas.height );
438 this.ctx.beginPath(); 637 this.ctx.beginPath();
439 638
440 let p = this.pExtPosition.copy(); 639 let p;
640 if( this.rMap.pPlayer === null )
641 p = this.pExtPosition.copy();
642 else
643 p = this.rMap.pPlayer.copy();
644
645 for( let x = 0; x < this.rMap.getSize( 0 ); x++ )
441 { 646 {
442 for( let x = 0; x < this.rMap.getSize( 0 ); x++ ) 647 for( let y = 0; y < this.rMap.getSize( 1 ); y++ )
443 { 648 {
444 for( let y = 0; y < this.rMap.getSize( 1 ); y++ ) 649 p.set( 0, x );
650 p.set( 1, y );
651 let c = this.rMap.get( p );
652 if( (c.iWalls&1) === 0 && x === 0)
445 { 653 {
446 p.set( 0, x ); 654 this.ctx.moveTo( x*iSize, y*iSize );
447 p.set( 1, y ); 655 this.ctx.lineTo( x*iSize, (y+1)*iSize );
448 let c = this.rMap.get( p ); 656 }
449 if( (c.iWalls&1) === 0 && x === 0) 657 if( (c.iWalls&2) === 0 )
450 { 658 {
451 this.ctx.moveTo( x*iSize, y*iSize ); 659 this.ctx.moveTo( (x+1)*iSize, y*iSize );
452 this.ctx.lineTo( x*iSize, (y+1)*iSize ); 660 this.ctx.lineTo( (x+1)*iSize, (y+1)*iSize );
453 } 661 }
454 if( (c.iWalls&2) === 0 ) 662 if( (c.iWalls&4) === 0 && y === 0)
455 { 663 {
456 this.ctx.moveTo( (x+1)*iSize, y*iSize ); 664 this.ctx.moveTo( x*iSize, y*iSize );
457 this.ctx.lineTo( (x+1)*iSize, (y+1)*iSize ); 665 this.ctx.lineTo( (x+1)*iSize, y*iSize );
458 } 666 }
459 if( (c.iWalls&4) === 0 && y === 0) 667 if( (c.iWalls&8) === 0 )
460 { 668 {
461 this.ctx.moveTo( x*iSize, y*iSize ); 669 this.ctx.moveTo( x*iSize, (y+1)*iSize );
462 this.ctx.lineTo( (x+1)*iSize, y*iSize ); 670 this.ctx.lineTo( (x+1)*iSize, (y+1)*iSize );
463 } 671 }
464 if( (c.iWalls&8) === 0 )
465 {
466 this.ctx.moveTo( x*iSize, (y+1)*iSize );
467 this.ctx.lineTo( (x+1)*iSize, (y+1)*iSize );
468 }
469 672
470 if( (c.iWalls&16) !== 0 ) 673 // Extended dimenisons (above 2 :-P)
674 let iIcon = 0;
675 for( let ed = 2; ed < this.rMap.getDims(); ed++ )
676 {
677 if( (c.iWalls&(1<<(ed*2))) !== 0 )
471 { 678 {
472 // Up 679 this.renderDirIcon( x, y, iIcon, ed*2 );
473 let bx = x*iSize+this.iBorder;
474 let by = y*iSize+this.iBorder;
475 this.ctx.moveTo(
476 bx,
477 by+this.iIconSize
478 );
479 this.ctx.lineTo(
480 bx+this.iIconSize/2,
481 by
482 );
483 this.ctx.lineTo(
484 bx+this.iIconSize,
485 by+this.iIconSize
486 );
487 } 680 }
488 if( (c.iWalls&32) !== 0 ) 681 iIcon++;
682 if( (c.iWalls&(1<<(ed*2+1))) !== 0 )
489 { 683 {
490 // Down 684 this.renderDirIcon( x, y, iIcon, ed*2+1 );
491 let bx = x*iSize+this.iBorder*2+this.iIconSize;
492 let by = y*iSize+this.iBorder;
493 this.ctx.moveTo(
494 bx,
495 by
496 );
497 this.ctx.lineTo(
498 bx+this.iIconSize/2,
499 by+this.iIconSize
500 );
501 this.ctx.lineTo(
502 bx+this.iIconSize,
503 by
504 );
505 } 685 }
686 iIcon++;
506 } 687 }
507 } 688 }
508 } 689 }
509 this.ctx.stroke(); 690 this.ctx.stroke();
691
692 // Draw the player
693 if( this.rMap.pPlayer !== null )
694 {
695 let bx = this.rMap.pPlayer.get(0)*iSize +
696 this.iBorder + (this.iIconSquare-1)*(this.iBorder+this.iIconSize);
697 let by = this.rMap.pPlayer.get(1)*iSize +
698 this.iBorder + (this.iIconSquare-1)*(this.iBorder+this.iIconSize);
699 this.rMap.pPlayer.equals( p );
700 this.ctx.beginPath();
701 this.ctx.ellipse(
702 bx+this.iIconSize*0.5, by+this.iIconSize*0.5,
703 this.iIconSize*0.4, this.iIconSize*0.4,
704 0,
705 Math.PI*2.0,
706 false
707 );
708 this.ctx.fill();
709 }
710}
711
712RenderCanvas2D.prototype.renderDirIcon = function renderDirIcon(
713 x, y, iIcon, iDir )
714{
715 let bx = x*this.iCellSize +
716 this.iBorder +
717 (iIcon%this.iIconSquare)*(this.iIconSize+this.iBorder);
718 let by = y*this.iCellSize +
719 this.iBorder +
720 Math.floor(iIcon/this.iIconSquare)*(this.iIconSize+this.iBorder);
721
722 //this.ctx.rect(bx, by, this.iIconSize, this.iIconSize );
723 switch( iDir )
724 {
725 case 4:
726 // Up
727 this.ctx.moveTo(
728 bx,
729 by+this.iIconSize
730 );
731 this.ctx.lineTo(
732 bx+this.iIconSize/2,
733 by
734 );
735 this.ctx.lineTo(
736 bx+this.iIconSize,
737 by+this.iIconSize
738 );
739 break;
740
741 case 5:
742 // Down
743 this.ctx.moveTo(
744 bx,
745 by
746 );
747 this.ctx.lineTo(
748 bx+this.iIconSize/2,
749 by+this.iIconSize
750 );
751 this.ctx.lineTo(
752 bx+this.iIconSize,
753 by
754 );
755 break;
756
757 case 6:
758 // In
759 this.ctx.moveTo(
760 bx+this.iIconSize,
761 by
762 );
763 this.ctx.lineTo(
764 bx,
765 by+this.iIconSize/2
766 );
767 this.ctx.lineTo(
768 bx+this.iIconSize,
769 by+this.iIconSize
770 );
771 break;
772
773 case 7:
774 // Out
775 this.ctx.moveTo(
776 bx,
777 by
778 );
779 this.ctx.lineTo(
780 bx+this.iIconSize,
781 by+this.iIconSize/2
782 );
783 this.ctx.lineTo(
784 bx,
785 by+this.iIconSize
786 );
787 break;
788 }
510} 789}
511 790
512RenderCanvas2D.prototype.setFloor = function setFloor( aFloor ) 791RenderCanvas2D.prototype.setFloor = function setFloor( aFloor )
@@ -521,29 +800,13 @@ RenderCanvas2D.prototype.setFloor = function setFloor( aFloor )
521// 800//
522// Initialize 801// Initialize
523// 802//
524let p = new Position( 3, 15, 15, 3 ); 803let p = new Position( 4, 3, 3, 3, 3 );
525let m = new Map( p ); 804let m = new Map( p );
526let exit1 = new Position( p.getDims() ); 805let exit1 = new Position( p.getDims() );
527let exit2 = new Position( p.getDims() ); 806let exit2 = new Position( p.getDims() );
528exit2.set( 1, p.get( 1 )-1 ); 807exit2.set( 1, p.get( 1 )-1 );
529let w = [ 808m.addWorm( exit1 );
530 new Worm( 1, exit1, m ), 809m.addWorm( exit2 );
531 new Worm( 2, exit2, m ) 810m.buildMaze();
532 ];
533
534do
535{
536 for( let j = 0; j < w.length; j++ )
537 {
538 if( !w[j].timestep() )
539 {
540 w.splice( j, 1 );
541 j--;
542 }
543 }
544} while( w.length > 0 );
545
546m.connect( 1, 2 );
547 811
548let rend = new RenderCanvas2D( m, document.body ); 812let rend = new RenderCanvas2D( m, document.body );
549//rend.render( document.body );