📜 ⬆️ ⬇️

We make our first browser 2d game with physics

On a warm summer evening, I visited a thought that, surely, visits many people: I want to make my game! Energy was over the edge, so the work went with a twinkle.

Racing game

The result was a small prototype of a browser-based 2d platform with physics.
Under the cut - a guide for beginners from a beginner to create such a game. If you are an experienced igrodel, come and share valuable tips!

Tools on the project


Classic JavaScript - For simplicity, I tried to use the most basic syntax of the language. Also in the project there is no collector: each file is connected as is. Thanks to this, I hope the project will be understood by a wide range of developers.

PixiJS - I liked this 2d graphics engine. Any comments on his work did not arise. Plus available - good documentation.
')
PhysicsJS - One of the reasons for the project was the desire to try in the finished physics engine. The choice fell on PhysicsJS. In the process of development sometimes there was not enough documentation, I had to open its source code. But he did his job, body physics looks quite realistic.

JQuery - Library features are used minimally and can be safely removed if desired. But personally, I like jQuery, I’m happy to use it for working with HTML.

Application architecture


A maximum of 60 times per second, the browser calls the screen redraw method.

Code
//render.RootStage function animate() { requestAnimationFrame(animate); //... } 

At each redrawing, the physical model is updated and the game layers are successively drawn: cards, gaming machines, prize stars.

Code
 //render.RootStage function animate() { requestAnimationFrame(animate); //  game.step(); //  for (var i=0; i< stages.length; i++) stages[i].update(); } 

If, between screen redraws, a user presses control buttons, then the model receives information about this, which will be taken into account during the next redraw.

Code
 //render.RootStage $("#moveRight").mousedown(function(){ game.car().startAccelerator(); }); $("#moveRight").mouseup(function(){ game.car().stopAccelerator(); }); 

You can depict this process as a diagram:

Game process

1. Update the model.
2. Call PhysicsJS to calculate physics.
3. Sequential call layers to redraw.
4. Poll the updated model and redraw using PixiJS.

Features of the implementation


Collisions - the physics engine provides a convenient collision detection API. No need to remember the math.

Code
 //physics.Game var world = Physics({...}); world.add([ Physics.behavior('body-collision-detection'), ... ]); world.on('collisions:detected', function(data){ for (var i = 0; i < data.collisions.length; i++) onCollision(data.collisions[i]); }); 

But sometimes collisions are not needed ... - for example, when you collect prize stars. It seems to me logical to include in the physical engine the type of objects that capture the fact of collision with them, but do not interact with other objects (ghost objects). Unfortunately, I did not find such a possibility in PhysicsJS. As a result, even if you delete the prize star after a collision, the engine has already changed the speed of the player, slowing it down.


I am sure there is a more beautiful solution, but I did this: after the fact of the collision, we return the player to his characteristics before the collision, the benefit of PhysicsJS allows himself to be deceived.

Code
 //model.car.Car function onCollision(otherBody, pos, norm){ if(otherBody.objType == model.ObjectType.POINT) carBody.backPrevForce(); } //physics.BodyPhysicsImpl function backPrevForce(){ var old = body.state.old; body.state.acc.set(old.acc.x, old.acc.y); body.state.vel.set(old.vel.x, old.vel.y); body.state.angular.vel = old.angular.vel; body.state.angular.acc = old.angular.acc; } 

The result - the collection of stars does not violate the speed of the player.


Different models of the engines - the physics engine rotates the object around its center of mass, and the graphics engine defaults to the left upper corner of the object. If this fact is not taken into account, the result will be quite funny.


By the way, I see something similar in the animation of the car turning in the Uber client on Android: there the turning point is also located in the upper left corner, and not in the center of the car. I think this is a bug that they are too lazy to fix.

Uber-like animation example

The solution is to draw the car relative to its center, rather than the upper left corner.

Code
 //render.car.PlayerCar function paintCabin(g, model){ //... g.drawRect(model.x - model.w/2, model.y - model.h/2, model.w, model.h); //... } 

Now everything looks right


Showing control buttons on a mobile device - made a curtsy in the direction of progress: showing large control buttons for mobile devices. The main thing is not to forget that pressing the button is done by touch events, and that it is necessary to prevent the appearance of text selection from this long press through the css style.

Code
 //render.RootStage $("#moveRight").on('touchstart', function(){ game.car().startAccelerator(); }); $("#moveRight").on('touchend', function(){ game.car().stopAccelerator(); }); //main.css .moveBtn { -webkit-user-select: none; -moz-user-select: none; } 




The battery consumption of the phone from the work of the game increases markedly. I think the physical engine is guilty, which actively loads the processor with work.

findings


In general, the process of creating the game did not seem very difficult to me. Using ready-made engines for graphics and physics, you can greatly simplify the development, almost without thinking about mathematics. How effective this approach is is a question for a separate article. Thank you all for your attention and I hope my work will help you to create something of your own, if you have been going to do it for a long time! Good luck!

[Sources on GitHub]

Source: https://habr.com/ru/post/311066/


All Articles