Write a game in python: "Alien Invasion" ---> Add Aliens

Project requirements:

In the game Alien Invasion, the player controls a spaceship that initially appears at the bottom center of the screen. Players can use the arrow keys to move the spaceship left and right, and the space bar to shoot. The game starts with a group of aliens appearing in the sky and they move down the screen. The player's task is to shoot and kill these aliens. After the player wipes out all the aliens, a new group of aliens will appear, and the speed at which they move. Whenever an alien hits the player's ship or reaches the bottom of the screen, the player loses a ship. The game ends after the player loses three ships.

In the first phase, we created a spaceship that can move left and right and fire when the user presses the space bar. With this behavior in place, we were able to turn our attention to the aliens and improve the gameplay of the game.

Past blog

About: Setting Up the Spaceship Blog

About: Adding shooting function to the spaceship blog


Objectives of this chapter:

In this chapter, we will add aliens to Alien Invasion. First, we add an alien near the top edge of the screen, then spawn a group of aliens. We made the group of aliens move to the sides and down, and deleted the ones that got hit by bullets. Finally, we'll display the number of ships the player has and end the game when the player runs out of ships.

Set the shortcut key to close the game

In the check_keydown_events method of the game_functions.py file:

def check_keydown_events(event,ai_settings,screen,ship,bullets):
	#在监听用户按键操作方法中添加 ctrl+q的快捷退出游戏
	elif event.key == pygame.K_q:
		sys.exit()
Create the first alien

Setting up aliens on screen is similar to setting up spaceships.
We set up an Alien class to control the alien, just as we set up a ship class to control the spaceship.

Similarly, we use bitmaps to represent aliens, because pygame loads bitmaps by default.

Since there are already pictures related to "Alien Invasion" in csdn, they cannot be uploaded, so I put the pictures here:
insert image description here

Create the Alien class
import pygame
from pygame.sprite import Sprite

class Alien(Sprite):
	def __init__(self,ai_settings,screen):
		#初始化外星人并设置其起始位置
		super(Alien,self).__init__()
		self.screen = screen
		self.ai_settings = ai_settings
		
		#加载外星人图像,并设置rect属性
		self.image = pygame.image.load('images/alien.bmp')
		self.rect = self.image.get_rect()
		
		#每个外星人都在屏幕左上角附近
		self.rect.x = self.rect.width
		self.rect.y = self.rect.height
		
		#存储外星人的准确位置
		self.x = float(self.rect.x)
		
	def blitme(self):
		self.screen.blit(self.image,self.rect)

After defining the class for controlling aliens, we need to instantiate it.
alien_invasion.py:

from alien import Alien 

def run_game():
	#创建外星人
	alien = Alien(ai_settings,screen)

#并且在主循环的 gf.update_screen()调用处添加新的形参
gf.update_screen(ai_settings,screen,ship,alien,bullets)
make aliens appear on the screen

game_functions.py:

def update_screen(ai_settings,screen,ship,alien,bullets):
	alien.blitem()

insert image description here

Now, we have successfully displayed the alien on the screen,
we have gone through three steps:

  1. Set the alien class that manages aliens. In this class, we first initialize its position, and then load the picture. After loading the picture and obtaining its properties, set the position where it appears, and store the precise position ,draw.
  2. Instantiate the alien class. The purpose of instantiating this class is to pass parameters to it when calling the update_screen() function in the game_functions module. With this parameter, it can be drawn to the screen.
  3. Finally, in order to display the aliens on the screen, call the biltem() function in update_screen() for drawing.
Create a group of aliens

To draw a group of aliens, you need to determine how many aliens fit in one row and how many rows of aliens you want to draw. We'll first calculate the horizontal spacing between the aliens and create a row of aliens, then determine the available vertical space and create the entire group of aliens.

Determine how many aliens can fit in a row

To determine how many aliens can fit in a row, let's see how much horizontal space is available:

The screen width is stored in ai_settings.screen_width, but you need to leave a certain margin on both sides of the screen. Set it to the width of the alien. Since there are two margins, the horizontal space that can be used to place the alien is the screen Width minus twice the width of the alien:

