I ran into an indentation problem, but I rechecked my code and couldn't find the error, please help
Game:
import pygame, controls
from gun import Gun
from pygame.sprite import Group
from stats import Stats
def run():
pygame.init()
screen = pygame.display.set_mode((700, 600))
pygame.display.set_caption('Game1')
bg_color = (0, 0, 0)
gun = Gun(screen)
bullets = Group()
inos = Group()
controls.create_army(screen, inos)
stats = Stats()
while True:
controls.events(screen, gun, bullets)
gun.update_gun()
controls.update(bg_color, screen, gun, inos, bullets)
controls.update_bullets(inos, bullets)
controls.update_inos(stats, screen, gun, inos, bullets)
run()
Gun:
import pygame
class Gun():
def __init__(self, screen):
self.screen = screen
self.image = pygame.image.load(r"C:\Users\ralph\Downloads\Python\Game\Image\t2.png")
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
self.rect.centerx = self.screen_rect.centerx
self.center = float(self.rect.centerx)
self.rect.bottom = self.screen_rect.bottom
self.mright = False
self.mleft = False
def output(self):
self.screen.blit(self.image, self.rect)
def update_gun(self):
if self.mright and self.rect.right < self.screen_rect.right:
self.center += 1.5
if self.mleft and self.rect.left > 0:
self.center -= 1.5
self.rect.centerx = self.center
def create_gun(self):
self.center = self.screen_rect.centerx
Bullet:
import pygame
class Bullet(pygame.sprite.Sprite):
def __init__(self, screen, gun):
super(Bullet, self).__init__()
self.screen = screen
self.rect = pygame.Rect(0, 0, 3, 12)
self.color = 150, 150, 150
self.speed = 1.5
self.rect.centerx = gun.rect.centerx
self.rect.top = gun.rect.top
self.y = float(self.rect.y)
def update(self):
self.y -= self.speed
self.rect.y = self.y
def draw_bullet(self):
pygame.draw.rect(self.screen, self.color, self.rect)
Control:
import pygame
import sys
from bullet import Bullet
from ino import Ino
import time
def events(screen, gun, bullets):
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_d:
gun.mright = True
elif event.key == pygame.K_a:
gun.mleft = True
elif event.key == pygame.K_SPACE:
new_bullet = Bullet(screen, gun)
bullets.add(new_bullet)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_d:
gun.mright = False
elif event.key == pygame.K_a:
gun.mleft = False
def update(bg_color, screen, gun, inos, bullets):
screen.fill(bg_color)
for bullet in bullets.sprites():
bullet.draw_bullet()
gun.output()
inos.draw(screen)
pygame.display.flip()
def update_bullets(inos, bullets):
bullets.update()
for bullet in bullets.copy():
if bullet.rect.bottom <= 0:
bullets.remove(bullet)
collisions = pygame.sprite.groupcollide(bullets, inos, True, True)
def gun_kill(stats, screen, gun, inos, bullets):
stats.guns_left -= 1
inos.empty()
bullets.empty()
create_army(screen, inos)
gun.create_gun()
time.sleep(2)
def update_inos(stats, screen, gun, inos, bullets):
inos.update()
if pygame.sprite.spritecollideany(gun, inos):
gun_kill(stats, screen, gun, inos, bullets)
def create_army(screen, inos):
ino = Ino(screen)
ino_width = ino.rect.width
number_ino_x = int((700 - 2 * ino_width) / ino_width)
ino_height = ino.rect.height
number_ino_y = int((800 - 300 - 2 * ino_height) / ino_height)
for row_number in range(number_ino_y):
for ino_number in range(number_ino_x):
ino = Ino(screen)
ino.x = ino_width + (ino_width * ino_number)
ino.y = ino_height + (ino_height * row_number)
ino.rect.x = ino.x
ino.rect.y = ino.rect.height + (ino.rect.height * row_number)
inos.add(ino)
Army:
import pygame
class Ino(pygame.sprite.Sprite):
def __init__(self, screen):
super(Ino, self).__init__()
self.screen = screen
self.image = pygame.image.load(r'C:\Users\ralph\Downloads\Python\Game\Image\solder.png')
self.rect = self.image.get_rect()
self.rect.x = self.rect.width
self.rect.y = self.rect.height
self.x = float(self.rect.x)
self.y = float(self.rect.y)
def draw(self):
self.screen.blit(self.image, self.rect)
def update(self):
self.y += 0.05
self.rect.y = self.y
Stat
class Stats():
def __init__(self):
def reset_stats(self):
self.guns_left = 2
Error:
Traceback (most recent call last):
File "C:\Users\ralph\Downloads\Python\Game\game1.py", line 4, in
from stats import Stats
File "C:\Users\ralph\Downloads\Python\Game\stats.py", line 7
def reset_stats(self):
^
IndentationError: expected an indented block after function definition on line 3
I couldn't find the cause of the error but I believe the whole code is correct
Related
There's no error in the code. I've fixed lots of errors before but it doesn't pop up any error. I've also checked the game_functions to see if it had something do to with that, but everything seems to be perfectly fine.
The error is that when I click the spacebar to shoot the bullets, the ship starts slowing down.
main code (alien_invasion.py):
import sys
import game_functions as gf
import pygame
from settings import Settings
from ship import Ship
from pygame.sprite import Group
def run_game():
# Initialize pygame, settings, and screen object.
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))
pygame.display.set_caption("Alien Invasion")
screen.fill(ai_settings.bg_color)
# Make a ship.
ship = Ship(ai_settings, screen)
bullets = Group()
# Background color
bg_color = (230, 230, 230)
while True:
gf.check_events(ai_settings, screen, ship, bullets)
gf.update_screen(ai_settings, bullets, screen, ship)
ship.update(ai_settings)
bullets.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
screen.fill(ai_settings.bg_color)
ship.blitme(screen)
pygame.display.flip()
run_game()
Bullet code (bullet.py):
import pygame
from pygame.sprite import Sprite
class Bullet(Sprite):
def __init__(self, ai_settings, screen, ship):
super().__init__()
self.screen = screen
self.rect = pygame.Rect(0, 0, ai_settings.bullet_width, ai_settings.bullet_height)
self.rect.centerx = ship.rect.centerx
self.rect.top = ship.rect.top
self.y = float(self.rect.y)
self.color = ai_settings.bullet_color
self.ship_speed_factor = ai_settings.bullet_speed_factor
def update(self):
self.y -= self.ship_speed_factor
self.rect.y = self.y
def draw_bullet(self):
pygame.draw.rect(self.screen, self.color, self.rect)
game_functions.py:
import pygame
from bullet import Bullet
def check_keydown_events(event, ship, ai_settings, screen, bullets):
if event.key == pygame.K_RIGHT:
ship.moving_right = True
elif event.key == pygame.K_LEFT:
ship.moving_left = True
elif event.key == pygame.K_SPACE:
new_bullet = Bullet(ai_settings, screen, ship)
bullets.add(new_bullet)
def check_keyup_events(event, ship):
if event.key == pygame.K_RIGHT:
ship.moving_right = False
elif event.key == pygame.K_LEFT:
ship.moving_left = False
def check_events(ai_settings, screen, ship, bullets):
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
check_keydown_events(event,ship, ai_settings, screen, bullets)
if event.key == pygame.K_RIGHT:
ship.moving_right = True
elif event.key == pygame.K_LEFT:
ship.moving_left = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
ship.moving_right = False
elif event.key == pygame.K_LEFT:
ship.moving_left = False
def update_screen(ai_settings, bullets, screen, ship):
for bullet in bullets.sprites():
bullet.draw_bullet()
ship.blitme(screen)
pygame.display.flip()
settings code (settings.py):
class Settings():
def __init__(self):
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230, 230, 230)
self.ship_speed_factor = 10
self.bullet_speed_factor = 1
self.bullet_width = 3
self.bullet_height = 12
self.bullet_color = (60, 60, 60)
self.bullet_limit = 5
ship code (ship.py):
import pygame
from pygame.sprite import Sprite
class Ship(Sprite):
def __init__(self, ai_settings, screen):
super(Ship, self).__init__()
self.screen = screen
self.ai_settings = ai_settings
self.image = pygame.image.load(r'C:\Users\user\Desktop\alien invasion\ship.bmp')
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
self.moving_right = False
self.moving_left = False
self.center = float(self.rect.centerx)
self.center += self.ai_settings.ship_speed_factor
def update(self, ai_settings):
self.ai_settings = ai_settings
if self.moving_right and self.rect.right < self.screen_rect.right:
self.rect.centerx += 1
self.center += self.ai_settings.ship_speed_factor
if self.moving_left and self.rect.left > 0:
self.center -= self.ai_settings.ship_speed_factor
self.rect.centerx -= 1
def blitme(self, screen):
self.screen.blit(self.image, self.rect)
Any help I would really appreciate it thank you!
The update_screen function looks suspicious here - redrawing the ship and flipping the display for every bullet is probably not what was intended. Moving those lines outside the loop should help:
def update_screen(ai_settings, bullets, screen, ship):
for bullet in bullets.sprites():
bullet.draw_bullet()
ship.blitme(screen)
pygame.display.flip()
I would very appreciate if someone could tell me how to fix this error:
AttributeError: 'Ship' object has no attribute 'bullet_width'
I am starting to learn Python, and I'm not sure what the solution to this would be. This always happens when I press the space bar.
Below are the modules in this project:
alien_invasion.py:
import sys
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
from pygame.sprite import Group
def run_game():
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode(
(ai_settings.screen_width, ai_settings.screen_height))
screen = pygame.display.set_mode((1100, 600))
pygame.display.set_caption("Alien Invasion")
bg_color = (230, 230, 230)
ship = Ship(screen, ai_settings)
bullets = Group()
while True:
gf.check_events(ship, screen, ai_settings, bullets)
ship.update()
bullets.update()
gf.update_screen(ai_settings, screen, ship, bullets)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
screen.fill(ai_settings.bg_color)
ship.blitme()
screen.fill(bg_color)
run_game()
ship.py:
import pygame
class Ship():
def __init__(self, screen, ai_settings):
self.screen = screen
self.ai_settings = ai_settings
self.image = pygame.image.load('images/spaceship.png')
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
self.center = float(self.rect.centerx)
self.moving_right = False
self.moving_left = False
def update(self):
if self.moving_right and self.rect.right < self.screen_rect.right:
self.center += self.ai_settings.ship_speed_factor
if self.moving_left and self.rect.left > 0:
self.center -= self.ai_settings.ship_speed_factor
self.rect.centerx = self.center
def blitme(self):
self.screen.blit(self.image, self.rect)
bullet.py:
import pygame
from pygame.sprite import Sprite
class Bullet(Sprite):
def __init__(self, ai_settings, screen, ship):
super(Bullet, self).__init__()
self.screen = screen
self.rect = pygame.Rect(0, 0, ai_settings.bullet_width,
ai_settings.bullet_height)
self.rect.centerx = ship.rect.top
self.y = float(self.rect.y)
self.color = ai_settings.bullet_color
self.speed_factor = ai_settings.bullet_speed_factor
def update(self):
self.y -= self.speed_factor
self.rect.y = self.y
def draw_bullet(self):
pygame.draw.rect(self.screen, self.color, self.rect)
game_functions.py
import sys
import pygame
from bullet import Bullet
def check_keydown_events(event, ai_settings, screen, ship, bullets):
if event.key == pygame.K_RIGHT:
ship.moving_right = True
elif event.key == pygame.K_LEFT:
ship.moving_left = True
elif event.key == pygame.K_SPACE:
new_bullet = Bullet(ai_settings, screen, ship)
bullets.add(new_bullet)
def check_keyup_events(event, ship):
if event.key == pygame.K_RIGHT:
ship.moving_right = False
elif event.key == pygame.K_LEFT:
ship.moving_left = False
def check_events(ai_settings, screen, ship, bullets):
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
check_keydown_events(event, ai_settings, screen, ship, bullets)
elif event.type == pygame.KEYUP:
check_keyup_events(event, ship)
def update_screen(ai_settings, screen, ship, bullets):
screen.fill(ai_settings.bg_color)
for bullet in bullets.sprites():
bullet.draw_bullet()
ship.blitme()
pygame.display.flip()
settings.py:
class Settings():
def __init__(self):
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230, 230, 230)
self.ship_speed_factor = 1.5
self.bullet_speed_factor = 1
self.bullet_width = 3
self.bullet_height = 15
self.bullet_color = 60, 60, 60
The order of the arguments is wrong when you call check_events:
check_events(ship, screen, ai_settings, bullets)
check_events(ai_settings, screen, ship, bullets)
The order of the arguments matters, except of Keyword Arguments.
I was trying to do the python crash course exercise 14-2, which is create a rectangle at the right edge of the screen that moves up and down at a steady rate. Then have a ship appear on the left edge of the screen that the player can move up and down while firing bullets at the moving rectangle target. Add a play button that starts the game, and the player misses the target three times, end the game and make the play button reappear. Let the player restart this game with the play button.
the game runs as normal, objects moving as programmed and key events also detected and moved up and down accordingly, but it is not detecting the condition of setting the game status for False. So the play_button never appears and the game keep playing even the player misses the target more than three times.
I've set the bullet allowed to fire one at a time, so it is easier to see by eye and more countable to test.
I think my if len(self.bullets) >= self.settings.firing_limit and not pygame.sprite.spritecollideany(self.rectangle, self.bullets): statement is wrong, cause I just come up with it on my own, cause from the level of my programming, I don't know how to keep a count of the bullets missing target. correct me if I'm wrong.
Below is the main file to run the game.
target_practice.py
import pygame
import sys
from time import sleep
from settings_target_practice import Settings
from ship import Ship
from bullet import Bullet
from rectangle import Rectangle
from game_stats import GameStats
from button import Button
class TargetPractice:
def __init__(self):
pygame.init()
self.settings = Settings()
self.screen = pygame.display.set_mode((self.settings.screen_width,
self.settings.screen_height))
pygame.display.set_caption("Target Practice")
self.stats = GameStats(self)
self.ship = Ship(self)
self.rectangle = Rectangle(self)
self.bullets = pygame.sprite.Group()
self.play_button = Button(self, "Play")
def run_game(self):
while True:
self._check_events()
if self.stats.game_active:
self.ship.update()
self._update_bullet()
self._update_rectangle()
self._update_screen()
def _fire_bullet(self):
new_bullet = Bullet(self)
if len(self.bullets) < self.settings.bullets_allowed:
self.bullets.add(new_bullet)
def _update_bullet(self):
self.bullets.update()
self.screen_rect = self.screen.get_rect()
for bullet in self.bullets:
self._check_bullet_rectangle_collision()
for bullet in self.bullets.copy():
if bullet.rect.left >= self.screen_rect.right:
self.bullets.remove(bullet)
def _update_rectangle(self):
self.rectangle.update()
self._rectangle_check_edges()
def _rectangle_check_edges(self):
if self.rectangle.check_edges():
self._change_direction()
def _change_direction(self):
self.settings.rectangle_direction *= -1
def _check_bullet_rectangle_collision(self):
if pygame.sprite.spritecollideany(self.rectangle, self.bullets):
self._start_game()
if len(self.bullets) >= self.settings.firing_limit and not pygame.sprite.spritecollideany(self.rectangle, self.bullets):
self.stats.game_active = False
pygame.mouse.set_visible(True)
def _check_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
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):
if event.key == pygame.K_q:
sys.exit()
elif event.key == pygame.K_UP:
self.ship.moving_up = True
elif event.key == pygame.K_DOWN:
self.ship.moving_down = True
elif event.key == pygame.K_SPACE:
self._fire_bullet()
elif event.key == pygame.K_p:
self._check_play_button( )
def _check_keyup_events(self, event):
if event.key == pygame.K_UP:
self.ship.moving_up = False
elif event.key == pygame.K_DOWN:
self.ship.moving_down = False
def _check_play_button(self):
if not self.stats.game_active:
self.stats.reset_stats()
self.stats.game_active = True
self._start_game()
def _start_game(self):
if self.stats.game_active:
#Get rid of any bullets.
self.bullets.empty()
#Create a new fleet and center the ship.
self.rectangle.draw()
self.ship.center_ship()
#Hide the mouse curser
pygame.mouse.set_visible(True)
sleep(0.5)
def _update_screen(self):
self.screen.fill(self.settings.bg_color)
self.ship.blitme()
for bullet in self.bullets:
bullet.draw_bullet()
self.rectangle.draw()
if self.stats.game_active:
pygame.mouse.set_visible(False)
if not self.stats.game_active:
self.play_button.draw_button()
pygame.display.flip()
if __name__ == '__main__':
tp_game = TargetPractice()
tp_game.run_game()
The below are the files which supplementing the above main file.
ship.py
import pygame
class Ship:
def __init__(self, tr_game):
self.screen = tr_game.screen
self.settings = tr_game.settings
self.screen_rect = self.screen.get_rect()
self.image = pygame.image.load('images/ship.bmp')
self.rect = self.image.get_rect()
self.rect.midleft = self.screen_rect.midleft
self.y = self.rect.y
self.moving_up = False
self.moving_down = False
def blitme(self):
self.screen.blit(self.image, self.rect)
def update(self):
if self.moving_up and self.rect.top > self.screen_rect.top:
self.y -= self.settings.ship_speed
if self.moving_down and self.rect.bottom < self.screen_rect.bottom:
self.y += self.settings.ship_speed
self.rect.y = self.y
def center_ship(self):
self.rect.midleft = self.screen_rect.midleft
self.y = float(self.rect.y)
retangle.py
import pygame.font
class Rectangle:
def __init__(self, tp_game):
self.screen = tp_game.screen
self.screen_rect = self.screen.get_rect()
self.rectangle_width, self.rectangle_height = 200, 50
self.rectangle_color = (0, 0, 255)
self.rect = pygame.Rect(0, 0, self.rectangle_width,
self.rectangle_height)
self.rect.midright = self.screen_rect.midright
self.settings = tp_game.settings
self.y = float(self.rect.y)
def update(self):
self.y += self.settings.rectangle_speed * self.settings.rectangle_direction
self.rect.y = self.y
def check_edges(self):
if self.rect.bottom >= self.screen_rect.bottom or self.rect.top <= 0:
return True
def draw(self):
pygame.draw.rect(self.screen, self.rectangle_color, self.rect)
bullet.py
from pygame.sprite import Sprite
import pygame
class Bullet(Sprite):
def __init__(self, tr_game):
super().__init__()
self.screen = tr_game.screen
self.settings = tr_game.settings
self.color = self.settings.bullet_color
self.rect = pygame.Rect(0, 0, self.settings.bullet_width,
self.settings.bullet_height)
self.rect.midright = tr_game.ship.rect.midright
self.x = float(self.rect.x)
def update(self):
self.x += self.settings.bullet_speed
self.rect.x = self.x
def draw_bullet(self):
pygame.draw.rect(self.screen, self.color, self.rect)
settings.py
class Settings:
def __init__(self):
self.screen_width = 1400
self.screen_height = 700
self.bg_color = (255, 255, 255)
self.ship_speed = 1.5
self.firing_limit = 3
self.bullet_speed = 2
self.bullet_width = 15
self.bullet_height = 5
self.bullet_color = (60, 60, 60)
self.bullets_allowed = 1
self.rectangle_speed = 1.0
self.rectangle_direction = 1
game_stats.py
class GameStats:
def __init__(self, rp_game):
self.settings = rp_game.settings
self.reset_stats()
self.game_active = True
def reset_stats(self):
self.player_chance = self.settings.firing_limit
button.py
import pygame.font
class Button:
def __init__(self, tp_game, msg):
"""Initialize button attributes."""
self.screen = tp_game.screen
self.screen_rect = self.screen.get_rect()
#Set the dimensions and properties of the button.
self.width, self.height = 200, 50
self.button_color = (0, 255, 0)
self.text_color = (255, 255, 255)
self.font = pygame.font.SysFont(None, 48)
#Build the button's rect object and center it.
self.rect = pygame.Rect(0, 0, self.width, self.height)
self.rect.center = self.screen_rect.center
#The button message needs to be prepped only once.
self._prep_msg(msg)
def _prep_msg(self, msg):
"""Turn message into a rendered image and center text on the screen."""
self.msg_image = self.font.render(msg, True, self.text_color,
self.button_color)
self.msg_image_rect = self.msg_image.get_rect()
self.msg_image_rect.center = self.rect.center
def draw_button(self):
#Draw blank button and then draw message.
self.screen.fill(self.button_color, self.rect)
self.screen.blit(self.msg_image, self.msg_image_rect)
The bullets are Sprites contained in the Group bullets.
If you want to remove a Sprite from all Groups, then all you have to do is to call the method kill() on the Sprite instance. e.g:
bullet.kill()
To count the miss add an attribute (self.missed) to the class TargetPractice. If the bullet leaves the screen the increment self.missed and if it exceeds the limit then end the game:
class TargetPractice:
def __init__(self):
pygame.init()
self.settings = Settings()
self.screen = pygame.display.set_mode((self.settings.screen_width,
self.settings.screen_height))
pygame.display.set_caption("Target Practice")
self.stats = GameStats(self)
self.ship = Ship(self)
self.rectangle = Rectangle(self)
self.bullets = pygame.sprite.Group()
self.play_button = Button(self, "Play")
self.missed = 0 # <----
# [...]
def _update_bullet(self):
self.bullets.update()
self.screen_rect = self.screen.get_rect()
for bullet in self.bullets:
self._check_bullet_rectangle_collision()
# find missing bullets and increment the counter for each
for bullet in self.bullets:
if bullet.rect.left >= self.screen_rect.width:
bullet.kill()
self.missed += 1
if self.missed >= 3:
self.stats.game_active = False
pygame.mouse.set_visible(True)
(instance.py)
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode(
(ai_settings.screen_width,ai_settings.screen_height))
pygame.display.set_caption('Alien Invasion')
ship = Ship(ai_settings,screen)
bullets = pygame.sprite.Group()
aliens = pygame.sprite.Group()
gf.create_fleet(ai_settings,screen,ship,aliens)
while 1:
gf.check_events(ai_settings,screen,ship,bullets)
ship.update()
gf.update_bullet(bullets)
gf.update_alien(ai_settings,aliens)
gf.update_screen(ai_settings,screen,ship,bullets,aliens)
run_game()
(game_functions.py)
import pygame
import sys
from bullet import Bullet
from alien import Alien
def check_events(ai_settings,screen,ship,bullets):
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
check_keydown_events(ai_settings,screen,ship,bullets,event)
if event.type == pygame.KEYUP:
check_keyup_events(ship,event)
def check_keydown_events(ai_settings,screen,ship,bullets,event):
if event.key == pygame.K_RIGHT:
ship.moving['right'] = True
elif event.key == pygame.K_LEFT:
ship.moving['left'] = True
elif event.key == pygame.K_UP:
ship.moving['up'] = True
elif event.key == pygame.K_DOWN:
ship.moving['down'] = True
elif event.key == pygame.K_SPACE:
new_bullet = Bullet(ai_settings,screen,ship)
bullets.add(new_bullet)
elif event.key == pygame.K_q:
sys.exit()
def check_keyup_events(ship,event):
if event.key == pygame.K_RIGHT:
ship.moving['right'] = False
elif event.key == pygame.K_LEFT:
ship.moving['left'] = False
elif event.key == pygame.K_UP:
ship.moving['up'] = False
elif event.key == pygame.K_DOWN:
ship.moving['down'] = False
def update_screen(ai_settings,screen,ship,bullets,aliens):
screen.fill(ai_settings.bg_color)
ship.blitme()
for bullet in bullets.sprites():
bullet.draw_bullet()
aliens.draw(screen)
pygame.display.flip()
def update_bullet(bullets):
bullets.update()
for bullet in bullets.copy():
if bullet.rect.y < 0:
bullets.remove(bullet)
def create_fleet(ai_settings,screen,ship,aliens):
sample_alien = Alien(ai_settings,screen)
alien_width = sample_alien.rect.width
alien_height = sample_alien.rect.height
available_space_x = ai_settings.screen_width - 2 * alien_width
numbers_alien_x = int(available_space_x / ( 2 * alien_width ))
available_space_y = ai_settings.screen_height - 3 * alien_height - ship.rect.height
numbers_alien_y = int(available_space_y / ( 2 * alien_height ))
for number_alien_y in range(numbers_alien_y):
for number_alien_x in range(numbers_alien_x):
alien = Alien(ai_settings,screen)
alien.rect.x = alien_width + 2 * alien_width * number_alien_x
alien.rect.y = alien_height + 2 * alien_height * number_alien_y
aliens.add(alien)
def update_alien(ai_settings,aliens):
check_fleet_edges(ai_settings,aliens)
aliens.update()
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
(settings.py)
class Settings(object):
def __init__(self):
self.screen_width = 1200
self.screen_height = 700
self.bg_color = 230,230,230
self.ship_speed_factor = 1.5
self.bullet_width = 3
self.bullet_height = 15
self.bullet_color = 15,15,15
self.bullet_speed_factor = 1
self.alien_speed_factor = 2
self.fleet_drop_speed = 10
self.fleet_direction = 1
(ship.py)
import pygame
class Ship(object):
def __init__(self,ai_settings,screen):
self.ai_settings = ai_settings
self.screen = screen
self.image = pygame.image.load('images/ship.bmp')
self.rect = self.image.get_rect()
self.screen_rect = self.screen.get_rect()
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
self.moving = {'right':False,'left':False,'up':False,'down':False}
self.centerx = float(self.rect.centerx)
self.centery = float(self.rect.centery)
self.speed = self.ai_settings.ship_speed_factor
def update(self):
if self.moving['right'] and self.rect.right < self.ai_settings.screen_width:
self.centerx += self.speed
if self.moving['left'] and self.rect.left > 0:
self.centerx -= self.speed
if self.moving['up'] and self.rect.top > 0:
self.centery -= self.speed
if self.moving['down'] and self.rect.bottom < self.ai_settings.screen_height:
self.centery += self.speed
self.rect.centerx = self.centerx
self.rect.centery = self.centery
def blitme(self):
self.screen.blit(self.image,self.rect)
(bullet.py)
import pygame
from random import randint
class Bullet(pygame.sprite.Sprite):
def __init__(self,ai_settings,screen,ship):
super().__init__()
self.ai_settings = ai_settings
self.screen = screen
self.ship = ship
self.rect = pygame.Rect(0,0,self.ai_settings.bullet_width,self.ai_settings.bullet_height)
self.rect.top = self.ship.rect.top
self.rect.centerx = self.ship.rect.centerx
self.speed = self.ai_settings.bullet_speed_factor
self.y = float(self.rect.y)
self.color = randint(1,255),randint(1,255),randint(1,255)
def update(self):
self.y -= self.speed
self.rect.y = self.y
def draw_bullet(self):
pygame.draw.rect(self.screen,self.color,self.rect)
(alien.py)
import pygame
class Alien(pygame.sprite.Sprite):
def __init__(self,ai_settings,screen):
super().__init__()
self.ai_settings = ai_settings
self.screen = screen
self.image = pygame.image.load('images/alien.bmp')
self.rect = self.image.get_rect()
self.speed = self.ai_settings.alien_speed_factor
self.x = float(self.rect.x)
self.y = float(self.rect.y)
def check_edges(self):
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.speed * self.ai_settings.fleet_direction)
self.rect.x = self.x
My goal is create alien fleet in the whole screen.
Why is there just one row of aliens?
The problem is that in Alien you update(self) using the value of self.x, but you never set this value when you run create_fleet(...). So all your aliens are there already, they are just all on top of each other!
A simple solution is to set self.x at the same time as you set self.rect.x for each Alien when you initialize them in create_fleet(...). So instead of:
alien.rect.x = alien_width + 2 * alien_width * number_alien_x
you would have:
alien.rect.x = alien.x = alien_width + 2 * alien_width * number_alien_x
(instance.py)
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode(
(ai_settings.screen_width,ai_settings.screen_height))
pygame.display.set_caption('Alien Invasion')
ship = Ship(ai_settings,screen)
bullets = pygame.sprite.Group()
aliens = pygame.sprite.Group()
gf.create_fleet(ai_settings,screen,ship,aliens)
while 1:
gf.check_events(ai_settings,screen,ship,bullets)
ship.update()
gf.update_bullet(bullets)
gf.update_alien(ai_settings,aliens)
gf.update_screen(ai_settings,screen,ship,bullets,aliens)
run_game()
(game_functions.py)
import pygame
import sys
from bullet import Bullet
from alien import Alien
def check_events(ai_settings,screen,ship,bullets):
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
check_keydown_events(ai_settings,screen,ship,bullets,event)
if event.type == pygame.KEYUP:
check_keyup_events(ship,event)
def check_keydown_events(ai_settings,screen,ship,bullets,event):
if event.key == pygame.K_RIGHT:
ship.moving['right'] = True
elif event.key == pygame.K_LEFT:
ship.moving['left'] = True
elif event.key == pygame.K_UP:
ship.moving['up'] = True
elif event.key == pygame.K_DOWN:
ship.moving['down'] = True
elif event.key == pygame.K_SPACE:
new_bullet = Bullet(ai_settings,screen,ship)
bullets.add(new_bullet)
elif event.key == pygame.K_q:
sys.exit()
def check_keyup_events(ship,event):
if event.key == pygame.K_RIGHT:
ship.moving['right'] = False
elif event.key == pygame.K_LEFT:
ship.moving['left'] = False
elif event.key == pygame.K_UP:
ship.moving['up'] = False
elif event.key == pygame.K_DOWN:
ship.moving['down'] = False
def update_screen(ai_settings,screen,ship,bullets,aliens):
screen.fill(ai_settings.bg_color)
ship.blitme()
for bullet in bullets.sprites():
bullet.draw_bullet()
aliens.draw(screen)
pygame.display.flip()
def update_bullet(bullets):
bullets.update()
for bullet in bullets.copy():
if bullet.rect.y < 0:
bullets.remove(bullet)
def create_fleet(ai_settings,screen,ship,aliens):
sample_alien = Alien(ai_settings,screen)
alien_width = sample_alien.rect.width
alien_height = sample_alien.rect.height
available_space_x = ai_settings.screen_width - 2 * alien_width
numbers_alien_x = int(available_space_x / ( 2 * alien_width ))
available_space_y = ai_settings.screen_height - 3 * alien_height - ship.rect.height
numbers_alien_y = int(available_space_y / ( 2 * alien_height ))
for number_alien_y in range(numbers_alien_y):
for number_alien_x in range(numbers_alien_x):
alien = Alien(ai_settings,screen)
alien.rect.x = alien_width + 2 * alien_width * number_alien_x
alien.rect.y = alien_height + 2 * alien_height * number_alien_y
aliens.add(alien)
def update_alien(ai_settings,aliens):
check_fleet_edges(ai_settings,aliens)
aliens.update()
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
(settings.py)
class Settings(object):
def __init__(self):
self.screen_width = 1200
self.screen_height = 700
self.bg_color = 230,230,230
self.ship_speed_factor = 1.5
self.bullet_width = 3
self.bullet_height = 15
self.bullet_color = 15,15,15
self.bullet_speed_factor = 1
self.alien_speed_factor = 2
self.fleet_drop_speed = 10
self.fleet_direction = 1
(ship.py)
import pygame
class Ship(object):
def __init__(self,ai_settings,screen):
self.ai_settings = ai_settings
self.screen = screen
self.image = pygame.image.load('images/ship.bmp')
self.rect = self.image.get_rect()
self.screen_rect = self.screen.get_rect()
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
self.moving = {'right':False,'left':False,'up':False,'down':False}
self.centerx = float(self.rect.centerx)
self.centery = float(self.rect.centery)
self.speed = self.ai_settings.ship_speed_factor
def update(self):
if self.moving['right'] and self.rect.right < self.ai_settings.screen_width:
self.centerx += self.speed
if self.moving['left'] and self.rect.left > 0:
self.centerx -= self.speed
if self.moving['up'] and self.rect.top > 0:
self.centery -= self.speed
if self.moving['down'] and self.rect.bottom < self.ai_settings.screen_height:
self.centery += self.speed
self.rect.centerx = self.centerx
self.rect.centery = self.centery
def blitme(self):
self.screen.blit(self.image,self.rect)
(bullet.py)
import pygame
from random import randint
class Bullet(pygame.sprite.Sprite):
def __init__(self,ai_settings,screen,ship):
super().__init__()
self.ai_settings = ai_settings
self.screen = screen
self.ship = ship
self.rect = pygame.Rect(0,0,self.ai_settings.bullet_width,self.ai_settings.bullet_height)
self.rect.top = self.ship.rect.top
self.rect.centerx = self.ship.rect.centerx
self.speed = self.ai_settings.bullet_speed_factor
self.y = float(self.rect.y)
self.color = randint(1,255),randint(1,255),randint(1,255)
def update(self):
self.y -= self.speed
self.rect.y = self.y
def draw_bullet(self):
pygame.draw.rect(self.screen,self.color,self.rect)
(alien.py)
import pygame
class Alien(pygame.sprite.Sprite):
def __init__(self,ai_settings,screen):
super().__init__()
self.ai_settings = ai_settings
self.screen = screen
self.image = pygame.image.load('images/alien.bmp')
self.rect = self.image.get_rect()
self.speed = self.ai_settings.alien_speed_factor
self.x = float(self.rect.x)
self.y = float(self.rect.y)
def check_edges(self):
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.speed * self.ai_settings.fleet_direction)
self.rect.x = self.x
My goal is create alien fleet in the whole screen.
Why is there just one row of aliens?
The problem is that in Alien you update(self) using the value of self.x, but you never set this value when you run create_fleet(...). So all your aliens are there already, they are just all on top of each other!
A simple solution is to set self.x at the same time as you set self.rect.x for each Alien when you initialize them in create_fleet(...). So instead of:
alien.rect.x = alien_width + 2 * alien_width * number_alien_x
you would have:
alien.rect.x = alien.x = alien_width + 2 * alien_width * number_alien_x