Python application examples (1) Alien invasion (2)

1. Add spaceship image

Now add the spaceship to the game. To draw the player's ship on the screen, we'll load an image and draw it using the Pygame method blit().

When selecting assets for your game, it's important to keep licensing in mind. The safest and least expensive way to do this is to use free graphics from sites like Pixabay, which can be used and modified without a license.

Almost any type of image file can be used in a game, but it is easiest to use a bitmap (.bmp) file, since Pygame loads bitmaps by default. While Pygame can be configured to use other file types, some file types require you to have the corresponding image library installed on your computer. Most images are in .jpg, .png, or .gif format, but they can be converted to bitmaps using tools such as Photoshop, GIMP, and Paint.

When choosing an image, pay special attention to the background color. Whenever possible, choose an image with a transparent or solid color background so you can easily replace its background with any color using an image editor. Games look best when the background color of the image matches the background color of the game. You can also set the background color of the game to the background color of the image.

For the game Alien Invasion, use the file ship.bmp, which has the same background color as the one used for the project. Please create a new folder named images in the project folder (alien_invasion), and save the file ship.bmp in it.

insert image description here

insert image description here

1.1 Create a ship class

Once the image to represent the spaceship is selected, it needs to be displayed on the screen. We create a module called ship that contains the Ship class that manages most of the ship's behavior.

  import pygame

  class Ship:
      """管理飞船的类"""

      def __init__(self, ai_game):
          """初始化飞船并设置其初始位置。"""
❶         self.screen = ai_game.screen
❷         self.screen_rect = ai_game.screen.get_rect()

          # 加载飞船图像并获取其外接矩形。
❸         self.image = pygame.image.load('images/ship.bmp')
          self.rect = self.image.get_rect()

          # 对于每艘新飞船,都将其放在屏幕底部的中央。
❹         self.rect.midbottom = self.screen_rect.midbottom
def blitme(self):
          """在指定位置绘制飞船。"""
          self.screen.blit(self.image, self.rect)

Pygame is efficient because it allows you to treat all game elements as rectangles (rect objects), even if their shape is not a rectangle. Treating game elements like rectangles is efficient because rectangles are simple geometric shapes. For example, by treating game elements as rectangles, Pygame can tell more quickly if they collide. This usually works so well that the game player hardly notices that we're not dealing with the actual shape of the game element. In this class, we'll treat the spaceship and screen as rectangles.

Before defining this class, the module pygame was imported. The Ship method __init__() takes two parameters: a reference to self and a reference to the current AlienInvasion instance. This gives Ship access to all game assets defined in AlienInvasion. At ❶, the screen is assigned to a property of Ship for easy access in all methods of this class. At ❷, the method get_rect() is used to access the rect property of the screen and assign it to self.screen_rect, which allows us to place the spaceship at the correct position on the screen.

Call pygame.image.load() to load the image, passing it the location of the spaceship image (see ❸). This function returns a surface representing the spaceship, and we assign this surface to self.image. After loading the image, use get_rect() to get the property rect of the corresponding surface, so that it can be used later to specify the position of the spaceship.

When dealing with rect objects, the [illustration] coordinates and [illustration] coordinates of the four corners and the center of the rectangle can be used. The position of the rectangle can be specified by setting these values. To center the game element, set the attributes center, centerx, or centery of the corresponding rect object; to align the game element to the edge of the screen, use the attributes top, bottom, left, or right. In addition, there are some combination properties, such as midbottom, midtop, midleft and midright. To adjust the horizontal or vertical position of a game element, use the properties x and y, which are the [inset] and [inset] coordinates of the upper-left corner of the corresponding rectangle, respectively. These properties save you from having to do calculations that game developers would otherwise have to do manually, so they are often used.

Note that in Pygame, the origin (0, 0) is located in the upper left corner of the screen, and the coordinate value will increase when moving to the lower right. On a 1200 × 800 screen, the origin is at the upper left corner, and the coordinates of the lower right corner are (1200, 800). These coordinates correspond to the game window, not the physical screen.

