(function() {
		

		var map = [  
			[ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
			[ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
			[ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
			[ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
			[ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
			[ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
			[ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
			[ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
			[ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
			[ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
			[ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
			[ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
			[ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
			[ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ],
			[ 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ],
			[ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ],
			[ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ]
		];

		var adds = { a1: [0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,1], a2: [0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,1],
			a3: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], a4: [0,0,0,0,0,0,0,0,0,2,2,2,0,0,2,2,1] };


		var runTime = 0;
		var times = [];

		function Platformer() {
			
			var gameSpecs = { 
				gWidth:10280, gHeight:272,cameraWidth:640, cameraHeight:272, 
				cameraFollowOffsetX:-9320, cameraFollowOffsetY:0,  tileW:16, tileH:16, 
				spriteSheetImage: null, containerDivId:"container", rootDivId:"root",
				controllerDivId:"controller", gameScale:2, useScreenOrganizer:true,startWidth:50, startHeight:25,
				controllerHeight:144, initialLives:3, initPlayerPosition:new tabageos.MoverPoint(32,32), 
				gameLoop:this.loop,initializationSpecifics:this.setup, disableBackgroundAlpha:0,
				addedResizeMethod:null, sceneResetSpecifics:null,fullResetSpecifics:null, additionalSceneResetSpecifics:null, 
				positionResetSpecifics:this._resetPosition, cameraType:1, backgroundColor:"#c8c8c8" 
			};

			tabageos.GameSkeleton.call(this,  gameSpecs);

			this.establishKeyEventsForReset();
		}
		
		Platformer.constructor = Platformer;
		//JavaScript basic inheritance, the tabageos library also includes an implementation of Object.assign if Object.assign is not already defined in the browser.
		Platformer.prototype = Object.create(tabageos.GameSkeleton.prototype);
		
		
		Platformer.prototype.setup = function(sax,say) {
			this.lives = 3000000;
            this.title.floor.context.fillStyle = "#ffffff";
			this.title.floor.context.fillRect(0,0,1280,272);
			
			//we add our own html to the title screen.
			var tdiv = document.createElement("div");
			tdiv.innerHTML = "<h1 style='color:#6495ed'>Endless Runner</h1><br />"+
				"Click start or press shift to start<br />"+
				"Press right or D to run. W or up to jump. <br /> To use a gamepad, after starting, press one of its directional buttons then follow the on screen prompts.";
				tdiv.setAttribute("style", "position:absolute;width:640px;top:0px;left:0px;text-align:center;color:#6495ed");
			this.title.div.appendChild(tdiv);
			
			var mp = tabageos.BlitMath.cloneMultiArray(map);//we clone map, because we'll use map to reset.
			//for now the player will just be a simple MapMover, by the end we will use TravelingSceneryThrower for it.
			this.player = new tabageos.MapMover(48,48,16,16,mp,0,1);
			this.player._jumps = 1;//gravity is now applied to the character, by default it does not move with gravity, ._jumps is 0 by default for MapMovers.
			this.player._jumpSpeed = 4;//default _jumpSpeed is 4
			this.player._gravityLevel = .305;//.285 is the default _gravityLevel.
			this.player._autoAnimate = 1;
			this.player._walkSpeed = 4;
			this.player._directCanvasObject = this.charLayer;
			//these are properties inherited from GameSkeleton.
			//this.resizeRootForNoTouch = 1; //when no touch, resize just the root instead of the whole container, root should be inside container, and controller should be under root also inside container.
			//resizeRootForNoTouch is for when your game is not fullscreen/page.
			this.dontResizeVertical = 1;
			this.addedResizeMethod = this.pageSpecificResizing;//allows to add additional functionality during resizing beyond just fitting the game/controller layers to the page.
			this.charLayer.context.fillStyle = "#6495ed";
            
			//now the user can plug in a game pad, and press one of the directional buttons to start using it.
			this.enableGamePad = 1;
			
			//colorValues tells 
			this.camera.colorValues = {1:"#c8c8c8",2:"#0c0c0c", 3:"#ffff00"};
			
			//with setupForRenderFromMap what is going to happen is that the display layer will be drawn directly from the map instead of from an offscreen canvas.
			//and when the map is about to run out, the mapUpdateMethod will be called.
			//and so the map array keeps growing in size, but there is no giant CanvasObject created.
			//however when using a predrawn offscreen canvas there is only 1 render call to render that offscreen canvas to the camera.
			//in this case the camera will render each tile from the map directly, so there is a render call for each tile.
			//smaller predrawn level layers perform better.
			//but this example shows how to set things up to draw from the array directly, and how to keep repopulating the array.
			this.camera.setupForRenderFromMap(mp,null,16,16,2,648,272);
			this.camera.mapUpdateMethod = this.updateMap;
			
			//adding html to the gameOverContainer.
			var goDiv = document.createElement("div");
			goDiv.setAttribute("style", "position:absolute;font-family: 'soupoj', sans-serif;width:640px;color:black;text-align:center");
			goDiv.innerHTML = "<h2>Game Over</h2><br /><br /><br /><span style='cursor:pointer' onclick='tabageos.GameSkeleton.game.hudExit()'>Press Start</span>";
			this.gameOverContainer.div.appendChild(goDiv);

		};
		Platformer.prototype._resetPosition = function() {
			//this method happens when the level is reset.
			//reset the player position.
			this.player.setX(48);
			this.player.setY(16);
			this.horizontalCameraMove = 0;
			//and camera position.
			this.camera.v.x = 0;
			this.camera.v.y = 0;
			
			//and reset map.
			var mp = tabageos.BlitMath.cloneMultiArray(map);
			this.camera._map = mp;
			this.player._map = mp;
			this.player._mapRows = mp.length;
			this.player._mapColumns = mp[0].length;

			//do camera operations once
			this.callCamera();
		};
		Platformer.prototype.updateMap = function() {
			//this method is being called from the camera not from 'this'.
			
			var mp = tabageos.GameSkeleton.game.camera._map;//which actually is this._map inside this function.
			tabageos.BlitMath.addSpecificValuesToMultiArray(mp, adds.a1);//add a1, the floor, 3 times.
			tabageos.BlitMath.addSpecificValuesToMultiArray(mp, adds.a1);
			tabageos.BlitMath.addSpecificValuesToMultiArray(mp, adds.a1);
			var ran = Math.floor(Math.random()*4) + 1;//pick a random number 1,2,3,4.
			tabageos.BlitMath.addSpecificValuesToMultiArray(mp, adds["a"+ran]);//add that random array set.
			if(ran == 3) { //if the added random set is the blank, drop set, add 6 more.
				tabageos.BlitMath.addSpecificValuesToMultiArray(mp, adds["a"+ran]);
				tabageos.BlitMath.addSpecificValuesToMultiArray(mp, adds["a"+ran]); 
				tabageos.BlitMath.addSpecificValuesToMultiArray(mp, adds["a"+ran]);
				tabageos.BlitMath.addSpecificValuesToMultiArray(mp, adds["a"+ran]);
				tabageos.BlitMath.addSpecificValuesToMultiArray(mp, adds["a"+ran]);
				tabageos.BlitMath.addSpecificValuesToMultiArray(mp, adds["a"+ran]);
			}
			tabageos.GameSkeleton.game.player._map = mp;//but we use the GameSkeleton.game reference to reference the player.
			tabageos.GameSkeleton.game.player._mapRows = mp.length;
			tabageos.GameSkeleton.game.player._mapColumns = mp[0].length;
			
		};
		
		Platformer.prototype.showRunTime = function(ts) {
			//this method hijacks the loop.
			//so we use _helperPoint to ensure this block happens just once.
			if(this._helperPoint.x == -444) {
				this._helperPoint.x = 0;
				var now = (new Date().getTime() - runTime) / 1000;
				times.push(now);
				var best = now+1-1;var i = 0;
				for(i;i<times.length;i++) {
					if(times[i] > best) {
						best = times[i]+1-1;
					}
				}
				//show text for 7 seconds.
				this.showText("Current Run Time: " + Math.floor(now) + " seconds &#13 Best Run Time: " + Math.floor(best) + " seconds",7000,17,640,270,-3,-3,'soupoj',0,'background-color:#6495ed00');
				
			}
			
			//textFinished actually happens a bit before the 7 seconds are up.
			//and if the user presses space also it would restart the level.
			if(this.textFinished() || this.controller.buttons.a) {
				this.hideText();
				this.endLevelComplete(0);
			}
			
		};
		
		Platformer.prototype.loop = function() { 
		
			//move and collide with the map
			this.player.move(this.horizontalCameraMove ? this.controller.buttons.left : 0, this.horizontalCameraMove ? 1 : 0,this.controller.buttons.up || this.controller.buttons.a,this.controller.buttons.down);
			
			//if horizontalCameraMove is not yet set, and the user presses right, set horizontalCameraMove.
			//horizontalCameraMove causes the camera to contiuosly move horizontally no longer following the player.
			if(this.controller.buttons.right && !this.horizontalCameraMove) { 
				this.controller.buttons.right = 0;
				runTime = new Date().getTime();//the run has begun, keep the start time.
				this.horizontalCameraMove = 2.6;
			}

			if(this.player.x + 16 < this.camera.v.x || this.player.y > 272 - 32 || this.player.x > this.camera.width - 32) {
				this._helperPoint.x = -444;
				this.levelComplete(this.showRunTime);
			}

			//that's it, move is handling movement and collision.
			//and the player animates itself also during move because we have set that up during the setup call.
			//GameSkeleton is smoothing a requestAnimationFrame call and calling this method in the middle of those calculations.
		};
		
		
		
		new Platformer();
		
		
	})();
		
		






back to top