Build your First Game with HTML5

C++ 3D游戏开发:构建高质量项目文档的架构与工程实践 在软件工程中,项目文档是团队协作与知识传承的核心基础设施,它系统化地记录了技术决策、设计原理与实现细节。其核心价值在于降低沟通成本、保障代码可维护性,并能有效应对人员流动带来的知识断层。从技术原理看,文档体系需遵循分层架构思想,涵盖战略愿景、模块设计、接口规范及部署流程,从而形成贯穿开发周期的“活地图”。在C++ 3D游戏开发领域,文档尤其需要聚焦于渲染管线、资源生命周期及实体组件系统(ECS)等复杂模块的清晰描述,并结合现代工具链(如Markdown、Doxygen)实现与代码的同步演进。通过将文档纳入版 阅读详情

某位有爱同学提供的这篇文章,很好的启蒙教程,我都在看呢

原文:http://net.tutsplus.com/tutorials/html-css-techniques/build-your-first-game-with-html5/


Build your First Game with HTML5

Tutorial Details
  • Technologies Used: HTML5, JS, CSS
  • Difficulty: Intermediate
  • Estimated Completion Time: 45-60 minutes

Final Product What You'll Be Creating

HTML5 is growing up faster than anyone could have imagined. Powerful and professional solutions are already being developed…even in the gaming world! Today, you’ll make your first game using Box2D and HTML5′s canvas tag.


What is Box2D?

Box2D is an open source and popular engine that simulates 2D physics for making games and applications. Primarily written in C++, it has been converted to numerous languages by community contributors.

With the same methods and objects, you have the ability to make your games’ physics in many languages, such as Objective C (iPhone/iPad), Actionscript 3.0 (Web), HTML 5 (Web), etc.


Step 1 - Setting up your Project

To begin developing your demo, download the Box2D engine for HTML5 here. Next, create a new HTML file with the following structure (copy js and lib directories from box2d-js project to your game folder).

Now, you must insert the necessary files to run box2D into your HTML file:

  1. <!--[if IE]><script src="lib/excanvas.js"></script><![endif]-->  
  2.  <script src="lib/prototype-1.6.0.2.js"></script>  
  3. <!-- box2djs -->  
  4.  <script src='js/box2d/common/b2Settings.js'></script>  
  5.  <script src='js/box2d/common/math/b2Vec2.js'></script>  
  6.  <script src='js/box2d/common/math/b2Mat22.js'></script>  
  7.  <script src='js/box2d/common/math/b2Math.js'></script>  
  8.  <script src='js/box2d/collision/b2AABB.js'></script>  
  9.  <script src='js/box2d/collision/b2Bound.js'></script>  
  10.  <script src='js/box2d/collision/b2BoundValues.js'></script>  
  11.  <script src='js/box2d/collision/b2Pair.js'></script>  
  12.  <script src='js/box2d/collision/b2PairCallback.js'></script>  
  13.  <script src='js/box2d/collision/b2BufferedPair.js'></script>  
  14.  <script src='js/box2d/collision/b2PairManager.js'></script>  
  15.  <script src='js/box2d/collision/b2BroadPhase.js'></script>  
  16.  <script src='js/box2d/collision/b2Collision.js'></script>  
  17.  <script src='js/box2d/collision/Features.js'></script>  
  18.  <script src='js/box2d/collision/b2ContactID.js'></script>  
  19.  <script src='js/box2d/collision/b2ContactPoint.js'></script>  
  20.  <script src='js/box2d/collision/b2Distance.js'></script>  
  21.  <script src='js/box2d/collision/b2Manifold.js'></script>  
  22.  <script src='js/box2d/collision/b2OBB.js'></script>  
  23.  <script src='js/box2d/collision/b2Proxy.js'></script>  
  24.  <script src='js/box2d/collision/ClipVertex.js'></script>  
  25.  <script src='js/box2d/collision/shapes/b2Shape.js'></script>  
  26.  <script src='js/box2d/collision/shapes/b2ShapeDef.js'></script>  
  27.  <script src='js/box2d/collision/shapes/b2BoxDef.js'></script>  
  28.  <script src='js/box2d/collision/shapes/b2CircleDef.js'></script>  
  29.  <script src='js/box2d/collision/shapes/b2CircleShape.js'></script>  
  30.  <script src='js/box2d/collision/shapes/b2MassData.js'></script>  
  31.  <script src='js/box2d/collision/shapes/b2PolyDef.js'></script>  
  32.  <script src='js/box2d/collision/shapes/b2PolyShape.js'></script>  
  33.  <script src='js/box2d/dynamics/b2Body.js'></script>  
  34.  <script src='js/box2d/dynamics/b2BodyDef.js'></script>  
  35.  <script src='js/box2d/dynamics/b2CollisionFilter.js'></script>  
  36.  <script src='js/box2d/dynamics/b2Island.js'></script>  
  37.  <script src='js/box2d/dynamics/b2TimeStep.js'></script>  
  38.  <script src='js/box2d/dynamics/contacts/b2ContactNode.js'></script>  
  39.  <script src='js/box2d/dynamics/contacts/b2Contact.js'></script>  
  40.  <script src='js/box2d/dynamics/contacts/b2ContactConstraint.js'></script>  
  41.  <script src='js/box2d/dynamics/contacts/b2ContactConstraintPoint.js'></script>  
  42.  <script src='js/box2d/dynamics/contacts/b2ContactRegister.js'></script>  
  43.  <script src='js/box2d/dynamics/contacts/b2ContactSolver.js'></script>  
  44.  <script src='js/box2d/dynamics/contacts/b2CircleContact.js'></script>  
  45.  <script src='js/box2d/dynamics/contacts/b2Conservative.js'></script>  
  46.  <script src='js/box2d/dynamics/contacts/b2NullContact.js'></script>  
  47.  <script src='js/box2d/dynamics/contacts/b2PolyAndCircleContact.js'></script>  
  48.  <script src='js/box2d/dynamics/contacts/b2PolyContact.js'></script>  
  49.  <script src='js/box2d/dynamics/b2ContactManager.js'></script>  
  50.  <script src='js/box2d/dynamics/b2World.js'></script>  
  51.  <script src='js/box2d/dynamics/b2WorldListener.js'></script>  
  52.  <script src='js/box2d/dynamics/joints/b2JointNode.js'></script>  
  53.  <script src='js/box2d/dynamics/joints/b2Joint.js'></script>  
  54.  <script src='js/box2d/dynamics/joints/b2JointDef.js'></script>  
  55.  <script src='js/box2d/dynamics/joints/b2DistanceJoint.js'></script>  
  56.  <script src='js/box2d/dynamics/joints/b2DistanceJointDef.js'></script>  
  57.  <script src='js/box2d/dynamics/joints/b2Jacobian.js'></script>  
  58.  <script src='js/box2d/dynamics/joints/b2GearJoint.js'></script>  
  59.  <script src='js/box2d/dynamics/joints/b2GearJointDef.js'></script>  
  60.  <script src='js/box2d/dynamics/joints/b2MouseJoint.js'></script>  
  61.  <script src='js/box2d/dynamics/joints/b2MouseJointDef.js'></script>  
  62.  <script src='js/box2d/dynamics/joints/b2PrismaticJoint.js'></script>  
  63.  <script src='js/box2d/dynamics/joints/b2PrismaticJointDef.js'></script>  
  64.  <script src='js/box2d/dynamics/joints/b2PulleyJoint.js'></script>  
  65.  <script src='js/box2d/dynamics/joints/b2PulleyJointDef.js'></script>  
  66.  <script src='js/box2d/dynamics/joints/b2RevoluteJoint.js'></script>  
  67.  <script src='js/box2d/dynamics/joints/b2RevoluteJointDef.js'></script>  

