Разработка игры HTML5

Разработка игры HTML5 с использованием canvas. HTML5 игра называется — Скайуокер. В основном — это симулятор полета с самолета и несколько врагов. Наша цель — добраться до финиша.  Ключевые функции: спрайты для самолета и взрывы, возможность нажать несколько клавиш (как пример — вы можете одновременно передвигаться и атаковать), на определенное расстояние уровня, расширение обнаружения столкновений ( враги могут повредить нашу плоскость), параметры жизни и оценки:
Демо

Шаг 1. HTML



<!DOCTYPE html>
<html lang="ru" >
    <head>
        <meta charset="utf-8" />
        <title>HTML5 Game Development (SkyWalker)</title>

        <!-- add styles -->
        <link href=
http://pixelcom.crimea.ua/"css/main.css" rel="stylesheet" type="text/css" />

        <!-- add scripts -->
        <!--[if lt IE 9]>
          <script src=
http://pixelcom.crimea.ua/"http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
        <![endif]-->
        <script src=
http://pixelcom.crimea.ua/"js/jquery.js"></script>
        <script src=
http://pixelcom.crimea.ua/"js/script.js"></script>
    </head>
    <body>
        <header>
            <h1>HTML5 Game Development</h1>
        </header>

        <div class="container">
            <canvas id="scene" width="700" height="700" tabindex="1"></canvas>
        </div>
    </body>
</html>



Шаг 2. JS

js/script.js

Создайте файл script.js (в папке ‘js’) и поместите этот код внутри (это полный код JS игры SkyWalker). Основные функции этого кода описаны ниже.



