var requestAnimFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback){ window.setTimeout(callback, 1000 / 60); }; })(); //create the canvas var canvas = document.createElement("canvas"); var ctx = canvas.getContext('2d'); var updateables = []; var fireballs = []; var player = new Mario.Player([0,0]); //we might have to get the size and calculate the scaling //but this method should let us make it however big. //Cool! //TODO: Automatically scale the game to work and look good on widescreen. //TODO: fiddling with scaled sprites looks BETTER, but not perfect. Hmm. canvas.width = 762; canvas.height = 720; ctx.scale(3,3); document.body.appendChild(canvas); //viewport var vX = 0, vY = 0, vWidth = 256, vHeight = 240; //load our images resources.load([ 'sprites/player.png', 'sprites/enemy.png', 'sprites/tiles.png', 'sprites/playerl.png', 'sprites/items.png', 'sprites/enemyr.png', ]); resources.onReady(init); var level; var sounds; var music; //initialize var lastTime; function init() { music = { overworld: new Audio('sounds/aboveground_bgm.ogg'), underground: new Audio('sounds/underground_bgm.ogg'), clear: new Audio('sounds/stage_clear.wav'), death: new Audio('sounds/mariodie.wav') }; sounds = { smallJump: new Audio('sounds/jump-small.wav'), bigJump: new Audio('sounds/jump-super.wav'), breakBlock: new Audio('sounds/breakblock.wav'), bump: new Audio('sounds/bump.wav'), coin: new Audio('sounds/coin.wav'), fireball: new Audio('sounds/fireball.wav'), flagpole: new Audio('sounds/flagpole.wav'), kick: new Audio('sounds/kick.wav'), pipe: new Audio('sounds/pipe.wav'), itemAppear: new Audio('sounds/itemAppear.wav'), powerup: new Audio('sounds/powerup.wav'), stomp: new Audio('sounds/stomp.wav') }; Mario.oneone(); lastTime = Date.now(); main(); } var gameTime = 0; //set up the game loop function main() { var now = Date.now(); var dt = (now - lastTime) / 1000.0; update(dt); render(); lastTime = now; requestAnimFrame(main); } function update(dt) { gameTime += dt; handleInput(dt); updateEntities(dt, gameTime); checkCollisions(); } function handleInput(dt) { if (player.piping || player.dying || player.noInput) return; //don't accept input if (input.isDown('RUN')){ player.run(); } else { player.noRun(); } if (input.isDown('JUMP')) { player.jump(); } else { //we need this to handle the timing for how long you hold it player.noJump(); } if (input.isDown('DOWN')) { player.crouch(); } else { player.noCrouch(); } if (input.isDown('LEFT')) { // 'd' or left arrow player.moveLeft(); } else if (input.isDown('RIGHT')) { // 'k' or right arrow player.moveRight(); } else { player.noWalk(); } } //update all the moving stuff function updateEntities(dt, gameTime) { player.update(dt, vX); updateables.forEach (function(ent) { ent.update(dt, gameTime); }); //This should stop the jump when he switches sides on the flag. if (player.exiting) { if (player.pos[0] > vX + 96) vX = player.pos[0] - 96 }else if (level.scrolling && player.pos[0] > vX + 80) { vX = player.pos[0] - 80; } if (player.powering.length !== 0 || player.dying) { return; } level.items.forEach (function(ent) { ent.update(dt); }); level.enemies.forEach (function(ent) { ent.update(dt, vX); }); fireballs.forEach(function(fireball) { fireball.update(dt); }); level.pipes.forEach (function(pipe) { pipe.update(dt); }); } //scan for collisions function checkCollisions() { if (player.powering.length !== 0 || player.dying) { return; } player.checkCollisions(); //Apparently for each will just skip indices where things were deleted. level.items.forEach(function(item) { item.checkCollisions(); }); level.enemies.forEach (function(ent) { ent.checkCollisions(); }); fireballs.forEach(function(fireball){ fireball.checkCollisions(); }); level.pipes.forEach (function(pipe) { pipe.checkCollisions(); }); } //draw the game! function render() { updateables = []; ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = level.background; ctx.fillRect(0, 0, canvas.width, canvas.height); //scenery gets drawn first to get layering right. for(var i = 0; i < 15; i++) { for (var j = Math.floor(vX / 16) - 1; j < Math.floor(vX / 16) + 20; j++){ if (level.scenery[i][j]) { renderEntity(level.scenery[i][j]); } } } //then items level.items.forEach (function (item) { renderEntity(item); }); level.enemies.forEach (function(enemy) { renderEntity(enemy); }); fireballs.forEach(function(fireball) { renderEntity(fireball); }) //then we draw every static object. for(var i = 0; i < 15; i++) { for (var j = Math.floor(vX / 16) - 1; j < Math.floor(vX / 16) + 20; j++){ if (level.statics[i][j]) { renderEntity(level.statics[i][j]); } if (level.blocks[i][j]) { renderEntity(level.blocks[i][j]); updateables.push(level.blocks[i][j]); } } } //then the player if (player.invincibility % 2 === 0) { renderEntity(player); } //Mario goes INTO pipes, so naturally they go after. level.pipes.forEach (function(pipe) { renderEntity(pipe); }); } function renderEntity(entity) { entity.render(ctx, vX, vY); }