Yep, that’s a huge number of HTTP requests!

Please note that, for deployment, it’s highly recommended that you concatenate all of these resources into one script file.

Next, create two more scripts inside the /js/ folder, called "box2dutils.js" and "game.js".

  • box2dutils.js – it’s a copy and paste from some demos that come with box2dlib, and is important for drawing functions (I will also explain some important parts here).
  • game.js – the game, itself; this is where we create the platforms, the player, apply the keyboard interactions, etc.

Copy and paste the following code into box2dutils.js. Don’t worry! I’ll explain it bit by bit!

  1. function drawWorld(world, context) {  
  2.     for (var j = world.m_jointList; j; j = j.m_next) {  
  3.         drawJoint(j, context);  
  4.     }  
  5.     for (var b = world.m_bodyList; b; b = b.m_next) {  
  6.         for (var s = b.GetShapeList(); s != null; s = s.GetNext()) {  
  7.             drawShape(s, context);  
  8.         }  
  9.     }  
  10. }  
  11. function drawJoint(joint, context) {  
  12.     var b1 = joint.m_body1;  
  13.     var b2 = joint.m_body2;  
  14.     var x1 = b1.m_position;  
  15.     var x2 = b2.m_position;  
  16.     var p1 = joint.GetAnchor1();  
  17.     var p2 = joint.GetAnchor2();  
  18.     context.strokeStyle = '#00eeee';  
  19.     context.beginPath();  
  20.     switch (joint.m_type) {  
  21.     case b2Joint.e_distanceJoint:  
  22.         context.moveTo(p1.x, p1.y);  
  23.         context.lineTo(p2.x, p2.y);  
  24.         break;  
  25.   
  26.     case b2Joint.e_pulleyJoint:  
  27.         // TODO  
  28.         break;  
  29.   
  30.     default:  
  31.         if (b1 == world.m_groundBody) {  
  32.             context.moveTo(p1.x, p1.y);  
  33.             context.lineTo(x2.x, x2.y);  
  34.         }  
  35.         else if (b2 == world.m_groundBody) {  
  36.             context.moveTo(p1.x, p1.y);  
  37.             context.lineTo(x1.x, x1.y);  
  38.         }  
  39.         else {  
  40.             context.moveTo(x1.x, x1.y);  
  41.             context.lineTo(p1.x, p1.y);  
  42.             context.lineTo(x2.x, x2.y);  
  43.             context.lineTo(p2.x, p2.y);  
  44.         }  
  45.         break;  
  46.     }  
  47.     context.stroke();  
  48. }  
  49. function drawShape(shape, context) {  
  50.     context.strokeStyle = '#000000';  
  51.     context.beginPath();  
  52.     switch (shape.m_type) {  
  53.     case b2Shape.e_circleShape:  
  54.         {  
  55.             var circle = shape;  
  56.             var pos = circle.m_position;  
  57.             var r = circle.m_radius;  
  58.             var segments = 16.0;  
  59.             var theta = 0.0;  
  60.             var dtheta = 2.0 * Math.PI / segments;  
  61.             // draw circle  
  62.             context.moveTo(pos.x + r, pos.y);  
  63.             for (var i = 0; i < segments; i++) {  
  64.                 var d = new b2Vec2(r * Math.cos(theta), r * Math.sin(theta));  
  65.                 var v = b2Math.AddVV(pos, d);  
  66.                 context.lineTo(v.x, v.y);  
  67.                 theta += dtheta;  
  68.             }  
  69.             context.lineTo(pos.x + r, pos.y);  
  70.   
  71.             // draw radius  
  72.             context.moveTo(pos.x, pos.y);  
  73.             var ax = circle.m_R.col1;  
  74.             var pos2 = new b2Vec2(pos.x + r * ax.x, pos.y + r * ax.y);  
  75.             context.lineTo(pos2.x, pos2.y);  
  76.         }  
  77.         break;  
  78.     case b2Shape.e_polyShape:  
  79.         {  
  80.             var poly = shape;  
  81.             var tV = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[0]));  
  82.             context.moveTo(tV.x, tV.y);  
  83.             for (var i = 0; i < poly.m_vertexCount; i++) {  
  84.                 var v = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[i]));  
  85.                 context.lineTo(v.x, v.y);  
  86.             }  
  87.             context.lineTo(tV.x, tV.y);  
  88.         }  
  89.         break;  
  90.     }  
  91.     context.stroke();  
  92. }  
  93.   
  94. function createWorld() {  
  95.     var worldAABB = new b2AABB();  
  96.     worldAABB.minVertex.Set(-1000, -1000);  
  97.     worldAABB.maxVertex.Set(1000, 1000);  
  98.     var gravity = new b2Vec2(0, 300);  
  99.     var doSleep = true;  
  100.     var world = new b2World(worldAABB, gravity, doSleep);  
  101.     return world;  
  102. }  
  103.   
  104. function createGround(world) {  
  105.     var groundSd = new b2BoxDef();  
  106.     groundSd.extents.Set(1000, 50);  
  107.     groundSd.restitution = 0.2;  
  108.     var groundBd = new b2BodyDef();  
  109.     groundBd.AddShape(groundSd);  
  110.     groundBd.position.Set(-500, 340);  
  111.     return world.CreateBody(groundBd)  
  112. }  
  113.   
  114. function createBall(world, x, y) {  
  115.     var ballSd = new b2CircleDef();  
  116.     ballSd.density = 1.0;  
  117.     ballSd.radius = 20;  
  118.     ballSd.restitution = 1.0;  
  119.     ballSd.friction = 0;  
  120.     var ballBd = new b2BodyDef();  
  121.     ballBd.AddShape(ballSd);  
  122.     ballBd.position.Set(x,y);  
  123.     return world.CreateBody(ballBd);  
  124. }  
  125.   
  126. function createBox(world, x, y, width, height, fixed, userData) {  
  127.     if (typeof(fixed) == 'undefined') fixed = true;  
  128.     var boxSd = new b2BoxDef();  
  129.     if (!fixed) boxSd.density = 1.0;  
  130.   
  131.     boxSd.userData = userData;  
  132.   
  133.     boxSd.extents.Set(width, height);  
  134.     var boxBd = new b2BodyDef();  
  135.     boxBd.AddShape(boxSd);  
  136.     boxBd.position.Set(x,y);  
  137.     return world.CreateBody(boxBd)  
  138. }  

