Forked from: rolandas_kairys's forked: Space Battles View Diff (103) forked: Space Battles rolandas_kai Follow 2014-05-03 20:17:44 License: MIT License Fork1 Fav0 View2107 Play Stop Reload Fullscreen Smart Phone Fork tree Readme JavaScript 879 lines HTML 29 lines CSS 61 lines forked: Space Battles // forked from rolandas_kairys's "forked: Space Battles " http://jsdo.it/rolandas_kairys/cGkM ////// forked from rolandas_kairys's "Space Battles " http://jsdo.it/rolandas_kairys/dNmW function MathUtil() {} MathUtil.clamp = function(a, v, b) { return Math.min(Math.max(a, v), b); } (function() { var lastTime = 0; var vendors = ['ms', 'moz', 'webkit', 'o']; for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame']; } if (!window.requestAnimationFrame) window.requestAnimationFrame = function(callback, element) { var currTime = new Date().getTime(); var timeToCall = Math.max(0, 16 - (currTime - lastTime)); var id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall); lastTime = currTime + timeToCall; return id; }; if (!window.cancelAnimationFrame) window.cancelAnimationFrame = function(id) { clearTimeout(id); }; }()); var Game = new function() { var boards = []; // Game Initialization this.initialize = function(canvasElementId,sprite_data,callback) { this.canvas = document.getElementById(canvasElementId); this.playerOffset = 10; this.canvasMultiplier= 1; this.setupMobile(); this.width = this.canvas.width; this.height= this.canvas.height; this.ctx = this.canvas.getContext && this.canvas.getContext('2d'); if(!this.ctx) { return alert("Please upgrade your browser to play"); } this.setupInput(); this.loop(); if(this.mobile) { this.setBoard(4,new TouchControls()); } SpriteSheet.load(sprite_data,callback); }; // Handle Input var KEY_CODES = { 37:'left', 38:'up', 39:'right', 40:'down', 32 :'fire' }; this.keys = {}; this.setupInput = function() { window.addEventListener('keydown',function(e) { var event = e || event || window.event; if(KEY_CODES[event.keyCode]) { Game.keys[KEY_CODES[event.keyCode]] = true; e.preventDefault(); } },false); window.addEventListener('keyup',function(e) { var event = e || event || window.event; if(KEY_CODES[event.keyCode]) { Game.keys[KEY_CODES[event.keyCode]] = false; e.preventDefault(); } },false); }; var lastTime = new Date().getTime(); var maxTime = 1/30; // Game Loop this.loop = function() { var curTime = new Date().getTime(); requestAnimationFrame(Game.loop); var dt = (curTime - lastTime)/1000; if(dt > maxTime) { dt = maxTime; } for(var i=0,len = boards.length;i<len;i++) { if(boards[i]) { boards[i].step(dt); boards[i].draw(Game.ctx); } } lastTime = curTime; }; // Change an active game board this.setBoard = function(num,board) { boards[num] = board; }; this.setupMobile = function() { var container = document.getElementById("container"), hasTouch = !!('ontouchstart' in window), w = window.innerWidth, h = window.innerHeight; if(hasTouch) { this.mobile = true; } if(screen.width >= 1280 || !hasTouch) { return false; } if(w > h) { alert("Please rotate the device and then click OK"); w = window.innerWidth; h = window.innerHeight; } container.style.height = h*2 + "px"; window.scrollTo(0,1); h = window.innerHeight + 2; container.style.height = h + "px"; container.style.width = w + "px"; container.style.padding = 0; if(h >= this.canvas.height * 1.75 || w >= this.canvas.height * 1.75) { this.canvasMultiplier = 2; this.canvas.width = w / 2; this.canvas.height = h / 2; this.canvas.style.width = w + "px"; this.canvas.style.height = h + "px"; } else { this.canvas.width = w; this.canvas.height = h; } this.canvas.style.position='absolute'; this.canvas.style.left="0px"; this.canvas.style.top="0px"; }; }; var SpriteSheet = new function() { this.map = { }; this.load = function(spriteData,callback) { this.map = spriteData; this.image = new Image(); this.image.onload = callback; this.image.src = 'http://jsrun.it/assets/k/V/e/v/kVevG.png'; }; this.draw = function(ctx,sprite,x,y,frame) { var s = this.map[sprite]; if(!frame) frame = 0; ctx.drawImage(this.image, s.sx + frame * s.w, s.sy, s.w, s.h, Math.floor(x), Math.floor(y), s.w, s.h); }; return this; }; var TitleScreen = function TitleScreen(title,subtitle,callback) { var up = false; this.step = function(dt) { if(!Game.keys['fire']) up = true; if(up && Game.keys['fire'] && callback) callback(); }; this.draw = function(ctx) { ctx.fillStyle = "#FFFF00"; ctx.font = "bold 37px Courier"; var measure = ctx.measureText(title); ctx.fillText(title,Game.width/2 - measure.width/2,Game.height/2); ctx.font = "bold 15px Courier"; var measure2 = ctx.measureText(subtitle); ctx.fillText(subtitle,Game.width/2 - measure2.width/2,Game.height/2 + 40); }; }; var GameBoard = function() { var board = this; // The current list of objects this.objects = []; this.cnt = {}; // Add a new object to the object list this.add = function(obj) { obj.board=this; this.objects.push(obj); this.cnt[obj.type] = (this.cnt[obj.type] || 0) + 1; return obj; }; // Mark an object for removal this.remove = function(obj) { var idx = this.removed.indexOf(obj); if(idx == -1) { this.removed.push(obj); return true; } else { return false; } }; // Reset the list of removed objects this.resetRemoved = function() { this.removed = []; }; // Removed an objects marked for removal from the list this.finalizeRemoved = function() { for(var i=0,len=this.removed.length;i<len;i++) { var idx = this.objects.indexOf(this.removed[i]); if(idx != -1) { this.cnt[this.removed[i].type]--; this.objects.splice(idx,1); } } }; // Call the same method on all current objects this.iterate = function(funcName) { var args = Array.prototype.slice.call(arguments,1); for(var i=0,len=this.objects.length;i<len;i++) { var obj = this.objects[i]; obj[funcName].apply(obj,args); } }; // Find the first object for which func is true this.detect = function(func) { for(var i = 0,val=null, len=this.objects.length; i < len; i++) { if(func.call(this.objects[i])) return this.objects[i]; } return false; }; // Call step on all objects and them delete // any object that have been marked for removal this.step = function(dt) { this.resetRemoved(); this.iterate('step',dt); this.finalizeRemoved(); }; // Draw all the objects this.draw= function(ctx) { this.iterate('draw',ctx); }; // Check for a collision between the // bounding rects of two objects this.overlap = function(o1,o2) { return !((o1.y+o1.h-1<o2.y) || (o1.y>o2.y+o2.h-1) || (o1.x+o1.w-1<o2.x) || (o1.x>o2.x+o2.w-1)); }; // Find the first object that collides with obj // match against an optional type this.collide = function(obj,type) { return this.detect(function() { if(obj != this) { var col = (!type || this.type & type) && board.overlap(obj,this); return col ? this : false; } }); }; }; var Sprite = function() { }; Sprite.prototype.setup = function(sprite,props) { this.sprite = sprite; this.merge(props); this.frame = this.frame || 0; this.w = SpriteSheet.map[sprite].w; this.h = SpriteSheet.map[sprite].h; }; Sprite.prototype.merge = function(props) { if(props) { for (var prop in props) { this[prop] = props[prop]; } } }; Sprite.prototype.draw = function(ctx) { SpriteSheet.draw(ctx,this.sprite,this.x,this.y,this.frame); }; Sprite.prototype.hit = function(damage) { this.board.remove(this); }; var Level = function(levelData,callback) { this.levelData = []; for(var i =0; i<levelData.length; i++) { this.levelData.push(Object.create(levelData[i])); } this.t = 0; this.callback = callback; }; Level.prototype.step = function(dt) { var idx = 0, remove = [], curShip = null; // Update the current time offset this.t += dt * 1000; // Start, End, Gap, Type, Override // [ 0, 4000, 500, 'step', { x: 100 } ] while((curShip = this.levelData[idx]) && (curShip[0] < this.t + 2000)) { // Check if we've passed the end time if(this.t > curShip[1]) { remove.push(curShip); } else if(curShip[0] < this.t) { // Get the enemy definition blueprint var enemy = enemies[curShip[3]], override = curShip[4]; // Add a new enemy with the blueprint and override this.board.add(new Enemy(enemy,override)); // Increment the start time by the gap curShip[0] += curShip[2]; } idx++; } // Remove any objects from the levelData that have passed for(var i=0,len=remove.length;i<len;i++) { var remIdx = this.levelData.indexOf(remove[i]); if(remIdx != -1) this.levelData.splice(remIdx,1); } // If there are no more enemies on the board or in // levelData, this level is done if(this.levelData.length === 0 && this.board.cnt[OBJECT_ENEMY] === 0) { if(this.callback) this.callback(); } }; Level.prototype.draw = function(ctx) { }; var TouchControls = function() { var gutterWidth = 10; var unitWidth = Game.width/5; var blockWidth = unitWidth-gutterWidth; this.drawSquare = function(ctx,x,y,txt,on) { ctx.globalAlpha = on ? 0.9 : 0.6; ctx.fillStyle = "#CCC"; ctx.fillRect(x,y,blockWidth,blockWidth); ctx.fillStyle = "#FFF"; ctx.globalAlpha = 1.0; ctx.font = "bold " + (3*unitWidth/4) + "px arial"; var txtSize = ctx.measureText(txt); ctx.fillText(txt, x+blockWidth/2-txtSize.width/2, y+3*blockWidth/4+5); }; this.draw = function(ctx) { ctx.save(); var yLoc = Game.height - unitWidth*2; this.drawSquare(ctx,gutterWidth + unitWidth*0.5, yLoc - unitWidth, "\u25B2", Game.keys['up']); this.drawSquare(ctx,gutterWidth + unitWidth*0.5, yLoc + unitWidth, "\u25BC", Game.keys['down']); this.drawSquare(ctx,gutterWidth,yLoc,"\u25C0", Game.keys['left']); this.drawSquare(ctx,unitWidth + gutterWidth,yLoc,"\u25B6", Game.keys['right']); this.drawSquare(ctx,4*unitWidth,yLoc+unitWidth,"A",Game.keys['fire']); ctx.restore(); }; this.step = function(dt) { }; this.trackTouch = function(e) { var touch, x, y; e.preventDefault(); Game.keys['left'] = false; Game.keys['right'] = false; Game.keys['up'] = false; Game.keys['down'] = false; for(var i=0;i<e.targetTouches.length;i++) { touch = e.targetTouches[i]; x = touch.pageX / Game.canvasMultiplier - Game.canvas.offsetLeft; y = Game.height - (touch.pageY / Game.canvasMultiplier - Game.canvas.offsetTop); if ( x < unitWidth*2 && y < unitWidth*3 ) { if ( y < unitWidth ) { Game.keys['down'] = true; } else if ( y > unitWidth* 2 ) { Game.keys['up'] = true; } else { if(x < unitWidth) { Game.keys['left'] = true; } if(x > unitWidth && x < 2*unitWidth) { Game.keys['right'] = true; } } } } if(e.type == 'touchstart' || e.type == 'touchend') { for(i=0;i<e.changedTouches.length;i++) { touch = e.changedTouches[i]; x = touch.pageX / Game.canvasMultiplier - Game.canvas.offsetLeft; if(x > 4 * unitWidth) { Game.keys['fire'] = (e.type == 'touchstart'); } } } }; Game.canvas.addEventListener('touchstart',this.trackTouch,true); Game.canvas.addEventListener('touchmove',this.trackTouch,true); Game.canvas.addEventListener('touchend',this.trackTouch,true); // For Android Game.canvas.addEventListener('dblclick',function(e) { e.preventDefault(); },true); Game.canvas.addEventListener('click',function(e) { e.preventDefault(); },true); Game.playerOffset = unitWidth + 20; }; var GamePoints = function() { Game.points = 0; var pointsLength = 7; this.draw = function(ctx) { ctx.save(); ctx.font = "bold 20px Courier"; ctx.fillStyle= "#33FF33"; var txt = "" + Game.points; var i = pointsLength - txt.length, zeros = ""; while(i-- > 0) { zeros += "0"; } ctx.fillText(zeros + txt,10,20); ctx.restore(); }; this.step = function(dt) { }; }; var GameLives = function(lives) { Game.lives = lives; this.draw = function(ctx) { ctx.save(); ctx.font = "bold 20px Courier"; ctx.fillStyle = "#33FF33"; var txt = "Lives: " + Game.lives; ctx.fillText(txt, 10, 40); ctx.restore(); }; this.step = function(dt) {}; }; var sprites = { ship: { sx: 0, sy: 0, w: 37, h: 42, frames: 1 }, missile: { sx: 0, sy: 30, w: 2, h: 10, frames: 1 }, enemy_purple: { sx: 37, sy: 0, w: 42, h: 43, frames: 1 }, enemy_bee: { sx: 79, sy: 0, w: 37, h: 43, frames: 1 }, enemy_ship: { sx: 116, sy: 0, w: 42, h: 43, frames: 1 }, enemy_circle: { sx: 158, sy: 0, w: 32, h: 33, frames: 1 }, explosion: { sx: 0, sy: 64, w: 64, h: 64, frames: 12 }, enemy_missile: { sx: 9, sy: 42, w: 3, h: 20, frame: 1, } }; var enemies = { straight: { x: 0, y: -50, sprite: 'enemy_ship', health: 10, E: 100 }, ltr: { x: 0, y: -100, sprite: 'enemy_purple', health: 10, B: 75, C: 1, E: 100, missiles: 1 }, circle: { x: 250, y: -50, sprite: 'enemy_circle', health: 10, A: 0, B: -100, C: 1, E: 20, F: 100, G: 1, H: Math.PI/2 }, wiggle: { x: 100, y: -50, sprite: 'enemy_bee', health: 20, B: 50, C: 4, E: 100, firePercentage: 0.001, missiles: 1 }, step: { x: 0, y: -50, sprite: 'enemy_circle', health: 10, B: 150, C: 1.2, E: 75 } //elipse: { x: 250, y: -50, sprite: 'enemy_circle', health: 10, // A: 0, B: -100, C: 1, E: 20, F: 100, G: 1, H: Math.PI/2 }, }; var OBJECT_PLAYER = 1, OBJECT_PLAYER_PROJECTILE = 2, OBJECT_ENEMY = 4, OBJECT_ENEMY_PROJECTILE = 8, OBJECT_POWERUP = 16; var startGame = function() { var ua = navigator.userAgent.toLowerCase(); // Only 1 row of stars if(ua.match(/android/)) { Game.setBoard(0,new Starfield(50,0.6,100,true)); } else { Game.setBoard(0,new Starfield(20,0.4,100,true)); Game.setBoard(1,new Starfield(50,0.6,100)); Game.setBoard(2,new Starfield(100,1.0,50)); } Game.setBoard(3,new TitleScreen("Space Battles", "Press space key to start playing", playGame)); }; var level1 = [ // Start, End, Gap, Type, Override //[ 0, 4000, 400, 'circle' ], //[ 0, 4000, 500, 'step' ], [ 0, 5000, 3800, 'ltr',{ x: 50 } ], [ 7000, 13000, 2800, 'ltr' ], [ 15000, 21000, 1800, 'ltr' ], [ 23000, 33000, 800, 'ltr' ], [ 35000, 43000, 500, 'ltr',{ x: 20 } ], //[ 7000, 9000, 400, 'wiggle', { x: 200 }], //[ 10000, 16000, 400, 'circle' ], // [ 17800, 20000, 500, 'straight', { x: 50 } ], //[ 18200, 20000, 1500, 'straight', { x: 90 } ], // [ 20200, 23000, 1500, 'straight', { x: 10 } ], //[ 22000, 25000, 400, 'wiggle', { x: 200 }], //[ 23000, 26000, 1400, 'wiggle', { x: 100 }], //[ 28800, 30000, 500, 'straight', { x: 50 } ], // [ 0, 2000, 500, 'straight', { x: 20 } ], // [ 0, 4000, 500, 'straight', { x: 50 } ], // [ 0, 6000, 500, 'straight', { x: 100 } ], // [ 0, 8000, 1500, 'straight', { x: 150 } ], // [ 0, 10000, 1500, 'straight', { x: 200 } ], // [ 0, 4000, 400, 'circle', { y: 200 } ], // [ 0, 5000, 600, 'elipse', { x: 300 } ], //[ 6000, 10000, 400, 'circle', { x: Math.floor(Math.random()) *10 } ], // [ 12000, 16000, 400, 'circle' ], //[ 12000, 16000, 400, 'circle' ], // [ 12000, 16000, 400, 'circle' ], // [ 18000, 21000, 500, 'step' ], // [ 10000, 16000, 400, 'circle' ], // [ 17800, 20000, 500, 'straight', { x: 50 } ], // [ 40200, 50000, 500, 'straight', { x: 190 } ], // [ 22000, 25000, 400, 'wiggle', { x: 150 }], // [ 22000, 25000, 400, 'wiggle', { x: 100 }] ]; var playGame = function() { var board = new GameBoard(); board.add(new PlayerShip()); board.add(new Level(level1,winGame)); Game.setBoard(3,board); Game.setBoard(5,new GamePoints(0)); Game.setBoard(6,new GameLives(3)); }; var winGame = function() { Game.setBoard(3,new TitleScreen("You win!", "Press space key to play again", playGame)); }; var loseGame = function() { Game.setBoard(3,new TitleScreen("You lose!", "Press space key to play again", playGame)); }; var Starfield = function(speed,opacity,numStars,clear) { // Set up the offscreen canvas var stars = document.createElement("canvas"); stars.width = Game.width; stars.height = Game.height; var starCtx = stars.getContext("2d"); var offset = 0; // If the clear option is set, // make the background black instead of transparent if(clear) { starCtx.fillStyle = "#000"; starCtx.fillRect(0,0,stars.width,stars.height); } // Now draw a bunch of random 2 pixel // rectangles onto the offscreen canvas starCtx.fillStyle = "#FFF"; starCtx.globalAlpha = opacity; for(var i=0;i<numStars;i++) { starCtx.fillRect(Math.floor(Math.random()*stars.width), Math.floor(Math.random()*stars.height), 2, 2); } // This method is called every frame // to draw the starfield onto the canvas this.draw = function(ctx) { var intOffset = Math.floor(offset); var remaining = stars.height - intOffset; // Draw the top half of the starfield if(intOffset > 0) { ctx.drawImage(stars, 0, remaining, stars.width, intOffset, 0, 0, stars.width, intOffset); } // Draw the bottom half of the starfield if(remaining > 0) { ctx.drawImage(stars, 0, 0, stars.width, remaining, 0, intOffset, stars.width, remaining); } }; // This method is called to update // the starfield this.step = function(dt) { offset += dt * speed; offset = offset % stars.height; }; }; var PlayerShip = function() { this.setup('ship', { vx: 0, reloadTime: 0.25, maxVel: 200 }); this.reload = this.reloadTime; this.x = Game.width/2 - this.w / 2; this.y = Game.height - Game.playerOffset - this.h; this.step = function(dt) { if(Game.keys['left']) { this.vx = -this.maxVel; } else if(Game.keys['right']) { this.vx = this.maxVel; } else { this.vx = 0; } if(Game.keys['up']) { this.vy = -this.maxVel; } else if(Game.keys['down']) { this.vy = this.maxVel; } else { this.vy = 0; } this.x += this.vx * dt; this.y += this.vy * dt; this.x = MathUtil.clamp(0, this.x, Game.width - this.w); this.y = MathUtil.clamp(0, this.y, Game.height - this.h); this.reload-=dt; if(Game.keys['fire'] && this.reload < 0) { this.reload = this.reloadTime; this.board.add(new PlayerMissile(this.x,this.y+this.h/2)); this.board.add(new PlayerMissile(this.x+this.w,this.y+this.h/2)); } }; }; PlayerShip.prototype = new Sprite(); PlayerShip.prototype.type = OBJECT_PLAYER; PlayerShip.prototype.hit = function(damage) { if ( --Game.lives <= 0 ) { Game.lives = 0; if(this.board.remove(this)) { this.board.add(new Explosion(this.x + this.w/2, this.y + this.h/2, loseGame)); } } }; var PlayerMissile = function(x,y) { this.setup('missile',{ vy: -700, damage: 10 }); this.x = x - this.w/2; this.y = y - this.h; }; PlayerMissile.prototype = new Sprite(); PlayerMissile.prototype.type = OBJECT_PLAYER_PROJECTILE; PlayerMissile.prototype.step = function(dt) { this.y += this.vy * dt; var collision = this.board.collide(this,OBJECT_ENEMY); if(collision) { collision.hit(this.damage); this.board.remove(this); } else if(this.y < -this.h) { this.board.remove(this); } }; var Enemy = function(blueprint,override) { this.merge(this.baseParameters); this.setup(blueprint.sprite,blueprint); this.merge(override); }; Enemy.prototype = new Sprite(); Enemy.prototype.type = OBJECT_ENEMY; Enemy.prototype.baseParameters = { xVelocity: 0, xAmplitude: 0, xFrequency: 0, xPhase: 0, yVelocity: 0, yAmplitude: 0, yFrequency: 0, yPhase: 0, t: 0, reloadTime: 0.75, reload: 0 }; Enemy.prototype.step = function(dt) { this.t += dt; var halfWidth = (Game.width + this.w) * 0.5; var halfHeight = (Game.height + this.h) * 0.5; this.vx = this.xVelocity + (this.xAmplitude * halfWidth) * Math.sin(this.xFrequency * this.t + this.xPhase); this.vy = this.yVelocity + (this.yAmplitude * halfHeight) * Math.sin(this.yFrequency * this.t + this.yPhase); this.x += this.vx * dt; this.y += this.vy * dt; var collision = this.board.collide(this,OBJECT_PLAYER); if(collision) { collision.hit(this.damage); this.board.remove(this); } if(Math.random() < 0.01 && this.reload <= 0) { this.reload = this.reloadTime; if(this.missiles == 2) { this.board.add(new EnemyMissile(this.x+this.w-2,this.y+this.h)); this.board.add(new EnemyMissile(this.x+2,this.y+this.h)); } else { this.board.add(new EnemyMissile(this.x+this.w/2,this.y+this.h)); } } this.reload-=dt; if(this.y > Game.height || this.x < -this.w || this.x > Game.width) { this.board.remove(this); } }; Enemy.prototype.hit = function(damage) { this.health -= damage; if(this.health <=0) { if(this.board.remove(this)) { Game.points += this.points || 100; this.board.add(new Explosion(this.x + this.w/2, this.y + this.h/2)); } } }; var EnemyMissile = function(x,y) { this.setup('enemy_missile',{ vy: 200, damage: 10 }); this.x = x - this.w/2; this.y = y; }; EnemyMissile.prototype = new Sprite(); EnemyMissile.prototype.type = OBJECT_ENEMY_PROJECTILE; EnemyMissile.prototype.step = function(dt) { this.y += this.vy * dt; var collision = this.board.collide(this,OBJECT_PLAYER) if(collision) { collision.hit(this.damage); this.board.remove(this); } else if(this.y > Game.height) { this.board.remove(this); } }; var Explosion = function(centerX,centerY, fn) { this.setup('explosion', { frame: 0 }); this.x = centerX - this.w/2; this.y = centerY - this.h/2; this.fn = fn; }; Explosion.prototype = new Sprite(); Explosion.prototype.step = function(dt) { this.frame++; if(this.frame >= 12) { this.board.remove(this); if ( this.fn != undefined ) { this.fn(this); } } }; window.addEventListener("load", function() { Game.initialize("game",sprites,startGame); }); <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title> Space Battles </title> <meta content="width=device-width, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0" name="viewport" > <meta content="yes" name="apple-mobile-web-app-capable" > <meta content="black" name="apple-mobile-web-app-status-bar-style" > </head> <body> <div id="container"> <canvas id="game" height="480" width="320"> </canvas> </div> </body> </html> forked: Space Battles /* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 License: none (public domain) */ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; } /* HTML5 display-role reset for older browsers */ article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; } body { line-height: 1; } ol, ul { list-style: none; } blockquote, q { quotes: none; } blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; } table { border-collapse: collapse; border-spacing: 0; } #container { padding-top:50px; margin:0 auto; width:480px; } canvas { background-color:black; } // forked from rolandas_kairys's "forked: Space Battles " http://jsdo.it/rolandas_kairys/cGkM ////// forked from rolandas_kairys's "Space Battles " http://jsdo.it/rolandas_kairys/dNmW function MathUtil() {} MathUtil.clamp = function(a, v, b) { return Math.min(Math.max(a, v), b); } (function() { var lastTime = 0; var vendors = ['ms', 'moz', 'webkit', 'o']; for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame']; } if (!window.requestAnimationFrame) window.requestAnimationFrame = function(callback, element) { var currTime = new Date().getTime(); var timeToCall = Math.max(0, 16 - (currTime - lastTime)); var id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall); lastTime = currTime + timeToCall; return id; }; if (!window.cancelAnimationFrame) window.cancelAnimationFrame = function(id) { clearTimeout(id); }; }()); var Game = new function() { var boards = []; // Game Initialization this.initialize = function(canvasElementId,sprite_data,callback) { this.canvas = document.getElementById(canvasElementId); this.playerOffset = 10; this.canvasMultiplier= 1; this.setupMobile(); this.width = this.canvas.width; this.height= this.canvas.height; this.ctx = this.canvas.getContext && this.canvas.getContext('2d'); if(!this.ctx) { return alert("Please upgrade your browser to play"); } this.setupInput(); this.loop(); if(this.mobile) { this.setBoard(4,new TouchControls()); } SpriteSheet.load(sprite_data,callback); }; // Handle Input var KEY_CODES = { 37:'left', 38:'up', 39:'right', 40:'down', 32 :'fire' }; this.keys = {}; this.setupInput = function() { window.addEventListener('keydown',function(e) { var event = e || event || window.event; if(KEY_CODES[event.keyCode]) { Game.keys[KEY_CODES[event.keyCode]] = true; e.preventDefault(); } },false); window.addEventListener('keyup',function(e) { var event = e || event || window.event; if(KEY_CODES[event.keyCode]) { Game.keys[KEY_CODES[event.keyCode]] = false; e.preventDefault(); } },false); }; var lastTime = new Date().getTime(); var maxTime = 1/30; // Game Loop this.loop = function() { var curTime = new Date().getTime(); requestAnimationFrame(Game.loop); var dt = (curTime - lastTime)/1000; if(dt > maxTime) { dt = maxTime; } for(var i=0,len = boards.length;i<len;i++) { if(boards[i]) { boards[i].step(dt); boards[i].draw(Game.ctx); } } lastTime = curTime; }; // Change an active game board this.setBoard = function(num,board) { boards[num] = board; }; this.setupMobile = function() { var container = document.getElementById("container"), hasTouch = !!('ontouchstart' in window), w = window.innerWidth, h = window.innerHeight; if(hasTouch) { this.mobile = true; } if(screen.width >= 1280 || !hasTouch) { return false; } if(w > h) { alert("Please rotate the device and then click OK"); w = window.innerWidth; h = window.innerHeight; } container.style.height = h*2 + "px"; window.scrollTo(0,1); h = window.innerHeight + 2; container.style.height = h + "px"; container.style.width = w + "px"; container.style.padding = 0; if(h >= this.canvas.height * 1.75 || w >= this.canvas.height * 1.75) { this.canvasMultiplier = 2; this.canvas.width = w / 2; this.canvas.height = h / 2; this.canvas.style.width = w + "px"; this.canvas.style.height = h + "px"; } else { this.canvas.width = w; this.canvas.height = h; } this.canvas.style.position='absolute'; this.canvas.style.left="0px"; this.canvas.style.top="0px"; }; }; var SpriteSheet = new function() { this.map = { }; this.load = function(spriteData,callback) { this.map = spriteData; this.image = new Image(); this.image.onload = callback; this.image.src = 'http://jsrun.it/assets/k/V/e/v/kVevG.png'; }; this.draw = function(ctx,sprite,x,y,frame) { var s = this.map[sprite]; if(!frame) frame = 0; ctx.drawImage(this.image, s.sx + frame * s.w, s.sy, s.w, s.h, Math.floor(x), Math.floor(y), s.w, s.h); }; return this; }; var TitleScreen = function TitleScreen(title,subtitle,callback) { var up = false; this.step = function(dt) { if(!Game.keys['fire']) up = true; if(up && Game.keys['fire'] && callback) callback(); }; this.draw = function(ctx) { ctx.fillStyle = "#FFFF00"; ctx.font = "bold 37px Courier"; var measure = ctx.measureText(title); ctx.fillText(title,Game.width/2 - measure.width/2,Game.height/2); ctx.font = "bold 15px Courier"; var measure2 = ctx.measureText(subtitle); ctx.fillText(subtitle,Game.width/2 - measure2.width/2,Game.height/2 + 40); }; }; var GameBoard = function() { var board = this; // The current list of objects this.objects = []; this.cnt = {}; // Add a new object to the object list this.add = function(obj) { obj.board=this; this.objects.push(obj); this.cnt[obj.type] = (this.cnt[obj.type] || 0) + 1; return obj; }; // Mark an object for removal this.remove = function(obj) { var idx = this.removed.indexOf(obj); if(idx == -1) { this.removed.push(obj); return true; } else { return false; } }; // Reset the list of removed objects this.resetRemoved = function() { this.removed = []; }; // Removed an objects marked for removal from the list this.finalizeRemoved = function() { for(var i=0,len=this.removed.length;i<len;i++) { var idx = this.objects.indexOf(this.removed[i]); if(idx != -1) { this.cnt[this.removed[i].type]--; this.objects.splice(idx,1); } } }; // Call the same method on all current objects this.iterate = function(funcName) { var args = Array.prototype.slice.call(arguments,1); for(var i=0,len=this.objects.length;i<len;i++) { var obj = this.objects[i]; obj[funcName].apply(obj,args); } }; // Find the first object for which func is true this.detect = function(func) { for(var i = 0,val=null, len=this.objects.length; i < len; i++) { if(func.call(this.objects[i])) return this.objects[i]; } return false; }; // Call step on all objects and them delete // any object that have been marked for removal this.step = function(dt) { this.resetRemoved(); this.iterate('step',dt); this.finalizeRemoved(); }; // Draw all the objects this.draw= function(ctx) { this.iterate('draw',ctx); }; // Check for a collision between the // bounding rects of two objects this.overlap = function(o1,o2) { return !((o1.y+o1.h-1<o2.y) || (o1.y>o2.y+o2.h-1) || (o1.x+o1.w-1<o2.x) || (o1.x>o2.x+o2.w-1)); }; // Find the first object that collides with obj // match against an optional type this.collide = function(obj,type) { return this.detect(function() { if(obj != this) { var col = (!type || this.type & type) && board.overlap(obj,this); return col ? this : false; } }); }; }; var Sprite = function() { }; Sprite.prototype.setup = function(sprite,props) { this.sprite = sprite; this.merge(props); this.frame = this.frame || 0; this.w = SpriteSheet.map[sprite].w; this.h = SpriteSheet.map[sprite].h; }; Sprite.prototype.merge = function(props) { if(props) { for (var prop in props) { this[prop] = props[prop]; } } }; Sprite.prototype.draw = function(ctx) { SpriteSheet.draw(ctx,this.sprite,this.x,this.y,this.frame); }; Sprite.prototype.hit = function(damage) { this.board.remove(this); }; var Level = function(levelData,callback) { this.levelData = []; for(var i =0; i<levelData.length; i++) { this.levelData.push(Object.create(levelData[i])); } this.t = 0; this.callback = callback; }; Level.prototype.step = function(dt) { var idx = 0, remove = [], curShip = null; // Update the current time offset this.t += dt * 1000; // Start, End, Gap, Type, Override // [ 0, 4000, 500, 'step', { x: 100 } ] while((curShip = this.levelData[idx]) && (curShip[0] < this.t + 2000)) { // Check if we've passed the end time if(this.t > curShip[1]) { remove.push(curShip); } else if(curShip[0] < this.t) { // Get the enemy definition blueprint var enemy = enemies[curShip[3]], override = curShip[4]; // Add a new enemy with the blueprint and override this.board.add(new Enemy(enemy,override)); // Increment the start time by the gap curShip[0] += curShip[2]; } idx++; } // Remove any objects from the levelData that have passed for(var i=0,len=remove.length;i<len;i++) { var remIdx = this.levelData.indexOf(remove[i]); if(remIdx != -1) this.levelData.splice(remIdx,1); } // If there are no more enemies on the board or in // levelData, this level is done if(this.levelData.length === 0 && this.board.cnt[OBJECT_ENEMY] === 0) { if(this.callback) this.callback(); } }; Level.prototype.draw = function(ctx) { }; var TouchControls = function() { var gutterWidth = 10; var unitWidth = Game.width/5; var blockWidth = unitWidth-gutterWidth; this.drawSquare = function(ctx,x,y,txt,on) { ctx.globalAlpha = on ? 0.9 : 0.6; ctx.fillStyle = "#CCC"; ctx.fillRect(x,y,blockWidth,blockWidth); ctx.fillStyle = "#FFF"; ctx.globalAlpha = 1.0; ctx.font = "bold " + (3*unitWidth/4) + "px arial"; var txtSize = ctx.measureText(txt); ctx.fillText(txt, x+blockWidth/2-txtSize.width/2, y+3*blockWidth/4+5); }; this.draw = function(ctx) { ctx.save(); var yLoc = Game.height - unitWidth*2; this.drawSquare(ctx,gutterWidth + unitWidth*0.5, yLoc - unitWidth, "\u25B2", Game.keys['up']); this.drawSquare(ctx,gutterWidth + unitWidth*0.5, yLoc + unitWidth, "\u25BC", Game.keys['down']); this.drawSquare(ctx,gutterWidth,yLoc,"\u25C0", Game.keys['left']); this.drawSquare(ctx,unitWidth + gutterWidth,yLoc,"\u25B6", Game.keys['right']); this.drawSquare(ctx,4*unitWidth,yLoc+unitWidth,"A",Game.keys['fire']); ctx.restore(); }; this.step = function(dt) { }; this.trackTouch = function(e) { var touch, x, y; e.preventDefault(); Game.keys['left'] = false; Game.keys['right'] = false; Game.keys['up'] = false; Game.keys['down'] = false; for(var i=0;i<e.targetTouches.length;i++) { touch = e.targetTouches[i]; x = touch.pageX / Game.canvasMultiplier - Game.canvas.offsetLeft; y = Game.height - (touch.pageY / Game.canvasMultiplier - Game.canvas.offsetTop); if ( x < unitWidth*2 && y < unitWidth*3 ) { if ( y < unitWidth ) { Game.keys['down'] = true; } else if ( y > unitWidth* 2 ) { Game.keys['up'] = true; } else { if(x < unitWidth) { Game.keys['left'] = true; } if(x > unitWidth && x < 2*unitWidth) { Game.keys['right'] = true; } } } } if(e.type == 'touchstart' || e.type == 'touchend') { for(i=0;i<e.changedTouches.length;i++) { touch = e.changedTouches[i]; x = touch.pageX / Game.canvasMultiplier - Game.canvas.offsetLeft; if(x > 4 * unitWidth) { Game.keys['fire'] = (e.type == 'touchstart'); } } } }; Game.canvas.addEventListener('touchstart',this.trackTouch,true); Game.canvas.addEventListener('touchmove',this.trackTouch,true); Game.canvas.addEventListener('touchend',this.trackTouch,true); // For Android Game.canvas.addEventListener('dblclick',function(e) { e.preventDefault(); },true); Game.canvas.addEventListener('click',function(e) { e.preventDefault(); },true); Game.playerOffset = unitWidth + 20; }; var GamePoints = function() { Game.points = 0; var pointsLength = 7; this.draw = function(ctx) { ctx.save(); ctx.font = "bold 20px Courier"; ctx.fillStyle= "#33FF33"; var txt = "" + Game.points; var i = pointsLength - txt.length, zeros = ""; while(i-- > 0) { zeros += "0"; } ctx.fillText(zeros + txt,10,20); ctx.restore(); }; this.step = function(dt) { }; }; var GameLives = function(lives) { Game.lives = lives; this.draw = function(ctx) { ctx.save(); ctx.font = "bold 20px Courier"; ctx.fillStyle = "#33FF33"; var txt = "Lives: " + Game.lives; ctx.fillText(txt, 10, 40); ctx.restore(); }; this.step = function(dt) {}; }; var sprites = { ship: { sx: 0, sy: 0, w: 37, h: 42, frames: 1 }, missile: { sx: 0, sy: 30, w: 2, h: 10, frames: 1 }, enemy_purple: { sx: 37, sy: 0, w: 42, h: 43, frames: 1 }, enemy_bee: { sx: 79, sy: 0, w: 37, h: 43, frames: 1 }, enemy_ship: { sx: 116, sy: 0, w: 42, h: 43, frames: 1 }, enemy_circle: { sx: 158, sy: 0, w: 32, h: 33, frames: 1 }, explosion: { sx: 0, sy: 64, w: 64, h: 64, frames: 12 }, enemy_missile: { sx: 9, sy: 42, w: 3, h: 20, frame: 1, } }; var enemies = { straight: { x: 0, y: -50, sprite: 'enemy_ship', health: 10, E: 100 }, ltr: { x: 0, y: -100, sprite: 'enemy_purple', health: 10, B: 75, C: 1, E: 100, missiles: 1 }, circle: { x: 250, y: -50, sprite: 'enemy_circle', health: 10, A: 0, B: -100, C: 1, E: 20, F: 100, G: 1, H: Math.PI/2 }, wiggle: { x: 100, y: -50, sprite: 'enemy_bee', health: 20, B: 50, C: 4, E: 100, firePercentage: 0.001, missiles: 1 }, step: { x: 0, y: -50, sprite: 'enemy_circle', health: 10, B: 150, C: 1.2, E: 75 } //elipse: { x: 250, y: -50, sprite: 'enemy_circle', health: 10, // A: 0, B: -100, C: 1, E: 20, F: 100, G: 1, H: Math.PI/2 }, }; var OBJECT_PLAYER = 1, OBJECT_PLAYER_PROJECTILE = 2, OBJECT_ENEMY = 4, OBJECT_ENEMY_PROJECTILE = 8, OBJECT_POWERUP = 16; var startGame = function() { var ua = navigator.userAgent.toLowerCase(); // Only 1 row of stars if(ua.match(/android/)) { Game.setBoard(0,new Starfield(50,0.6,100,true)); } else { Game.setBoard(0,new Starfield(20,0.4,100,true)); Game.setBoard(1,new Starfield(50,0.6,100)); Game.setBoard(2,new Starfield(100,1.0,50)); } Game.setBoard(3,new TitleScreen("Space Battles", "Press space key to start playing", playGame)); }; var level1 = [ // Start, End, Gap, Type, Override //[ 0, 4000, 400, 'circle' ], //[ 0, 4000, 500, 'step' ], [ 0, 5000, 3800, 'ltr',{ x: 50 } ], [ 7000, 13000, 2800, 'ltr' ], [ 15000, 21000, 1800, 'ltr' ], [ 23000, 33000, 800, 'ltr' ], [ 35000, 43000, 500, 'ltr',{ x: 20 } ], //[ 7000, 9000, 400, 'wiggle', { x: 200 }], //[ 10000, 16000, 400, 'circle' ], // [ 17800, 20000, 500, 'straight', { x: 50 } ], //[ 18200, 20000, 1500, 'straight', { x: 90 } ], // [ 20200, 23000, 1500, 'straight', { x: 10 } ], //[ 22000, 25000, 400, 'wiggle', { x: 200 }], //[ 23000, 26000, 1400, 'wiggle', { x: 100 }], //[ 28800, 30000, 500, 'straight', { x: 50 } ], // [ 0, 2000, 500, 'straight', { x: 20 } ], // [ 0, 4000, 500, 'straight', { x: 50 } ], // [ 0, 6000, 500, 'straight', { x: 100 } ], // [ 0, 8000, 1500, 'straight', { x: 150 } ], // [ 0, 10000, 1500, 'straight', { x: 200 } ], // [ 0, 4000, 400, 'circle', { y: 200 } ], // [ 0, 5000, 600, 'elipse', { x: 300 } ], //[ 6000, 10000, 400, 'circle', { x: Math.floor(Math.random()) *10 } ], // [ 12000, 16000, 400, 'circle' ], //[ 12000, 16000, 400, 'circle' ], // [ 12000, 16000, 400, 'circle' ], // [ 18000, 21000, 500, 'step' ], // [ 10000, 16000, 400, 'circle' ], // [ 17800, 20000, 500, 'straight', { x: 50 } ], // [ 40200, 50000, 500, 'straight', { x: 190 } ], // [ 22000, 25000, 400, 'wiggle', { x: 150 }], // [ 22000, 25000, 400, 'wiggle', { x: 100 }] ]; var playGame = function() { var board = new GameBoard(); board.add(new PlayerShip()); board.add(new Level(level1,winGame)); Game.setBoard(3,board); Game.setBoard(5,new GamePoints(0)); Game.setBoard(6,new GameLives(3)); }; var winGame = function() { Game.setBoard(3,new TitleScreen("You win!", "Press space key to play again", playGame)); }; var loseGame = function() { Game.setBoard(3,new TitleScreen("You lose!", "Press space key to play again", playGame)); }; var Starfield = function(speed,opacity,numStars,clear) { // Set up the offscreen canvas var stars = document.createElement("canvas"); stars.width = Game.width; stars.height = Game.height; var starCtx = stars.getContext("2d"); var offset = 0; // If the clear option is set, // make the background black instead of transparent if(clear) { starCtx.fillStyle = "#000"; starCtx.fillRect(0,0,stars.width,stars.height); } // Now draw a bunch of random 2 pixel // rectangles onto the offscreen canvas starCtx.fillStyle = "#FFF"; starCtx.globalAlpha = opacity; for(var i=0;i<numStars;i++) { starCtx.fillRect(Math.floor(Math.random()*stars.width), Math.floor(Math.random()*stars.height), 2, 2); } // This method is called every frame // to draw the starfield onto the canvas this.draw = function(ctx) { var intOffset = Math.floor(offset); var remaining = stars.height - intOffset; // Draw the top half of the starfield if(intOffset > 0) { ctx.drawImage(stars, 0, remaining, stars.width, intOffset, 0, 0, stars.width, intOffset); } // Draw the bottom half of the starfield if(remaining > 0) { ctx.drawImage(stars, 0, 0, stars.width, remaining, 0, intOffset, stars.width, remaining); } }; // This method is called to update // the starfield this.step = function(dt) { offset += dt * speed; offset = offset % stars.height; }; }; var PlayerShip = function() { this.setup('ship', { vx: 0, reloadTime: 0.25, maxVel: 200 }); this.reload = this.reloadTime; this.x = Game.width/2 - this.w / 2; this.y = Game.height - Game.playerOffset - this.h; this.step = function(dt) { if(Game.keys['left']) { this.vx = -this.maxVel; } else if(Game.keys['right']) { this.vx = this.maxVel; } else { this.vx = 0; } if(Game.keys['up']) { this.vy = -this.maxVel; } else if(Game.keys['down']) { this.vy = this.maxVel; } else { this.vy = 0; } this.x += this.vx * dt; this.y += this.vy * dt; this.x = MathUtil.clamp(0, this.x, Game.width - this.w); this.y = MathUtil.clamp(0, this.y, Game.height - this.h); this.reload-=dt; if(Game.keys['fire'] && this.reload < 0) { this.reload = this.reloadTime; this.board.add(new PlayerMissile(this.x,this.y+this.h/2)); this.board.add(new PlayerMissile(this.x+this.w,this.y+this.h/2)); } }; }; PlayerShip.prototype = new Sprite(); PlayerShip.prototype.type = OBJECT_PLAYER; PlayerShip.prototype.hit = function(damage) { if ( --Game.lives <= 0 ) { Game.lives = 0; if(this.board.remove(this)) { this.board.add(new Explosion(this.x + this.w/2, this.y + this.h/2, loseGame)); } } }; var PlayerMissile = function(x,y) { this.setup('missile',{ vy: -700, damage: 10 }); this.x = x - this.w/2; this.y = y - this.h; }; PlayerMissile.prototype = new Sprite(); PlayerMissile.prototype.type = OBJECT_PLAYER_PROJECTILE; PlayerMissile.prototype.step = function(dt) { this.y += this.vy * dt; var collision = this.board.collide(this,OBJECT_ENEMY); if(collision) { collision.hit(this.damage); this.board.remove(this); } else if(this.y < -this.h) { this.board.remove(this); } }; var Enemy = function(blueprint,override) { this.merge(this.baseParameters); this.setup(blueprint.sprite,blueprint); this.merge(override); }; Enemy.prototype = new Sprite(); Enemy.prototype.type = OBJECT_ENEMY; Enemy.prototype.baseParameters = { xVelocity: 0, xAmplitude: 0, xFrequency: 0, xPhase: 0, yVelocity: 0, yAmplitude: 0, yFrequency: 0, yPhase: 0, t: 0, reloadTime: 0.75, reload: 0 }; Enemy.prototype.step = function(dt) { this.t += dt; var halfWidth = (Game.width + this.w) * 0.5; var halfHeight = (Game.height + this.h) * 0.5; this.vx = this.xVelocity + (this.xAmplitude * halfWidth) * Math.sin(this.xFrequency * this.t + this.xPhase); this.vy = this.yVelocity + (this.yAmplitude * halfHeight) * Math.sin(this.yFrequency * this.t + this.yPhase); this.x += this.vx * dt; this.y += this.vy * dt; var collision = this.board.collide(this,OBJECT_PLAYER); if(collision) { collision.hit(this.damage); this.board.remove(this); } if(Math.random() < 0.01 && this.reload <= 0) { this.reload = this.reloadTime; if(this.missiles == 2) { this.board.add(new EnemyMissile(this.x+this.w-2,this.y+this.h)); this.board.add(new EnemyMissile(this.x+2,this.y+this.h)); } else { this.board.add(new EnemyMissile(this.x+this.w/2,this.y+this.h)); } } this.reload-=dt; if(this.y > Game.height || this.x < -this.w || this.x > Game.width) { this.board.remove(this); } }; Enemy.prototype.hit = function(damage) { this.health -= damage; if(this.health <=0) { if(this.board.remove(this)) { Game.points += this.points || 100; this.board.add(new Explosion(this.x + this.w/2, this.y + this.h/2)); } } }; var EnemyMissile = function(x,y) { this.setup('enemy_missile',{ vy: 200, damage: 10 }); this.x = x - this.w/2; this.y = y; }; EnemyMissile.prototype = new Sprite(); EnemyMissile.prototype.type = OBJECT_ENEMY_PROJECTILE; EnemyMissile.prototype.step = function(dt) { this.y += this.vy * dt; var collision = this.board.collide(this,OBJECT_PLAYER) if(collision) { collision.hit(this.damage); this.board.remove(this); } else if(this.y > Game.height) { this.board.remove(this); } }; var Explosion = function(centerX,centerY, fn) { this.setup('explosion', { frame: 0 }); this.x = centerX - this.w/2; this.y = centerY - this.h/2; this.fn = fn; }; Explosion.prototype = new Sprite(); Explosion.prototype.step = function(dt) { this.frame++; if(this.frame >= 12) { this.board.remove(this); if ( this.fn != undefined ) { this.fn(this); } } }; window.addEventListener("load", function() { Game.initialize("game",sprites,startGame); }); <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title> Space Battles </title> <meta content="width=device-width, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0" name="viewport" > <meta content="yes" name="apple-mobile-web-app-capable" > <meta content="black" name="apple-mobile-web-app-status-bar-style" > </head> <body> <div id="container"> <canvas id="game" height="480" width="320"> </canvas> </div> </body> </html> /* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 License: none (public domain) */ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; } /* HTML5 display-role reset for older browsers */ article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; } body { line-height: 1; } ol, ul { list-style: none; } blockquote, q { quotes: none; } blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; } table { border-collapse: collapse; border-spacing: 0; } #container { padding-top:50px; margin:0 auto; width:480px; } canvas { background-color:black; } use an iframe compat browser, deer Play on jsdo.it games Author Share ブログに埋め込む QR Tag Download Complete! Description What kind of game? Control Device Smartphone Controllerjsdo.it WebSocket Controller» Mouse Keyboard Touch Device Fullscreen Activated Inactivated jsdo.it games から削除する Submit Author rolandas_kairys Tweet Default Panel Auto play Screenshot Readme JavaScript HTML CSS Size Width: px Height: px code <script type="text/javascript" src="http://jsdo.it/blogparts/eKgm/js"></script> application game game, javascript, mobile Discussion Questions on this code? Tags application game game, javascript, mobile Forked sort by latest page views favorite forked forked: Space Battles teetteet 00 1051 880/29/61 application game game, javascript, mobile