available_space_x = ai_settings.screen_width-(2 * alien_width)

insert image description here

We also need some space between the aliens, the alien width. Therefore, the horizontal space required to display an alien is twice the width of the alien: one width for the alien, and one width for the empty space to the right of the alien. To determine how many aliens can fit in a row, we divide the available space by twice the width of the alien:

number_aliens_x = available_space_x / (2 * alien_width)

These two formulas will be used in --> to create the alien.

Create multi-line aliens

We create an empty group called aliens in alien_invasion to store all aliens,
and then call the alien function in game_functions.py to create aliens:

	#创建外星人编组
	aliens =Group()
	#创建外星人群
	gf.crate_fleet(ai_settings,screen,aliens)

# while 循环来控制游戏
	while True:
		gf.update_screen(ai_settings,screen,ship,aliens,bullets)

Since we no longer create aliens directly in alien_settings.py,
there is no need to import the Alien class in this file.

Next, call the function crate_fleet() that you will write later, passing it the ai_settings, the object screen, and the empty marshal aliens. Then, modify the call to update_screen() to give it access to the alien marshalling.

Modify update_screen():

def update_screen(ai_settings,screen,ship,aliens,bullets):
		#每次循环时都重绘屏幕
		screen.fill(ai_settings.bg_color)
		#在飞船和外星人后面重绘所有子弹
		for bullet in bullets.sprites():
			bullet.draw_bullet()
		ship.blitme()
		aliens.draw(screen)
		
		#让最近绘制的屏幕可见
		pygame.display.flip()

When calling draw() on the group, pygame automatically draws each element of the group, and the drawing position is determined by the attribute rect of the element. Here, aliens.draw(screen) draws each alien in the group on the screen.

Create Alien Crowds

Alien swarms can now be created. Below is the new function crate_flect(), we put it at the end of game_functions.py, we also need to import the Alien class, so be sure to add the corresponding import statement at the beginning of the file game_functions.py:

from alien import Alien

def crate_fleet(ai_settings,screen,aliens):
	#创建外星人群
	
	#创建一个外星人,并计算一行可容纳多少个外星人
	alien = Alien(ai_settings,screen)
	alien_width = alien.rect.width
	available_space_x = ai_settings.screen_width - 2 * alien_width
	#外星人间距为外星人宽度
	number_aliens_x = int(available_space_x /(2 * alien_width))
	
	#创建一行外星人
	for alien_number in range(number_aliens_x):
		#创建第一个外星人并将其加入当前行
		alien = Alien(ai_settings,screen)
		alien.x = alien_width + 2 * alien_width * alien_number
		alien.rect.x = alien.x
		aliens.add(alien)

insert image description here

summary

In order to place the alien, we need to know the width and height of the alien, so we create an alien before performing the calculations.
alien = Alien(ai_settings,screen)
This alien is not a member of the alien population, so it is not added to the group aliens.
alien_width = alien. rect. width. In this code statement, we get the width of the alien from the rect attribute of the alien, and store this value in alien_width to avoid repeatedly accessing the attribute rect.
available_space_x = ai_settings. screen_width - 2 * alien_width. Here, we calculate the horizontal space available to place aliens, and how many aliens can fit in it.
number_aliens_x = int(available_space_x /(2 * alien_width)). Compared to before, we use int() here to ensure that the calculated number of aliens is an integer.
The final loop, which counts from zero to the number of aliens to create. In the body of the loop, we create a new alien and add it to the current row by setting the x coordinate. Push each alien one alien width to the right. Next, we multiply the width of the alien by 2 to get the space occupied by each alien, and then calculate the current position of the alien in the current row based on this. Finally, we add each newly created alien to the group aliens.

Refactor crate_fleet()

If we're creating alien swarms, maybe we should leave crate_fleet() as it is, but since we haven't finished creating aliens, let's clean up the function a bit. Below is crate_fleet() and two new functions: get_number_aliens_x() and crate_alien()