Step 2 - Developing the Game

Open the index.html file that you previously created, and add a canvas element (600x400) within thebody element. This is where we'll work with the HTML5 drawing API:

  1. <canvas id="game" width="600" height="400"></canvas>  

Also, while you're here, reference game.js and box2dutils.js.

  1. <script src='js/box2dutils.js'></script>  
  2. <script src='js/game.js'></script>  

That'll do it for the HTML! Let's work on the fun JavaScript now!

Open game.js, and insert the code below:

  1. // some variables that we gonna use in this demo  
  2. var initId = 0;  
  3. var player = function(){  
  4.     this.object = null;  
  5.     this.canJump = false;  
  6. };  
  7. var world;  
  8. var ctx;  
  9. var canvasWidth;  
  10. var canvasHeight;  
  11. var keys = [];  
  12.   
  13. // HTML5 onLoad event  
  14. Event.observe(window, 'load', function() {  
  15.     world = createWorld(); // box2DWorld  
  16.     ctx = $('game').getContext('2d'); // 2  
  17.     var canvasElm = $('game');  
  18.     canvasWidth = parseInt(canvasElm.width);  
  19.     canvasHeight = parseInt(canvasElm.height);  
  20.     initGame(); // 3  
  21.     step(); // 4  
  22.   
  23. // 5  
  24.     window.addEventListener('keydown',handleKeyDown,true);  
  25.     window.addEventListener('keyup',handleKeyUp,true);  
  26. });  

Box2DWorld - that's why we're here

Okay, let's figure out what this chunk of code does!

Box2DWorld is one of the classes that is made available, via the core of box2d. Its function is simple: combine everything into one class. In box2DWorld, you have the bodies definition and collisions manager of your game or application.

