Enemy Squadron JavaScript CSS Game Development Demo

Published :
Author :
Adam Khoury
Learn some animation and control techniques in the DOM for creating browser-based games. The primary techniques of the example are randomized enemy flight patterns, keeping things in bounds, increasing difficulty, enemy collision for shield depletion when hit, and simple character control. <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Enemy Squadron by Adam Khoury</title> <meta name="author" content="Adam Khoury"> <style> body{margin:0px; overflow-x:hidden; background:#000; font-family:Arial, Helvetica, sans-serif; font-size:17px;} div#gamewindow{ height:500px; background:#000; border-bottom:#666 1px solid; min-width:1000px; max-width:2000px; overflow:hidden; } div#gamewindow > #game_bg{ background: url(graphics/space_BG.jpg) repeat; width: 3000px; height: 500px; position: relative; top: 0px; right: 0px; animation: game_bg_roll linear 1.5s infinite; } @keyframes game_bg_roll { 100% { right: 50px; } } div#gamewindow > div#rocket{ position:absolute; background:url(graphics/rocket.png); width:144px; height:76px; overflow:hidden; top:200px; left:0px; } div.enemy{ position:absolute; background: url(graphics/enemy_red.png); width:100px; height:50px; overflow:hidden; top:200px; right:-102px; } .efp1{ animation: efp_1 linear 5s 1; } .efp2{ animation: efp_2 linear 5s 1; } .efp3{ animation: efp_3 linear 5s 1; } .efp4{ animation: efp_4 linear 5s 1; } .efp5{ animation: efp_5 linear 5s 1; } .efp6{ animation: efp_6 linear 5s 1; } .efp7{ animation: efp_7 linear 5s 1; } .efp8{ animation: efp_8 linear 5s 1; } .efp9{ animation: efp_9 linear 5s 1; } .efp10{ animation: efp_10 linear 5s 1; } @keyframes efp_1 { 0% { right: 0%; top:50px; } 50% { right: 50%; top:50px; } 100% { right: 100%; top:50px; } } @keyframes efp_2 { 0% { right: 0%; top:150px; } 50% { right: 50%; top:150px; } 100% { right: 100%; top:150px; } } @keyframes efp_3 { 0% { right: 0%; top:250px; } 50% { right: 50%; top:250px; } 100% { right: 100%; top:250px; } } @keyframes efp_4 { 0% { right: 0%; top:350px; } 50% { right: 50%; top:350px; } 100% { right: 100%; top:350px; } } @keyframes efp_5 { 0% { right: 0%; top:450px; } 50% { right: 50%; top:450px; } 100% { right: 100%; top:450px; } } @keyframes efp_6 { 0% { right: 0%; top:450px; } 20% { right: 20%; top:200px; } 100% { right: 100%; top:50px; } } @keyframes efp_7 { 0% { right: 0%; top:50px; } 50% { right: 50%; top:50px; } 100% { right: 100%; top:450px; } } @keyframes efp_8 { 0% { right: 0%; top:250px; } 25% { right: 25%; top:50px; } 50% { right: 50%; top:450px; } 75% { right: 75%; top:50px; } 100% { right: 100%; top:450px; } } @keyframes efp_9 { 0% { right: 0%; top:300px; } 10% { right: 10%; top:50px; } 30% { right: 30%; top:450px; } 50% { right: 50%; top:200px; } 80% { right: 80%; top:450px; } 100% { right: 100%; top:50px; } } @keyframes efp_10 { 0% { right: 0%; top:450px; } 10% { right: 10%; top:400px; } 20% { right: 20%; top:200px; } 30% { right: 30%; top:400px; } 40% { right: 40%; top:200px; } 50% { right: 50%; top:400px; } 60% { right: 60%; top:200px; } 70% { right: 70%; top:50px; } 80% { right: 80%; top:200px; } 90% { right: 90%; top:400px; } 100% { right: 100%; top:450px; } } div#gameconsole{ position:absolute; top:20px; left:0px; color:#999; font-weight:bold; padding-left:20px; opacity:0.7; display:none; } div#gameconsole > #stopwatch{font-family:"Courier New", Courier, monospace; color:#FFF;} div#gameconsole > #health_meter_mc{float:left; width:300px; height:16px; border: #86A800 1px solid;} div#gameconsole > #health_meter_mc > #healthmeter{width:300px; height:16px; background: #01f9df; color:#000; font-size:12px;} div#newgamewindow{ position:fixed; top:40px; left:40px; width:550px; height:340px; background:#000; display:none; border:#666 1px solid; border-radius:5px; opacity:0.6; color:#FFF; padding:36px; line-height:1.7em; } div#newgamewindow > button{ font-size:24px; padding:12px; } div#endgamewindow{ position:fixed; top:40px; left:40px; width:550px; height:340px; background:#000; display:none; border:#666 1px solid; border-radius:5px; opacity:0.6; color:#FFF; padding:36px; line-height:1.7em; } div#gameloadwindow{ position:fixed; top:100px; left:40px; width:320px; height:120px; background:#000; display:block; border:#666 1px solid; border-radius:5px; color:#FFF; padding:36px; } /* NORMAL ELEMENT STYLING */ div#bottom{ color:#CCC; } div#bottom > #keyinstructions{padding-right:36px;} div#bottom > #keyinstructions > b{ padding:4px 6px; margin-left:24px; border:#999 1px solid; background:#333; border-radius:4px; } </style> <script> // Run user-agent checks here for outdated browser users and give them a message let rocket_health = 1000; let d_pressed = false; let a_pressed = false; let w_pressed = false; let s_pressed = false; let game_stopped = false; document.onkeydown = function(event) { let kc = event.keyCode; if(kc == 68){ // D d_pressed = true; if(w_pressed == true){rocketNorthEast();} else if(s_pressed == true){rocketSouthEast();} else {rocketEast();} } else if(kc == 65){ // A a_pressed = true; if(s_pressed == true){rocketSouthWest();} else if(w_pressed == true){rocketNorthWest();} else {rocketWest();} } else if(kc == 87){ // W w_pressed = true; if(a_pressed == true){rocketNorthWest();} else if(d_pressed == true){rocketNorthEast();} else {rocketNorth();} } else if(kc == 83){ // S s_pressed = true; if(a_pressed == true){rocketSouthWest();} else if(d_pressed == true){rocketSouthEast();} else {rocketSouth();} } } document.onkeyup = function(event){ let kc = event.keyCode; if(kc == 68){ // D d_pressed = false; if(w_pressed == true){rocketNorth();} else if(s_pressed == true){rocketSouth();} else if(a_pressed == true){rocketWest();} } else if(kc == 65){ // A a_pressed = false; if(w_pressed == true){rocketNorth();} else if(s_pressed == true){rocketSouth();} else if(d_pressed == true){rocketEast();} } else if(kc == 87){ // W w_pressed = false; if(a_pressed == true){rocketWest();} else if(d_pressed == true){rocketEast();} else if(s_pressed == true){rocketSouth();} } else if(kc == 83){ // S s_pressed = false; if(a_pressed == true){rocketWest();} else if(d_pressed == true){rocketEast();} else if(w_pressed == true){rocketNorth();} } if(d_pressed == false && a_pressed == false && w_pressed == false && s_pressed == false){ rocketStop(); } } function rocketEast() { rocket.style.top = rocket.offsetTop+"px"; rocket.style.transition = "left 2s linear 0s"; rocket.style.left = window.innerWidth-rocket.offsetWidth+"px"; } function rocketWest() { rocket.style.top = rocket.offsetTop+"px"; rocket.style.transition = "left 2s linear 0s"; rocket.style.left = "0px"; } function rocketNorth() { rocket.style.left = rocket.offsetLeft+"px"; rocket.style.transition = "top 1s linear 0s"; rocket.style.top = "0px"; } function rocketSouth() { rocket.style.left = rocket.offsetLeft+"px"; rocket.style.transition = "top 1s linear 0s"; rocket.style.top = "420px"; } function rocketNorthEast() { rocket.style.transition = "left 2s linear 0s, top 1s linear 0s"; rocket.style.left = window.innerWidth-rocket.offsetWidth+"px"; rocket.style.top = "0px"; } function rocketSouthEast() { rocket.style.transition = "left 2s linear 0s, top 1s linear 0s"; rocket.style.left = window.innerWidth-rocket.offsetWidth+"px"; rocket.style.top = "420px"; } function rocketNorthWest() { rocket.style.transition = "left 2s linear 0s, top 1s linear 0s"; rocket.style.left = "0px"; rocket.style.top = "0px"; } function rocketSouthWest() { rocket.style.transition = "left 2s linear 0s, top 1s linear 0s"; rocket.style.left = "0px"; rocket.style.top = "420px"; } function rocketStop() { rocket.style.top = rocket.offsetTop+"px"; rocket.style.left = rocket.offsetLeft+"px"; } function Endgame(){ this.ender = function ender(){ game_stopped = true; window.onblur = function() { return false; }; //gamewindow.removeChild(rocket); gameconsole.style.display = "none"; window.squadGenerate = function() { return false; } endgamewindow.style.display = "block"; endtimedisplay.innerHTML = "You survived for " + stopwatch.innerHTML; } } function enemy(){ this.spawn = function spawn(efp){ let new_enemy = document.createElement("div"); new_enemy.id = "enemy_"+Math.floor(Math.random() * 1000000000000); new_enemy.setAttribute("class","enemy efp"+efp+""); gamewindow.appendChild(new_enemy); this.hittest(new_enemy.id); } this.hiteffects = function hiteffects(rocket){ if( healthmeter.offsetWidth > 1 ){ rocket.style.background = "url(graphics/rocket_hit.png)"; setTimeout(function(){ rocket.style.background = "url(graphics/rocket.png)";}, 100 ); } } this.hittest = function hittest(eid){ if( game_stopped ){ return false; } let me = this; let enemy = document.getElementById(eid); let rt = rocket.offsetTop; let rb = rocket.offsetTop+rocket.offsetHeight; let rl = rocket.offsetLeft; let rr = rocket.offsetLeft+rocket.offsetWidth; let et = enemy.offsetTop; let eb = enemy.offsetTop+enemy.offsetHeight; let el = enemy.offsetLeft; let er = enemy.offsetLeft+enemy.offsetWidth; if(rr > el && rl < er && rb > et && rt < eb){ healthmeter.style.width = healthmeter.offsetWidth - 3+"px"; if(healthmeter.offsetWidth < 1){ rocket.style.background = "url(graphics/rocket_explode.png)"; setTimeout(function(){me.ender();}, 500); return false; } else { this.hiteffects(rocket); } } setTimeout(function(){me.hittest(eid);}, 33); } } enemy.prototype = new Endgame(); function startNewGame(){ window.onresize = resizeHandler; window.onblur = blurHandler; newgamewindow.style.display = "none"; gameconsole.style.display = "block"; let hero = document.createElement("div"); hero.id = "rocket"; gamewindow.appendChild(hero); squadGenerate(0,1); clockem(0); } function squadGenerate(wc,sc){ let na = "1 2 3 4 5 6 7 8 9 10".split(" "); for(let i=0; i < sc; i++){ let rand = Math.floor(Math.random() * na.length); let efp = na.splice(rand,1); let en = new enemy(); en.spawn(efp); } wc++; if(wc > 80){ sc = 7; } else if(wc > 40){ sc = 6; } else if(wc > 20){ sc = 5; } else if(wc > 10){ sc = 4; } else if(wc > 5){ sc = 3; } else if(wc > 2){ sc = 2; } setTimeout('squadGenerate('+wc+','+sc+')',5000); } function clockem(secs) { secs++; let m = Math.floor(secs / 60); let s = secs % 60; if(s<10) {s="0"+s;} if(m<10) {m="0"+m;} stopwatch.innerHTML = m+":"+s; let timer = setTimeout('clockem('+secs+')',1000); } function resizeHandler(){ alert("You cannot resize the game viewport during play. We will restart the game now."); window.location = window.location; } function blurHandler(){ alert("You cannot minimize or tab away during game play. We will restart the game now."); window.location = window.location; } function init(){ gameloadwindow.style.display = "none"; newgamewindow.style.display = "block"; } window.onload = init; </script> </head> <body> <div id="gamewindow"><div id="game_bg"></div></div> <div id="newgamewindow"> <h1>Enemy Squadron<img src="graphics/rocket.png" alt="rocket" style="float:right;"></h1> <button onclick="startNewGame()">START NEW GAME</button> <p>Enemy Squadron is an experimental browser based game demo that has been programmed using CSS as the animation engine, and JavaScript as the user-interaction control system. Adam did not spend much time on it, about 4 hours total programming. It is very incomplete. It was made only to showcase randomized flight patterns, enemy hit-test for shield depletion on contact, and simple character control.</p> <p style="text-align:right; font-style:italic; font-size:14px;">CSS+JS Game Demo By Adam Khoury</p> </div> <div id="endgamewindow"> <h2>GAME OVER</h2> <p id="endtimedisplay"></p> <p id="endgamestatus"></p> </div> <div id="gameloadwindow"> <h2>Loading game assets...</h2> </div> <div id="gameconsole"><div id="health_meter_mc"><div id="healthmeter">SHIELDS</div></div> &nbsp; Time Elapsed: <span id="stopwatch"></span></div> <div id="bottom"> <h1 style="display:inline; padding-right:36px;">Enemy Squadron</h1> <span id="keyinstructions"><b>W</b> &uarr; <b>S</b> &darr; <b>A</b> &larr; <b>D</b> &rarr;</span> <h2>Objective: Stay alive as long as you can.</h2> <audio controls="controls" autoplay="autoplay" loop="loop"><source src="game_audio.mp3" type="audio/mpeg"></audio> </div> <div style="width:10px; height:1px; overflow:hidden; position:fixed; left:-200px;"><img src="graphics/rocket.png" alt="rocket"><img src="graphics/enemy_red.png" alt="enemy_red"><img src="graphics/rocket_hit.png" alt="rocket_hit"><img src="graphics/rocket_explode.png" alt="rocket_explode"></div> </body> </html>