game_functions.py

def get_number_aliens_x(ai_settings,alien_width):
	#计算可容纳多少个外星人
	available_space_x = ai_settings.screen_width - 2 * alien_width
	#外星人间距为外星人宽度
	number_aliens_x = int(available_space_x /(2 * alien_width))
	return number_aliens_x	

def crate_alien(ai_settings,screen,aliens,alien_number):
	#创建一个外星人在当前行
	alien = Alien(ai_settings,screen)
	alien_width = alien.rect.width
	alien.x = alien_width + 2 * alien_width * alien_number
	alien.rect.x = alien.x
	aliens.add(alien)

def crate_fleet(ai_settings,screen,aliens):
	#创建外星人群
	#创建一个外星人,计算每行可以容纳多少个外星人
	alien = Alien(ai_settings,screen)
	number_aliens_x = get_number_aliens_x(ai_settings,alien.rect.width)
	
	#创建一行外星人
	for alien_number in range(number_aliens_x):
		#创建第一个外星人并将其加入当前行
		crate_alien(ai_settings,screen,aliens,alien_number)
add line

To create the alien crowd, calculate how many rows the screen will fit, and create a cycle of aliens that repeats that number of times. To calculate the number of rows to fit, we calculate the available vertical space by subtracting the screen height from the top margin of the first row of aliens (alien height), the height of the spaceship, and the original alien height plus the alien Margins (twice the height of the alien):

alailable_space_y = ai_settings.screen_height- 3 * alien_height - ship_height

This will leave some empty space above the ship, giving the player time to shoot the aliens.

Leave some space below each row and set it to the height of the alien. To calculate the number of rows that can fit, we divide the available vertical space by twice the height of the alien.

number_rows = alailable_space_y /(2 * alien_height)

game_functions.py:

def get_number_rows(ai_settings,ship_height,alien_height):
	#计算屏幕可容纳多少个外星人
	available_space_y = (ai_settings.screen_height- (3 * alien_height) - ship_height)
	number_rows =int(available_space_y /(2 * alien_height))
	return number_rows	

def crate_alien(ai_settings,screen,aliens,alien_number,row_number):
	#创建一个外星人在当前行
	alien = Alien(ai_settings,screen)
	alien_width = alien.rect.width
	alien.x = alien_width + 2 * alien_width * alien_number
	alien.rect.x = alien.x
	alien.rect.y = alien.rect.height + 2 * alien.rect.height * row_number
	aliens.add(alien)

def crate_fleet(ai_settings,screen,ship,aliens):
	#创建外星人群
	#创建一个外星人,计算每行可以容纳多少个外星人
	alien = Alien(ai_settings,screen)
	number_aliens_x = get_number_aliens_x(ai_settings,alien.rect.width)
	number_rows = get_number_rows(ai_settings,ship.rect.height,alien.rect.height) 
	
	#创建外星人群
	for row_number in range(number_rows):
		#创建一行外星人
		for alien_number in range(number_aliens_x):
			#创建第一个外星人并将其加入当前行
			crate_alien(ai_settings,screen,aliens,alien_number,row_number)

Modify alien_invasion.py call

gf.crate_fleet(ai_settings,screen,ship,aliens)

If we run the game now, we can see this effect:
insert image description here

make aliens move

Next, let's make the alien crowd move left and right on the screen, hit the edge of the screen and move down a certain distance, and then move in the opposite direction. We'll keep moving all the aliens around until all the aliens are wiped out, some aliens hit the ship, or some aliens reach the lower end of the screen.

Move the alien to the right

To move the aliens, we will use the method update() in alien.py and call it for each alien in the alien population. First, add a setting that controls the speed of the alien:

settings.py:

#外星人的设置
	self.alien_speed_factor = 1

Then, implement update() with this setup:

alien.py:

def update(self):
	#向右移动外星人
	self.x += self.ai_settings.alien_speed_factor
	self.rect.x = self.x

Every time the alien's position is updated, it is moved to the right by the value of alien_speed_factor. We keep track of the exact location of each alien using the property self.x, which stores a fractional value. We then use the value of self.x to update the position of the alien's rect.

