home download get support documentation weaver games

How To Make a Vector Game

Weaver

You already learned the most primitive drawing functions present in Weaver (I'm assuming that you are reading the documentation in the right order). But to do more complex image manipulations (like zoom or rotation), we need to play with vectors and a vector space.

In a 2-dimensional vector space, we can intify every point as an ordered pair. We only need to choose a point as the origin, a distance as an unit of measure and the x/y axis direction. Usually, the result is like this:

Cartesian Coordinate

But when we deal with computers, the coordinate is a little different. The X-axis still goes from left to right. But the Y-axis goes from top to down. It means that if you draw a point in coordinate (0.0, 3.0), it will appear in your screen under the point (0.0, 2.0).

Well, let's start a new project to practice a little:

weaver vector

In a vector game, the first thing to do is decide wich place of our cartesian coordinate the screen will show. You can think in this question as "where will we position a camera to show the action in a 2-dimentional space"? Well, the point (0.0, 0.0) appears to be a good place, don't you think? And I think that if our camera covers a horizontal distance of 100.0 and vertical distance of 100.0, we won't miss nothing important. So, we can declare our camera in the beginning of the main function in src/game.c:

  camera *cam = new_camera(0.0, 0.0, 100.0, 100.0);

An empty vector space is very boring. Let's create something inside it. What about a circle? It's a good start, because it's the simplest entity that Weaver can create in a vector space. Declaring a circle is easy:

  circle *star   = new_circle(50.0, 50.0, 20.0);
  circle *planet = new_circle(90.0, 90.0,  5.0);

This creates a circle whose center is in the coordinate (50.0, 50.0) and whose radius is 20.0 and another one whose center is in (90.0, 90.0) and whose radius is 5.0.

Circles are very easy. So let's create something more challenging: some rectangles:

  rectangle *trash = new_rectangle(75.0, 50.0, 1.25, 2.5);
  rectangle *ufo   = new_rectangle(25.0, 50.0, 1.5,  1.5);

Now just before the main loop, let's "film" our objects with our "camera". This makes them appear in the screen:

  film_fullcircle(cam, star, YELLOW);
  film_fullcircle(cam, planet, BLUE);
  film_rectangle(cam, trash, GREEN);
  film_fullrectangle(cam, ufo, WHITE);

The "film_rectangle" puts in the screen the rectangle perimeter. The "film_fullrectangle" draws all the rectangle. Also exists a "film_circle" and "film_fullcircle". You can see it by yourself compiling what we already done:

make
./vector

Note that in most computers, the horizontal resolution is bigger than the vertical. As we are trying to show a 100x100 area in the screen, the image will be distorted (especially in wide screen monitors). Now we aren't worried with this, but in more serious projects, we can't let this happen.

It looks like that there's nothing more to initialize. It's time to work in the main loop. If there's a camera in this game, we should have the power to move it to catch better angles. So let's program a basic camera logic.

First, declare a variable to store if we changed the camera or not (this will be the last variable):

  int camera_moved = 0;

And finally, in the main loop, we implement this input instructions:

    get_input();
    if(keyboard[ESC]){
      break;
    }
    if(keyboard[UP] || keyboard[DOWN] || keyboard[LEFT] || keyboard[RIGHT] ||
       keyboard[MINUS] || keyboard[PLUS] || keyboard[ENTER]){
      film_fullcircle(cam, star, BLACK);
      film_fullcircle(cam, planet, BLACK);
      film_rectangle(cam, trash, BLACK);
      film_fullrectangle(cam, ufo, BLACK);
      camera_moved = 1;
    }
    if(keyboard[UP])
      cam -> y -= 1.0;
    if(keyboard[DOWN])
      cam -> y += 1.0;
    if(keyboard[LEFT])
      cam -> x -= 1.0;
    if(keyboard[RIGHT])
      cam -> x += 1.0;

Now the game will exits only if the player presses the <ESC> key. The arrow keys will move the camera and marks our variable that detects camera moves. When any of that large set of keys is pressed, the objects in the screen are erased. Don't worry. We will redraw them again after the processing of the input, when their position in the screen could change.

Are you satisfied with this? I'm not. If we have a camera, we should have the ability to zoom in and zoom out with the "+" and "-" keys:

    if(keyboard[PLUS])
      zoom_camera(cam, 1.01);
    if(keyboard[MINUS])
      zoom_camera(cam, 0.99);

We choosed 0.99 and 1.01 because they are multiplicative inverse. When they are multiplied, the result is (almost) 1.0. So, each frame the player presses the "+" key, the objects become 1.01 times bigger and when the player presses "-", the objects become 0.99 times bigger (they lose 1% of their size).

There's one more important thing. The vector space is a very big place. The player can get lost there. I would hate to be lost alone in such an empty universe. To avoid such a terrible fate, let's implement an "I'm lost!" key. When the player hits <ENTER>, he gets teleported to the center of the big circle that we defined:

    if(keyboard[ENTER])
      center_camera(cam, 50.0, 50.0);

As we finished the input handling, we can draw again our objects in the end of the main loop, just before the "weaver_rest":

    if(camera_moved){
      film_fullcircle(cam, star, YELLOW);
      film_rectangle(cam, trash, GREEN);
      film_fullrectangle(cam, ufo, WHITE);
      camera_moved = 0;
    }

Err... Aren't we forgetting nothing? What about the blue circle, the one that we declared with the name of "planet"? Well, we didn't handled it yet because this is a different circle. A planet should be in the orbit of some star. So, between the input handling and the drawing of other things, place:

    film_fullcircle(cam, planet, BLACK);
    rotate_circle(planet, 50.0, 50.0, 0.01);
    film_fullcircle(cam, planet, BLUE);

Done! Now, in each frame, we erase the blue planet, rotate it in orbit of point (50.0, 50.0) (it's the star center) making it moves 0.01 radians, and then draw it again. Test it:

make
./vector

Unfortunally, you can't rotate the rectangles like he circle. The reason is that if you rotate it, it would not be a rectangle anymore. It would turn in a rhombus. If you expect to create a rotationable rectangle, you should declare it as a Polygon. But to learn more about this, wait for the next tutorial.


XHTML 1.1 válido! CSS válido!