Pygame - 外星人入侵:让外星人还击
Pygame - Alien Invasion: Making aliens shoot back
我目前正在尝试让我的外星人在游戏过程中向玩家投掷 'bombs'。我目前的目标是让所有外星人都投下炸弹,然后最终让外星人在达到一定水平后随机投下炸弹。
Currently is seems that all bombs are coming from the starting location of my first alien.
alien_invasion.py
import sys, pygame
from settings import Settings
from ship import Ship
from bombs import Bomb
from alien import Alien
class AlienInvasion:
"""Overall class to manage game assets and behavior."""
def __init__(self):
"""Initlize the game, and create game resources."""
pygame.init()
self.settings = Settings()
self.screen = pygame.display.set_mode((self.settings.screen_width,
self.settings.screen_height))
self.settings.screen_width = self.screen.get_rect().width
self.settings.screen_height = self.screen.get_rect().height
pygame.display.set_caption("Alien Invasion")
self.ship = Ship(self)
self.alien = Alien(self)
self.bullets = pygame.sprite.Group()
self.bombs = pygame.sprite.Group()
self.aliens = pygame.sprite.Group()
self._create_fleet()
#Set our background color
self.bg_color = (230, 230, 230)
def run_game(self):
"""Start main loop for our game."""
while True:
self._check_events()
self.ship.update()
self._drop_bombs()
self._update_bombs()
self._update_aliens()
self._update_screen()
def _check_events(self):
"""Respond to kepresses and mouse events."""
#for each event in game capture that event
for event in pygame.event.get():
#if player preses close, quit game
if event.type == pygame.QUIT:
sys.exit()
# if event is a key press
elif event.type == pygame.KEYDOWN:
self._check_keydown_events(event)
elif event.type == pygame.KEYUP:
self._check_keyup_events(event)
def _check_keydown_events(self, event):
"""respond to keydown events"""
if event.key == pygame.K_RIGHT:
self.ship.moving_right = True
elif event.key == pygame.K_LEFT:
self.ship.moving_left = True
elif event.key == pygame.K_ESCAPE:
sys.exit()
def _check_keyup_events(self, event):
if event.key == pygame.K_RIGHT:
self.ship.moving_right = False
elif event.key == pygame.K_LEFT:
self.ship.moving_left = False
def _drop_bombs(self):
"""drop bombs from alien ships"""
new_bomb = Bomb(self)
for alien in self.aliens:
self.bombs.add(new_bomb)
def _update_bombs(self):
"""update bombs positions and gets rid of old bombs"""
self.screen_rect = self.screen.get_rect()
self.bombs.update()
for bomb in self.bombs.copy():
if bomb.rect.bottom >= self.screen_rect.bottom:
self.bombs.remove(bomb)
def _update_aliens(self):
"""update the position of the aliens"""
self._check_fleet_edges()
self.aliens.update()
self._check_aliens_bottom()
def _create_fleet(self):
"""create our fleet of aliens"""
# creat an alien and fine the number that fits in a row
# spacing between each alien is equal to one alien
alien = Alien(self)
alien_width, alien_height = alien.rect.size
available_space_x = self.settings.screen_width - (2 * alien_width)
number_aliens_x = available_space_x // (2 * alien_width)
# determine the number of rows that fit on the screen
ship_height = self.ship.rect.height
available_space_y = (self.settings.screen_height -
(5 * alien_height) - ship_height)
number_rows = available_space_y // (2 * alien_height)
# create a full fleet of aliens
for row_number in range(number_rows):
for alien_number in range(number_aliens_x):
self._create_alien(alien_number, row_number)
def _create_alien(self, alien_number, row_number):
alien = Alien(self)
alien_width, alien_height = alien.rect.size
alien.x = alien_width + 2 * alien_width * alien_number
alien.rect.x = alien.x
alien.rect.y = 2 * alien_height + 2 * alien.rect.height * row_number
self.aliens.add(alien)
def _check_fleet_edges(self):
"""respond if any aliens reach the edge"""
for alien in self.aliens.sprites():
if alien.check_edges():
self._change_fleet_direction()
break
def _check_aliens_bottom(self):
"""check if any aliens have reached the bottom of the screen"""
screen_rect = self.screen.get_rect()
for alien in self.aliens.sprites():
if alien.rect.bottom >= screen_rect.bottom:
self._ship_hit()
break
def _change_fleet_direction(self):
"""drop entire fleet and change direction"""
for alien in self.aliens.sprites():
alien.rect.y += self.settings.fleet_drop_speed
self.settings.fleet_direction *= -1
def _update_screen(self):
"""Update images on screen and flip to the new screen."""
#fill our background with our bg_color
self.screen.fill(self.settings.bg_color)
#draw ship to screen
self.ship.blitme()
for bullet in self.bullets.sprites():
bullet.draw_bullet()
self.aliens.draw(self.screen)
for bomb in self.bombs.sprites():
bomb.draw_bomb()
#Make the most recently drawn screen visible.
#this clears our previous screen and updates it to a new one
#this gives our programe smooth movemnt
pygame.display.flip()
if __name__ == '__main__':
#Make a game instance, and run the game
ai = AlienInvasion()
ai.run_game()
alien.py
import pygame
from pygame.sprite import Sprite
class Alien(Sprite):
"""A class to represent a sinlge alien in the fleet"""
def __init__(self, ai_game):
"""initlize alien and set its starting position"""
super().__init__()
self.screen = ai_game.screen
self.settings = ai_game.settings
self.screen_rect = ai_game.screen.get_rect()
# load alien image at set its rect
self.image = pygame.image.load('images/alien.bmp')
self.rect = self.image.get_rect()
# start each new alien at the top left of the screen
self.rect.x = self.rect.width
self.rect.y = self.rect.height
# store aliens exact position (decimal)
self.x = float(self.rect.x)
def check_edges(self):
"""return true if alien is at edge of screen"""
screen_rect = self.screen.get_rect()
if self.rect.right >= screen_rect.right or self.rect.left <= 0:
return True
def update(self):
"""move the alien to the right or left"""
self.x += (self.settings.alien_speed *
self.settings.fleet_direction)
self.rect.x = self.x
bombs.py
from pygame.sprite import Sprite
class Bomb(Sprite):
"""create a bullet that is dropped by aliens"""
def __init__(self, ai_game):
super().__init__()
self.screen = ai_game.screen
self.settings = ai_game.settings
self.color = self.settings.bullet_color
self.rect = pygame.Rect(0, 0, self.settings.bullet_width,
self.settings.bullet_height)
self.rect.midbottom = ai_game.alien.rect.midbottom
self.y = float(self.rect.y)
def update(self):
"""move bullet down screen"""
self.y += self.settings.bullet_speed
self.rect.y = self.y
def draw_bomb(self):
"""draw bullet to screen"""
pygame.draw.rect(self.screen, self.color, self.rect)
settings.py
class Settings:
"""A class to store our settings for Alien Invasion game."""
def __init__(self):
"""Initlize the games settings."""
# screen settings
self.screen_width = 1600
self.screen_height = 900
self.bg_color = (230, 230, 230)
# ship settings
self.ship_limit = 3
# bullet settings
self.bullet_width = 3
self.bullet_height = 15
self.bullet_color = (60, 60, 60)
self.bullets_allowed = 3
# alien settings
self.fleet_drop_speed = 10
# how quickly the game speeds up
self.speedup_scale = 1.1
# how muct alien poits value increses
self.score_scale = 1.5
self.initialize_dynamic_settings()
def initialize_dynamic_settings(self):
"""settings that change through the game"""
self.ship_speed = 1.5
self.bullet_speed = 1.5
self.alien_speed = 0.5
self.fleet_direction = 1
# scoring
self.alien_points = 50
def increse_speed(self):
"""increse speed settings"""
self.ship_speed *= self.speedup_scale
self.bullet_speed *= self.speedup_scale
self.alien_speed *= self.speedup_scale
self.alien_points = int(self.alien_points * self.score_scale)
ship.py
from pygame.sprite import Sprite
class Ship(Sprite):
"""A class for managing our ship."""
def __init__(self, ai_game):
"""Initlize the ship and set its starting position."""
super().__init__()
self.screen = ai_game.screen
self.settings = ai_game.settings
self.screen_rect = ai_game.screen.get_rect()
# load ship image and get its rect.(rect stands for rectangle)
self.image = pygame.image.load('images/ship.bmp')
self.rect = self.image.get_rect()
# Start each new ship at the bottom center of the screen.
self.rect.midbottom = self.screen_rect.midbottom
# store a decimal value for the ship's horizontal position
self.x = float(self.rect.x)
# movement flags
# we start our flag at false so the ship doesnt move by itself
self.moving_right = False
self.moving_left = False
def update(self):
"""Update ships position based on our movement flags"""
# update ship's x value, not its rectange
if self.moving_right and self.rect.right < self.screen_rect.right:
self.x += self.settings.ship_speed
if self.moving_left and self.rect.left > 0:
self.x -= self.settings.ship_speed
# update rect object for self.x
self.rect.x = self.x
def blitme(self):
"""Draw the ship at its current location."""
self.screen.blit(self.image, self.rect)
def center_ship(self):
"""center ship"""
self.rect.midbottom = self.screen_rect.midbottom
self.x = float(self.rect.x)
我将如何让每个外星人投下他们自己的炸弹?
希望这遵循对你们更好的最小可重现示例。
你需要在炸弹的 __init__
中包含炸弹的 x y 位置:
class Bomb(sprite):
def __init__(self, ai_game, x, y):
# [...]
self.rect = pygame.Rect(x, y, self.settings.bullet_width,
self.settings.bullet_height)
self.y = y
现在在创建炸弹时(在 _drop_bombs
中),您需要包括外星人的 x 和 y 位置:
class AlienInvasion:
# [...]
def _drop_bombs(self):
"""drop bombs from alien ships"""
for alien in self.aliens:
new_bomb = Bomb(self, alien.x, alien.y) # top left of alien
# do alien.x + 5 or something to drop the bomb in the middle
self.bombs.add(new_bomb)
我还建议在 __init__
中包含外星人的 x 和 y 位置,而不是事后修改它。
我目前正在尝试让我的外星人在游戏过程中向玩家投掷 'bombs'。我目前的目标是让所有外星人都投下炸弹,然后最终让外星人在达到一定水平后随机投下炸弹。
Currently is seems that all bombs are coming from the starting location of my first alien.
alien_invasion.py
import sys, pygame
from settings import Settings
from ship import Ship
from bombs import Bomb
from alien import Alien
class AlienInvasion:
"""Overall class to manage game assets and behavior."""
def __init__(self):
"""Initlize the game, and create game resources."""
pygame.init()
self.settings = Settings()
self.screen = pygame.display.set_mode((self.settings.screen_width,
self.settings.screen_height))
self.settings.screen_width = self.screen.get_rect().width
self.settings.screen_height = self.screen.get_rect().height
pygame.display.set_caption("Alien Invasion")
self.ship = Ship(self)
self.alien = Alien(self)
self.bullets = pygame.sprite.Group()
self.bombs = pygame.sprite.Group()
self.aliens = pygame.sprite.Group()
self._create_fleet()
#Set our background color
self.bg_color = (230, 230, 230)
def run_game(self):
"""Start main loop for our game."""
while True:
self._check_events()
self.ship.update()
self._drop_bombs()
self._update_bombs()
self._update_aliens()
self._update_screen()
def _check_events(self):
"""Respond to kepresses and mouse events."""
#for each event in game capture that event
for event in pygame.event.get():
#if player preses close, quit game
if event.type == pygame.QUIT:
sys.exit()
# if event is a key press
elif event.type == pygame.KEYDOWN:
self._check_keydown_events(event)
elif event.type == pygame.KEYUP:
self._check_keyup_events(event)
def _check_keydown_events(self, event):
"""respond to keydown events"""
if event.key == pygame.K_RIGHT:
self.ship.moving_right = True
elif event.key == pygame.K_LEFT:
self.ship.moving_left = True
elif event.key == pygame.K_ESCAPE:
sys.exit()
def _check_keyup_events(self, event):
if event.key == pygame.K_RIGHT:
self.ship.moving_right = False
elif event.key == pygame.K_LEFT:
self.ship.moving_left = False
def _drop_bombs(self):
"""drop bombs from alien ships"""
new_bomb = Bomb(self)
for alien in self.aliens:
self.bombs.add(new_bomb)
def _update_bombs(self):
"""update bombs positions and gets rid of old bombs"""
self.screen_rect = self.screen.get_rect()
self.bombs.update()
for bomb in self.bombs.copy():
if bomb.rect.bottom >= self.screen_rect.bottom:
self.bombs.remove(bomb)
def _update_aliens(self):
"""update the position of the aliens"""
self._check_fleet_edges()
self.aliens.update()
self._check_aliens_bottom()
def _create_fleet(self):
"""create our fleet of aliens"""
# creat an alien and fine the number that fits in a row
# spacing between each alien is equal to one alien
alien = Alien(self)
alien_width, alien_height = alien.rect.size
available_space_x = self.settings.screen_width - (2 * alien_width)
number_aliens_x = available_space_x // (2 * alien_width)
# determine the number of rows that fit on the screen
ship_height = self.ship.rect.height
available_space_y = (self.settings.screen_height -
(5 * alien_height) - ship_height)
number_rows = available_space_y // (2 * alien_height)
# create a full fleet of aliens
for row_number in range(number_rows):
for alien_number in range(number_aliens_x):
self._create_alien(alien_number, row_number)
def _create_alien(self, alien_number, row_number):
alien = Alien(self)
alien_width, alien_height = alien.rect.size
alien.x = alien_width + 2 * alien_width * alien_number
alien.rect.x = alien.x
alien.rect.y = 2 * alien_height + 2 * alien.rect.height * row_number
self.aliens.add(alien)
def _check_fleet_edges(self):
"""respond if any aliens reach the edge"""
for alien in self.aliens.sprites():
if alien.check_edges():
self._change_fleet_direction()
break
def _check_aliens_bottom(self):
"""check if any aliens have reached the bottom of the screen"""
screen_rect = self.screen.get_rect()
for alien in self.aliens.sprites():
if alien.rect.bottom >= screen_rect.bottom:
self._ship_hit()
break
def _change_fleet_direction(self):
"""drop entire fleet and change direction"""
for alien in self.aliens.sprites():
alien.rect.y += self.settings.fleet_drop_speed
self.settings.fleet_direction *= -1
def _update_screen(self):
"""Update images on screen and flip to the new screen."""
#fill our background with our bg_color
self.screen.fill(self.settings.bg_color)
#draw ship to screen
self.ship.blitme()
for bullet in self.bullets.sprites():
bullet.draw_bullet()
self.aliens.draw(self.screen)
for bomb in self.bombs.sprites():
bomb.draw_bomb()
#Make the most recently drawn screen visible.
#this clears our previous screen and updates it to a new one
#this gives our programe smooth movemnt
pygame.display.flip()
if __name__ == '__main__':
#Make a game instance, and run the game
ai = AlienInvasion()
ai.run_game()
alien.py
import pygame
from pygame.sprite import Sprite
class Alien(Sprite):
"""A class to represent a sinlge alien in the fleet"""
def __init__(self, ai_game):
"""initlize alien and set its starting position"""
super().__init__()
self.screen = ai_game.screen
self.settings = ai_game.settings
self.screen_rect = ai_game.screen.get_rect()
# load alien image at set its rect
self.image = pygame.image.load('images/alien.bmp')
self.rect = self.image.get_rect()
# start each new alien at the top left of the screen
self.rect.x = self.rect.width
self.rect.y = self.rect.height
# store aliens exact position (decimal)
self.x = float(self.rect.x)
def check_edges(self):
"""return true if alien is at edge of screen"""
screen_rect = self.screen.get_rect()
if self.rect.right >= screen_rect.right or self.rect.left <= 0:
return True
def update(self):
"""move the alien to the right or left"""
self.x += (self.settings.alien_speed *
self.settings.fleet_direction)
self.rect.x = self.x
bombs.py
from pygame.sprite import Sprite
class Bomb(Sprite):
"""create a bullet that is dropped by aliens"""
def __init__(self, ai_game):
super().__init__()
self.screen = ai_game.screen
self.settings = ai_game.settings
self.color = self.settings.bullet_color
self.rect = pygame.Rect(0, 0, self.settings.bullet_width,
self.settings.bullet_height)
self.rect.midbottom = ai_game.alien.rect.midbottom
self.y = float(self.rect.y)
def update(self):
"""move bullet down screen"""
self.y += self.settings.bullet_speed
self.rect.y = self.y
def draw_bomb(self):
"""draw bullet to screen"""
pygame.draw.rect(self.screen, self.color, self.rect)
settings.py
class Settings:
"""A class to store our settings for Alien Invasion game."""
def __init__(self):
"""Initlize the games settings."""
# screen settings
self.screen_width = 1600
self.screen_height = 900
self.bg_color = (230, 230, 230)
# ship settings
self.ship_limit = 3
# bullet settings
self.bullet_width = 3
self.bullet_height = 15
self.bullet_color = (60, 60, 60)
self.bullets_allowed = 3
# alien settings
self.fleet_drop_speed = 10
# how quickly the game speeds up
self.speedup_scale = 1.1
# how muct alien poits value increses
self.score_scale = 1.5
self.initialize_dynamic_settings()
def initialize_dynamic_settings(self):
"""settings that change through the game"""
self.ship_speed = 1.5
self.bullet_speed = 1.5
self.alien_speed = 0.5
self.fleet_direction = 1
# scoring
self.alien_points = 50
def increse_speed(self):
"""increse speed settings"""
self.ship_speed *= self.speedup_scale
self.bullet_speed *= self.speedup_scale
self.alien_speed *= self.speedup_scale
self.alien_points = int(self.alien_points * self.score_scale)
ship.py
from pygame.sprite import Sprite
class Ship(Sprite):
"""A class for managing our ship."""
def __init__(self, ai_game):
"""Initlize the ship and set its starting position."""
super().__init__()
self.screen = ai_game.screen
self.settings = ai_game.settings
self.screen_rect = ai_game.screen.get_rect()
# load ship image and get its rect.(rect stands for rectangle)
self.image = pygame.image.load('images/ship.bmp')
self.rect = self.image.get_rect()
# Start each new ship at the bottom center of the screen.
self.rect.midbottom = self.screen_rect.midbottom
# store a decimal value for the ship's horizontal position
self.x = float(self.rect.x)
# movement flags
# we start our flag at false so the ship doesnt move by itself
self.moving_right = False
self.moving_left = False
def update(self):
"""Update ships position based on our movement flags"""
# update ship's x value, not its rectange
if self.moving_right and self.rect.right < self.screen_rect.right:
self.x += self.settings.ship_speed
if self.moving_left and self.rect.left > 0:
self.x -= self.settings.ship_speed
# update rect object for self.x
self.rect.x = self.x
def blitme(self):
"""Draw the ship at its current location."""
self.screen.blit(self.image, self.rect)
def center_ship(self):
"""center ship"""
self.rect.midbottom = self.screen_rect.midbottom
self.x = float(self.rect.x)
我将如何让每个外星人投下他们自己的炸弹?
希望这遵循对你们更好的最小可重现示例。
你需要在炸弹的 __init__
中包含炸弹的 x y 位置:
class Bomb(sprite):
def __init__(self, ai_game, x, y):
# [...]
self.rect = pygame.Rect(x, y, self.settings.bullet_width,
self.settings.bullet_height)
self.y = y
现在在创建炸弹时(在 _drop_bombs
中),您需要包括外星人的 x 和 y 位置:
class AlienInvasion:
# [...]
def _drop_bombs(self):
"""drop bombs from alien ships"""
for alien in self.aliens:
new_bomb = Bomb(self, alien.x, alien.y) # top left of alien
# do alien.x + 5 or something to drop the bomb in the middle
self.bombs.add(new_bomb)
我还建议在 __init__
中包含外星人的 x 和 y 位置,而不是事后修改它。