📜 ⬆️ ⬇️

The history of Losharik

Foreword


image It was Thursday evening, when spiff and I got the idea to write an OpenSource game on HTML5, which is progressive in our time, as they say, from scratch and just for fun.

Since we work in the field of system programming and web application development experience, we had very little, it was decided to implement a fairly simple clone of the world famous and popular game for the first Nokia phones - RapidRoll .

A week later, we released the first stable release , and are ready to share the first gained experience.
')


Step 1. Design Document


Any game that will conquer the world, in our opinion, must begin with a design document. Usually it consists of the following items:

The meaning of the game is to keep Losharik in the visible part of the screen, by moving it along the rising platforms, preventing it from falling or leaving the upper edge of the screen.

Link to the design document

Step 2. Architecture


The architecture of the application is shown in the following diagram:

image

As you can see, the diagram resembles the MVC model. The following main classes are available:

The implementation of the skeleton architecture is presented below:

function GameModel() { this.setView = function(v) { view = v; }; this.getView = function() { return view; }; this.moveLeft = function() { ... }; this.moveRight = function() { ... }; this.next = function() { // build next/new frame ... view.update(); //update view }; } function HTML5View(canvas) { var model; this.setModel = function(m) { model = m; }; this.getModel = function() { return model; }; var context = canvas.getContext("2d"); this.update = function() { // clear view ... // drawing model to canvas ... }; } function KeyboardController() { var model = null; this.setModel = function(m) { model = m; }; this.getModel = function() { return model; }; this.keydown = function(event) { if (event.keyCode == LEFT_KEY_CODE) { model.moveLeft(); } else if (event.keyCode == RIGHT_KEY_CODE) { model.moveRight(); } }; document.onkeydown = this.keydown; } function Game(model, view, ctrl) { view.setModel(model); ctrl.setModel(model); model.setView(view); this.run = function() { setInterval(model.next, 1000 / DEFAULT_FPS); }; } function main(canvas) { var view = new HTML5View(canvas); var model = new GameModel(); var ctrl = new KeyboardController(); var game = new Game(model, view, ctrl); game.run(); } 


Step 3. First prototype


A day later, the first working prototype was received, measuring 150 lines of HTML5 code.

image

Algorithms for platform generation, Losharik and world movement were added to the framework code. And it was already possible to play, although there were problems with physics and testing of hitting the platforms.

The main feature of the prototype was the algorithm for generating platforms - new platforms are generated after the destruction of the topmost one and this provides the ability to dynamically change the number of platforms on the screen and the distance between them. The algorithm code is presented below:

 var generatePlatforms = function() { do { var type = (Math.random() 0.6) ? PLATFORM_TYPE.SOLID : PLATFORM_TYPE.KILLER; var baseline = pCounter > 0 ? platforms[pCounter - 1].y : 0; platforms[pCounter++] = { x: Math.floor(Math.random() * (WIDTH - DEFAULT_PLATFORM_WIDTH)), y: Math.floor(baseline + (Math.random() * (DEFAULT_MAX_PLATFORM_INTERVAL - DEFAULT_MIN_PLATFORM_INTERVAL + 1)) + DEFAULT_MIN_PLATFORM_INTERVAL), w: DEFAULT_PLATFORM_WIDTH, h: DEFAULT_PLATFORM_HEIGHT, type: type }; } while (platforms[pCounter - 1].y < (HEIGHT + DEFAULT_PLATFORM_HEIGHT)); }; 


Step 4. Second prototype


In the second prototype, the algorithm for checking platform hit was revised and rewritten to the method of checking the intersection of segments. First, a new one is built on the basis of the previous Losharik, taking into account the proposed movement in space. The coordinates of the new, current Losharik and the platform under test are transferred to a function that searches for the intersection points P1 and P2 and returns them true when they are found, taking into account this, the decision is made whether to attach Losharika to the platform or not.

image

Later, the function was optimized and performed only for those platforms that could fall into the intersection.

As a result, the following code was born:

 var isRollCrossPlatform = function(platform, rollPrev, rollNext) { // we should to check only platforms between prev roll and next roll if (platform.y <= rollPrev.y || platform.y > rollNext.y + rollNext.h) return false; var s1 = { x1: platform.x, y1: platform.y, x2: platform.x + platform.w, y2: platform.y }; var s2 = { x1: rollPrev.x, y1: rollPrev.y + rollPrev.h - worldSpeed, x2: rollNext.x, y2: rollNext.y + rollNext.h }; var s3 = { x1: rollPrev.x + rollPrev.w, y1: rollPrev.y + rollPrev.h - worldSpeed, x2: rollNext.x + rollNext.w, y2: rollNext.y + rollNext.h }; var zn1 = (s2.y2 - s2.y1) * (s1.x2 - s1.x1) - (s2.x2 - s2.x1) * (s1.y2 - s1.y1); var zn2 = (s3.y2 - s3.y1) * (s1.x2 - s1.x1) - (s3.x2 - s3.x1) * (s1.y2 - s1.y1); if (Math.abs(zn1) < Math.EPS && Math.abs(zn2) < Math.EPS) return false; var ch11 = (s2.x2 - s2.x1) * (s1.y1 - s2.y1) - (s2.y2 - s2.y1) * (s1.x1 - s2.x1); var ch21 = (s1.x2 - s1.x1) * (s1.y1 - s2.y1) - (s1.y2 - s1.y1) * (s1.x1 - s2.x1); if ((ch11/zn1 <= 1.0 && ch11/zn1 >= 0.0) && (ch21/zn1 <= 1.0 && ch21/zn1 >= 0.0)) { return true; } var ch12 = (s3.x2 - s3.x1) * (s1.y1 - s3.y1) - (s3.y2 - s3.y1) * (s1.x1 - s3.x1); var ch22 = (s1.x2 - s1.x1) * (s1.y1 - s3.y1) - (s1.y2 - s1.y1) * (s1.x1 - s3.x1); if ((ch12/zn2 <= 1.0 && ch12/zn2 >= 0.0) && (ch22/zn2 <= 1.0 && ch22/zn2 >= 0.0)) { return true; } return false; }; 


In the second prototype, various types of platforms were added: moving, killing and melting, and the ability to move beyond the side borders of the screen.

Step 4. The third prototype


An algorithm was implemented for counting and drawing the number of points that are multiples of the distance traveled in free fall, as well as the counter of lives and the possibility of losing this life.

image

Step 5. Release!


Almost a week has passed since the beginning of the project and we already had a fully functional working prototype, which until the release had only one class to change - HTML5View and add some additional features:

All drawing graphics in the form of canvas shapes, was replaced by drawing sprites (images).

 context.fillRect(x, y, width, height) -> context.drawImage(roll, x, y, width, height) 


It was decided to receive the FPS counter value on the basis of the last 10 frames and the total time of their drawing. Ultimately, the counter code looks like this:

 // draw current fps var fps = (frameCounter / totalTime) * 1000.0; context.fillText(fps.toFixed(2) + " fps", 4, HEIGHT - 6); // calc FPS if (frameCounter > FPS_REFRESH_INTERVAL) { frameCounter = 0; totalTime = 0; } frameCounter++; var currentTime = new Date().getTime(); totalTime += (currentTime - lastTime); lastTime = currentTime; 


In addition, in the release, the game physics coefficients — gravity, acceleration along X for more confident control — were worked out, and difficulty switching points (levels) were changed for a longer game.

image

Statistics


In one week, a working release of Losharik was received, containing 1130 lines of code:

Plans for Losharika 2.0



Instead of conclusion


We would like to make a small announcement. As you can see, Loshariku needs a good designer in the team to conquer the world. If someone has a desire to participate in an interesting OpenSource project and upgrade their skills, you are welcome - you can leave comments or contact spiff .

PS Once again the link to PLAY!
PPS Losharik on Googlecode .

UPDATE: thanks to the user qmax for the patch that adds the rotation to Losharik!

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


All Articles