We're going to center the spaceship at the bottom of the screen. To do this, set self.rect.midbottom to the property midbottom of the rectangle representing the screen (see ❹ ). Pygame uses these rect attributes to position the spaceship image so it is aligned with the bottom edge of the screen and centered horizontally.

At ❺, the method blitme() is defined, which draws the image to the position specified by self.rect.

1.2 Draw the spaceship on the screen

Let's update alien_invasion.py to create a spaceship and call its method blitme():

  --snip--
  from settings import Settings
  from ship import Ship

  class AlienInvasion:
      """管理游戏资源和行为的类"""

      def __init__(self):
          --snip--
          pygame.display.set_caption("Alien Invasion")

❶         self.ship = Ship(self)

      def run_game(self):
              --snip--
              # 每次循环时都重绘屏幕。
              self.screen.fill(self.settings.bg_color)
❷             self.ship.blitme()

              # 让最近绘制的屏幕可见。
              pygame.display.flip()
  --snip--

Import the Ship class and create a Ship instance after the creation screen (see ❶). When calling Ship(), one parameter must be provided: an AlienInvasion instance. Here, self points to the current AlienInvasion instance. This parameter allows the Ship to access game resources such as the object screen. We assign this Ship instance to self.ship.

After filling the background, call ship.blitme() to draw the ship to the screen, making sure it appears in front of the background (see ❷).

Now if you run alien_invasion.py, you will see the spaceship centered at the bottom of the empty game screen as shown.

insert image description here

2. Refactoring: methods _check_events() and _update_screen()

In large projects, it is often necessary to refactor existing code before adding new code. Refactoring aims to simplify the structure of existing code and make it easier to extend. This section will split the longer and longer method run_game() into two helper methods. Helper methods perform tasks within a class, but are not invoked through an instance. In Python, helper method names start with a single underscore.

2.1 method_check_events()

We will move the code for managing events into a method called _check_events() to simplify run_game() and isolate the event management loop. By isolating the event loop, event management is decoupled from other aspects of the game, such as updating screens.

The following is the AlienInvasion class after the new method _check_events(), only the code of run_game() is affected:

      def run_game(self):
          """开始游戏主循环。"""
          while True:
❶             self._check_events()
              # 每次循环时都重绘屏幕。
              --snip--
def _check_events(self):
          """响应按键和鼠标事件。"""
          for event in pygame.event.get():
              if event.type == pygame.QUIT:
                  sys.exit()

Add a new method _check_events() (see ❷), and move the code to check whether the player clicked the close window button into this method.

To call a method of the current class, use the period notation, and specify the variable name self and the name of the method to call (see ❶). We call this new method in the while loop of run_game().

2.2 Method _update_screen()

To further simplify run_game(), move the code that updates the screen into a method called _update_screen():

      def run_game(self):
          """开始游戏主循环。"""
          while True:
              self._check_events()
              self._update_screen()

      def _check_events(self):
          --snip--

      def _update_screen(self):
          """更新屏幕上的图像,并切换到新屏幕。"""
          self.screen.fill(self.settings.bg_color)
          self.ship.blitme()

          pygame.display.flip()

We moved the code for drawing the background and spaceship and switching screens into the method _update_screen(). Now, the main loop in run_game() is much simpler, and it's easy to see that in each loop new events are detected and the screen is updated.

If you've developed a lot of games, you've probably started putting code like this in different methods already. But if you have never developed such a project, you may not know how to organize the code. The approach used here is to write feasible code first, and then refactor when the code becomes more and more complex, so as to show you the real development process: first write as simple code as possible, and then refactor it when the project becomes more and more complex. Do the refactoring.

After refactoring the code to make it easier to extend, it's time to start working on the dynamic aspects of the game!

Guess you like

Origin blog.csdn.net/qq_41600018/article/details/131359166