Prototype for RetroTanks, Simple Controls and HTML5 Canvas

In this example below you will see how to do a Prototype for RetroTanks, Simple Controls and HTML5 Canvas with some HTML / CSS and Javascript

Thumbnail
This awesome code was written by enesser, you can see more from this user in the personal repository.
You can find the original code on Codepen.io
Copyright enesser ©
  • HTML
  • CSS
  • JavaScript
<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  <title>Prototype for RetroTanks, Simple Controls and HTML5 Canvas</title>
  
  
  
      <link rel="stylesheet" href="css/style.css">

  
</head>

<body>

  <!-- 

https://github.com/enesser/retroTanks

-->


<canvas id="canvas" width="800" height="400"></canvas>

<div class="tank info">
  <div><label>Tank x:</label><span class="x"></span></div>
  <div><label>Tank y:</label><span class="y"></span></div>
  <div><label>Tank angle:</label><span class="angle"></span></div>
  <div><label>Tank mod:</label><span class="mod"></span></div>
</div>

<div class="graphics info">
  <div><label>Color (c):</label><span class="color">atari pallete 1</span></div>
  <div><label>Level (l):</label><span class="level">retro tanks classic</span></div>
  <div><label>Shadow Blur (y):</label><span class="shadowBlur">false</span></div>
  <div><label>Scanlines (x):</label><span class="scanlinesValue">false</span></div>
</div>
  
  

    <script  src="js/index.js"></script>




</body>

</html>

/*Downloaded from https://www.codeseek.co/enesser/prototype-for-retrotanks-simple-controls-and-html5-canvas-YyzRaG */
body {
  background: #2d2d2d;
  color: white;
  height: 100%;
  margin: 0;
}

canvas {
  height: 100%;
  width: 100%;
}

.info {
  font-size: 1.6em;
  font-families: 'Lucida Console', Monaco, monospace;
  margin-top: .1em;
  padding: 1em;
}
.info label {
  display: inline-block;
  width: 10em;
}

/*
  CSS scan lines effect adapted from an example by Meduzen on Codepen.
  https://codepen.io/meduzen/pen/zxbwRV
 */
.scanlines {
  overflow: hidden;
  position: relative;
}

.scanlines:before,
.scanlines:after {
  content: '';
  display: block;
  pointer-events: none;
  position: absolute;
}

.scanlines:before {
  background: rgba(0, 0, 0, 0.3);
  height: 1px;
  opacity: 0.65;
  width: 100%;
  z-index: 2147483649;
  -webkit-animation: scanline 8s linear infinite;
          animation: scanline 8s linear infinite;
}

.scanlines:after {
  background: linear-gradient(to bottom, transparent 50%, rgba(0, 0, 0, 0.3) 51%);
  background-size: 100% 3px;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 2147483648;
}

/* ANIMATE UNIQUE SCANLINE */
@-webkit-keyframes scanline {
  0% {
    -webkit-transform: translate3d(0, 200000%, 0);
            transform: translate3d(0, 200000%, 0);
  }
}
@keyframes scanline {
  0% {
    -webkit-transform: translate3d(0, 200000%, 0);
            transform: translate3d(0, 200000%, 0);
  }
}
@-webkit-keyframes scanlines {
  0% {
    background-position: 0 50%;
  }
}
@keyframes scanlines {
  0% {
    background-position: 0 50%;
  }
}


/*Downloaded from https://www.codeseek.co/enesser/prototype-for-retrotanks-simple-controls-and-html5-canvas-YyzRaG */
/*****************************
/** Graphic Effects***********
/*****************************/
var shadowBlur = false;
var scanlines = false;

