I'm trying to build a game that moves a ship left and right with the arrow keys and fires bullets when the spacebar is pressed. When I press the spacebar my game crashes and this error is shown:
Traceback (most recent call last):
TypeError: add() argument after * must be a sequence, not Settings
Here's my code:
class Settings():
"""A class to store all settings for Alien Invasion."""
def __init__(self):
"""Initialize the game's settings."""
# Screen settings
self.screen_width = 800
self.screen_height = 480
self.bg_color = (230, 230, 230)
# Ship settings
self.ship_speed_factor = 1.5
# Bullet settings
self.bullet_speed_factor = 1
self.bullet_width = 3
self.bullet_height = 15
self.bullet_color = 60, 60, 60
import pygame
from pygame.sprite import Sprite
class Bullet(Sprite):
"""A class to manage bullets fired from the ship"""
def _init__(self, ai_settings, screen, ship):
"""Create a bullet object at the ship's current position."""
super(Bullet, self).__init__()
self.screen = screen
# Create a bullet rect at (0, 0) and then set correct position.
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
# Store the bullet's position as a decimal value.
self.y = float(self.rect.y)
self.color = ai_settings.bullet_color
self.speed_factor = ai_settings.bullet_speed_factor
def update(self):
"""Move the bullet up the screen"""
# Update the decimal position of the bullet.
self.y -= self.speed_factor
# Update the rect position.
self.rect.y = self.y
def draw_bullet(self):
"""Draw the bullet to the screen."""
pygame.draw.rect(self.screen, self.color, self.rect)
import sys
import pygame
from bullet import Bullet
def check_keydown_events(event, ai_settings, screen, ship, bullets):
"""Respond to keypresses."""
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:
# Create a new bullet and add it to the bullets group.
new_bullet = Bullet(ai_settings, screen, ship)
bullets.add(new_bullet)
def check_keyup_events(event, ship):
"""Respind to key releases."""
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):
"""Respond to keypresses and mouse events."""
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)
And finally the main file:
import pygame
from pygame.sprite import Group
from settings import Settings
from ship import Ship
import game_functions as gf
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")
# Make a ship.
ship = Ship(ai_settings, screen)
# Make a group to store bullets in.
bullets = Group()
# Start the main loop for the game.
while True:
# Watch the keyboard and mouse events.
gf.check_events(ai_settings, screen, ship, bullets)
ship.update()
bullets.update()
gf.update_screen(ai_settings, screen, ship, bullets)
run_game()
The trace:
Traceback (most recent call last):
File "C:\Users\martin\Desktop\python_work\alien_invasion\alien_invasion.py", line 30, in <module>
run_game()
File "C:\Users\martin\Desktop\python_work\alien_invasion\alien_invasion.py", line 25, in run_game
gf.check_events(ai_settings, screen, ship, bullets)
File "C:\Users\martin\Desktop\python_work\alien_invasion\game_functions.py", line 33, in check_events
check_keydown_events(event, ai_settings, screen, ship, bullets)
File "C:\Users\martin\Desktop\python_work\alien_invasion\game_functions.py", line 15, in check_keydown_events
new_bullet = Bullet(ai_settings, screen, ship)
File "C:\Users\martin\Anaconda3\lib\site-packages\pygame\sprite.py", line 124, in __init__
self.add(*groups)
File "C:\Users\martin\Anaconda3\lib\site-packages\pygame\sprite.py", line 142, in add
self.add(*group)
TypeError: add() argument after * must be a sequence, not Settings
You are missing an underscore _ in your Bullet.__init__ method. You currently have _init__ when it should be __init__.
This results in Python calling the Sprite.__init__ method with ai_settings as the first argument, since it cannot find any overridden __init__ for Bullet. That leads to problems.
Yes Jokab is right, you forgot the extra underscore. However, for future practice it is important to learn to read the Python TrackBack. It usually gives you a good idea of where the problem is. For example, take the TrackBack you pasted here. Python first tells you it had a problem running run_game(). So python then says that in your game running function it has a problem calling the method gf.check_events(ai_settings, screen, ship, bullets). It then looked at your initialization of the bullet class new_bullet = Bullet(ai_settings, screen, ship and has a problem with it. And in the very next line is were it gives the TypeError. Now, while you could figure out exactly what python is saying about the TypeError, which is a viable option. But just from looking at it you could determine that it has a problem adding your bullet object to the sprites group. Which means that if I were you, I'd start my searching in the Bullet class. And sure enough there is a typo in your __init__ function.
While it is not the end of the world if you don't learn how to read python TrackBack's, It will save you plenty of time in the long run.
Related
Following "Python Crash Course" and I'm stuck while trying to group all the bullets on the screen, I Get an AttributeError:
Traceback (most recent call last):
File "C:/Users/esmai/PycharmProjects/AllienInvasion1/allien_invasion.py", line 27, in <module>
run_game()
File "C:/Users/esmai/PycharmProjects/AllienInvasion1/allien_invasion.py", line 24, in run_game
gf.update_screen(ai_settings, screen, ship, bullets)
File "C:\Users\esmai\PycharmProjects\AllienInvasion1\game_functions.py", line 36, in update_screen
for bullet in bullets.sprite():
AttributeError: 'Group' object has no attribute 'sprite'
Process finished with exit code 1
Here are the files (as the error only occurred in alien_invasion.py and game_functions.py, those two will be the first two folders you see followed by bullet.py...):
alien_invasion.py:
import pygame
from pygame.sprite import Group
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
pygame.init()
# the .display tells python to set display somehow, duh
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 = Group()
while True:
gf.check_event(ai_settings, screen, ship, bullets)
ship.update()
bullets.update()
gf.update_screen(ai_settings, screen, ship, bullets)
run_game()
game_functions.py:
import pygame
import sys
from bullet import Bullet
def check_keydown_event(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_event(event, ship):
if event.key == pygame.K_RIGHT:
ship.moving_right = False
elif event.key == pygame.K_LEFT:
ship.moving_left = False
def check_event(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_event(event, ai_settings, screen, ship, bullets)
elif event.type == pygame.KEYUP:
check_keyup_event(event, ship)
def update_screen(ai_settings, screen, ship, bullets):
screen.fill(ai_settings.bg_color)
for bullet in bullets.sprite():
bullet.draw_bullet()
'the Group AttributeError occurs here as grouping bullets do not have attribute sprite, apparently.'
ship.blitme()
pygame.display.flip()
bullet.py:
import pygame
from pygame.sprite import Sprite
class Bullet(Sprite):
def __init__(self, ai_settings, ship, screen):
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.centerx
self.rect.top = 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)
ship.py:
import pygame
class Ship:
def __init__(self, ai_settings, screen):
self.screen = screen
self.image = pygame.image.load('ship.bmp')
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
self.ai_settings = ai_settings
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)
settings.py:
class Settings:
def __init__(self):
self.screen_width = 1200
self.screen_height = 700
self.bg_color = (230, 230, 230)
self.bullet_speed_factor = 1
self.bullet_width = 3
self.bullet_height = 15
self.bullet_color = 225, 69, 0
# For ship Speed
self.ship_speed_factor = 1.5
This post here has a couple of problems.
the biggest problem is that the code was generated from an old edition of the book, as the author of the book stated in the comments.
next, the problems in this post have stated from the perspective of a newcomer (I). so the main problem occurred from naming the variables wrong or different from a file to another, again stated by the author. So when I redo the project, I nailed it in the head >>boom<<, of course, by changing to the second edition of the Python Crash course.
so what to learn from this.
name variables correctly.
listen to the author's podcasts, in a podcast he once said that "new programmers buy early editions..." and he was right (check the edition of the book, K?)
don't follow the code blindly, change aspects of the code to your tunning.
download the resources, it is free but the knowledge in it boils the ocean.
thanks for the help, each comment put me on pins and needles. in short thanks.
I'm beginner in Python and working on a space invader game. I want to make the ship fire bullets but when I press the key for firing, no bullets are shot. After multiple presses, the program closes.
AlienGame.py
import sys
import pygame
from pygame.sprite import Group
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("TemplAReeb's First Game")
ship = Ship(ai_settings, screen)
bullets = Group()
bg_color = (230, 230, 230)
while True:
gf.check_events(ship, bullets)
ship.update()
bullets.update()
gf.update_screen(ai_settings, screen, ship, bullets)
screen.fill(bg_color)
ship.blitme()
pygame.display.flip()
for event in pygame.event.get():
if event.type==pygame.QUIT:
sys.exit()
screen.fill(bg_color)
ship.blitme()
pygame.display.flip()
run_game()
gamefunctions.py
import sys
import pygame
from bullet import Bullet
def check_keydown_events (event, bullets):
if event.key == pygame.K_SPACE:
new_bullet = Bullet(ai_settings, screen, ship)
bullets.add(new_bullet)
def check_events(ship, bullets):
keys = pygame.key.get_pressed()
ship.moving_right = keys[pygame.K_RIGHT]
ship.moving_left = keys[pygame.K_LEFT]
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
check_keydown_events(event, bullets)
def update_screen(ai_settings, screen, ship, bullets):
bg_color = (230, 230, 230)
screen.fill(bg_color)
ship.blitme()
for bullet in bullets.sprites():
bullet.draw_bullet()
pygame.display.flip()
I'm getting the error that ai_settings in not defined
Traceback (most recent call last):
File "C:/Users/Areeb Irfan/.PyCharmCE2018.3/config/scratches/AlienGame.py", line 32, in <module>
run_game()
File "C:/Users/Areeb Irfan/.PyCharmCE2018.3/config/scratches/AlienGame.py", line 19, in run_game
gf.check_events(ship, bullets)
File "C:\Users\Areeb Irfan\.PyCharmCE2018.3\config\scratches\game_functions.py", line 16, in check_events
check_keydown_events(event, bullets)
File "C:\Users\Areeb Irfan\.PyCharmCE2018.3\config\scratches\game_functions.py", line 7, in check_keydown_events
new_bullet = Bullet(ai_settings, screen, ship)
NameError: name 'ai_settings' is not defined
Your error is coming from this line in check_keydown_events:
new_bullet = Bullet(ai_settings, screen, ship)
You're trying to pass ai_settings to the Bullet constructor, but it's not defined in the current check_keydown_events function's namespace. Unlike update_screen, you're not passing ai_settings in as an argument.
You probably need to fix that. You already know how, since you're already passing ai_settings to update_screen (where it's not currently used, did you perhaps add it to the wrong place?). You just need to extend it to check_events and check_keydown_events.
My Alien Invasion game does not show bullets being fired. I am copying most of the code from the Python Crash Course book (with minor changes here and there), so I'm guessing it is due to a syntax error that I can't find.
I've looked over the code in the book and tried to find differences between them. I changed K_SPACE to K_w to see if the spacebar wasn't registering or something like that, but the bullets still would not fire.
alien_invasion.py
import pygame
from pygame.sprite import Group
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
# initialize game and create a 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')
# set the background color
bg_color= ai_settings.bg_color
# make a ship
ship = Ship(ai_settings, screen)
# make a group to store bullets in
bullets = Group()
# start the main loop for the game
running = True
while running:
running = gf.check_events(ai_settings, screen, ship, bullets)
ship.update()
bullets.update()
gf.update_screen(ai_settings, screen, ship, bullets)
pygame.quit()
run_game()
game_functions.py
import pygame
from bullet import Bullet
def check_events(ai_settings, screen, ship, bullets):
"""respond to keypresses and mouse events"""
running = True
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False # different from Python Crash Course
elif event.type == pygame.KEYDOWN:
check_keydown_events(event, ai_settings, screen, ship, bullets)
elif event.type == pygame.KEYUP:
check_keyup_events(event, ship)
return running
def update_screen(ai_settings, screen, ship, bullets):
"""update images on the screen and flip to the new screen"""
# redraw the screen during each pass through the loop
screen.fill(ai_settings.bg_color)
ship.blitme()
# make the most recently drawn screen visible
pygame.display.flip()
# redraw all bullets behind ship and aliens
for bullet in bullets.sprites():
bullet.draw_bullet()
def check_keydown_events(event, ai_settings, screen, ship, bullets):
"""respond to keypresses"""
if event.key == pygame.K_d:
ship.moving_right = True
elif event.key == pygame.K_a:
ship.moving_left = True
elif event.key == pygame.K_SPACE:
# create a new bullet and add it to the bullets groups
new_bullet = Bullet(ai_settings, screen, ship)
bullets.add(new_bullet)
def check_keyup_events(event, ship):
"""respond to key releases"""
if event.key == pygame.K_d:
ship.moving_right = False
elif event.key == pygame.K_a:
ship.moving_left = False
bullet.py
import pygame
from pygame.sprite import Sprite
class Bullet(Sprite):
"""a class to manage bullets fired from the ship"""
def __init__(self, ai_settings, screen, ship):
"""create a bullet object at the ship's current position"""
super().__init__()
self.screen = screen
# create a bullet rect at (0, 0) and then set correct position
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
# store the bullet's position as a decimal value
self.y = float(self.rect.y)
self.color = ai_settings.bullet_color
self.speed_factor = ai_settings.bullet_speed_factor
def update(self):
"""move the bullet up the screen"""
# update the decimal position of the bullet
self.y -= self.speed_factor
# update the rect position
self.rect.y = self.y
def draw_bullet(self):
"""draw the bullet to the screen"""
pygame.draw.rect(self.screen, self.color, self.rect)
left out settings.py and ship.py but can provide them if necessary
Expected outcome: bullet go pew pew
Actual outcome: Game does not crash, but nothing happens when spacebar is pressed.
The problem seems to be on the update_screen function - you first draw
everything, updates the screen, and then draws the bullets, after the screen is updated. Simply moving the call to ...display.flip() to the end of the function might make your bullets show up (unless there is something other that is also wrong).
def update_screen(ai_settings, screen, ship, bullets):
"""update images on the screen and flip to the new screen"""
# redraw the screen during each pass through the loop
screen.fill(ai_settings.bg_color)
ship.blitme()
# take this out of here
# pygame.display.flip()
# redraw all bullets behind ship and aliens
for bullet in bullets.sprites():
bullet.draw_bullet()
# to here
pygame.display.flip()
I know this must have been answered a number of times, but unfortunately, the topic is difficult to search and I am truly at a los, as Python is not throwing an error.
I am following a Python Crash Course tutorial (Eric Matthes) and am programming a game along the lines of space invaders. The below Module is intended to control the bullets:
import pygame
from pygame.sprite import Sprite
class Bullet(Sprite):
"""A class to manage bullets fired from the ship"""
def __init__(self, ai_settings, screen, ship):
"""Create bullet at the ships current positio"""
super().__init__()
self.screen = screen
# Create a bullet rect at (0, 0) and then set the correct position.
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
# Store the bullet's position as a decimal value.
self.y = float(self.rect.y)
self.color = ai_settings.bullet_color
self.speed_factor = ai_settings.bullet_speed_factor
def update(self):
"""Move the bullet up the screen."""
# Update the decimal position of the bullet.
self.y -= self.speed_factor
# Update the rect position.
self.rect.y = self.y
def draw_bullet(self):
"""Draw the bullet on the screen."""
pygame.draw.rect(self.screen, self.color, self.rect)
The actual game screen is printing the bullet count, so I know the bullets are on the screen and also vanish again, as the move towards the edge of the screen, but they are not displayed.
The game itself looks as follows:
import sys
import pygame
from pygame.sprite import Group
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
# Initialize game and create a 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")
# Make a ship.
ship = Ship(ai_settings, screen)
# Make a group to store the bullets in.
bullets = Group()
# Start main loop for the game
while True:
#Watch for keyboard and mouse events.
gf.check_events(ai_settings, screen, ship, bullets)
ship.update()
gf.update_bullets(bullets)
gf.update_screen(ai_settings, screen, ship, bullets)
# Redraw Screen during each pass through.
screen.fill(ai_settings.bg_color)
ship.blitme()
# Make most recently drawn visible
pygame.display.flip()
run_game()
The settings are there and no, the bullets are not the same color as the screen;-)
Can anyone help me find my error in thinking?
My impression is, the pygame.draw.rect function should make them display in combination with the gf.update_bullets(bullets) call.
Many thanks and best regards,
Simon
Additional File added:
game_functions.py
import sys
import pygame
from bullet import Bullet
def check_keydown_events(event, ai_settings, screen, ship, bullets):
"""Respond to keypresses"""
if event.key == pygame.K_RIGHT:
# Move the ship to the right.
ship.moving_right = True
elif event.key == pygame.K_LEFT:
ship.moving_left = True
elif event.key == pygame.K_SPACE:
fire_bullet(ai_settings, screen, ship, bullets)
def fire_bullet(ai_settings, screen, ship, bullets):
# Create a new bullet and add it to the bullets group.
if len(bullets) < ai_settings.bullets_allowed:
new_bullet = Bullet(ai_settings, screen, ship)
bullets.add(new_bullet)
def check_keyup_events(event, ship):
"""Respond to keypresses"""
if event.key == pygame.K_RIGHT:
# Move the ship to the right.
ship.moving_right = False
elif event.key == pygame.K_LEFT:
ship.moving_left = False
def check_events(ai_settings, screen, ship, bullets):
"""Respond to keypresses and mouse events."""
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if 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):
# Redraw all bullets behind the ship and aliens
for bullet in bullets.sprites():
bullet.draw_bullet()
def update_bullets(bullets):
"""Update position of bullets and get rid of old bullets"""
# Update bullet position
bullets.update()
# Get rid of bullets that have disappeared.
for bullet in bullets.copy():
if bullet.rect.bottom <= 0:
bullets.remove(bullet)
print(len(bullets))
"""Update images on the screen and flip to the new screen."""
Check the order in which you draw things to the screen surface.
You call gf.update_screen(ai_settings, screen, ship, bullets), and after that, you actually erase the whole screen with screen.fill(ai_settings.bg_color).
Make sure to call screen.fill(ai_settings.bg_color) first, then draw your other stuff.
There are some other issues with your code, e.g.
you use the Sprite class, but your sprites don't have an image attribute, which makes using Sprite kind of pointless
you already use the Group class for your sprites, but draw them manually with a for loop and the draw_bullet function. Just give your bullets an image and call bullets.draw(screen) instead
you check if bullets are outside the screen in update_bullets. The the bullet class handle it itself, by simply using something like this:
if not self.screen.rect.contains(self.rect):
self.kill
your entire game_functions.py file makes your code hard to read
I'm making a game with pygame using python 3. I can't get the image of a alien to display on the "screen" surface.
I've looked for hours and reviewed the book its based on but I can't find the source of the problem. I have also looked at other questions on here. Thanks
Heres's the trackback:
Traceback (most recent call last):
File "alien_invasion.py", line 35, in <module>
run_game()
File "alien_invasion.py", line 33, in run_game
g_funcs.update_screen(ai_settings, ai_screen, a_ship, aliens_g, bullets)
File ...
aliens_g.draw(ai_screen)
File...
self.spritedict[spr] = surface_blit(spr.image, spr.rect)
AttributeError: 'Alien' object has no attribute 'image'
Here's my game module:
import pygame
from pygame.sprite import Group
from settings import Settings
from ship import Ship
import game_function as g_funcs
def run_game():
"""Games definition with control while loop"""
#Initialize pygame, settings and screen surface
pygame.init()
ai_settings = Settings()
ai_screen = pygame.display.set_mode(
(ai_settings.screen_width, ai_settings.screen_length))
pygame.display.set_caption("Alien Invasion")
#make a ship, group of bullets, group of aliens
a_ship = Ship(ai_settings, ai_screen)
bullets = Group()
aliens_g = Group()
#Create FLEET of aliens
g_funcs.create_fleet(ai_settings, ai_screen, aliens_g)
#start the main loop for the game
while True:
g_funcs.check_events(ai_settings, ai_screen, a_ship, bullets)
a_ship.update_location()
g_funcs.update_bullet(bullets)
g_funcs.update_screen(ai_settings, ai_screen, a_ship, aliens_g, bullets)
run_game()
Here's all the functions:
import sys
import pygame
from bullet import Bullet
from alien import Alien
def check_events(ai_settings, ai_screen, a_ship, bullets):
"""Respond to keypresses and mouse events."""
#watch for keyboard and mouse events
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
check_keydown_event(event, ai_settings, ai_screen, a_ship, bullets)
elif event.type == pygame.KEYUP:
check_keyup_event(event, a_ship)
def check_keydown_event(event, ai_settings, ai_screen, a_ship, bullets):
"""ONLY callable by check_events function when keydown."""
if event.key == pygame.K_RIGHT:
a_ship.moving_right = True
elif event.key == pygame.K_LEFT:
a_ship.moving_left = True
elif event.key == pygame.K_UP:
a_ship.moving_up = True
elif event.key == pygame.K_DOWN:
a_ship.moving_down = True
elif event.key == pygame.K_SPACE:
fire_bullet(ai_settings, ai_screen, a_ship, bullets)
elif event.key == pygame.K_q:
sys.exit()
def fire_bullet(ai_settings, ai_screen, a_ship, bullets):
"""Fire bullets if bullets limit is not met"""
#CREATE a new bullet INSTANCE and add it to the bullets GROUP
if len(bullets) < ai_settings.bullets_allowed:
new_bullet = Bullet(ai_settings, ai_screen, a_ship)
bullets.add(new_bullet)
def check_keyup_event(event, a_ship):
"""ONLY callable by check_events function when keyup."""
if event.key == pygame.K_RIGHT:
a_ship.moving_right = False
if event.key == pygame.K_LEFT:
a_ship.moving_left = False
if event.key == pygame.K_UP:
a_ship.moving_up = False
if event.key == pygame.K_DOWN:
a_ship.moving_down = False
def update_screen(ai_settings, ai_screen, a_ship, aliens_g, bullets):
"""Update image on the screen and flip to the new screen."""
#Redraw the screen during each pass through the loop
ai_screen.fill(ai_settings.bg_color)
#REDRAW all bullets behind ship and aliens
for bullet in bullets.sprites():
bullet.draw_bullet()
a_ship.blitme()
aliens_g.draw(ai_screen)
#Make the most recently drawn screen visible
pygame.display.flip()
def update_bullet(bullets):
"""Update positions of bullets and delete old ones."""
#Update bullet positions
bullets.update()
#get rid of the old bullets that go off screen
for bullet in bullets.copy():
if bullet.bullet_rect.bottom <= 0:
bullets.remove(bullet)
def create_fleet(ai_settings, ai_screen, aliens_g):
"""Create a full fleet of aliens"""
alien = Alien(ai_settings, ai_screen)
alien_amount_x = get_number_aliens_x(ai_settings, alien.alien_rect.width)
#Create the first row of aliens
for one in range(alien_amount_x):
create_alien(ai_settings, ai_screen, aliens_g, one)
def get_number_aliens_x(ai_settings, alien_width):
"""Determine the amount of alien that fits in a row"""
#Calulations:
availabe_space_x = ai_settings.screen_width - 2 * alien_width
alien_amount_x = int(availabe_space_x / (2 * alien_width))
return alien_amount_x
def create_alien(ai_settings, ai_screen, aliens_g, one):
"""Create an alien and place it in the row."""
alien = Alien(ai_settings, ai_screen)
alien_width = alien.alien_rect.width
alien.x = alien_width + 2 * alien_width * one
alien.alien_rect.x = alien.x
aliens_g.add(alien)
And... heres my alien module:
import pygame
from pygame.sprite import Sprite
class Alien(Sprite):
"""A CLASS that MANAGES a single alienn in the fleet."""
def __init__(self, ai_settings, ai_screen):
"""Initialize the alien and start position"""
super().__init__()
self.ai_settings = ai_settings
self.screen = ai_screen
#Load the alien image and SET RECT attribute
self.alien_image = pygame.image.load('images/alien.bmp')
self.alien_rect = self.alien_image.get_rect()
#Set starting point of alien at the top left corner of screen
#settings the space(top and left) to the width and height of image_rect
self.alien_rect.x = self.alien_rect.width
self.alien_rect.y = self.alien_rect.height
self.x_float = float(self.alien_rect.x)
def blit_a(self):
"""Draw alien at its current location"""
self.screen.blit(self.alien_image, self.alien_rect)
Pygame sprites must have a self.image and a self.rect attribute, otherwise the sprite group won't be able to blit the image and an AttributeError gets raised.
If you take a look at the draw method of the sprite groups, you'll see that it iterates over the contained sprites and blits the spr.image at the spr.rect.
Use name self.image instead of self.alien_image and self.rect instead of self.alien_rect
naming conventions are important in pygame.sprites, so there's an another method to solve this
instead of group.draw(surface) you can use a for loop to print individual alien on screen
for alien in aliens_g.sprites():
alien.blit_a()