Enemy Squadron JavaScript CSS Game Development Demo
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> 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> ↑ <b>S</b> ↓ <b>A</b> ← <b>D</b> →</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>