{lang: ‘ru’}

уроки html5, html5 canvas, html5 примеры, html5 игрыУроки HTML5. Разработка игр

Сегодня мы продолжаем серию статей о разработке игры в HTML5 с использованием холста. На сегодняшний день я подготовил новую игру. За основу был взят результат 4 урока, были добавлены, огненные шары, враги и обнаружение столкновений. Итак, теперь наш дракон может бросать огненные шары и убивать врагов. Теперь эта игра стала гораздо более интерактивной.

С предыдущим уроком Вы можете ознакомиться тут: Разработка игр на HTML5 — Урок 8

 
 


Demo Исходники

 
 


Шаг 1. HTML

<!DOCTYPE html>
<html lang="ru" >
    <head>
        <meta charset="utf-8" />
        <title>HTML5 Game Development - Lesson 9 | Script Tutorials</title>
        <link href="css/main.css" rel="stylesheet" type="text/css" />

        <!--[if lt IE 9]>
          <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
        <![endif]-->
        <script src="js/jquery.js"></script>
        <script src="js/script.js"></script>
    </head>
    <body>
        <header tabindex="0">
            <h2>Разработка игр на HTML5 — Урок 9</h2>
            <a  href="http://officialplat-tt.ru/?p=2045" class="stuts">Вернуться обратно на <span>officialplat-tt.ru</span></a>
        </header>

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

Шаг 2. CSS

css/main.css

Файл стилей содержит только разметку страницы, так что я его не публикую. Как всегда его можно найти в исходниках.

Step 3. JS

js/script.js

// переменные
var canvas, ctx;
var backgroundImage;
var iBgShiftX = 100;

var dragon, enemy = null; // игровые объекты
var balls = [];
var enemies = [];

var dragonW = 75; // ширина дракона
var dragonH = 70; // высота дракона
var iSprPos = 0; // начальный кадр спрайта
var iSprDir = 0; // начальное направление дракона
var iEnemyW = 128; // ширина врага
var iEnemyH = 128; // высота врага
var iBallSpeed = 10; // скорость шара
var iEnemySpeed = 2; // скорость врага

var dragonSound; // звук дракона
var wingsSound; // звук крыльев
var explodeSound, explodeSound2; // звуки взрыва
var laughtSound; // смех

var bMouseDown = false; // состояние мыши
var iLastMouseX = 0;
var iLastMouseY = 0;
var iScore = 0;
// -------------------------------------------------------------

// объекты:
function Dragon(x, y, w, h, image) {
    this.x = x;
    this.y = y;
    this.w = w;
    this.h = h;
    this.image = image;
    this.bDrag = false;
}
function Ball(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;
}
// -------------------------------------------------------------
// получить случайное число между X и Y
function getRand(x, y) {
    return Math.floor(Math.random()*y)+x;
}

// функции рисования :
function drawScene() { // основная функция отрисовки сцены
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); //очистить холст

    // нарисовать фон
    iBgShiftX += 4;
    if (iBgShiftX >= 1045) {
        iBgShiftX = 0;
    }
    ctx.drawImage(backgroundImage, 0 + iBgShiftX, 0, 1000, 940, 0, 0, 1000, 600);

    // обновить позиции спрайтов
    iSprPos++;
    if (iSprPos >= 9) {
        iSprPos = 0;
    }

    // если зажата кнопка мыши - перемещение дракона ближе к курсору
    if (bMouseDown) {
        if (iLastMouseX > dragon.x) {
            dragon.x += 5;
        }
        if (iLastMouseY > dragon.y) {
            dragon.y += 5;
        }
        if (iLastMouseX < dragon.x) {
            dragon.x -= 5;
        }
        if (iLastMouseY < dragon.y) {
            dragon.y -= 5;
        }
    }

    // рисуем дракона
    ctx.drawImage(dragon.image, iSprPos*dragon.w, iSprDir*dragon.h, dragon.w, dragon.h, dragon.x - dragon.w/2, dragon.y - dragon.h/2, dragon.w, dragon.h);

    // рисуем огненные шары
    if (balls.length > 0) {
        for (var key in balls) {
            if (balls[key] != undefined) {
                ctx.drawImage(balls[key].image, balls[key].x, balls[key].y);
                balls[key].x += balls[key].speed;

                if (balls[key].x > canvas.width) {
                    delete balls[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].x += enemies[ekey].speed;

                if (enemies[ekey].x < - iEnemyW) {
                    delete enemies[ekey];

                    // включаем звук смеха 
                    laughtSound.currentTime = 0;
                    laughtSound.play();
                }
            }
        }
    }

    // обнаружение столкновения
    if (balls.length > 0) {
        for (var key in balls) {
            if (balls[key] != undefined) {

                if (enemies.length > 0) {
                    for (var ekey in enemies) {
                        if (enemies[ekey] != undefined && balls[key] != undefined) {
                            if (balls[key].x + balls[key].w > enemies[ekey].x && balls[key].y + balls[key].h > enemies[ekey].y && balls[key].y < enemies[ekey].y + enemies[ekey].h) {
                                delete enemies[ekey];
                                delete balls[key];
                                iScore++;

                                // включаем звук взрыва #2
                                explodeSound2.currentTime = 0;
                                explodeSound2.play();
                            }
                        }
                    }
                }
            }
        }
    }

    // обновление счета
    ctx.font = '16px Verdana';
    ctx.fillStyle = '#fff';
    ctx.fillText('Счет: ' + iScore * 10, 900, 580);
    ctx.fillText('Нажмите "1" для запуска огненного шара', 100, 580);

}

// -------------------------------------------------------------

