{lang: ‘ru’}

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

Мы продолжаем серию статей о создании игр на HTML5 с использованием холста (тег canvas). Сегодня я покажу, как можно добавить немного физики в свой проект (мы будем использовать Box2D). Box2D — это популярный движок с открытым исходным кодом, который позволяет имитировать физические свойства 2D объектов в создаваемых приложениях. Использование физических 2D движков — это важная тема в разработке игр. С помощью физического движка, мы можем с легкостью создать играбельную игру просто определив окружающую среду и задав простые правила. Вы можете ознакомиться с предыдущим уроком здесь: Разработка игр на HTML5 — Урок 7.




Шаг 0. Подготовка

Для начала нужно скачать движок Box2D. Его можно скачать или в исходниках.

Шаг 1. HTML

В главном файле нужно подключить все библиотеки движка

index.html

<!DOCTYPE html>
<html lang="ru" >
    <head>
        <meta charset="utf-8" />
        <title>Разработка игр на HTML5 — Урок 8 | officialplat-tt.ru</title>
        <link href="css/main.css" rel="stylesheet" type="text/css" />

        <script src="js/protoclass.js"></script>
        <script src="js/jquery-1.6.min.js"></script>

        <!-- box2djs -->
        <script src='js/box2d/common/b2Settings.js'></script>
        <script src='js/box2d/common/math/b2Vec2.js'></script>
        <script src='js/box2d/common/math/b2Mat22.js'></script>
        <script src='js/box2d/common/math/b2Math.js'></script>
        <script src='js/box2d/collision/b2AABB.js'></script>
        <script src='js/box2d/collision/b2Bound.js'></script>
        <script src='js/box2d/collision/b2BoundValues.js'></script>
        <script src='js/box2d/collision/b2Pair.js'></script>
        <script src='js/box2d/collision/b2PairCallback.js'></script>
        <script src='js/box2d/collision/b2BufferedPair.js'></script>
        <script src='js/box2d/collision/b2PairManager.js'></script>
        <script src='js/box2d/collision/b2BroadPhase.js'></script>
        <script src='js/box2d/collision/b2Collision.js'></script>
        <script src='js/box2d/collision/Features.js'></script>
        <script src='js/box2d/collision/b2ContactID.js'></script>
        <script src='js/box2d/collision/b2ContactPoint.js'></script>
        <script src='js/box2d/collision/b2Distance.js'></script>
        <script src='js/box2d/collision/b2Manifold.js'></script>
        <script src='js/box2d/collision/b2OBB.js'></script>
        <script src='js/box2d/collision/b2Proxy.js'></script>
        <script src='js/box2d/collision/ClipVertex.js'></script>
        <script src='js/box2d/collision/shapes/b2Shape.js'></script>
        <script src='js/box2d/collision/shapes/b2ShapeDef.js'></script>
        <script src='js/box2d/collision/shapes/b2BoxDef.js'></script>
        <script src='js/box2d/collision/shapes/b2CircleDef.js'></script>
        <script src='js/box2d/collision/shapes/b2CircleShape.js'></script>
        <script src='js/box2d/collision/shapes/b2MassData.js'></script>
        <script src='js/box2d/collision/shapes/b2PolyDef.js'></script>
        <script src='js/box2d/collision/shapes/b2PolyShape.js'></script>
        <script src='js/box2d/dynamics/b2Body.js'></script>
        <script src='js/box2d/dynamics/b2BodyDef.js'></script>
        <script src='js/box2d/dynamics/b2CollisionFilter.js'></script>
        <script src='js/box2d/dynamics/b2Island.js'></script>
        <script src='js/box2d/dynamics/b2TimeStep.js'></script>
        <script src='js/box2d/dynamics/contacts/b2ContactNode.js'></script>
        <script src='js/box2d/dynamics/contacts/b2Contact.js'></script>
        <script src='js/box2d/dynamics/contacts/b2ContactConstraint.js'></script>
        <script src='js/box2d/dynamics/contacts/b2ContactConstraintPoint.js'></script>
        <script src='js/box2d/dynamics/contacts/b2ContactRegister.js'></script>
        <script src='js/box2d/dynamics/contacts/b2ContactSolver.js'></script>
        <script src='js/box2d/dynamics/contacts/b2CircleContact.js'></script>
        <script src='js/box2d/dynamics/contacts/b2Conservative.js'></script>
        <script src='js/box2d/dynamics/contacts/b2NullContact.js'></script>
        <script src='js/box2d/dynamics/contacts/b2PolyAndCircleContact.js'></script>
        <script src='js/box2d/dynamics/contacts/b2PolyContact.js'></script>
        <script src='js/box2d/dynamics/b2ContactManager.js'></script>
        <script src='js/box2d/dynamics/b2World.js'></script>
        <script src='js/box2d/dynamics/b2WorldListener.js'></script>
        <script src='js/box2d/dynamics/joints/b2JointNode.js'></script>
        <script src='js/box2d/dynamics/joints/b2Joint.js'></script>
        <script src='js/box2d/dynamics/joints/b2JointDef.js'></script>
        <script src='js/box2d/dynamics/joints/b2DistanceJoint.js'></script>
        <script src='js/box2d/dynamics/joints/b2DistanceJointDef.js'></script>
        <script src='js/box2d/dynamics/joints/b2Jacobian.js'></script>
        <script src='js/box2d/dynamics/joints/b2GearJoint.js'></script>
        <script src='js/box2d/dynamics/joints/b2GearJointDef.js'></script>
        <script src='js/box2d/dynamics/joints/b2MouseJoint.js'></script>
        <script src='js/box2d/dynamics/joints/b2MouseJointDef.js'></script>
        <script src='js/box2d/dynamics/joints/b2PrismaticJoint.js'></script>
        <script src='js/box2d/dynamics/joints/b2PrismaticJointDef.js'></script>
        <script src='js/box2d/dynamics/joints/b2PulleyJoint.js'></script>
        <script src='js/box2d/dynamics/joints/b2PulleyJointDef.js'></script>
        <script src='js/box2d/dynamics/joints/b2RevoluteJoint.js'></script>
        <script src='js/box2d/dynamics/joints/b2RevoluteJointDef.js'></script>
        <script src="js/script.js"></script>
    </head>
    <body>
        <header>
            <h2>Разработка игр на HTML5 — Урок 8</h2>
            <a href="http://officialplat-tt.ru/?p=1878" class="stuts">Вернуться обратно на <span>officialplat-tt.ru</span></a>
        </header>
        <div class="container">
            <canvas id="game" width="800" height="600"></canvas>
        </div>
    </body>