Keep the game.js and box2dutils.js files open, and search for the createWorld() function withinbox2dutils.js.

  1. function createWorld() {  
  2.     // here we create our world settings for collisions  
  3.     var worldAABB = new b2AABB();  
  4.     worldAABB.minVertex.Set(-1000, -1000);  
  5.     worldAABB.maxVertex.Set(1000, 1000);  
  6.     // set gravity vector  
  7.     var gravity = new b2Vec2(0, 300);  
  8.     var doSleep = true;  
  9.     // init our world and return its value  
  10.     var world = new b2World(worldAABB, gravity, doSleep);  
  11.     return world;  
  12. }  

It's quite simple to create the box2DWorld.


Back to game.js

Refer to the commented numbers in the two blocks of code above. On number two, we retrieve the canvaselement's context by using the selector API (looks like jQuery or MooTools selectors, don't they?). On number three, we have a new interesting function: initGame(). This is where we create the scenery.

Copy and paste the code below into game.js, and then we'll review it together.

  1. function initGame(){  
  2.     // create 2 big platforms  
  3.     createBox(world, 3, 230, 60, 180, true, 'ground');  
  4.     createBox(world, 560, 360, 50, 50, true, 'ground');  
  5.   
  6.     // create small platforms  
  7.     for (var i = 0; i < 5; i++){  
  8.         createBox(world, 150+(80*i), 360, 5, 40+(i*15), true, 'ground');  
  9.     }  
  10.   
  11.     // create player ball  
  12.     var ballSd = new b2CircleDef();  
  13.     ballSd.density = 0.1;  
  14.     ballSd.radius = 12;  
  15.     ballSd.restitution = 0.5;  
  16.     ballSd.friction = 1;  
  17.     ballSd.userData = 'player';  
  18.     var ballBd = new b2BodyDef();  
  19.     ballBd.linearDamping = .03;  
  20.     ballBd.allowSleep = false;  
  21.     ballBd.AddShape(ballSd);  
  22.     ballBd.position.Set(20,0);  
  23.     player.object = world.CreateBody(ballBd);  
  24.   
  25. }  
  26.   
  27.  Inside <code>box2dutils.js</code>, we've created a function, called <code>createBox</code>. This creates a static rectangle body.  
  28.  
  29. function createBox(world, x, y, width, height, fixed, userData) { 
  30.     if (typeof(fixed) == 'undefined') fixed = true;  
  31.     //1  
  32. var boxSd = new b2BoxDef();  
  33.     if (!fixed) boxSd.density = 1.0;  
  34.     //2  
  35.     boxSd.userData = userData;  
  36.     //3  
  37.     boxSd.extents.Set(width, height);  
  38.   
  39.     //4  
  40.     var boxBd = new b2BodyDef();  
  41.     boxBd.AddShape(boxSd);  
  42.     //5  
  43.     boxBd.position.Set(x,y);  
  44.     //6  
  45.     return world.CreateBody(boxBd)  
  46. }  

Box2DBody

