AttributeError: 'Group' object has no attribute 'update_bullets' - python

As a beginner, I was trying the "Alien invasion' project in the python crash course a hands-on project-based introduction to programming and got stuck, I was just trying to copy the code but it always get the same feedback:
Traceback (most recent call last):
File "D:/snake/venv/Alien_Invasion/main_game.py", line 29, in <module>
run_game()
File "D:/snake/venv/Alien_Invasion/main_game.py", line 26, in run_game
bullets.update_bullets()
AttributeError: 'Group' object has no attribute 'update_bullets'
and here's my code:
main_game.py
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
import bullet
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()
#游戏主循环
while True:
gf.check_events(ai_settings, screen, ship, bullets)
ship.update_ship()
bullets.update_bullets()
gf.update_screen(ai_settings, screen, ship, bullets)
run_game()
bullet.py
import pygame
class Bullet(pygame.sprite.Sprite):
"""一个对飞船发射的子弹管理的类"""
def __init__(self, ai_settings, screen, ship):
"""在飞船所在位置创建一个子弹对象"""
self.screen = screen
super(Bullet, self).__init__()
#在(0,0)处创建一个表示子弹的矩形,在放置到正确的位置
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_bullets(self):
"""向上移动子弹"""
#更新浮点数的子弹纵坐标
self.y -= self.speed_factor
#更新子弹纵坐标位置
self.rect.y = self.y
def draw_bullet(self):
"""在屏幕上绘制子弹"""
pygame.draw.rect(screen, self.color, self.rect)
game_functions.py
import sys
import pygame
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
#创建一个子弹,并加入bullets编组
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_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_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.sprites():
bullet.draw_bullet()
ship.blitme()
#最近绘制屏幕可见
pygame.display.flip()
there are two other files, but I don't think they are related to this problem.
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_heght = 15
self.bullet_color = 60, 60, 60
ship.py
import pygame
class Ship():
def __init__(self, ai_settings, screen):
self.screen = screen
self.ai_settings = ai_settings
""""加载飞船并获取其外接矩形"""
self.image = pygame.image.load("images/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
#创建属性center存储坐标小数值
self.center = float(self.rect.centerx)
#飞船移动标志
self.moving_right = False
self.moving_left = False
def update_ship(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
#根据center更新rect.centerx值
self.rect.centerx = self.center
def blitme(self):
"""在指定位置绘制飞船"""
self.screen.blit(self.image, self.rect)
Can someone please tell me what I did wrong here? It would be much appreciated!

In your traceback error it says:
Traceback (most recent call last):
File "D:/snake/venv/Alien_Invasion/main_game.py", line 2, in <module>
from pygame import Group
importError: cannot import name 'Group' from 'pygame' (D:\snake\venv\lib\site-packages\pygame\__init__.py)
Which says there should be this line:
from pygame import Group
on line 2 of your main_game.py module. However in the code you have included, that is not there:
main_game.py
import pygame
from settings import Settings
from ship import Ship
Are you sure you are showing he correct code?
Ignoring the code and just looking at the error message it shows that you had this line:
from pygame import Group
There is no pygame.Group which is why you are getting the error telling you that. I think you are looking for pygame.sprite.Group
Edit
Now that we have the right code and the right question :-)
Sprite groups have some built-in methods which can be seen in the docs here. One of these is update() which will then call the update() function in all the sprites in the group. Your problem is that you named your sprite function update_bullets() not just update() and then you tried to call update_bullets() on the group and the group does not have that method.
So to fix your code you have to rename your Bullet method to just update() and then call the sprite.Group method update() to have it called on all the bullets in the group.
You have the same issue with your draw_bullet() method but you worked around it by iterating over the group and calling your method. That works, but you should correct it to take advantage of the builtin group method. You need to change it to just draw() and then you can call it on all the bullets by just calling bullets.draw(). As I said, in your code now, because you are not using the name that the sprite.Group knows how to find, you are iterating over the group. If you rename it, you can then replace this:
for bullet in bullets.sprites():
bullet.draw_bullet()
with just:
bullets.draw()

Related

Pygame keyup/keydown sometimes works [duplicate]

This question already has an answer here:
Faster version of 'pygame.event.get()'. Why are events being missed and why are the events delayed?
(1 answer)
Closed 2 years ago.
I am working on the Alien Invasion game from Python Crash Course.pdf
import sys
import pygame
def check_events(ship):
"""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, ship)
elif event.type == pygame.KEYUP:
check_keyup_events(event, ship)
def check_keydown_events(event, ship):
"""respond to keypresses."""
if event.key == pygame.K_d:
ship.moving_right = True
if event.key == pygame.K_a:
ship.moving_left = True
def check_keyup_events(event, ship):
"""respond to key releases."""
if event.key == pygame.K_d:
ship.moving_right = False
if event.key == pygame.K_a:
ship.moving_left = False
# Move the ship to the right.
#ship.rect.centerx += 1
def update_screen(ai_settings, screen, ship):
"""update images on 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()
#alien invasion
import sys
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
#intialize 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)
#set the background color
#bg_color = (52, 86, 139)
# start the main loop for the game
while True:
gf.check_events(ship)
ship.update()
gf.update_screen(ai_settings, screen, ship)
#watch for keyboard and mouse events.
#redraw the screen during each pass through the loop.
screen.fill(ai_settings.bg_color)
ship.blitme()
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
#make the most recently drawn screen visible
pygame.display.flip()
run_game()
import pygame
class Ship():
def __init__(self, ai_settings, screen):
"""initialize the ship and set its starting position."""
self.screen = screen
self.ai_settings = ai_settings
# Load the ship image and get its rect.
self.image = pygame.image.load('images/ship.bmp')
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
# Start each new ship at the bottom center of the screen.
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
#store a decimal value for the ships center
self.center = float(self.rect.centerx)
#Movement flags
self.moving_right = False
self.moving_left = False
def update(self):
"""update the ships position based on the movement flag"""
# Update the ships center value, not the rect.
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
# Update rect object from self.center
self.rect.centerx = self.center
if self.moving_right:
self.rect.centerx += 1
if self.moving_left:
self.rect.centerx -= 1
def blitme(self):
"""Draw the ship at its current location."""
# pygame.draw.rect(self, (255,0,0), (100, 100), 36)
self.screen.blit(self.image, self.rect)
class Settings():
"""A class to store all settings for Alien Invasion"""
def __init__(self):
"""intialize the games settings."""
# Screen settings
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (52, 86, 139)
#ship settings
self.ship_speed_factor = 1.5
This is the code from my game_functions class
When I press 'D', 85% of the time nothing happens. Sometimes it non stop slides to the left or right, either or. Same thing when pressing "A".
Why is this happening? What am I doing wrong in this code? This code is fairly basic I just want it to move left or right.
Their is no code that turns self.moving_right and self.moving_left to
false to stop them from moving.
I would use something like this:
if event.type == pygame.KEYUP :
if event.key == pygame.K_RIGHT:
self.moving_right = False
elif event.key == pygame.K_ESCAPE :
self.moving_left = False
Here's the documantation:
https://www.pygame.org/docs/ref/key.html

AttributeError: 'pygame.Surface' object has no attribute 'screen'

I am learning Python from the book, "PYTHON CRASH COURSE: A Hands-On, Project-Based Introduction to Programming", 2E.
In that while making game, I am getting the error
Traceback (most recent call last):
File "d:\BOOKS\python\my-projects\AlienInvasion\tempCodeRunnerFile.py", line 69, in <module>
alinv = AlienInvasion()
File "d:\BOOKS\python\my-projects\AlienInvasion\tempCodeRunnerFile.py", line 22, in __init__
self.ship = Ship(self.screen)
File "d:\BOOKS\python\my-projects\AlienInvasion\ship.py", line 10, in __init__
self.screen = alinv_game.screen
AttributeError: 'pygame.Surface' object has no attribute 'screen'
My Code is:
AlienInvasion.py
# Importing modules
import sys
import pygame
from settings import Settings
from ship import Ship
class AlienInvasion:
'''Class to manage game assets and behavior'''
def __init__(self):
'''Constructor to initialize the game and its assets'''
pygame.init()
self.settings = Settings()
self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
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.screen)
def run_game(self):
'''Starts the main loop for the game'''
while True:
self._check_events()
self.ship.update()
self._update_screen()
def _check_events(self):
'''Watch for the keyboard and mouse events'''
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):
"""Respond to keypresses."""
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):
"""Respond to key releases."""
if event.key == pygame.K_RIGHT:
self.ship.moving_right = False
elif event.key == pygame.K_LEFT:
self.ship.moving_left = False
def _update_screen(self):
'''Redraw the screen during each pass of the loop'''
self.screen.fill(self.settings.bg_color)
self.ship.blitme()
'''Make the most recently drawn screen visible'''
pygame.display.flip()
if __name__ == '__main__':
'''Make a game instance, and run the game'''
alinv = AlienInvasion()
alinv.run_game()
ship.py
import pygame
class Ship:
'''A class to manage the ship'''
def __init__(self, alinv_game):
'''Initialize the ship and set its starting position'''
self.screen = alinv_game.screen
self.settings = alinv_game.settings
self.screen_rect = alinv_game.screen.get_rect()
'''Load the ship image and get its rect'''
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 ship's horizontal position'''
self.x = float(self.rect.x)
'''Movement Flag'''
self.moving_right = False
self.moving_left = False
def update(self):
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 obj from self.x'''
self.rect.x = self.x
def blitme(self):
'''Draw the ship at its current location.'''
self.screen.blit(self.image, self.rect)
In the update method of class Ship, I Implemented two separate blocks to allow ship.rect.x value
to be increased and then decreased when both left and right
arrow keys are pressed. Otherwise, the self.moving_right will
have more priority if 'elif' is implemented.
settings.py
class Settings:
'''A class to store all settings for Alien Invasion Game.'''
def __init__(self):
'''Initialize the game's settings'''
# Screen Settings:
self.screen_width = 1280
self.screen_height = 720
self.bg_color = (230, 230, 230)
# Ship Settings:
self.ship_speed = 1.5
I think the error should be with the screen declaration because I think Pygame.Surface do not have 'screen' attribute but we can though get it by get_rect method. Kindly help me finding the bug. I am not able to solve the issue.
I believe you meant to make the line self.ship = Ship(self.screen) say self.ship = Ship(self). That way the Ship object can access all of the attributes of the AlienInvasion object, instead of just it's screen attribute (and that attribute doesn't have a screen attribute, thus the error).

Alien Invasion Python Crash Course | After firing bullets, the ship starts slowing down

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()

(Python Crash Course) Alien Invasion Project

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.

why this - AttributeError: 'Alien' object has no attribute 'image' is coming from aliens.draw(screen)?

**There are six modules in this game
and the main problem is its showing this all errors
actually i was doing this
project from a book called python crash course
everything was going fine till this error came and i m trying every possible way but its not going forward
**
"Traceback (most recent call last):
File "C:/Users/oracle.DESKTOP-DESAP2E/PycharmProjects/Alien_invasion/start_game", line 29, in <module>
run_game()
File "C:/Users/oracle.DESKTOP-DESAP2E/PycharmProjects/Alien_invasion/start_game", line 27, in run_game
gf.update_screen(ai_settings, screen, ship, aliens, bullets)
File "C:\Users\oracle.DESKTOP-DESAP2E\PycharmProjects\Alien_invasion\game_functions.py", line 74, in update_screen
aliens.draw(screen)
File "C:\Users\oracle.DESKTOP-DESAP2E\PycharmProjects\Alien_invasion\venv\lib\site-packages\pygame\sprite.py", line 476, in draw
self.spritedict[spr] = surface_blit(spr.image, spr.rect)
AttributeError: 'Alien' object has no attribute 'image'"
-----and the code is here....
start_game.py
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.screenwidth,ai_settings.screenheight))
pygame.display.set_caption("Alien Invasion")
# Make a ship, a group of bullets, and a group of aliens.
ship = Ship(ai_settings,screen)
# Make a group to store bullets in.
bullets = Group()
aliens = Group()
# Create a fleet of aliens
gf.create_fleet(ai_settings, screen, aliens)
while True:
gf.check_events(ai_settings,screen,ship,bullets)
ship.update()
bullets.update()
gf.update_bullets(bullets)
gf.update_screen(ai_settings, screen, ship, aliens, bullets)
run_game()
game_functions.py
import sys
import pygame
from bullet import Bullet
from alien import Alien
def check_keydown_evnets(event,ai_settings,screen,ship,bullets):
"""This part works when right arrow key is pressed"""
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:
fire_bullet(ai_settings,screen,ship,bullets)
elif event.key == pygame.K_q:
sys.exit()
def check_keyup_events(event,ship):
"""This part works when right arrow key is released"""
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_evnets(event, ai_settings, screen, ship, bullets)
elif event.type == pygame.KEYUP:
check_keyup_events(event,ship)
def update_bullets(bullets):
"""Update position of bullets and get rid of old bullets."""
# Update bullet positions.
for bullet in bullets.copy():
if bullet.rect.bottom <= 0:
bullets.remove(bullet)
def fire_bullet(ai_settings, screen, ship, bullets):
# checks whether max bullets on screen are 3 and adds new bullet
if len(bullets) < ai_settings.bullets_allowed:
new_bullet = Bullet(ai_settings, screen, ship)
bullets.add(new_bullet)
def create_fleet(ai_settings, screen, aliens):
"""Create a full fleet of aliens."""
# Create an alien and find the number of aliens in a row.
# Spacing between each alien is equal to one alien width.
alien = Alien(ai_settings,screen)
alien_width = alien.rect.width
available_space_x = ai_settings.screenwidth - (2 * alien_width)
number_alien_x = int(available_space_x / (2 * alien_width))
# Create the first row of the alien
for alien_number in range(number_alien_x):
# Create an alien and place it in a row
alien = Alien(ai_settings, screen)
alien.x = alien_width + 2 * alien_width * alien_number
alien.rect.x = alien.x
aliens.add(alien)
"""updates the screen"""
def update_screen(ai_settings,screen,ship,aliens,bullets):
# redraw the screen during each pass of the loop
screen.fill(ai_settings.bg_color)
# Redraw all bullets behind ship and aliens.
for bullet in bullets.sprites():
bullet.draw_bullet()
ship.blitme()
aliens.draw(screen)
# Make the most recently drawn screen visible.
pygame.display.flip()
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 from ship current position
super().__init__()
self.screen = screen
# create a bullet
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
# stores bullets position as a decimal
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 bullets to the screen"""
pygame.draw.rect(self.screen,self.color,self.rect)
settings.py
class Settings():
"""A class to store all the settings of the game"""
def __init__(self):
"""Initializes the game settings"""
#screen settings
self.screenwidth = 1200
self.screenheight = 600
self.bg_color = (200,230,230)
#ship settings
self.ship_speed_factor = 1.5
# Bullet settings
self.bullet_speed_factor = 0.5
self.bullet_width = 3
self.bullet_height = 15
self.bullet_color = 60, 60, 60
self.bullets_allowed = 3
ship.py
import pygame
class Ship():
def __init__(self,ai_settings,screen):
"""Initialize ship at starting position"""
self.screen = screen
self.ai_settings = ai_settings
self.image = pygame.image.load('images/ship2.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
# Store a decimal value for the ship's center.
self.center = float(self.rect.centerx)
# movement flags
self.moving_right = False
self.moving_left = False
"""Updates ship when key is pressed whether left or right based on movement flags"""
def update(self):
# Update the ship's center value, not the rect.
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
# Update rect object from self.center.
self.rect.centerx = self.center
def blitme(self):
"""Draw the ship at its current location"""
self.screen.blit(self.image,self.rect)
alien.py
from pygame.sprite import Sprite
import pygame
class Alien(Sprite):
"""A class to represent a single alien in the fleet."""
def __init__(self, ai_settings, screen):
"""Initialize the alien and set its starting position."""
super().__init__()
self.screen = screen
self.ai_settings = ai_settings
# Load the alien image and set its rect attribute.
self.alien_img = pygame.image.load('images/alien.bmp')
self.rect = self.alien_img.get_rect()
# Start each new alien near the top left of the screen.
self.rect.x = self.rect.width
self.rect.y = self.rect.height
# Stores alien's exact position
self.x = float(self.rect.x)
def blitme(self):
""" Draw the aliens at its current position"""
self.screen.blit(self.alien_img, self.rect)
If you use pygame's Sprite and Group to draw a sprite on the screen, the sprite needs an image attribute.
That's neither the case for the Alien class nor the Bullet class.
A quick fix for the Alien class is to rename the alien_img attribute to image, as Nathan already said in a comment.
There are also a lot of other strange things in this code, like this copy/remove
for bullet in bullets.copy():
if bullet.rect.bottom <= 0:
bullets.remove(bullet)
instead of using kill() of the Ship class, which looks like a Sprite with its rect and image attribute, but it doesn't inherit from pygame.Sprite etc etc.

Categories