// переменные
  var canvas, ctx;

  // Изображения
  var backgroundImage;
  var oRocketImage;
  var oExplosionImage;
  var introImage;
  var oEnemyImage;

  var iBgShiftY = 9300; //10000 (длина уровня) - 700 (высота холста)
  var bPause = true; // пауза
  var plane = null; // самолет
  var rockets = []; // массив ракет
  var enemies = []; // массив врагов
  var explosions = []; // массив взрывов
  var planeW = 200; // ширина самолета
  var planeH = 110; // высота самолета
  var iSprPos = 2; // начало спрайт кадров для плоскости
  var iMoveDir = 0; // направление перемещения
  var iEnemyW = 128; // ширина врага
  var iEnemyH = 128; // высота врага
  var iRocketSpeed = 10; // начальная скорость полета ракеты
  var iEnemySpeed = 5; // начальная врага скорость
  var pressedKeys = []; // массив нажатия клавиши
  var iScore = 0; // общая оценка
  var iLife = 100; // жизни
  var iDamage = 10; // - повреждения самолета врага
  var enTimer = null; // случайные таймер для нового врага
  // -------------------------------------------------------------

  // объекты :
  function Plane(x, y, w, h, image) {
  this.x = x;
  this.y = y;
  this.w = w;
  this.h = h;
  this.image = image;
  this.bDrag = false;
  }
  function Rocket(x, y, w, h, speed, image) {
  this.x = x;
  this.y = y;
  this.w = w;
  this.h = h;
  this.speed = speed;
  this.image = image;
  }
  function Enemy(x, y, w, h, speed, image) {
  this.x = x;
  this.y = y;
  this.w = w;
  this.h = h;
  this.speed = speed;
  this.image = image;
  }
  function Explosion(x, y, w, h, sprite, image) {
  this.x = x;
  this.y = y;
  this.w = w;
  this.h = h;
  this.sprite = sprite;
  this.image = image;
  }
  // -------------------------------------------------------------
  // получить случайное число между X и Y
  function getRand(x, y) {
  return Math.floor(Math.random()*y)+x;
  }

  // Дисплей функции Intro (вступление)
  function displayIntro() {
  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  ctx.drawImage(introImage, 0, 0,700, 700);
  }

  // Основные функции сцены
  function drawScene() {

  if (! bPause) {
  iBgShiftY -= 2; // двигаться
  if (iBgShiftY < 5) { // остановиться   bPause = true;      // счет   ctx.font = '40px Verdana';   ctx.fillStyle = '#fff';   ctx.fillText('Finish, your score: ' + iScore * 10 + ' points', 50, 200);   return;   }      // процесс нажатия клавиши, (перемещение)   processPressedKeys();      // очистка холста   ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);      // фон   ctx.drawImage(backgroundImage, 0, 0 + iBgShiftY, 700, 700, 0, 0, 700, 700);      // самолет   ctx.drawImage(plane.image, iSprPos*plane.w, 0, plane.w, plane.h, plane.x - plane.w/2, plane.y - plane.h/2, plane.w, plane.h);      // ракеты   if (rockets.length > 0) {
  for (var key in rockets) {
  if (rockets[key] != undefined) {
  ctx.drawImage(rockets[key].image, rockets[key].x, rockets[key].y);
  rockets[key].y -= rockets[key].speed;

  // if a rocket is out of screen - remove it
  if (rockets[key].y < 0) {   delete rockets[key];   }   }   }   }      // взрывы   if (explosions.length > 0) {
  for (var key in explosions) {
  if (explosions[key] != undefined) {
  // display explosion sprites
  ctx.drawImage(explosions[key].image, explosions[key].sprite*explosions[key].w, 0, explosions[key].w, explosions[key].h, explosions[key].x - explosions[key].w/2, explosions[key].y - explosions[key].h/2, explosions[key].w, explosions[key].h);
  explosions[key].sprite++;

  // удалите взрыв объекта, когда он исчезнет
  if (explosions[key].sprite > 10) {
  delete explosions[key];
  }
  }
  }
  }

  // враги
  if (enemies.length > 0) {
  for (var ekey in enemies) {
  if (enemies[ekey] != undefined) {
  ctx.drawImage(enemies[ekey].image, enemies[ekey].x, enemies[ekey].y);
  enemies[ekey].y -= enemies[ekey].speed;

  // remove an enemy object if it is out of screen
  if (enemies[ekey].y > canvas.height) {
  delete enemies[ekey];
  }
  }
  }
  }

  if (enemies.length > 0) {
  for (var ekey in enemies) {
  if (enemies[ekey] != undefined) {

  // столкновения с ракетами
  if (rockets.length > 0) {
  for (var key in rockets) {
  if (rockets[key] != undefined) {
  if (rockets[key].y < enemies[ekey].y + enemies[ekey].h/2 && rockets[key].x > enemies[ekey].x && rockets[key].x + rockets[key].w < enemies[ekey].x + enemies[ekey].w) {
  explosions.push(new Explosion(enemies[ekey].x + enemies[ekey].w / 2, enemies[ekey].y + enemies[ekey].h / 2, 120, 120, 0, oExplosionImage));

  // убить врага, ракетой, и добавить +1 балл
  delete enemies[ekey];
  delete rockets[key];
  iScore++;
  }
  }
  }
  }

  // столкновения с самолетом
  if (enemies[ekey] != undefined) {
  if (plane.y - plane.h/2 < enemies[ekey].y + enemies[ekey].h/2 && plane.x - plane.w/2 < enemies[ekey].x + enemies[ekey].w && plane.x + plane.w/2 > enemies[ekey].x) {
  explosions.push(new Explosion(enemies[ekey].x + enemies[ekey].w / 2, enemies[ekey].y + enemies[ekey].h / 2, 120, 120, 0, oExplosionImage));

  // удалить врага и нанести ущерб
  delete enemies[ekey];
  iLife -= iDamage;

  if (iLife <= 0) { // Конец игры   bPause = true;      // счет   ctx.font = '38px Verdana';   ctx.fillStyle = '#fff';   ctx.fillText('Game over, your score: ' + iScore * 10 + ' points', 25, 200);   return;   }   }   }   }   }   }      // отображение жизни и оценок   ctx.font = '14px Verdana';   ctx.fillStyle = '#fff';   ctx.fillText('Life: ' + iLife + ' / 100', 50, 660);   ctx.fillText('Score: ' + iScore * 10, 50, 680);   }   }      // функция нажатия клавиши    function processPressedKeys() {   if (pressedKeys[37] != undefined) { // 'влево' key   if (iSprPos > 0) {
  iSprPos--;
  iMoveDir = -7;
  }
  if (plane.x - plane.w / 2 > 10) {
  plane.x += iMoveDir;
  }
  }
  else if (pressedKeys[39] != undefined) { // 'вправо' key
  if (iSprPos < 4) {
  iSprPos++;
  iMoveDir = 7;
  }
  if (plane.x + plane.w / 2 < canvas.width - 10) {   plane.x += iMoveDir;   }   }   }      // добавить врага (функция добавляет новый врагов беспорядочно)   function addEnemy() {   clearInterval(enTimer);      var randX = getRand(0, canvas.height - iEnemyH);   enemies.push(new Enemy(randX, 0, iEnemyW, iEnemyH, - iEnemySpeed, oEnemyImage));      var interval = getRand(1000, 4000);   enTimer = setInterval(addEnemy, interval); // цикл   }      // Основные Инициализации   $(function(){   canvas = document.getElementById('scene');   ctx = canvas.getContext('2d');      // загрузка изображения фона   backgroundImage = new Image();   backgroundImage.src = 'images/levelmap.jpg';   backgroundImage.onload = function() {   }   backgroundImage.onerror = function() {   console.log('Error loading the background image.');   }      introImage = new Image();   introImage.src = 'images/intro.jpg';      // инициализация пустой ракеты   oRocketImage = new Image();   oRocketImage.src = 'images/rocket.png';   oRocketImage.onload = function() { }      // инициализация изображения взрыва   oExplosionImage = new Image();   oExplosionImage.src = 'images/explosion.png';   oExplosionImage.onload = function() { }      // инициализация пустого врага   oEnemyImage = new Image();   oEnemyImage.src = 'images/enemy.png';   oEnemyImage.onload = function() { }      // инициализация самолета   var oPlaneImage = new Image();   oPlaneImage.src = 'images/plane.png';   oPlaneImage.onload = function() {   plane = new Plane(canvas.width / 2, canvas.height - 100, planeW, planeH, oPlaneImage);   }      $(window).keydown(function (evt){ // обработка событий   var pk = pressedKeys[evt.keyCode];   if (! pk) {   pressedKeys[evt.keyCode] = 1; // добавить все нажатия клавиш в массиве   }      if (bPause && evt.keyCode == 13) { // в случае Enter   bPause = false;      // начало анимации   setInterval(drawScene, 30); // loop drawScene      // добавить первого противника   addEnemy();   }   });      $(window).keyup(function (evt) { // onkeyup обработки событий   var pk = pressedKeys[evt.keyCode];   if (pk) {   delete pressedKeys[evt.keyCode]; // удаление нажатии клавиши из массива   }   if (evt.keyCode == 65) { // 'A' button - add a rocket   rockets.push(new Rocket(plane.x - 16, plane.y - plane.h, 32, 32, iRocketSpeed, oRocketImage));   }   if (evt.keyCode == 37 || evt.keyCode == 39) {   // вернуть самолет в положение по умолчанию   if (iSprPos > 2) {
  for (var i = iSprPos; i >= 2; i--) {
  iSprPos = i;
  iMoveDir = 0;
  }
  } else {
  for (var i = iSprPos; i <= 2; i++) {
  iSprPos = i;
  iMoveDir = 0;
  }
  }
  }
  });

  // когда отображать вступление
  introImage.onload = function() {
  displayIntro(); // Показать первое вступление
  }
  });
  