</html>

Шаг 2. CSS

css/main.css

В этот раз я не публикую CSS стили, так как там только макет страницы. Файл стилей находится в исходниках.

Шаг 3. JS

js/jquery-1.6.min.js and js/protoclass.js

Обе библиотеки есть в исходниках. Следующий файл самый главный — там находится весь основной код нашей игры:

js/script.js

var canvas, ctx;
var canvasWidth;
var canvasHeight;
var world;
var iBorder = 5;

// получить случайное число в диапазоне между X и Y
function getRand(x, y) {
    return Math.floor(Math.random()*y)+x;
}

$(function() {
    // создать мир
    world = createWorld();

    // получаем канвас и контекст отрисовки
    canvas = document.getElementById('game');
    ctx = canvas.getContext('2d');
    canvasWidth = parseInt(canvas.width);
    canvasHeight = parseInt(canvas.height);

    // создать основание
    createGround(canvasWidth / 2, canvasHeight - iBorder, canvasWidth / 2, iBorder, 0);
    createGround(iBorder, canvasHeight / 2, iBorder, canvasHeight / 2, 0); // left border
    createGround(canvasWidth - iBorder, canvasHeight / 2, iBorder, canvasHeight / 2, 0); // right border

    // добавить первый случайный объект
    addObjects();

    // отрисовать фрейм
    frame();
});

// добавить случайные объекты
function addObjects() {
    var iVar = getRand(1, 2);

    if (iVar == 1) {
        var x = getRand(100, 600);
        var y = 0;
        var r = getRand(10, 40);
        createCircleAt(x, y, r);
    } else if (iVar == 2) {
        var x = getRand(100, 600);
        var y = 0;
        var w = getRand(5, 40);
        var h = getRand(5, 40);
        createBoxAt(x, y, w, h);
    }

    // задать таймер
    setTimeout(addObjects, 500);
}