Call the update function in the main loop to update the position of each alien:

alien_incasion.py:

while True:
	gf.update_alien(aliens)
	#在更新子弹的后面,更新外星人的位置
	#因为之后还要检查是否有子弹撞到了外星人

Finally, add a new function update_aliens() at the end of the file game_function.py:

def update(aliens):
	#更新外星人群中所有外星人的位置
	aliens.updete()

Let's create a setup where the alien hits the right edge of the screen and then moves down and then to the left.

Create a setup representing the direction the alien is moving

settings.py:

		#外星人的设置
		self.alien_speed_factor = 1
		self.fleet_drop_speed =10
		#fleet_direction为1表示向右移动,为-1表示向左移动
		self.fleet_direction =1

The setting fleet_drop_speed specifies how fast the alien moves down when it hits the edge of the screen. It is beneficial to separate this speed from the horizontal speed so that the two speeds can be adjusted separately.

To implement the fleet_direction setting, it could be set to a text value such as 'left' or 'right', but then an if-elif statement would have to be written to check the direction the alien swarm is moving. Since there are only two possible orientations, we use the values ​​-1 and 1 to represent them. And toggle between these two values ​​when the alien crowd changes direction.

Check if the alien hits the edge of the screen

We now write a method to check if any aliens have hit the edge of the screen, and we need to change update() so that each alien moves in the correct direction:

alien.py:

def check_edges(self):
		#如果外星人位于屏幕边缘,就返回True
		screen_rect = self.screen.get_rect()
		if self.rect.right >= screen_rect.right:
			return True
		elif self.rect.left <= 0:
			return True	
		
	def update(self):
		#向右移动外星人
		self.x += (self.ai_settings.alien_speed_factor 
		* self.ai_settings.fleet_direction)
		self.rect.x = self.x

We can call the method check_edges() on any alien to see if it is on the left or right edge of the screen. If the reght property of the alien's rect is greater than the right property of the screen's rect, it means the alien is on the right edge of the screen. If the left property of the alien's rect is less than or equal to 0, it means the alien is on the left edge of the screen.
We also modified update() to set the amount of movement to be a multiplier of the alien's speed and fleet_direction, making the alien move left or right. If fleet_direction is 1, increase the current x coordinate of the alien by alien_speed_factor, thereby moving the alien to the right; if the current x coordinate of the alien subtracts alien_speed_factor, thereby moving the alien to the left.

Move alien crowd down and change direction of movement

When an alien reaches the edge of the screen, it is necessary to move the entire group of aliens down and change their direction of movement.

We'll need to make a major change to game_functions.py, because here we're going to check to see if any aliens have reached the left or right edge. To do this, we write functions: check_fleet_edges() and change_fleet_direction(), and modify update_aliens():

def check_fleet_edges(ai_settings,aliens):
	#有外星人到达边缘时采取相应的措施
	for alien in aliens.sprites():
		if alien.check_edges():
			change_fleet_direction(ai_settings,aliens)
			break
			
def change_fleet_direction(ai_settings,aliens):
	#将整群外星人下移,并改变他们的方向
	for alien in aliens.sprites():
		alien.rect.y += ai_settings.fleet_drop_speed
	ai_settings.fleet_direction *= -1
	

def update_aliens(ai_settings,aliens):
	#检查是否有外星人位于屏幕边缘,并更新整群外星人的位置
	check_fleet_edges(ai_settings,aliens)
	
	#更新外新人群中所有外星人的位置
	aliens.update()
		

illustrate:

check_fleet_edges:

We iterate over the alien population and call check_edges() on each alien in it. If check_edges() returns True, we know that the corresponding alien is at the edge of the screen and need to change the direction of the alien crowd, so we call change_fleet_direction() and exit the loop.

check_fleet_direction:

We iterate through all aliens, move each alien down by the value set by fleet_drop_speed, and then modify the value of fleet_direction to the multiplier of the current value and -1.

update_aliens:

In it, check to see if any aliens are at the edge of the screen by calling check_fleet_edges().

alien_invasion.py:

# while 循环来控制游戏
	while True:
		gf.update_aliens(ai_settings,aliens)

If you run the game now, the swarm of aliens will move back and forth across the screen and down after reaching the edge of the screen.

Now you can start shooting aliens, check to see if any aliens have hit the ship, or reached the bottom of the screen.

shoot aliens

We created the spaceship and the alien crowd, but when the bullet hits the alien, it will pass through the alien because we haven't checked for collisions yet.
In game programming, collision refers to the overlapping of game elements. To enable the bullet to defeat the alien, we'll use sprite.groupcollide() to detect collisions between members of two groups.

Check bullets for collisions with aliens

The method sprite.groupcollide() compares the rect property of each bullet to the rect property of the alien and returns a dictionary containing the colliding bullets and aliens. In this dictionary, each key is a bullet, and the corresponding value is the alien that was hit.

In the function update_bullets(), write the code to check the collision:

def update_bullets(aliens,bullets):
	#更新子弹的位置,并删除已消失的子弹
	#更新子弹的位置
	bullets.update()
	
	#删除已消失的子弹
	for bullet in bullets.copy():
		if bullet.rect.bottom <= 0:
			bullets.remove(bullet)
			
	#检查是否有子弹击中外星人,如果是,删除相应子弹和外星人。
	pygame.sprite.groupcollide(bullets,aliens,True,True)

pygame.sprite.groupcollide(bullets,aliens,True,True) 说明:

This line of code iterates over each bullet in the group bullets, and then iterates over each alien in the group aliens.
Whenever the bullet's rect property overlaps with the alien's rect property, groupcollide() adds a key-value pair to the dictionary it returns. The two arguments True tell pygame to delete colliding bullets and aliens.

Finally, when calling update_bullets(), pass the actual parameter aliens:

gf.update_bullets(aliens,bullets)
Generate new alien populations

After the current alien crowd is eliminated, no new aliens will be generated. In order for the alien crowd to display new enemies now, we can code like this:

First check if aliens is empty, if it is empty, call crate_fleet(), we will perform this check in update_bullets(), because aliens are all eliminated here:

def update_bullets(ai_settings,screen,ship,aliens,bullets):
	#更新子弹的位置,并删除已消失的子弹
	#更新子弹的位置
	bullets.update()
	
	#删除已消失的子弹
	for bullet in bullets.copy():
		if bullet.rect.bottom <= 0:
			bullets.remove(bullet)
			
	#检查是否有子弹击中外星人,如果是,删除相应子弹和外星人。
	pygame.sprite.groupcollide(bullets,aliens,True,True)
	
	if len(aliens) ==0:
		bullets.empty()
		crate_fleet(ai_settings,screen,ship,aliens)

Checking out in the if statement, we call empty() which removes all sprites remaining in the group, thereby removing the existing bullets, and then calls crate_fleet() to display the alien crowd on screen again.

Refactor update_bullets()

Next we refactor update_bullets() so that it doesn't do so many tasks anymore. We'll move the code that handles bullet and alien collisions into a separate function:

def update_bullets(ai_settings,screen,ship,aliens,bullets):
	#更新子弹的位置,并删除已消失的子弹
	#更新子弹的位置
	bullets.update()
	
	#删除已消失的子弹
	for bullet in bullets.copy():
		if bullet.rect.bottom <= 0:
			bullets.remove(bullet)
			
	check_bullet_alien_collisions(ai_settings,screen,ship,aliens,bullets)
	
	
	
def check_bullet_alien_collisions(ai_settings,screen,ship,aliens,bullets):	
	#检查是否有子弹击中外星人,如果是,删除相应子弹和外星人。
	pygame.sprite.groupcollide(bullets,aliens,True,True)
	
	if len(aliens) ==0:
		bullets.empty()
		crate_fleet(ai_settings,screen,ship,aliens)

Guess you like

Origin blog.csdn.net/tianlei_/article/details/129847209