A Box2DBody has some unique characteristics:

  • It can be static (not affected by collisions impacts), kinematic (it isn't affected by collisions, but it can be moved by your mouse, for example), or dynamic (interacts with everything)
  • Must have a shape definition, and should indicate how the object appears
  • May have more than one fixture, which indicates how the object will interact with collisions
  • Its position is set by the center of your object, not the left top edge as many other engines do.
Reviewing the code:
  1. Here, we create one shape definition that will be a square or rectangle, and setup its density (how often it gonna be moved, or rotate by forces).
  2. We setup the userData, usually you setup graphics objects here, but in this example, I just setup strings that will be the identifier of the type of the object for collisions. This parameter doesn't affect physics algorithms.
  3. Setup half of the size of my box (it's a line from the position point, or the center point of the object to a corner)
  4. We create the body definition, and add to it the box shape definition.
  5. Setup the position.
  6. Create the body in the world and return its value.

Creating the Player Ball Body

I've coded the player (ball) directly in the game.js file. It follows the same sequence of creating boxes, but, this time, it's a ball.

  1. var ballSd = new b2CircleDef();  
  2.     ballSd.density = 0.1;  
  3.     ballSd.radius = 12;  
  4.     ballSd.restitution = 0.5;  
  5.     ballSd.friction = 1;  
  6.     ballSd.userData = 'player';  
  7.     var ballBd = new b2BodyDef();  
  8.     ballBd.linearDamping = .03;  
  9.     ballBd.allowSleep = false;  
  10.     ballBd.AddShape(ballSd);  
  11.     ballBd.position.Set(20,0);  
  12.     player.object = world.CreateBody(ballBd);  

So how do we create a body, step by step?

  1. Create the shape, fixture and sensor definition
  2. Create the body definition
  3. Add into the body your shape, fixtures or sensors (not explained in this article)
  4. Create the body in the world

Box2DCircle

As I noted earlier, this follows the same creation process of a box, but now you must set some new parameters.

  • radius - This is the length of a line from the center of the circle to any point on its edge.
  • restitution - How the ball will lose, or gain force when collides with other body.
  • friction - How the ball will roll.

Box2DBody - More Properties

  • damping is used to reduce the velocity of the body - there's angular damping and linear damping.
  • sleep in box2D, bodies can sleep to solve performance issues. For example, let's suppose you are developing a platform game, and the level is defined by a 6000x400 screen. Why do you need to perform physics for objects that are off screen? You don't; that's the point! So the correct choice is to put them to sleep, and improve your game's performance.

We've already created our world; you can test the code that you have so far. You'll see the player falling above the west platform.

Now, if you tried to run the demo, you should be wondering, why is the page as barren as white paper?

Always remember: Box2D doesn't render; it only calculates physics.


Step 3 - Rendering Time

Next, let's render the box2DWorld.

Open your game.js script, and add the following code:

  1. function step() {  
  2.   
  3.     var stepping = false;  
  4.     var timeStep = 1.0/60;  
  5.     var iteration = 1;  
  6.     // 1  
  7.     world.Step(timeStep, iteration);  
  8.     // 2  
  9.     ctx.clearRect(0, 0, canvasWidth, canvasHeight);  
  10.     drawWorld(world, ctx);  
  11.     // 3  
  12.     setTimeout('step()', 10);  
  13. }  
What we accomplish here:
  1. Instructed box2dWorld to perform physics simulations
  2. Cleared canvas screen and draw again
  3. Execute the step() function again in ten milliseconds

With this bit of code, we are now working with physics and drawing. You can test yourself, and watch for a falling ball, as demonstrated below:


drawWorld in box2dutils.js

  1. function drawWorld(world, context) {  
  2.     for (var j = world.m_jointList; j; j = j.m_next) {  
  3.         drawJoint(j, context);  
  4.     }  
  5.     for (var b = world.m_bodyList; b; b = b.m_next) {  
  6.         for (var s = b.GetShapeList(); s != null; s = s.GetNext()) {  
  7.             drawShape(s, context);  
  8.         }  
  9.     }  
  10. }  

What we've written above is a debug function that draws our world into the canvas, using the graphics API provided by HTML5's Canvas API.

The first loop draws all joints. We didn't use joints in this article. They are a bit complex for a first demo, but, nonetheless, they're essential for your games. They allow you to create very interesting bodies.

The second loop draws all bodies, which is why we're here!

  1. function drawShape(shape, context) {  
  2.     context.strokeStyle = '#000000';  
  3.     context.beginPath();  
  4.     switch (shape.m_type) {  
  5.     case b2Shape.e_circleShape:  
  6.         {  
  7.             var circle = shape;  
  8.             var pos = circle.m_position;  
  9.             var r = circle.m_radius;  
  10.             var segments = 16.0;  
  11.             var theta = 0.0;  
  12.             var dtheta = 2.0 * Math.PI / segments;  
  13.             // draw circle  
  14.             context.moveTo(pos.x + r, pos.y);  
  15.             for (var i = 0; i < segments; i++) {  
  16.                 var d = new b2Vec2(r * Math.cos(theta), r * Math.sin(theta));  
  17.                 var v = b2Math.AddVV(pos, d);  
  18.                 context.lineTo(v.x, v.y);  
  19.                 theta += dtheta;  
  20.             }  
  21.             context.lineTo(pos.x + r, pos.y);  
  22.   
  23.             // draw radius  
  24.             context.moveTo(pos.x, pos.y);  
  25.             var ax = circle.m_R.col1;  
  26.             var pos2 = new b2Vec2(pos.x + r * ax.x, pos.y + r * ax.y);  
  27.             context.lineTo(pos2.x, pos2.y);  
  28.         }  
  29.         break;  
  30.     case b2Shape.e_polyShape:  
  31.         {  
  32.             var poly = shape;  
  33.             var tV = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[0]));  
  34.             context.moveTo(tV.x, tV.y);  
  35.             for (var i = 0; i < poly.m_vertexCount; i++) {  
  36.                 var v = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[i]));  
  37.                 context.lineTo(v.x, v.y);  
  38.             }  
  39.             context.lineTo(tV.x, tV.y);  
  40.         }  
  41.         break;  
  42.     }  
  43.     context.stroke();  
  44. }  

We're looping through every vertices of the object and drawing it with lines (context.moveTo andcontext.lineTo). Now, it's useful to have an example... but not so useful in practice. When you use graphics, you only need to pay attention to the bodies' positioning. You don't need to loop vertices, as this demo does.


Step 4 - Interactivity

A game without interactivity is a movie, and a movie with interactivity is a game.

Let's develop the keyboard arrow functionality to jump and move the ball.

Add the following code to your game.js file:

  1. function handleKeyDown(evt){  
  2.     keys[evt.keyCode] = true;  
  3. }  
  4.   
  5. function handleKeyUp(evt){  
  6.     keys[evt.keyCode] = false;  
  7. }  
  8.   
  9. // disable vertical scrolling from arrows :)  
  10. document.οnkeydοwn=function(){return event.keyCode!=38 && event.keyCode!=40}  

With handleKeyDown and handleKeyUp, we setup an array which tracks every key the user types. Withdocument.onkeydown, we disable the browser's native vertical scrolling function for up and down arrows. Have you ever played an HTML5 game, and when you jump, the player, enemies and objects go off screen? That won't be an issue now.

Add this next bit of code to the beginning of your step() function:

  1. handleInteractions();  

