Play using math graphs instead of graphs



This screenshot shows you a seemingly ordinary game with pixel graphics. However, not all so simple.

In some places, the relief of the earth resembles a sine wave, and the bullets resemble two symmetrical graphs of the root of x.

In fact, everything you see on the screen in one way or another relates to mathematics, mathematical curves and graphs.

Prehistory


Once, while watching the video of the channel “Numberphile”, I came across a very interesting video material called “The Formula of Everything” .

In this video, Tupper's self-referential formula was presented , which, with a certain value of k, recreated its image on the graph. This formula looks like this:

$ \ frac {1} {2} <\ lfloor mod (\ lfloor \ frac {y} {17} \ rfloor 2 ^ {-17 \ lfloor x \ rfloor - mod (\ lfloor y \ rfloor, 17)}, 2 ) \ rfloor $


This formula really interested me, and I had an idea:

“What if you create a game, where instead of ordinary textures that are stored in various format .png and .jpg files, mathematical graphs and curves will be used?”

I found this idea quite interesting and difficult to implement.

Tasks


I had the following tasks:

  • Come up with the meaning of the game, the gameplay
  • Derive formulas, graphs which will be the silhouettes of characters, bullets, surfaces I need
  • Implement it all in the game

Gameplay and sense of the game


The gameplay and the meaning of the game changed several times during the development of this game. This is all because there were some difficulties, in particular, with the derivation of formulas for certain silhouettes. But in general, this game is about a lonely flying saucer that flies around the planets, exploring them and killing the enemies that stand in its way.

Formulas and their subsequent implementation in the game


I have combined the following two points into one subtitle, because it is not expedient to “jump” between one formula and its implementation.

To create the game, the c ++ programming language and the SFML library were chosen, to create windows and draw something on them.

Since I study at school and only recently learned about what a sine wave is and how it looks, I had quite big problems with finding various formulas. Most often it ended with the simplest selection.

At the end of the article there will be a link to GitHub, where all the code is laid out. The article will be given only small pieces of code, so as not to clog it.

Surface of the planet


For the surface of the planet, I derived the following formula:

$ f (x) = | sin (x) | $

Quite a simple formula, but when implemented, the need arose to control the height and length of a given sinusoid. Also, in order to avoid the curvature of the relief, x is multiplied by π. So the final code looks like this:

int groundC = ceil(abs(sin(((i+1)*groundScale*M_PI)))*groundHeight);

The texture of the planet in space






The texture of the planet consists of a circle and a pattern on it. The game has 4 formulas for creating patterns and 12 textures of planets with different patterns. Depending on the “step” of the formula, different patterns are created. Also, when a planet is generated, its color, size and position in space is set in a pseudo - random way.

Bullets




An image of a bullet from a game. The bullet is turned.

For the bullets a very simple formula was chosen:

$\sqrt{x}$

The graph of this formula is mirrored on the abscissa axis.

The main character


So we got to the most complex formulas.

I derived the formula of the main character with great difficulty. It looks like this:

$ \ sqrt {x ^ {\ frac {1} {2.8}} + x ^ {10.9-x ^ {9.3-x}}} - 0.3 $

Yes, a very crooked, very ugly formula. But the main thing is not the formula, the main result.

To achieve the result, at first I just wanted to move along the x axis with a certain step, record the y coordinates, and after connecting all these points, thereby obtaining our plate. But then, I accidentally took a step too small, and my whole plate was beautifully outlined with the exception of two end points, which eventually merged. As a result, the plate looks like this:



Next, the texture of the main character in space was needed. It looks like this:



It is based on a circle. The main cabin is made using the following formula:

$ (x ^ {7-x}) ^ {\ frac {0.8} {x}} $

The graph of this formula is mirrored on the ordinate axis.

This is how the formula looks like in c ++:

int x = round(pow(pow(i, 7 - i), 0.8 / i));

Enemies and their spawner



On the right in the image is a blue spuner, red objects are enemies.

Spawner is an ordinary planet with an unusual pattern. This pattern is a formula chart:

$ sin (x) * x ^ {0.8} $


The formula of the textures of enemies:

$ (x ^ {3-x}) ^ {\ frac {1} {x}} $



Trees


I confess, the formula for creating the silhouette of trees to withdraw or pick up I could not. But, in order not to violate the basic concept of the whole game and the rules not to use any .png and .jpg format files, I used one trick. I used fractals to create trees.


An example of a fractal tree.

Most likely you will agree that the fractal trees themselves look pretty dull. If you add a few elements of randomness, for example, it may not necessarily grow 2 branches, but also 3 or 1, or not at all. Also, you can not make the same angle of inclination everywhere.

Of course, one could make an ordinary machine pseudorand , which was based on computer ticks, but the following idea seemed to me more interesting:

“And what if you give each tree a certain number (sid) from which pseudo-random numbers will be calculated that affect the parameters of the tree?”

Fortunately, in c ++ there is a separate library responsible for the pseudo-brand.

As a result, the generated trees look like this:



On the left is a tree with 13 sid, and on the right - 22

And the code that generates these trees is:

Branch Branch::createNewBranch(Branch cur, Tree* parent, float angleMultiplier, int level) {
  Vector2f sp(cur.startPoint.x, cur.startPoint.y);
  float randomAngle = ((*parent).getRand() * 15) - 5;
  float t = cur.thickness * 0.75;
  float l = cur.length * 0.67;
  float a = cur.angle + 30*angleMultiplier + randomAngle;
  sp.y -= (cos((cur.angle-180)*3.1415926 / 180) * cur.length);
  sp.x += (sin((cur.angle-180)*3.1415926 / 180) * cur.length);
  Branch gen(sp, t, l, a, level);
    if (level > 0) {
      int count = 100 * (*parent).getRand();
      if (count >= 25 && count < 80) {  //только после многочисленных тестов я заметил, что в этом месте пропустил && count < 80, по этому дальнейшие скрины могут иметь небольшие неточности, почти незаметные. Также, из-за этого пришлось понизить шанс не выростания одной ветки с 20% до 10%, по этому, в конечном коде count<90
	(*parent).addBranch(gen.createNewBranch(gen, parent, 1, level - 1));
	(*parent).addBranch(gen.createNewBranch(gen, parent, -1, level - 1));
      }
      if (count >= 80) { //как я уже объяснял раньше, в конечном варианте count >= 90if (count % 2 == 0) {
	   (*parent).addBranch(gen.createNewBranch(gen, parent, -1, level - 1));
	}
	else {
	   (*parent).addBranch(gen.createNewBranch(gen, parent, 1, level - 1));
	}
      }
    }
  return gen;
}

Note. Yes, I know that I "scardcode" some variables, but please do not blame me for this. I decided that it does not make sense to create separate constant variables that, in principle, affect only the chance of creating a new branch.

More code


Above I gave the code only for generating textures. In this subtitle I will describe the code of the game itself. All code is on GitHub, the link to the project is in the conclusion.

Player


The player has two different methods update - spaceUpdate and planetUpdate. Accordingly, spaceUpdate updates the player when he is in space, planetUpdate - when on the planet. The planet calculates the acceleration and speed of the player. Depending on its horizontal acceleration, the angle of inclination of the plate changes from 30 degrees to -30. Approaching the barriers decreases the player’s speed. Such barriers exist for the x axis (0; mapSize.x) and for the y axis. For the y axis everything is a bit more complicated. There is a minimum height, which is calculated as follows: the minimum height of the earth is taken, it is added to the height of the sine wave, and the height of the trees is still added. The height of the trees is calculated in a very simple way - the initial length of the branch is multiplied by the number of cycles performed when generating the tree.

SpaceUpdate works as follows: the acceleration and speed of the player is calculated. Next, calculate the angle of rotation of the player. The angle is calculated as follows: if the acceleration is zero, then the angle is calculated relative to the player’s speed, if not, relative to the acceleration. Also, in space, the player has the possibility of shooting. Shooting takes place as follows - a bullet is created with turning like a player’s and added to the list. When a player is upgraded in space, each bullet in this list is also updated. When a player draws, bullets are also drawn. Also, in space, things are a little more complicated with barriers. Space is divided into sectors, in each sector there are 4 planets, in total - 1,000,000 planets and 25,000 sectors. Each sector has a unique id. If the remainder in the division by 500 is 0 - there is a left barrier, if the remainder of 499 is right, if, when divided by 500, the result is 0, the upper barrier is present, and 499 is the upper barrier. If there are no barriers, then when flying out of bounds, the player moves to the appropriate sector.

Space


I have already stated most of it, but there are still some things left. In each of the sectors of space there are 4 planets. When a player presses the E key, if he is at a distance of a radius from this planet, then the player moves to the planet.

The enemies


AI enemies are very stupid - if there is a player in the radius of their visibility, then they simply tend to crash into it, and there is a small error, therefore their trajectory is quite a curve. If there is no player within the radius of their visibility, they are sent to their spawner.

Spawner


In each sector of space there is 1 spuner. Spawners can be of different sizes. Size affects the visibility of the player. If the player is in their zone of visibility, then the spuner creates enemies every 5 seconds, but the number of enemies cannot exceed 10.

Conclusion


After spending about a week, I created a game that does not use any .png or .jpg files.

Link to the project on GitHub

For those who are too lazy to download the project and run the game, a short video on the gameplay of the game:


Also popular now: