Уроки 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, с помощью которого можно создавать хорошие и качественные игры. Я буду рад, если Вы поделитесь ссылкой на этот урок с друзьями и оставите свои комментарии. Удачи в работе!
Получайте новые статьи блога прямо себе на почту
Интересная тематика сайта, но только для тех, кто знаком с программированием.
А как отследить столкновение например шарика с квадратом и при этом чтоб квадрат удалялся?