В основном инициализация сценария загружает все необходимые изображения (уровень карты, введение экран, ракеты, взрыв, враги и спрайты самолетов). Тогда, для того, чтобы справиться с несколькими нажатием клавиш используется Array (pressedKeys), чтобы сохранить все нажатия клавиш (во время появления на главной сцене, мы будем использовать массив манипулирования с нашим самолетом), и наконец, один раз при загрузке страницы — на экране мы показываем вступление. Одним из важных моментов — обработка нескольких клавиш, посмотрите на этот код:



var pressedKeys = []; // массив нажатии клавиши

  $(window).keydown(function (evt){ // onkeydown обработки событий
  var pk = pressedKeys[evt.keyCode];
  if (! pk) {
  pressedKeys[evt.keyCode] = 1; // добавить все нажатия клавиш в массиве
  }
  });

  $(window).keyup(function (evt) { // onkeyup обработки событий
  var pk = pressedKeys[evt.keyCode];
  if (pk) {
  delete pressedKeys[evt.keyCode]; // удаление нажатий клавиш из массива
  }
  });
  


Эта техника позволяет работать с несколькими ключами. И во время оказания основной сцены мы вызываем следующие объекты: фон уровня, основной самолет, ракеты (самолета), врагов и взрывы. Как только мы попали в врага — мы рисуем спрайт взрыва на последнем месте прибывания противника. И, наконец, наши оппоненты не безвредны, как только они касаются нашего самолета — они взрываются и наносят ущерб нашему самолету. И, если значение жизни будет нуль — игра окончена. Для реализации столкновений и взрывов, следующий код:



if (plane.y - plane.h/2 < enemies[ekey].y + enemies[ekey].h/2 && plane.x - plane.w/2 < enemies[ekey].x + enemies[ekey].w && plane.x + plane.w/2 > enemies[ekey].x) {
  explosions.push(new Explosion(enemies[ekey].x + enemies[ekey].w / 2, enemies[ekey].y + enemies[ekey].h / 2, 120, 120, 0, oExplosionImage));

  // удалить врага и нанести ущерб
  delete enemies[ekey];
  iLife -= iDamage;

  if (iLife <= 0) { // Конец игры
  bPause = true;

  // счет
  ctx.font = '38px Verdana';
  ctx.fillStyle = '#fff';
  ctx.fillText('Game over, your score: ' + iScore * 10 + ' points', 25, 200);
  return;
  }
  }
  


Шаг 3. Графика

enemy.png, explosion.png, intro.jpg, levelmap.jpg, plane.png, rocket.png

Все используемые изображения доступны в пакете: скачать .

Статья подготовлена для вас коллективом сайта www.pixelcom.crimea.ua
Оригинал статьи: script-tutorials.com/html5-game-development-lesson-10
Перевел: Виктор Клим
Правила использования материалов сайта!

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML -теги и атрибуты: <a href= http://pixelcom.crimea.ua/"" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>