And outside, declare the function:

  1. function handleInteractions(){  
  2.     // up arrow  
  3.     // 1  
  4.     var collision = world.m_contactList;  
  5.     player.canJump = false;  
  6.     if (collision != null){  
  7.         if (collision.GetShape1().GetUserData() == 'player' || collision.GetShape2().GetUserData() == 'player'){  
  8.             if ((collision.GetShape1().GetUserData() == 'ground' || collision.GetShape2().GetUserData() == 'ground')){  
  9.                 var playerObj = (collision.GetShape1().GetUserData() == 'player' ? collision.GetShape1().GetPosition() :  collision.GetShape2().GetPosition());  
  10.                 var groundObj = (collision.GetShape1().GetUserData() == 'ground' ? collision.GetShape1().GetPosition() :  collision.GetShape2().GetPosition());  
  11.                 if (playerObj.y < groundObj.y){  
  12.                     player.canJump = true;  
  13.                 }  
  14.             }  
  15.         }  
  16.     }  
  17.     // 2  
  18.     var vel = player.object.GetLinearVelocity();  
  19.     // 3  
  20.     if (keys[38] && player.canJump){  
  21.         vel.y = -150;  
  22.     }  
  23.   
  24.     // 4  
  25.     // left/right arrows  
  26.     if (keys[37]){  
  27.         vel.x = -60;  
  28.     }  
  29.     else if (keys[39]){  
  30.         vel.x = 60;  
  31.     }  
  32.   
  33.     // 5  
  34.     player.object.SetLinearVelocity(vel);  
  35. }  

The most complicated piece of the code above is the first one, where we check for a collision, and write some conditions to determine if the shape1 or the shape2 is the player. If it is, we verify if shape1 orshape2 is a ground object. Again, if so, the player is colliding with the ground. Next, we check if the player is above the ground. If that's the case, then the player can jump.

On the second commented line (2), we retrieve the LinearVelocity of the player.

The third and forth commented regions verify if arrows are being pressed, and adjust the velocity vector, accordingly.

In the fifth region, we setup the player with the new velocity vector.

The interactions are now done! But there's no objective, We just jump, jump, jump… and jump!


Step 5 - "You Win" Message

Add the code below to the beginning of your LinearVelocity function:

  1. if (player.object.GetCenterPosition().y > canvasHeight){  
  2.     player.object.SetCenterPosition(new b2Vec2(20,0),0)  
  3. }  
  4. else if (player.object.GetCenterPosition().x > canvasWidth-50){  
  5.     showWin();  
  6.     return;  
  7. }  
  • The first condition determines if the player falls, and should be transported back to the start point (above the west platform).
  • The second condition checks if the player is above the second platform, and won the game. Here's the showWin() function.
  1. function showWin(){  
  2.     ctx.fillStyle    = '#000';  
  3.     ctx.font         = '30px verdana';  
  4.     ctx.textBaseline = 'top';  
  5.     ctx.fillText('Ye! you made it!', 30, 0);  
  6.     ctx.fillText('thank you, andersonferminiano.com', 30, 30);  
  7.     ctx.fillText('@andferminiano', 30, 60);  
  8. }  

And that's it! You've just completed your first simple game with HTML5 and Box2D. Congratulations!


本地搭建Claude Code AI游戏开发中枢:Node.js+Git+PowerShell环境实战 AI智能体开发并非简单安装工具,而是构建可编程、可扩展的AI原生工作流。其底层依赖Node.js运行时、Git版本控制与上下文感知、PowerShell跨平台命令自动化,以及精细化管理的环境变量体系。这些技术共同支撑AI Agent完成需求解析、代码生成、测试验证与Git提交的全链路闭环。尤其在Unity游戏开发中,Claude Code通过Agent SDK实现自然语言到C#脚本与单元测试的端到端转化,显著降低重复配置成本,提升创意落地效率。本文聚焦claudecode与Node.js协同实践,提供Win 阅读详情

相关推荐

Google Play接入与Firebase参数耦合实战指南

Android应用上架Google Play本质是建立一套跨平台、多组件的身份信任链,其核心在于包名、签名证书SHA-1、Firebase应用ID等关键参数的严格一致性。这些参数贯穿编译期(Keystore)、配置期(Play Console/Firebase控制台)与运行期(google-services.json、AndroidManifest.xml),任一环节错位都会导致登录失败、推送丢失、数据打点归零等静默故障。尤其在Unity等跨引擎项目中,本地构建参数与云端服务配置的割裂极易引发‘出参’失效—

3617

Gemini 3.5 Flash:小模型驱动Agent落地的工程革命

大型语言模型(LLM)正从单点推理范式转向可编排、可验证的智能体(Agent)架构。其核心原理在于将‘智能’解耦为原子化、可监控的执行单元,通过运行时环境(如Antigravity)实现任务调度与状态管理。这种设计显著提升长流程可靠性、降低首token延迟,并支持按需计算的多模态理解,从而在真实业务场景中实现高成功率、低失败率与确定性交付。尤其在跨工具协同、多文档分析、自动化代码生成等典型Agent任务中,Gemini 3.5 Flash展现出远超传统LLM的工程适配性与生产就绪度,成为企业级AI应用落地的

weixin_34414650的博客 546

Unity微信小游戏视频黑屏问题全解析:从编码规范到平台适配的完整解决方案

