Video link: http://www.youtube.com/watch?v=DusPphBj98A
In this example you can control the 2 famous tanks from the previous step. But some features were added: The map or “playground” is larger than the screen resolution. . The player sprite(s) can be steered around the whole map (but not over the map edge). The position of all Tank, Bullet and Tracer sprites and the current visible area of the map can be seen in the minimap or radar-map. The minimap is always visible on the top right corner of the screen. The minimap itself is also a Sprite, called Radarmap. The dimensions of screen, the big map and the radarmap are all visible inside the Config class. Minimaps or Radar-maps are very common in a lot of games, and de-facto standard in real-time-strategy games (rts-games).
In the Code examples of this part of the book, all sprites have a self.pos attribute, a list of two coordinates [x,y]. This self.pos variable is used for all calculations (angle, movement etc.). Until now, the self.pos variable was identical with the self.rect position (self.rect.centerx, self.rect.centery), the only difference being that self.rect demands integer values while the self.pos variables could handle decimal points.
But now with the bigmap being by far larger as the visible screen area, the math gets more complex. While the self.pos variables stay more or less untouched, the position of the visible screen area in realation to the big map is to be calculated when blitting the sprites at the self.rect.center position.
In this example, the offset of the visible screen to the bigmap is calculated with the aid of the variable Config.cornerpoint. It's a list of 2 coordinates [x,y] and stored inside the Config-class so that other classes can comfortably access it. It's values are the coordinates of the topleft corner of the visible screen area. At the beginning, those are set to [0,0] and there is no difference between the self.rect coordinates and the self.pos coordinates.
As soon as the player moves the visible area with the Cursor - Keys, the value of Config.cornerpoint is changed (this is done inside the mainloop):
#... # -------- scroll the big map ---------- scrollx = 0 scrolly = 0 pressedkeys = pygame.key.get_pressed() # --- handle Cursor keys to scroll map ---- if pressedkeys[pygame.K_LEFT]: scrollx -= Config.scrollstepx if pressedkeys[pygame.K_RIGHT]: scrollx += Config.scrollstepx if pressedkeys[pygame.K_UP]: scrolly -= Config.scrollstepy if pressedkeys[pygame.K_DOWN]: scrolly += Config.scrollstepy # -------- scroll the visible part of the map ------ Config.cornerpoint += scrollx Config.cornerpoint += scrolly #...
Config.scrollstepx and Config.scrollstepy are variables to control how many pixels the visible area should scroll each frame. Do not make those values too big, or the scrolling look jumpy.
Now, let's take a look inside a typical Sprite class, like the Tank class. At the end of its update(self)-function, there is the blitting of the self.rect.center variables. Here the values of Config.cornerpoint are subtracted. Change the - into a + for a funny effect:
#... self.rect.centerx = round(self.pos - Config.cornerpoint, 0) #x self.rect.centery = round(self.pos - Config.cornerpoint, 0) #y #...
Also note that in contrast to the previous step, in this code example the Bullet sprite class has it's own book dictionary to store all Bullet (and Tracer) sprites. This is necessary so that the Radarmap sprite can iterate throug all Tank sprites (in the Tank book) and all Bullets (in the Bullet book) to draw little dots. Inside the Radarmap class, self.factorx and self.factory are variables indication the relation between bigmap to radarmap.
#... inside Radarmap class , update function... for tanknumber in Tank.book: # tank are circles with radius 4 pos = Tank.book[tanknumber].pos color = Tank.book[tanknumber].color pygame.draw.circle(self.image,color, (round(pos * self.factorx,0), round(pos * self.factory,0)), 4 ) for bulletnumber in Bullet.book: if Bullet.book[bulletnumber].tracer: dotlength = 2 # bullets are rectangles with sidelength 4 (bullets) or 2 (tracer) else: dotlength = 4 # rect with length 1 is not visible pos = Bullet.book[bulletnumber].pos color = Bullet.book[bulletnumber].color pygame.draw.rect(self.image, color,(round(pos * self.factorx,0), round(pos * self.factory,0), dotlength, dotlength)) #...
<note tip>How powerful is your computer ? Change all those variables in the Config class to make a big map with a big screen resolution. See if the framerate is dropping.</note> <note tip>Remember loading images (step007) ? try to load an existing image to use as bigmap</note> <note tip>What of building obstacles for the tanks to navigate around?</note> <note tip>What about lobbing projectiles over obstacles by calculating kinetic energy required to move an object that weighs X amount Y distance?</note>
no additional resources necessary
To run this example you need:
|022_minimap.py|| || Download the whole Archive with all files from Github:
View/Edit/Download the file directly in Github: https://github.com/horstjens/ThePythonGameBook/blob/master/pygame/022_minimap.py
click reload in your browser if you see no code here: