5.1 Images

A modern 2D game will almost always contain images. Whatever happens on the screen, it mostly comes down to showing and manipulating images. And because every image is a rectangle, you will use the Rect class to show them on the screen.

 
Images(=== drop image here ===).draw(Rect(-0.1, -0.1, 0.1, 0.1));  

You can use Images() to refer to any image in your project. The image in question can be dropped as the function argument, between the parentheses. Once that is done, you use the function draw with a Rect argument to show the image on the screen. It is very easy to make your image move this way. The only thing your application has to remember is the current position. The actual rectangle can be derived from that point.

 
Vec2 ship(0, -0.8); 
 
// during update: 
if(Kb.b(KB_LEFT )) ship.x -= Time.d(); 
5if(Kb.b(KB_RIGHT)) ship.x += Time.d(); 
 
// during draw: 
Images(=== spaceship ===).draw(Rect(ship - 0.1,  ship + 0.1));  

Note
When you’re looking for images like the one in this example, just use google images. Mostly you will want images with a transparent background. This will be an image in GIF or PNG format. But Esenthel doesn’t support GIF, so PNG is your target of choice. The search tools on Google Images allow you to search specifically for transparent images. Can’t find what you’re looking for? Try adding the term ‘icon’ or ‘sprites’ to your query.

Just remember this is great while you’re experimenting. But once you’re working on a real game you should not use images which aren’t yours, unless you really verified their license permits the use you intend.

To add realism to your game it is a good idea to use variations on an image. In the next example, two alternate versions of the same image are used during movement.

 
if(Kb.b(KB_LEFT)) 
{ 
  Images(=== spaceship ===      ).draw(Rect(ship - 0.1,  ship + 0.1)); 
} else if(Kb.b(KB_RIGHT)) 
5{ 
  Images(=== spaceship_left === ).draw(Rect(ship - 0.1,  ship + 0.1)); 
} else 
{ 
  Images(=== spaceship_right ===).draw(Rect(ship - 0.1,  ship + 0.1)); 
10}  

Exercise
Find 3 very sad images and create an application with a moving image. Make sure the images are switched one way or another.

Another way to add some dimension is by varying the image over time. You actually create a little animation by rotating through a list of images all the time. The following example presents a player class with three variations for every direction.

 
class player 
{ 
private
   Vec2 pos; 
5   float timer = 0.4; 
   DIR_ENUM dir = DIRE_DOWN; 
 
public
   void update() 
10   { 
      // adjust direction 
      if(Kb.bp(KB_UP   )) dir = DIRE_UP   ; 
      if(Kb.bp(KB_DOWN )) dir = DIRE_DOWN ; 
      if(Kb.bp(KB_LEFT )) dir = DIRE_LEFT ; 
15      if(Kb.bp(KB_RIGHT)) dir = DIRE_RIGHT; 
 
      // update position 
      switch(dir) 
      { 
20         case DIRE_UP   : pos.y += Time.d() * 0.5; break
         case DIRE_DOWN : pos.y -= Time.d() * 0.5; break
         case DIRE_LEFT : pos.x -= Time.d() * 0.5; break
         case DIRE_RIGHT: pos.x += Time.d() * 0.5; break
      } 
25 
      // animation timer 
      timer -= Time.d(); 
      if(timer < 0) timer = 0.4; 
   } 
30 
   void draw() 
   { 
      // pointer to an image 
      ImagePtr current; 
35 
      // evaluate direction 
      switch(dir) 
      { 
         case DIRE_UP: 
40         { 
            // pick an image according to time (changes between 1 - 2 - 3 - 2) 
            if      (timer > 0.3) current = Images(=== back1 ===); 
            else if (timer > 0.2) current = Images(=== back2 ===); 
            else if (timer > 0.1) current = Images(=== back3 ===); 
45            else                  current = Images(=== back2 ===); 
            break
         } 
 
         case DIRE_DOWN: 
50         { 
            if      (timer > 0.3) current = Images(=== front1 ===); 
            else if (timer > 0.2) current = Images(=== front2 ===); 
            else if (timer > 0.1) current = Images(=== front3 ===); 
            else                  current = Images(=== front2 ===); 
55            break
         } 
 
         case DIRE_LEFT: 
         { 
60            if      (timer > 0.3) current = Images(=== left1 ===); 
            else if (timer > 0.2) current = Images(=== left2 ===); 
            else if (timer > 0.1) current = Images(=== left3 ===); 
            else                  current = Images(=== left2 ===); 
            break
65         } 
 
         case DIRE_RIGHT: 
         { 
            if      (timer > 0.3) current = Images(=== right1 ===); 
70            else if (timer > 0.2) current = Images(=== right2 ===); 
            else if (timer > 0.1) current = Images(=== right3 ===); 
            else                  current = Images(=== right2 ===); 
            break
         } 
75      } 
 
      // show the current image on the screen 
      current->draw(Rect(pos - 0.05, pos + 0.05)); 
   } 
80}  

Exercise
The example above can be found in the course template. Create an object of the player class and use it in an application to see the result of this code.

Note
On line 39 there’s an object ‘current’ of the class ImagePtr. this class is a ‘pointer’ to an Image. The code below that line will make the pointer ‘point’ to the image we want to show next. At the bottom, current->draw() is used to draw that image. Note the arrow instead of the dot. This is a sign that current is not a real image object, but just points to one. (Don’t worry if you find this hard to grasp. You will learn more about pointers in another chapter.)

Exercise
The Image class in Esenthel contains a whole bunch of functions. Most of them you will not need any time soon, but it is good to remember that whatever you want to do with your image, there’s a good chance there is a function which has you covered.

For now, experiment a bit with the functions below to learn about their intent.