视频播放是多媒体应用和游戏开发中的基础功能,其核心原理涉及视频文件的编码、解码与渲染管线。在跨平台开发中,不同运行环境对视频编解码器的支持存在差异,这直接影响了播放的兼容性与稳定性。对于追求高性能与流畅体验的工程实践而言,解决平台特定的视频播放问题具有重要价值,尤其是在微信小游戏这类定制化运行时环境中。本文将聚焦于Unity引擎在微信小游戏平台遇到的典型“视频黑屏”问题,深入剖析其根源在于平台运行时环境差异与视频编码规范不匹配。解决方案涵盖从视频源文件的标准化预处理(如强制使用H.264 Baseline

weixin_30621959的博客 391

COCOSCreator解决:导出WebMobile 出现Please load bundle xxx first Error: Please load bundle xxx first

导致这个原因是 项目中的自定义bundle的优先级和系统内置的优先级一样 ,当程序运行加载bundle的时候 发现有多个优先级相同的bundle在同一时间加载 就会报这个错误,一般导致这样的情况是,项目中自定义bundle和系统内置的internal。一致甚至更高,当场景中存在2个相同优先级bundle的时候 就会报错,需要让其中一个bundle先加载完 再去做其它如添加UI组件到界面的操作,对 就是添加UI组件到界面也会报让某个bundle先加载完!

weixin_39114763的博客 1312

cocos creator第一个星星游戏

本人也是第一次接触cocos creator,现在也正处于学习阶段,按照官网的教程一点一点来练习。下面是练习官网的第一个实例: 《Star.js》 cc.Class({     extends: cc.Component,     properties: {         pickRadius: 0     },     // use this for initia

u011874528的专栏 1万+

Cocos游戏开发第一步,安装需要的软件和环境配置

本篇是基础篇,引导大家最基本的项目配置 东市买鞍鞯 安装Cocos:Cocos官网​​​​​​​

Liu_ChangC的博客 3959

开启你的 Cocos Creator 第一个小游戏吧!

这是一个官方文档的补充版,以官方文档的「快速上手:制作第一个游戏」为基础,整合了其他文档内容,同时添加一下自己学习文档的理解,不仅能复习自己学到的知识,也帮助新人学习开发更加简单,好了,话不多说,进入正题。ps:1、观看这篇的同学默认都掌握了 Javascript 基础知识2、直到编写主角脚本部分之前基本是官方文档的内容,从编写主角脚本部分开始会在官方文档的基础上加入自己的理解并且整合了官方...

Cocos的博客 766

一文带你完成ARMv8架构中的cache知识点

【摘要】 在最初开发ARM架构时,处理器的时钟速度和内存的访问速度大致相同。今天的处理器内核要复杂得多,其时钟速度可以快上几个数量级。但是,外部总线和内存设备的频率并没有扩大到同样的程度。有可能实现小块的片上SRAM,它可以以与内核相同的速度运行,但是与标准的DRAM块相比,这种RAM非常昂贵,因为后者的容量可以达到数千倍。在许多基于ARM处理器的系统中,访问外部存储器需要几十甚至几百个内核周期。 cache的技术背景 在最初开发ARM架构时,处理器的时钟速度和内存的访问速度大致相同。今天的处.

ABCCloud的博客 1854

Cocos Creator 制作第一个游戏

Cocos Creator 制作第一个游戏 您正在阅读的手册文档包括了系统化的介绍 Cocos Creator 的编辑器界面、功能和工作流程,但如果您想快速上手体验使用 Cocos Creator 开发游戏的大体流程和方法,这一章将满足您的好奇心。完成本章教程之后,您应该能获得足够上手制作游戏的信息,不过我们还是推荐您继续阅读本手册来了解各个功能模块的细节和完整的工作流程。 接下来就让我们

一入編程深似海! 5388

西门子TM PosInput1模块SSI编码器配置与速度测量实战

本文详细介绍了西门子TM PosInput1模块配置SSI绝对值编码器的实战步骤,涵盖硬件组态、工艺对象配置、编程实现与速度测量优化。重点解析了高分辨率编码器的数值处理技巧和常见调试问题,帮助工程师快速实现高精度位置与速度检测,提升自动化项目效率。

emacs5lisp的博客 340

混沌系统在图像加密中的应用(随机性测试之FIPS 140-2测试和SP800-22测试)

本节内容我们将学习混沌序列的随机性测试,那么前面讲了,混沌系统产生的随机序列,它的随机性到底好不好,除了看相图、分岔图、指数图以外,还有一个非常重要的指标,那就是FIPS 140-2测试和SP800-22测试。(1)保证密码学模块的安全性:密码学模块在加密和解密敏感信息时使用随机数生成器来增加对手动解密和猜测攻击的抵抗力。通过进行FIPS 140-2测试,可以验证密码学模块是否符合安全标准,确保其实施和设计的安全性,以有效地保护敏感信息。

weixin_42207434的博客 2085

Cocos打包移植Android平台问题集锦

原文:http://www.cocoachina.com/bbs/simple/?t226339.html

IT一分子 1744

MIC(Maximal Information Coefficient)最大互信息系数

MIC(Maximal Information Coefficient)最大互信息系数是一种用于衡量两个变量之间相关性的统计量。它扩展了传统的互信息(MI)和条件互信息(CMI)的概念,具有更广泛的应用范围。MIC能够捕获包括功能性和非功能性的广泛的关联,具有普遍性和公平性。普遍性意味着在足够的样本量下,MIC能够捕捉到广泛的相关关系,而不仅仅局限于特定的功能类型;公平性则意味着MIC对不同类型的包含同等噪声的关系给出了相似的分数。需要注意的是,虽然MIC具有很多优点,但它也有一些局限性。

qlkaicx的博客 4605

【GitHub 每周热点项目解析】第 1 期:build-your-own-x

这是我新开的一个栏目——GitHub 每周热点项目深度解析。预计每周一篇。挑 GitHub Trending 周榜上数据最值得看的项目,做一次比"30 秒 README 速读"更深的拆解:从项目历史、作者背景、到具体怎么用、为什么值得用、有没有同类项目可以横向对比。

qq_52949075的博客 385

NIST随机性测试实战:从理论公式到结果解读

本文详细解析了NIST随机性测试的实战应用,从基础测试到高级测试,涵盖频数测试、块频数测试、游程测试等核心方法。通过实际案例和参数设置经验,帮助读者理解如何解读测试结果并排查常见问题,提升随机数生成质量。文章还分享了自动化测试流程和硬件RNG特殊处理技巧,适合密码学和区块链开发者参考。

weixin_29323365的博客 314

【C#学习记录】如何让界面控件实现自适应布局(Winform)

小伙伴们大家好,我是雷工!在软件界面设计中,客户常常要求设计的界面可以随意缩放,缩放过程中,界面中的按钮等控件也会随着窗体变大缩小自动调整显示位置和尺寸大小。在C#的Winform窗体中如何实现这个效果,下面我们一起学习下。

做有价值的事,积累有价值的笔记! 1万+

Unity Android log view(Android Debug Bridge)

Android Debug Bridge

蛰伏--当你不够强大时,就不要放弃努力 4158

ESP32-S3模组上跑通esp32-camera(32)

ESP32-S3模组上跑通esp32-camera(32)

phmatthaus的专栏 772

Cocos笔记

【代码】Cocos笔记。

qq_54756591的博客 588

【35】软考软件设计师——设计模式代码填空(C++版)满分精讲|第5/6题二选一必考

本文是《软件设计师·50讲通关|从零基础到工程师职称》专栏第35篇,聚焦下午选做题**第5/6题C++版设计模式代码填空**,与上一篇Java版形成双子配套,单题分值稳定12~15分。全文超4000字深度拆解C++独有核心考点:虚函数/纯虚函数、构造与析构函数规范、继承权限、模板类编程在设计模式中的应用;精讲单例、工厂、策略、观察者、适配器五大高频模式的C++专属代码写法,标注所有填空核心点位、语法陷阱、内存安全规范

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 543

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

工作中使用到的单词(软件开发)_第五版

本文摘要: 本文为软件开发相关的术语与技术要点整理,主要包含2020-2025年间四版内容更新(No.01-41)。重点包括: 证书文件格式(PEM/P12)差异 外部API通信注意事项(Accept头设置、HTTPS连接问题) Postman工具使用技巧(Cookie管理、请求头设置) WAS配置相关经验(JVM设置、SSL连接问题) 数据库操作命令(DB2表结构修改) IBM安全管理组件(TAM/iv-user机制) 网络通信细节(chunked传输编码特性) 常用开发工具(curl、Postman)的

sun0322 2520

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

cocoscreator扩展编辑器菜鸟简易上手教程

cocoscreator扩展编辑器菜鸟简易上手教程 ** 个人开发过程中的见解 官方文档:https://docs.cocos.com/creator/manual/zh/extension/ 首先在项目的packages文件夹下新建一个文件夹(命名为扩展包的名字) 扩展包底下必须含有这几个文件 其中: index.js为具体页面结构编写(若不需要弹出的panel界面则不需要) main.js...

dearest_z的博客 2205

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

cocos creator报错

A problem occurred configuring project ':libcocos2dx'. > You have not accepted the license agreements of the following SDK components:   [Android SDK Build-Tools 26.0.2].   Before building your pro

安逸风声 2439

解决 Your project contains error(s),please fix them before running your application问题

http://hi.baidu.com/zht7216/blog/item/18bf86a942ee1ae11f17a286.html 解决 Your project contains error(s),please fix them before running your application问题 1.网上查询最多的是:project--clean 2.在项目列表里删除该项目,再导入

Skypine_Lee的专栏 1103

HTML5游戏开发–第10课

HTML5 Game Development – Lesson 10 Finally we can continue the series of articles on game development in HTML5 using canvas. Today I have prepared a new game – SkyWalker. Basically – this is a flight ...

cukengwei3786的博客 246

【技术专题】HTML5 网页技术 - HTML5 地理定位 API & Web Workers

Java1234_小锋老师推出《一天学会 HTML5 视频教程(无废话版)》,涵盖HTML5核心知识点,包括语义化标签、音频视频、Canvas动画、SVG、Web Storage、File API、拖放与地理定位API,以及关键的Web Workers多线程技术。通过实战示例详解navigator.geolocation获取位置信息及Worker后台执行耗时任务,实现页面流畅交互。配套课件、源码打包下载,助力快速掌握现代Web开发技能。

java1234的博客 214
上一篇: 5 款傻瓜式手机 APP 开发工具
下一篇: 这才是真正的爱好,看到这个我震惊了!
程序员迈克
博客等级 码龄16年 36粉丝 71原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值