Мы продолжаем серию статей о создании игр в HTML5 с использованием canvas. И в этот раз, в качестве примера, будет более-менее полноценная игра — мы будем делать аналог старой приставочной игры — Battle City. Я научу вас использовать массивы в виде игровой карты, плюс я покажу — как обнаружить столкновение движущегося объекта (в данном случае это танк) с окружающей средой (объекты на карте).
Шаг 1. HTML
index.html
<!DOCTYPE html> <html lang="ru" > <head> <meta charset="utf-8" /> <title>Разработка игр на HTML5 — Урок 6 | officialplat-tt.ru</title> <link href="css/main.css" rel="stylesheet" type="text/css" /> <script src="js/jquery-1.5.2.min.js"></script> <script src="js/script.js"></script> </head> <body> <header> <h2>Разработка игр на HTML5 — Урок 6</h2> <a href="http://officialplat-tt.ru/?p=1769" class="stuts">Вернуться обратно на <span>officialplat-tt.ru</span></a> </header> <div class="container"> <canvas id="scene" width="800" height="600"></canvas> </div> </body> </html>
Шаг 2. CSS
css/main.css
В этот раз CSS стили не публикую, так как там только разметка страницы. Файл стилей доступен в исходниках.
Шаг 3. JS
js/jquery-1.5.2.min.js
Как и в прошлые разы мы используем jQuery. Следующий файл содержит основной функционал:
js/script.js
// внутренние переменные var canvas, context; var imgBrick, imgSteel, imgWater, imgForest, imgTank; // изображения var aMap; // массив карта var oTank; // объект танк var iCellSize = 24; // ширина клетки var iXCnt = 26; // количество клеток X var iYCnt = 26; // количество клеток Y // объекты : function Tank(x, y, w, h, image) { this.x = x; this.y = y; this.w = w; this.h = h; this.i = 0; this.image = image; } // функции function clear() { // функция очистки canvas context.clearRect(0, 0, canvas.width, canvas.height); } function drawScene() { // функция отрисовки сцены clear(); // очистить canvas // заполнить фон context.fillStyle = '#111'; context.fillRect(0, 0, canvas.width, canvas.height); // сохранить текущее положение context.save(); // обход нашего массива for (var y = 0; y < iYCnt; y++) { for (var x = 0; x < iXCnt; x++) { switch (aMap[y][x]) { case 0: // пропуск break; case 1: // рисуем кирпичный блок context.drawImage(imgBrick, 0, 0, iCellSize, iCellSize, x*iCellSize, y*iCellSize, iCellSize, iCellSize); break; case 2: // рисуем стальной блок context.drawImage(imgSteel, 0, 0, iCellSize, iCellSize, x*iCellSize, y*iCellSize, iCellSize, iCellSize); break; case 3: // рисуем блок леса context.drawImage(imgForest, 0, 0, iCellSize, iCellSize, x*iCellSize, y*iCellSize, iCellSize, iCellSize); break; case 4: // рисуем водяной блок context.drawImage(imgWater, 0, 0, iCellSize, iCellSize, x*iCellSize, y*iCellSize, iCellSize, iCellSize); break; } } } // восстановление текущего положения context.restore(); // рисуем танк context.drawImage(oTank.image, oTank.i*oTank.w, 0, oTank.w, oTank.h, oTank.x, oTank.y, oTank.w, oTank.h); } // ------------------------------------------------------------- // инициализация $(function(){ canvas = document.getElementById('scene'); canvas.width = iXCnt * iCellSize; canvas.height = iYCnt * iCellSize; context = canvas.getContext('2d'); // массив - карта aMap = ([ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0], [0, 0, 1, 1, 4, 4, 4, 4, 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 4, 4, 4, 4, 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 4, 4, 4, 4, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 0, 0, 2, 2, 0, 0], [0, 0, 0, 0, 4, 4, 4, 4, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 0, 0, 2, 2, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 1, 1, 0, 0, 0, 0], [0, 0, 2, 2, 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 2, 2, 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [3, 3, 3, 3, 1, 1, 0, 0, 4, 4, 4, 4, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0], [3, 3, 3, 3, 1, 1, 0, 0, 4, 4, 4, 4, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0], [3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 2, 2], [3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 2, 2], [0, 0, 1, 1, 4, 4, 4, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 4, 4, 4, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2, 2, 0, 0, 4, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 0, 0, 1, 1, 0, 0], [2, 2, 0, 0, 4, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 0, 0, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 4, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 4, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 0, 0], [0, 0, 0, 0, 0, 0, 2, 2, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 4, 4, 4, 4, 0, 0], [0, 0, 0, 0, 0, 0, 2, 2, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 4, 4, 4, 4, 0, 0], [0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 2, 2, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 2, 2, 0, 0, 0, 0] ]); // загружаем изображения imgBrick = new Image(); imgBrick.src = 'images/brick.png'; imgSteel = new Image(); imgSteel.src = 'images/steel.png'; imgWater = new Image(); imgWater.src = 'images/water.png'; imgForest = new Image(); imgForest.src = 'images/forest.png'; imgTank = new Image(); imgTank.src = 'images/tank.png'; oTank = new Tank(iCellSize*9, iCellSize*24, 48, 48, imgTank); $(window).keydown(function(event){ // обработчики нажатия клавиш клавиатуры switch (event.keyCode) { case 38: // клавиша вверх oTank.i = 2; // проверка столкновений var iCurCelX = (2 * oTank.x) / 48; var iCurCelY = (2 * oTank.y) / 48; if (iCurCelY) { var iTest1 = aMap[iCurCelY-1][iCurCelX]; var iTest2 = aMap[iCurCelY-1][iCurCelX+1]; if ((iTest1 == 0 || iTest1 == 3) && (iTest2 == 0 || iTest2 == 3)) { oTank.y-=24; if (oTank.y < 0) { oTank.y = 0; } } } break; case 40: // клавиша вниз oTank.i = 3; // проверка столкновений var iCurCelX = (2 * oTank.x) / 48; var iCurCelY = (2 * oTank.y) / 48; if (iCurCelY+2 < iYCnt) { var iTest1 = aMap[iCurCelY+2][iCurCelX]; var iTest2 = aMap[iCurCelY+2][iCurCelX+1]; if ((iTest1 == 0 || iTest1 == 3) && (iTest2 == 0 || iTest2 == 3)) { oTank.y+=24; if (oTank.y > 576) { //iCellSize * (iYCnt-2) oTank.y = 576; } } } break; case 37: // клавиша влево oTank.i = 1; // проверка столкновений var iCurCelX = (2 * oTank.x) / 48; var iCurCelY = (2 * oTank.y) / 48; var iTest1 = aMap[iCurCelY][iCurCelX-1]; var iTest2 = aMap[iCurCelY+1][iCurCelX-1]; if ((iTest1 == 0 || iTest1 == 3) && (iTest2 == 0 || iTest2 == 3)) { oTank.x-=24; if (oTank.x < 0) { oTank.x = 0; } } break; case 39: // клавиша вправо oTank.i = 0; // проверка столкновений var iCurCelX = (2 * oTank.x) / 48; var iCurCelY = (2 * oTank.y) / 48; var iTest1 = aMap[iCurCelY][iCurCelX+2]; var iTest2 = aMap[iCurCelY+1][iCurCelX+2]; if ((iTest1 == 0 || iTest1 == 3) && (iTest2 == 0 || iTest2 == 3)) { oTank.x+=24; if (oTank.x > 576) { //iCellSize * (iXCnt-2) oTank.x = 576; } } break; } }); setInterval(drawScene, 40); // отрисовка сцены });
В коде я оставил комментарии, чтобы было понятнее.
Итог
Сегодня мы сделали основу HTML5 игры — BattleCity. Я буду рад если Вы поделитесь ссылкой на этот урок со своими друзьями и оставите комментарии. Удачи!
Получайте новые статьи блога прямо себе на почту
Подробно и интересно!
Спасибо!