// инициализация
$(function(){
    canvas = document.getElementById('scene');
    ctx = canvas.getContext('2d');

    var width = canvas.width;
    var height = canvas.height;

    // загрузка фона
    backgroundImage = new Image();
    backgroundImage.src = 'images/hell.jpg';
    backgroundImage.onload = function() {
    }
    backgroundImage.onerror = function() {
        console.log('Error');
    }

    // инициализация звуковых файлов
    dragonSound = new Audio('media/dragon.wav');
    dragonSound.volume = 0.9;

    laughtSound = new Audio('media/laught.wav');
    laughtSound.volume = 0.9;

    explodeSound = new Audio('media/explode1.wav');
    explodeSound.volume = 0.9;
    explodeSound2 = new Audio('media/explosion.wav');
    explodeSound2.volume = 0.9;

    wingsSound = new Audio('media/wings.wav');
    wingsSound.volume = 0.9;
    wingsSound.addEventListener('ended', function() { // зациклить воспроизведение звука крыльев
        this.currentTime = 0;
        this.play();
    }, false);
    wingsSound.play();

    // инициализация пустого шара
    var oBallImage = new Image();
    oBallImage.src = 'images/fireball.png';
    oBallImage.onload = function() { }

    // инициализация пустого врага
    var oEnemyImage = new Image();
    oEnemyImage.src = 'images/enemy.png';
    oEnemyImage.onload = function() { }

    // инициализация дракона
    var oDragonImage = new Image();
    oDragonImage.src = 'images/dragon.gif';
    oDragonImage.onload = function() {
        dragon = new Dragon(400, 300, dragonW, dragonH, oDragonImage);
    }

    $('#scene').mousedown(function(e) { //обработчик нажатия клавиши мыши (для перетаскивания)
        var mouseX = e.layerX || 0;
        var mouseY = e.layerY || 0;
        if(e.originalEvent.layerX) { 
            mouseX = e.originalEvent.layerX;
            mouseY = e.originalEvent.layerY;
        }

        bMouseDown = true;

        if (mouseX > dragon.x- dragon.w/2 && mouseX < dragon.x- dragon.w/2 +dragon.w &&
            mouseY > dragon.y- dragon.h/2 && mouseY < dragon.y-dragon.h/2 +dragon.h) {

            dragon.bDrag = true;
            dragon.x = mouseX;
            dragon.y = mouseY;
        }
    });

    $('#scene').mousemove(function(e) { // обработчик движения мыши
        var mouseX = e.layerX || 0;
        var mouseY = e.layerY || 0;
        if(e.originalEvent.layerX) {
            mouseX = e.originalEvent.layerX;
            mouseY = e.originalEvent.layerY;
        }

        // сохранение последних координат
        iLastMouseX = mouseX;
        iLastMouseY = mouseY;

        // перемещение дракона
        if (dragon.bDrag) {
            dragon.x = mouseX;
            dragon.y = mouseY;
        }

        // изменение направления дракона (зависит от положения курсора мыши)
        if (mouseX > dragon.x && Math.abs(mouseY-dragon.y) < dragon.w/2) {
            iSprDir = 0;
        } else if (mouseX < dragon.x && Math.abs(mouseY-dragon.y) < dragon.w/2) {
            iSprDir = 4;
        } else if (mouseY > dragon.y && Math.abs(mouseX-dragon.x) < dragon.h/2) {
            iSprDir = 2;
        } else if (mouseY < dragon.y && Math.abs(mouseX-dragon.x) < dragon.h/2) {
            iSprDir = 6;
        } else if (mouseY < dragon.y && mouseX < dragon.x) {
            iSprDir = 5;
        } else if (mouseY < dragon.y && mouseX > dragon.x) {
            iSprDir = 7;
        } else if (mouseY > dragon.y && mouseX < dragon.x) {
            iSprDir = 3;
        } else if (mouseY > dragon.y && mouseX > dragon.x) {
            iSprDir = 1;
        }
    });

    $('#scene').mouseup(function(e) { // обработчик отжатия мыши
        dragon.bDrag = false;
        bMouseDown = false;

        // воспроизвести звук дракона
        dragonSound.currentTime = 0;
        dragonSound.play();
    });

    $(window).keydown(function(event){ // обработчик нажатия клавиш на клавиатуре
        switch (event.keyCode) {
            case 49: // '1'
                balls.push(new Ball(dragon.x, dragon.y, 32, 32, iBallSpeed, oBallImage));

                // воспроизвести звук взрыва #1
                explodeSound.currentTime = 0;
                explodeSound.play();
                break;
        }
    });

    setInterval(drawScene, 30); // повторение кадров

    // генерировать врагов случайно
    var enTimer = null;
    function addEnemy() {
        clearInterval(enTimer);

        var randY = getRand(0, canvas.height - iEnemyH);
        enemies.push(new Enemy(canvas.width, randY, iEnemyW, iEnemyH, - iEnemySpeed, oEnemyImage));

        var interval = getRand(5000, 10000);
        enTimer = setInterval(addEnemy, interval); // повторение кадров
    }
    addEnemy();
});

В начале я добавил два новых объекта: Ball (огненный шар) и Enemy (враг). Каждый объект имеет свой набор атрибутов (например, положение, размер изображения, скорость). После, я добавил отрисовку шаров и врагов  в функцию «DrawScene». И, наконец, добавление врагов происходит периодически, случайным образом.

Шаг 4. Медиа файлы

images/dragon.gif, images/enemy.png, images/fireball.png, images/hell.jpg

media/dragon.wav, media/explode1.wav, media/explosion.wav, media/laught.wav, media/wings.wav

Всё это можно найти в исходниках.


Demo Исходники

 
 


Итоги

Ну как Вам обновленный вариант игры? :) Я буду рад если Вы оставите комментарии и поделитесь ссылкой с друзьями в соц. сетях. Удачи!


Получайте новые статьи блога прямо себе на почту