âš ī¸ Warning âš ī¸ Deprecated Code! This video tutorial contains outdated code.
💡 If you wish to update it, any AI assistant will update the code for you in seconds.

Enemy Squadron JavaScript CSS Game Development Demo

Published : February 3, 2023   •   Last Edited : November 24, 2025   •   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>