/*****************************
/** Color Schemes ************
/*****************************/
var currentScheme = 0;
var colorSchemes = [{
  name: 'atari pallete 1',
  field: 'rgb(94, 121, 26)',
  walls: 'rgb(0, 0, 0)',
  tank: 'rgb(198, 111, 193)'
}, {
  name: 'atari pallete 2',
  field: 'rgb(48, 24, 160)',
  walls: 'rgb(48, 97, 163)',
  tank: 'rgb(172, 217, 112)'
}, {
  name: 'atari pallete 3',
  field: 'rgb(97, 27, 3)',
  walls: 'rgb(252, 222, 160)',
  tank: 'rgb(184, 175, 240)'
}, {
  name: 'experiment 1',
  field: 'rgb(51, 111, 51)',
  walls: 'rgb(169, 125, 93)',
  tank: 'rgb(207, 83, 83)'
}, {
  name: 'experiment 2',
  field: 'rgb(201, 214, 223)',
  walls: 'rgb(82, 97, 107)',
  tank: 'rgb(240, 245, 249)'
}, {
  name: 'experiment 3',
  field: 'rgb(63, 76, 72)',
  walls: 'rgb(149, 151, 122)',
  tank: 'rgb(255, 215, 190)'
}];

/*****************************
/** Wall *********************
/*****************************/
var Wall = function(x, y, width, height) {
  this.x = x;
  this.y = y;
  this.width = width;
  this.height = height;
};

Wall.prototype.draw = function() {
  context.save();

  if (shadowBlur) {
    context.shadowBlur = 20;
    context.shadowColor = '#000';
  }

  context.fillStyle = colorSchemes[currentScheme].walls;
  context.fillRect(this.x, this.y, this.width, this.height);
  context.restore();
};

/*****************************
/** Tank *********************
/*****************************/
var Tank = function(x, y) {
  this.x = x;
  this.y = y;
  this.mod = 0;
  this.speed = 5;
  this.angle = 0;
};

Tank.prototype.goForward = function() {
  this.mod = 1;
  this.x = this.x + (this.speed * this.mod) * Math.cos(Math.PI / 180 * this.angle);
  this.y = this.y + (this.speed * this.mod) * Math.sin(Math.PI / 180 * this.angle);
}

Tank.prototype.goBack = function() {
  this.mod = -1;
  this.x = this.x + (this.speed * this.mod) * Math.cos(Math.PI / 180 * this.angle);
  this.y = this.y + (this.speed * this.mod) * Math.sin(Math.PI / 180 * this.angle);
}

Tank.prototype.rotateRight = function() {
  this.angle += 5;
}

Tank.prototype.rotateLeft = function() {
  this.angle -= 5;
}

Tank.prototype.draw = function() {
  var width = 47;
  var height = 33;

  var cx = this.x + 0.5 * width;
  var cy = this.y + 0.5 * height;

  context.save();
  context.translate(cx, cy);
  context.rotate(this.angle * Math.PI / 180);
  context.translate(-cx, -cy);

  if (shadowBlur) {
    context.shadowBlur = 20;
    context.shadowColor = '#000';
  }

  context.fillStyle = colorSchemes[currentScheme].tank;
  context.fillRect(this.x + 20, this.y + 14, 28, 6); //turret
  context.fillRect((this.x + 10), this.y + 6, 18, 24); //body
  context.fillRect((this.x + 0), this.y, 32, 8); //left track
  context.fillRect((this.x + 0), this.y + 26, 32, 8); //right track
  context.restore();
}

var docX = document.querySelector('.tank .x');
var docY = document.querySelector('.tank .y');
var docAngle = document.querySelector('.tank .angle');
var docMod = document.querySelector('.tank .mod');

Tank.prototype.diag = function() {
  docX.innerHTML = this.x;
  docY.innerHTML = this.y;
  docAngle.innerHTML = this.angle;
  docMod.innerHTML = this.mod;
}

/*****************************
/** Levels *******************
/*****************************/
var currentLevel = 0;
var levelHeight = 400;
var levelWidth = 800;

