World War II aircraft to achieve an enhanced version of Python

Disclaimer: This article is a blogger original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
This link: https://blog.csdn.net/marble_xu/article/details/87886325

World War II aircraft to achieve an enhanced version of Python

Game description World War II aircraft

Based on an airplane on github Python implementation shooter PythonShootGmae
original version is relatively simple, there is only one enemy. But where the resource folder contains three enemy aircraft pictures and sound, it has been enhanced based on existing resources.

On this basis, an enhanced version adds the following features

  • It supports three types of enemy
  • Support enemy firing bullets
  • Add weapon type of aircraft (bombs, bullets simultaneously transmit multiple lines)
  • The enemy can appear from three directions left, above and to the right
  • A number of life-support aircraft
  • Add props acquisition (can get bombs, bullets and enhancements)

Code Description

There are four file code implementation

  • shooter.py: Initialization and circulated game game main function
  • gameRole.py: contains additional class definition games enemy bullets, props and heroes (our aircraft) class, and management of these classes
  • resource.py: responsible for picture and sound initialization
  • config.py: You can set the difficulty of the parameters of the game

gameRole.py

The case here defined enemy, bullets, props and hero classes inherit the pygame sprite class (pygame.sprite.Sprite), because the collision detection use the wizard class support, there are multiple enemies in multiple bullets using wizard class, you can simplify the complexity of the code.

Enemy herein illustrates the relationship class and its associated class EnemyGroup class.
According to the documentation pygame.sprite.Sprite, subclasses need to implement the update function, and to Sprite class member variable of the image, rect assignment.
The base class for visible game objects. Derived classes will want to override the Sprite.update () and assign a Sprite.image and Sprite.rect attributes.

Enemy class
initialization function sets the class member variable image pygame sprite class needs at the time of the drawing, rect, direction of flight, and weapons.
update function will update the location of the enemy, if you have weapons, but also regularly fired bullets.

class Enemy(pygame.sprite.Sprite):
	def __init__(self, enemy_surface, enemy_init_pos, direction, weapon_group):
		pygame.sprite.Sprite.__init__(self)
		self.image = enemy_surface
		self.rect = self.image.get_rect()
		self.rect.topleft = enemy_init_pos
		self.direction = direction
		self.down_index = 0
		self.damage = 0
		self.is_down = 0
		self.is_hit = 0
		self.ticks = 0
		self.weapon_group = weapon_group

	def update(self, enemy_surface, hit_surface=0):
		def shootWeapon(weapon_group, position, direction):
			weapon_group.shootWeapon(position, direction)
			
		#direction[0]:x , direction[1]:y
		should_kill = False
		self.rect.x += self.direction[0]
		self.rect.y += self.direction[1]
		if self.rect.x > SCREEN_WIDTH or self.rect.x < -self.image.get_width():
			should_kill = True
		if self.rect.y > SCREEN_HEIGHT or self.rect.y < -self.image.get_height():
			should_kill = True
				
		if should_kill:
			self.kill()
		else:
			if self.ticks >= ENEMY_SHOOT_CYCLE:
				self.ticks = 0
				
			if self.is_hit:
				self.is_hit -= 1
				self.image = hit_surface
			elif len(enemy_surface) >= 2:
				self.image = enemy_surface[self.ticks//(ENEMY_SHOOT_CYCLE//2)]
			else:
				self.image = enemy_surface[0]

			self.ticks += 1
			if self.weapon_group is not None:
				if self.ticks % ENEMY_SHOOT_CYCLE == 0:
					shootWeapon(self.weapon_group, [self.rect.centerx, self.rect.y + self.image.get_height()], [0, ENEMY_SHOOT_SPEED])

EnemyGroup class
currently supports three types of enemy, the enemy will be set in the initialization function of the type of enemy_type, create a group spirit group, used to store and manage all types generated by the enemy, the enemy has set up weapons.
createEnemy function will create random enemy aircraft appear from a certain direction (left, above, left), and added to the group.
checkBulletCollide function detects if a bullet heroes and launch of this type of enemy aircraft collided with each collision will cause some damage when the enemy's life is less than the cumulative damage, it is judged to be eliminated.
checkBulletCollide function detects whether the hero and this type of enemy, or enemy bullets launch of a collision.

class EnemyGroup():
	def __init__(self, surface, hit_surface, down_surface, down_sound, score, health, speed, enemy_type, weapon_group):
		self.surface = surface
		self.hit_surface = hit_surface
		self.down_surface = down_surface
		self.group = pygame.sprite.Group()
		self.down_group = pygame.sprite.Group()
		self.down_sound = down_sound
		self.score = score
		self.health = health
		self.speed = speed
		self.enemy_type = enemy_type
		self.weapon_group = weapon_group
	
	def createEnemy(self):
		def getDirection(surface, speed, enemy_type):
			if enemy_type == EnemyType.EnemyType3:
				enemy_init_pos = [randint(0, SCREEN_WIDTH - surface.get_width()), -surface.get_height()]
				direction = [0, speed]
			else:
				# enemy can appear from top side, left side,  and right side
				appearSide = randint(0, 2)
				if appearSide == 0: # from top side
					enemy_init_pos = [randint(0, SCREEN_WIDTH - surface.get_width()), -surface.get_height()]
					direction = [0, speed]
				elif appearSide == 1: # from left side
					enemy_init_pos = [-surface.get_width(), randint(0, (ENEMY_APPEAR_HEIGHT - surface.get_height()))]
					direction = [randint(1, speed), randint(1, speed)]
				elif appearSide == 2: # from right side
					enemy_init_pos = [SCREEN_WIDTH, randint(0, (ENEMY_APPEAR_HEIGHT - surface.get_height()))]
					direction = [randint(-speed, -1), randint(1, speed)]
			return (enemy_init_pos, direction)
		
		(enemy_init_pos, direction)	= getDirection(self.surface[0], self.speed, self.enemy_type)
		enemy = Enemy(self.surface[0], enemy_init_pos, direction, self.weapon_group)
		self.group.add(enemy)
		
	def update(self):
		self.group.update(self.surface, self.hit_surface)
		if self.weapon_group is not None:
			self.weapon_group.update()
	
	def draw(self, screen):
		self.group.draw(screen)
		if self.weapon_group is not None:
			self.weapon_group.draw(screen)
	
	def checkBulletCollide(self, bullets, screen, ticks):
		score = 0
		self.down_group.add(pygame.sprite.groupcollide(self.group, bullets.group, False, True))
		for enemy_down in self.down_group:
			if enemy_down.is_down:
				screen.blit(self.down_surface[enemy_down.down_index], enemy_down.rect)
				if ticks % (ANIMATE_CYCLE//2) == 0:
					if enemy_down.down_index < (len(self.down_surface)-1):
						if enemy_down.down_index == 0:
							self.down_sound.play()
						enemy_down.down_index += 1
					else:
						self.down_group.remove(enemy_down)
						score += self.score
			else:
				enemy_down.damage += bullets.damage
				enemy_down.is_hit = ANIMATE_CYCLE//3
				if enemy_down.damage >= self.health:
					enemy_down.is_down = 1
					self.group.remove(enemy_down)
				else:
					self.down_group.remove(enemy_down)
		return score

	def checkHeroCollide(self, hero):
		enemy_down_list = pygame.sprite.spritecollide(hero, self.group, False)
		collide = False
		if len(enemy_down_list) > 0:
			for enemy_down in enemy_down_list:
				if pygame.sprite.collide_circle_ratio(0.7)(enemy_down, hero):
					self.group.remove(enemy_down)
					self.down_group.add(enemy_down)
					enemy_down.is_down = 1
					collide = True
		
		if not collide and self.weapon_group is not None:
			bullet_hit_list = pygame.sprite.spritecollide(hero, self.weapon_group.group, False)
			if len(bullet_hit_list) > 0:
				for bullet_hit in bullet_hit_list:
					if pygame.sprite.collide_circle_ratio(0.7)(bullet_hit, hero):
						self.weapon_group.group.remove(bullet_hit)
						collide = True
			
		return collide

shooter.py

Defines a Game class, which paly () handler is the main game loop, is responsible for updating the background image every so often generate enemy and props, to detect bullets and whether the aircraft collided detect whether the hero and enemy aircraft collision . And call the enemy, the hero of their own class to refresh the drawing.

class Game():
	def __init__(self, caption, hero, screen_info):
		self.screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
		pygame.display.set_caption(caption)
		self.hero = hero
		self.clock = pygame.time.Clock()
		self.screen_info = screen_info
		self.ticks = 0
		self.pause = False
		self.backgound_y = SCREEN_HEIGHT - background.get_height() # height of background image must be larger than SCREEN_HEIGHT
	
	def play(self, enemy_groups, gift_groups):
		def updateBackground(screen, image_height, current_y):
			if current_y <= 0:
				screen.blit(background, (0, 0), (0, -current_y, SCREEN_WIDTH, SCREEN_HEIGHT))
			elif current_y < SCREEN_HEIGHT:
				screen.blit(background, (0, 0), (0, image_height - current_y, SCREEN_WIDTH, current_y))
				screen.blit(background, (0, current_y), (0, 0, SCREEN_WIDTH, SCREEN_HEIGHT - current_y))
				
		def checkBulletCollide(enemy_group, bullets_group, screen, ticks):
			score = 0
			for group in enemy_group:
				for bullet_group in bullets_group:
					score += group.checkBulletCollide(bullet_group, screen, ticks) 
			return score

		def checkHeroCollide(hero, enemy_group):
			collide = False
			for group in enemy_group:
				if group.checkHeroCollide(hero):
					collide = True
					break;
			return collide
		
		self.clock.tick(FRAME_RATE)
		if self.backgound_y == SCREEN_HEIGHT:
			self.backgound_y = SCREEN_HEIGHT - background.get_height()
		updateBackground(self.screen, background.get_height(), self.backgound_y)	
		self.backgound_y += 1
		
		if self.ticks >= FRAME_RATE:
			self.ticks = 0
			
		self.hero.play()
		
		self.createEnemy(enemy_groups, self.ticks, self.screen_info.getScore())
		self.createGift(gift_groups, self.ticks, self.screen_info)
		
		self.screen_info.addScore(checkBulletCollide(enemy_groups, self.hero.weapon_groups, self.screen, self.ticks))
		
		if checkHeroCollide(self.hero, enemy_groups):
			if self.hero.isHeroCrash():
				game_over_sound.play()
		
		for gift_group in gift_groups:
			gift_group.checkHeroCollide(self.hero)

		for weapon_group in self.hero.weapon_groups:
			weapon_group.draw(self.screen)
			
		for enemy_group in enemy_groups:
			enemy_group.update()
			enemy_group.draw(self.screen)

		for gift_group in gift_groups:
			gift_group.update()
			gift_group.draw(self.screen)
			
		self.screen.blit(self.hero.image, self.hero.rect)
		self.ticks += 1
		
		self.screen_info.displayInfo(self.screen, 0, self.hero.bomb_num, self.hero.life)
	

The main loop of the game is as follows

  • To determine the state of the game
    • If the game ends, the end of the display screen
    • If the game is paused, do not do the operation
    • If the game does not pause, for processing
  • Get pygame event, read keyboard input and processing
  • If there is a direction key input, the mobile hero
while True:
	if myGame.isGameOver():
		myGame.showGameOver()
	elif not myGame.isPause():
		myGame.play(enemy_groups, gift_groups)
		
	pygame.display.update()
	
	for event in pygame.event.get():
		if event.type == pygame.QUIT:
			pygame.quit()
			exit()
		# get keyboard input
		if event.type == pygame.KEYDOWN:
			if event.key in offset:
				offset[event.key] = 3
			elif event.key == pygame.K_SPACE:
				myGame.hero.useBomb()
			# press z to pause or resume game
			elif event.key == pygame.K_z:
				myGame.setPause()
		elif event.type == pygame.KEYUP:
			if event.key in offset:
				offset[event.key] = 0

	if not myGame.hero.is_hit:
		myGame.hero.move(offset)

Game results

Screenshot game execution is as follows:
Here Insert Picture Description

The complete code

Complete implementation of the code github link aircraft World War II enhanced version
here is the download link csdn aircraft World War II enhanced version of the
compiler environment
python3.7 + pygame1.9

Guess you like

Origin blog.csdn.net/marble_xu/article/details/87886325