// отрисовать фрейм
function frame() {
    world.Step(1.0 / 60, 1);
    ctx.clearRect(0, 0, canvasWidth, canvasHeight);

    // отрисовать мир
    drawWorld(world, ctx);

    // задать таймер
    setTimeout(frame, 10);
}

// создать мир
function createWorld() {

    // задать размер мира
    var worldAABB = new b2AABB();
    worldAABB.minVertex.Set(-1000, -1000);
    worldAABB.maxVertex.Set(1000, 1000);

    // установить силу тяжести
    var gravity = new b2Vec2(0, 200);

    // игнорировать неактивные объекты
    var doSleep = false;

    // создать мир с заданными параметрами
    return new b2World(worldAABB, gravity, doSleep);
}

// создать основание (объект прямоугольной формы)
function createGround(x, y, width, height, rotation) {
    // определение границ фигуры
    var groundSd = new b2BoxDef();
    groundSd.extents.Set(width, height);
    groundSd.restitution = 0.4;

    var groundBd = new b2BodyDef();
    groundBd.AddShape(groundSd);
    groundBd.position.Set(x, y);
    groundBd.rotation = rotation * Math.PI / 180;
    return world.CreateBody(groundBd);
}

// создать прямоугольник
function createBoxAt(x, y, w, h) {
    var boxSd = new b2BoxDef();
    boxSd.density = 1.0;
    boxSd.friction = 1.0;
    boxSd.restitution = .5;
    boxSd.extents.Set(w, h);

    // добавить в мир как фигуру
    var boxBd = new b2BodyDef();
    boxBd.AddShape(boxSd);
    boxBd.position.Set(x,y);
    return world.CreateBody(boxBd);
}

// создать окружность
function createCircleAt(x, y, r) {
    var boxSd = new b2CircleDef();
    boxSd.density = 1.0;
    boxSd.friction = 1.0;
    boxSd.restitution = .5;
    boxSd.radius = r;

    // добавить в мир как фигуру
    var boxBd = new b2BodyDef();
    boxBd.AddShape(boxSd);
    boxBd.position.Set(x,y);
    return world.CreateBody(boxBd);
}

// отрисовка мира
function drawWorld(world, context) {
    for (var b = world.m_bodyList; b != null; b = b.m_next) {
        for (var s = b.GetShapeList(); s != null; s = s.GetNext()) {
            drawShape(s, context);
        }
    }
}

// отрисовка фигуры
function drawShape(shape, context) {
    context.strokeStyle = '#0000ff';
    context.fillStyle = 'rgba(100, 100, 255, 0.8)';
    context.beginPath();

    switch (shape.m_type) {
        case b2Shape.e_circleShape:
            var circle = shape;
            var pos = circle.m_position;
            var r = circle.m_radius;
            var segments = 16.0;
            var theta = 0.0;
            var dtheta = 2.0 * Math.PI / segments;
            context.moveTo(pos.x + r, pos.y);
            for (var i = 0; i < segments; i++) {
                var d = new b2Vec2(r * Math.cos(theta), r * Math.sin(theta));
                var v = b2Math.AddVV(pos, d);
                context.lineTo(v.x, v.y);
                theta += dtheta;
            }
            context.lineTo(pos.x + r, pos.y);
            context.moveTo(pos.x, pos.y);
            var ax = circle.m_R.col1;
            var pos2 = new b2Vec2(pos.x + r * ax.x, pos.y + r * ax.y);
            context.lineTo(pos2.x, pos2.y);
            break;
        case b2Shape.e_polyShape:
            var poly = shape;
            var tV = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[0]));
            context.moveTo(tV.x, tV.y);
            for (var i = 0; i < poly.m_vertexCount; i++) {
                var v = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[i]));
                context.lineTo(v.x, v.y);
            }
            context.lineTo(tV.x, tV.y);
            break;
    }
    context.fill();
    context.stroke();
}

Я оставил комментарии в коде, надеюсь, что весь этот код достаточно понятен.




Итоги

В этот раз мы ознакомились с физическим движком Box2D, с помощью которого можно создавать хорошие и качественные игры. Я буду рад, если Вы поделитесь ссылкой на этот урок с друзьями и оставите свои комментарии. Удачи в работе! :)

 


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