var levels = [{
  name: 'retro tanks classic',
  walls: [
    //interior walls
    new Wall(100, 100, 14, 200), //left
    new Wall(680, 100, 14, 200), //right
    new Wall((levelWidth / 2) - 50, (levelHeight / 2) - 40, 100, 80), //middle

    //exterior walls
    new Wall(0, 0, levelWidth, 14), //top
    new Wall(0, 14, 14, levelHeight - 28), //left
    new Wall(levelWidth - 14, 14, 14, levelHeight - 28), //right
    new Wall(0, levelHeight - 14, levelWidth, 14), //bottom	        
  ],
  spawnPoints: [{
    x: 35,
    y: 170
  }]
}, {
  name: 'minimal',
  walls: [
    //interior walls    
    new Wall((levelWidth / 2) - 50, (levelHeight / 2) - 40, 100, 80), //middle

    //exterior walls
    new Wall(0, 0, levelWidth, 14), //top
    new Wall(0, 14, 14, levelHeight - 28), //left
    new Wall(levelWidth - 14, 14, 14, levelHeight - 28), //right
    new Wall(0, levelHeight - 14, levelWidth, 14), //bottom	        
  ],
  spawnPoints: [{
    x: 35,
    y: 170
  }]
}, {
  name: 'open',
  walls: [
    //exterior walls
    new Wall(0, 0, levelWidth, 14), //top
    new Wall(0, 14, 14, levelHeight - 28), //left
    new Wall(levelWidth - 14, 14, 14, levelHeight - 28), //right
    new Wall(0, levelHeight - 14, levelWidth, 14), //bottom	        
  ],
  spawnPoints: [{
    x: 35,
    y: 170
  }]
}];

/*****************************
/** Game code ****************
/*****************************/

var myTank = new Tank(levels[currentLevel].spawnPoints[0].x,
  levels[currentLevel].spawnPoints[0].y);
var keyMap = {};

window.addEventListener('keydown',
  function(event) {
    keyMap[event.keyCode] = true;
  }, false);

window.addEventListener('keyup',
  function(event) {
    keyMap[event.keyCode] = false;

    if (event.keyCode === 89) { //Y
      shadowBlur = !shadowBlur;
      document.querySelector('.graphics .shadowBlur').innerHTML = shadowBlur.toString();
    }

    if (event.keyCode === 88) { //X
      scanlines = !scanlines;
      document.querySelector('.graphics .scanlinesValue').innerHTML = scanlines.toString();
      document.getElementsByTagName('body')[0].className = (scanlines ? 'scanlines' : '');
    }

    if (event.keyCode === 67) { //C
      currentScheme++;
      if (currentScheme + 1 > colorSchemes.length) {
        currentScheme = 0;
      }
      document.querySelector('.graphics .color').innerHTML = colorSchemes[currentScheme].name;
    }

    if (event.keyCode === 76) { //L
      currentLevel++;
      if (currentLevel + 1 > levels.length) {
        currentLevel = 0;
      }
      document.querySelector('.graphics .level').innerHTML = levels[currentLevel].name;
    }

  }, false);

setInterval(function() {
  if (keyMap[87] || keyMap[38]) { //W, up
    myTank.goForward();
  }

  if (keyMap[83] || keyMap[40]) { //S, down
    myTank.goBack();
  }

  if (keyMap[65] || keyMap[37]) { //A, left
    myTank.rotateLeft();
  }

  if (keyMap[68] || keyMap[39]) { //D, right
    myTank.rotateRight();
  }
}, 40);

var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');

(function render() {

  context.fillStyle = colorSchemes[currentScheme].field;
  context.fillRect(0, 0, 800, 400);
  context.fillStyle = 'rgb(0, 0, 0)';

  //draw walls
  for (var i = 0; i < levels[currentLevel].walls.length; i++) {
    levels[currentLevel].walls[i].draw();
  }

  //draw tank
  myTank.draw();
  myTank.diag();

  window.requestAnimationFrame(render);

})();

Comments