NameError: name 'sideways_target' is not defined - python

I have an error where python is not able to find my file. (if I understand correctly) I can't find what I have missed. If anyone could take the time to point it out to me, it would be much appreciated.
def _check_target_edges(self):
"""Respond appropriately if the target has reached an edge."""
if sideways_target.check_edges():
self._change_target_direction()
this code is giving error messages
pygame 2.1.2 (SDL 2.0.18, Python 3.10.5)
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
File "C:\Users\2\Desktop\python_work\Chapter 11 - 15\Chapter 14\14.2 Target Practice.py", line 218, in <module>
ss.run_game()
File "C:\Users\2\Desktop\python_work\Chapter 11 - 15\Chapter 14\14.2 Target Practice.py", line 53, in run_game
self._update_target()
File "C:\Users\2\Desktop\python_work\Chapter 11 - 15\Chapter 14\14.2 Target Practice.py", line 157, in _update_target
self._check_target_edges()
File "C:\Users\2\Desktop\python_work\Chapter 11 - 15\Chapter 14\14.2 Target Practice.py", line 207, in _check_target_edges
if sideways_target.check_edges():
NameError: name 'sideways_target' is not defined
[Finished in 2.7s]
def check_edges(self):
"""Return True if target is at edge of screen."""
screen_rect = self.screen.get_rect()
if self.rect.bottom >= screen_rect.bottom or self.rect.top <= 0:
return True
This is what I want the code to find. So it updates any changes in True/False.
I would like to know where can I define 'sideways_target' so the error clears up and I can run the project.
If you need more detail... the files are down below
File of the 1st piece of code
# ship spawns on the left side
# bullets travel to the right
# target moves up and down
# shoot the target
#
import sys, pygame
from sideways_settings import Settings
from sideways_ship import Ship
from sideways_bullet import Bullet
from sideways_game_stats import GameStats
from sideways_target import Target
from sideways_button import Button
class ShipShooter:
"""Overall class to manage game assets and behavior."""
def __init__(self):
"""Initialize the game, and create game resources."""
pygame.init()
self.sideways_settings = Settings()
self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
self.sideways_settings.screen_width = self.screen.get_rect().width
self.sideways_settings.screen_width = self.screen.get_rect().height
pygame.display.set_caption("Sideways Shooter")
# Create an instance to store game statistics.
self.sideways_stats = GameStats(self)
self.sideways_ship = Ship(self)
self.bullets = pygame.sprite.Group()
# Make the button.
self.sideways_play_button = Button(self, "Play")
# Make the target
self.sideways_target = Target(self)
# Set the background color.
self.bg_color = (230, 230, 230)
def run_game(self):
"""Start the main loop for the game."""
while True:
self._check_events()
if self.sideways_stats.game_active:
self.sideways_ship.update()
self._update_bullets()
self._update_target()
self._update_screen()
def _check_events(self):
"""Respond to keypresses 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)
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = pygame.mouse.get_pos()
self._check_play_button(mouse_pos)
def _check_play_button(self, mouse_pos):
"""Start a new game when the player clicks Play."""
button_clicked = self.sideways_play_button.rect.collidepoint(mouse_pos)
if button_clicked and not self.sideways_stats.game_active:
# Reset the game statistics.
self.sideways_stats.reset_stats()
self.sideways_stats.game_active = True
# Get rid of any remaining bullets.
self.bullets.empty()
# Center the ship
self.sideways_ship.center_ship()
# Hide the mouse cursor.
pygame.mouse.set_visible(False)
def _check_play_button2(self):
"""Start a new game when the player clicks Play."""
if self.key_p == True:
# Reset the game statistics.
self.sideways_stats.reset_stats()
self.sideways_stats.game_active = True
# Get rid of any remaining bullets.
self.bullets.empty()
# Center the ship
self.sideways_ship.center_ship()
# Hide the mouse cursor.
pygame.mouse.set_visible(False)
def _check_keydown_events(self, event):
"""Respond to keypresses."""
if event.key == pygame.K_UP:
self.sideways_ship.moving_up = True
elif event.key == pygame.K_DOWN:
self.sideways_ship.moving_down = True
elif event.key == pygame.K_q:
sys.exit()
elif event.key == pygame.K_SPACE:
self._fire_bullet()
elif event.key == pygame.K_p:
self.key_p = True
self._check_play_button2()
def _check_keyup_events(self, event):
"""Respond to key releases."""
if event.key == pygame.K_UP:
self.sideways_ship.moving_up = False
elif event.key == pygame.K_DOWN:
self.sideways_ship.moving_down = False
def _fire_bullet(self):
"""Create a new bullet and add it to the bullets group."""
if len(self.bullets) < self.sideways_settings.bullets_allowed:
new_bullet = Bullet(self)
self.bullets.add(new_bullet)
def _update_bullets(self):
"""Update position of bullets and get rid of old bullets."""
# Update bullet positions.
self.bullets.update()
# Get rid of bullets that have disappeared.
for bullet in self.bullets.copy():
if bullet.rect.right >= self.sideways_ship.screen_rect.right :
self.bullets.remove(bullet)
# print(len(self.bullets))
# Look for bullets hitting the side of the screen.
self._check_bullets_bottom()
def _check_bullet_target_collisions(self):
"""Respond to bullet-target collisions."""
# Remove any bullets that have collided with the target
collisions = pygame.sprite.groupcollide(
self.bullets, self.sideways_target, True, True)
def _update_target(self):
"""
Check if the target is at the edge,
then update the position of the target
"""
self._check_target_edges()
self.sideways_target.update()
# Look for bullet-target collisions.
if pygame.sprite.spritecollideany(self.bullets, self.sideways_target):
self._target_hit()
def _target_hit(self):
"""Respond to the target being hit by a bullet."""
if self.sideways_stats.targets_left > 0:
# Decrement targets_left.
self.sideways_stats.targets_left -= 1
# Get rid of any remaining bullets.
self.bullets.empty()
# Center the ship.
self.sideways_ship.center_ship()
# Pause.
sleep(1.5)
else:
self.sideways_stats.game_active = False
pygame.mouse.set_visible(True)
def _check_bullets_bottom(self):
"""Check if any bullets have reached the side of your screen."""
screen_rect = self.screen.get_rect()
for bullet in self.bullets.sprites():
if bullet.rect.right >= screen_rect.right:
# Treat this the same as if the target got hit.
self.target_hit()
break
def _update_screen(self):
"""Update images on the screen, and flip to the new screen."""
self.screen.fill(self.sideways_settings.bg_color)
self.sideways_ship.blitme()
for bullet in self.bullets.sprites():
bullet.draw_bullet()
self.sideways_target.draw_target()
# Draw the play button if the game is inactive.
if not self.sideways_stats.game_active:
self.sideways_play_button.draw_button()
pygame.display.flip()
def _check_target_edges(self):
"""Respond appropriately if the target has reached an edge."""
if sideways_target.check_edges():
self._change_target_direction()
def _change_target_direction(self):
"""Change the target's direction."""
self.sideways_settings.target_direction *= -1
if __name__ == '__main__':
# Make a game instance, and run the game.
ss = ShipShooter()
ss.run_game()
File of the 2nd piece of code
import pygame
from pygame.sprite import Sprite
class Target:
def __init__(self, ai_game):
"""Initialize target attributes."""
self.screen = ai_game.screen
self.screen_rect = self.screen.get_rect()
# Set the dimensions and properties of the target
self.width, self.height = 70, 300
self.target_color = (0, 0, 0)
# Build the target's rect object and center it.
self.rect = pygame.Rect(0, 0, self.width, self.height)
self.rect.midright = self.screen_rect.midright
# Store the target's exact vertical position.
self.y = float(self.rect.y)
def check_edges(self):
"""Return True if target is at edge of screen."""
screen_rect = self.screen.get_rect()
if self.rect.bottom >= screen_rect.bottom or self.rect.top <= 0:
return True
def update(self):
"""Move the target up or down."""
self.y += (self.sideways_settings.target_speed *
self.sideways_settings.target_direction)
self.rect.y = self.y
def draw_target(self):
# Draw the target to the screen
pygame.draw.rect(self.screen, self.target_color, self.rect)

Related

Python Crash Course, Alien Invasion - a ship doesn't move after reaching the screen's right corner

I'm working on the Alien Invasion from "Python Crash Course" by Erick Matthes. I've bogged down on trying to make a ship move across a screen. Most of time, the ship moves as expected. However, after reaching the very right corner of the screen, the ship ceases to react to pressed keys. Pressing a left arrow key on keyboard doesn't move the ship leftwards at all. What's wrong with my code?
alien_invasion.py
"""The main module of the Alien Invasion"""
import sys
import pygame
from settings import Settings
from ship import Ship
class AlienInvasion():
"""A class storing and managing all game's functionality."""
def __init__(self):
"""Initialize essential settings."""
self.settings = Settings()
self.screen = pygame.display.set_mode((0,0), pygame.FULLSCREEN)
self.settings.window_width = self.screen.get_rect().width
self.settings.window_height = self.screen.get_rect().height
pygame.display.set_caption(self.settings.game_title)
self.ship = Ship(self)
self._run_game()
def _end_game(self):
"""Close the game's window."""
pygame.quit()
sys.exit()
def _check_events(self):
"""Check events and react to them."""
for event in pygame.event.get():
if event.type == pygame.QUIT:
self._end_game()
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):
"""Detect pressed keys and react accordingly."""
if event.key == pygame.K_q:
self._end_game()
if event.key == pygame.K_RIGHT:
self.ship.moving_right = True
if event.key == pygame.K_LEFT:
self.ship.moving_left = True
def _check_keyup_events(self, event):
"""Detect released keys and react accordingly."""
if event.key == pygame.K_RIGHT:
self.ship_moving_right = False
if event.key == pygame.K_LEFT:
self.ship.moving_left = False
def _update_screen(self):
"""Draw the most recent surface on the screen."""
self.screen.fill(self.settings.background_colour)
self.ship.update()
self.ship.blitme()
pygame.display.flip()
def _run_game(self):
"""Start a new game"""
while True:
#Main loop
self._check_events()
self._update_screen()
ai = AlienInvasion()
ship.py
"""A module containing a Ship class"""
import pygame
class Ship():
"""A simple attempt to represent a ship."""
def __init__(self, ai):
"""Initialize a ship's settings."""
self.ai = ai
self.screen = self.ai.screen
self.image = pygame.image.load('ship.bmp')
self.rect = self.image.get_rect()
self.screen_rect = self.screen.get_rect()
self.rect.midbottom = self.screen_rect.midbottom
#Motions' attributes
self.moving_right = False
self.moving_left = False
self.x = float(self.rect.x)
self.speed = self.ai.settings.ship_speed
def blitme(self):
"""Draw a ship on the screen."""
self.screen.blit(self.image, self.rect)
def update(self):
"""Update a ship's position on the screen."""
if self.moving_right and self.rect.right < self.screen_rect.right:
self.x += self.speed
if self.moving_left and self.rect.left > 0:
self.x -= self.speed
self.rect.x = self.x
settings.py
"""Module containing a Settings class"""
class Settings():
"""A module managing all game's essential settings."""
def __init__(self):
"""Initialize settings."""
self.background_colour = (230, 230, 230)
self.game_title = 'Alien Invasion'
self.window_width = 1200
self.window_height = 600
self.window_size = (self.window_width, self.window_height)
#Ship's settings
self.ship_speed = 1.5
The ship won't move left, which means it's probably stuck moving right. That points to an issue in releasing the movement to the right, which happens in _check_keydown_events():
def _check_keyup_events(self, event):
"""Detect released keys and react accordingly."""
if event.key == pygame.K_RIGHT:
self.ship_moving_right = False
if event.key == pygame.K_LEFT:
self.ship.moving_left = False
Here's the problematic line:
self.ship_moving_right = False
This should be self.ship.moving_right, not self.ship_moving_right. The correct version finds the ship attribute of the game, and sets the ship's moving_right attribute to False. The incorrect version creates a new game attribute ship_moving_right, and sets it to False; it never changes the value of self.ship.moving_right. So, the ship tries to move right for the rest of the game. This is a great example of how one character can produce no Python errors, but has a significant impact on the overall behavior of the game.

Alien Invasion struggling

I'm working on the Alien Invasion game from the Python Crash course book, but i can't run the game.
Here's my code:
# Alien Invasion game
import sys
from time import sleep
import pygame
from settings import Settings
from game_stats import GameStats
from button import Button
from ship import Ship
from bullet import Bullet
from alien import Alien
from scoreboard import Scoreboard
class AlienInvasion :
def __init__(self):
'''Initialize the game, and create game resources'''
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")
# Create an instance to store game statistics and create a scoreboard
self.stats = GameStats(self)
self.sb = Scoreboard()
self.bg_color = (230, 230, 230)
self.settings = Settings()
self.ship = Ship(self)
self.bullets = pygame.sprite.Group()
self.aliens = pygame.sprite.Group()
self._create_fleet()
self.screen = pygame.display.set_mode(
(self.settings.screen_width, self.settings.screen_height))
# Make the Play button
self.play_button = Button(self, "Play")
# Make the difficulty level buttons.
self._make_difficulty_buttons()
def _make_difficulty_buttons(self):
"""Make buttons that allow player to select difficulty level."""
self.easy_button = Button(self, "Easy")
self.medium_button = Button(self, "Medium")
self.difficult_button = Button(self, "Difficult")
# Position buttons so they don't all overlap.
self.easy_button.rect.top = (
self.play_button.rect.top + 1.5*self.play_button.rect.height)
self.easy_button._update_msg_position()
self.medium_button.rect.top = (
self.easy_button.rect.top + 1.5*self.easy_button.rect.height)
self.medium_button._update_msg_position()
self.difficult_button.rect.top = (
self.medium_button.rect.top + 1.5*self.medium_button.rect.height)
self.difficult_button._update_msg_position()
def run_game(self):
'''Start the main loop for the game'''
while True :
self._check_events()
if self.stats.game_active:
self.ship.update()
self._update_bullets()
self._update_aliens()
self._update_screen()
def _update_bullets(self):
'''Update position of bullets and get rid of old bullets'''
# Update bullet positions
self.bullets.update()
# Get rid of bullets that have disappeared
for bullet in self.bullets.copy():
if bullet.rect.bottom <= 0:
self.bullets.remove(bullet)
self._check_bullet_alien_collisions()
def _check_bullet_alien_collisions(self):
'''Respond to bullet - alien collisions'''
# Remove any bullets and aliens that have collided
collisions = pygame.sprite.groupcollide(
self.bullets, self.aliens, True, True)
if collisions :
for aliens in collisions.values():
self.stats.score += self.settings.alien_points
self.sb.prep_score()
self.sb.check_high_score()
if not self.aliens :
# Destroy existing bullets and create new fleet
self.bullets.empty()
self._create_fleet()
self.settings.increase_speed()
# Increase level.
self.stats.level += 1
self.sb.prep_level()
def _update_aliens(self):
'''
Check if the fleet is at an edge,
then update the positions of all
aliens in the fleet
'''
self._check_fleet_edges()
self.aliens.update()
# Look for alien - ship collisions
if pygame.sprite.spritecollideany(self.ship, self.aliens):
self._ship_hit()
# Look for aliens hitting the bottom of the screen
self._check_aliens_bottom()
def _ship_hit(self):
'''Respond to the ship being hit by an alien'''
if self.stats.ships_left > 0 :
# Decrement ships_left, and update scoreboards
self.stats.ships_left -= 1
self.sb.prep_ships()
# Get rid of any remaining aliens and bullets
self.aliens.empty()
self.ship.center_ship()
# Create a new fleet and center the ship.
self._create_fleet()
self.ship.center_ship()
# Pause
sleep(0.5)
else:
self.stats.game_active = False
pygame.mouse.set_visible(True)
def _check_events(self):
'''Respond to keypresses 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)
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = pygame.mouse.get_pos()
self._check_play_button(mouse_pos)
self._check_difficulty_buttons(mouse_pos)
def _check_play_button(self, mouse_pos):
'''Start a new game when the player clicks Play'''
button_clicked = self.play_button.rect.collidepoint(mouse_pos)
if button_clicked and not self.stats.game_active :
# Reset the game statistics
self.stats.reset_stats()
self.stats.game_active = True
self.sb.prep_score()
self.sb.prep_level()
self.sb.prep_ships()
self.aliens.empty()
self.bullets.empty()
self._create_fleet()
self.ship.center_ship()
pygame.mouse.set_visible(False)
def _check_difficulty_buttons(self, mouse_pos):
"""Set the appropriate difficulty level."""
easy_button_clicked = self.easy_button.rect.collidepoint(mouse_pos)
medium_button_clicked = self.medium_button.rect.collidepoint(
mouse_pos)
diff_button_clicked = self.difficult_button.rect.collidepoint(
mouse_pos)
if easy_button_clicked:
self.settings.difficulty_level = 'easy'
elif medium_button_clicked:
self.settings.difficulty_level = 'medium'
elif diff_button_clicked:
self.settings.difficulty_level = 'difficult'
#def _start_game(self):
'''Start a new game'''
# Reset the game statistics
#self.stats.reset_stats()
#self.stats.game_active = True
#self.sb.prep_score()
#
# Get rid of any remaining aliens and bullets
#self.aliens.empty()
#self.bullets.empty()
# Create a new fleet and center the ship
#self.create_fleet()
#self.ship.center_ship()
# Hide the mouse cursor
#pygame.mouse.set_visible(False)
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_q:
sys.exit()
elif event.key == pygame.K_SPACE:
self._fire_bullet()
elif event.key == pygame.K_p and not self.stats.game_active:
self._start_game()
def check_keyup_events(self, event):
if event.key == pygame.K_RIGHT:
self.ship.moving_right = False
elif event.key == pygame.K_LEFT:
self.ship.moving_left = False
def _fire_bullet(self):
'''Create a new bullet and add it to the bullets group'''
if len(self.bullets) < self.settings.bullets_allowed :
new_bullet = Bullet(self)
self.bullets.add(new_bullet)
def _create_fleet(self):
'''Create the fleet of aliens'''
# Make an alien
alien = Alien(self)
alien_width, alien_height = alien.rect.size
available_space_x = settings.screen_width - (2 * alien_width)
number_aliens_x = available.space_x // (2 * alien_width)
# Determine the number of rows of aliens that fit on the screen
ship_height = self.ship.rect.height
available_space_y = (self.settings.screen_height -
3 * (alien_height)- ship_height)
number_rows = available_space_y // 2 * (alien_height)
# Create the full fleet of aliens.
for row_number in range(number_rows):
for alien_number in range(number_aliens_x):
self._create_alien(alien_number, row_number)
def _create_alien(self, alien_number):
'''Create an alien and place it in the row'''
self._create_alien(alien_number)
alien = Alien(self)
alien_width, alien_height = alien.rect.size
alien.x = alien_width + 2 * alien_wdith * alien_number
alien.rect.x = alien.x
alien.rect.y = alien.rect.height + 2 * alien.rect.height * row_number
self.aliens.add(alien)
def _check_fleet_edges(self):
'''Respond appropriately if any alien has reached an edge'''
for alien in self.aliens.sprites():
if alien.check_edges():
self._change_fleet_direction()
break
def _change_fleet_direction(self):
'''Drop the entire fleet and change the fleet's direction'''
for alien in self.aliens.sprites():
alien.rect.y += self.settings.fleet_drop_speed
self.settings.fleet_direction *= -1
def _check_aliens_bottom(self):
'''Check if any aliens have reached the bottom of the screen'''
screen_rect = self.screen.get_rect()
for alien in self.aliens.sprites():
if alien.rect.midbottom > screen_rect.bottom:
# Treat this the same as if the ship got hit
self._ship_hit()
break
def _update_screen(self):
self.screen.fill(self.settings.bg_color)
self.ship.blitme()
for bullet in self.bullets.sprites():
bullet.draw_bullet()
self.aliens.draw(self.screen)
# Draw the score information
self.sb.show_score()
# Draw the play button if the game is inactive
if not self.stats.game_active:
self.play_button.draw_button
self.easy_button.draw_button()
self.medium_button.draw_button()
self.difficult_button.draw_button()
pygame.display.flip()
if __name__ == "__main__":
ai = AlienInvasion()
ai.run_game()
# Ship
import pygame
from pygame.sprite import Sprite
class Ship(Sprite) :
shipimage = r'C:\Users\basti\OneDrive\Documents\Python\Images and sprites\Spaceships\Spaceshipt.png'
with open(shipimage) as f:
def __init__(self, ai_game):
'''Initialize the ship and set its starting position'''
super().__init__()
self.screen = ai_game.screen
self.screen_rect = ai_game.screen.get_rect()
self.settings = ai_game.settings
# Load the ship and get its rect
self.image = pygame.image.load
self.rect = self.image.get_rect()
# Start each new ship at the bottom center of the screen
self.rect.midbottom = self.screen_rect.midbottom
self.x = float(self.rect.x)
# Movement flag
self.moving_right = False
self.moving_left = False
# Ship settings
self.ship_speed = 1.5
def blitme(self):
'''Draw the ship at its current location.'''
self.screen.blit(self.image, self.rect)
def update(self):
'''Update the ship's position based on the movement flag'''
# Update the ship's x value, not the rect.
if self.moving_right and self.rect.right < self.screen_rect.right :
self.x += self.settings.ship_speed
if self.moving_left and self. rect.left > 0 :
self.x -= self.settings. ship_speed
# Update rect object from self.x
self.rect.x = self.x
def center_ship(self):
'''Center the ship on the screen'''
self.rect.midbottom = self.screen_rect.midbottom
self.x = float(self.rect.x)
# Scoreboard
import pygame.font
from pygame.sprite import Group
from Ship import Ship
class Scoreboard :
'''A class to represent scoring information'''
def __init__(self, ai_game):
'''Initialize scorekeeping attributes'''
self.ai_game = ai_game
self.screen = ai_game.screen
self.screen_rect = self.screen.get_rect()
self.settings = ai_game.settings
self.stats = ai_game.stats
# Font settings for scoring information
self.text_color = (30, 30, 30)
self.font = pygame.font.SysFont(None, 48)
# Prepare the initial score images
self.prep_score()
self.prep_high_score()
self.prep_level()
# High score should never be reset
self.high_score = 0
def prep_level(self):
'''Turn the level into a rendered image'''
level_str = str(self.stats.level)
self.level_image = self.font.render(level_str, True,
self.text_color, self.settings.bg_color)
# Position the level below the score
self.level_rect = self.level_image.get_rect()
self.level_rect.right = self.score_rect.right
self.level_rect.top = self.score_rect.bottom + 10
def prep_score(self):
'''Turn the score into a rendered image'''
rounded_score = round(self.stats.score, -1)
score_str = "{:,},".format(rounded_score)
score_str = str(self.stats.score)
self.score_image = self.font.render(score_str, True,
self.text_color, self.settings.bg_color)
# Display the score at the top right of the screen
self.score_rect = self.score_image.get_rect()
self.score_rect.right = self.screen_rect.right - 20
self.score_rect.top = 20
def prep_ships(self):
'''Show how many ships are left'''
self.ships = Group()
for ship_number in range(self.stats.ships_left):
ship = Ship(self.ai_game)
ship.rect.x = 10 + ship_number * ship.rect.width
ship.rect.y = 10
self.ships.add(ship)
def show_score(self):
'''Draw scores, level, and ships to the screen'''
self.screen.blit(self.score_image, self.score_rect)
self.screen.blit(self.high_score_image, self.high_score_rect)
self.screen.blit(self.level_image, self.level_rect)
self.ships.draw(self.screen)
def prep_high_score(self):
'''Turn the high score into a rendered_image'''
high_score = round(self.stats.high_score, -1)
high_score_str = "{:,}".format(high_score)
self.high_score_image = self.font.render(high_score_str, True,
self.text_color, self.settings.bg_color)
# Center the high score at the top of the screen
self.high_score_rect = self.high_score_image.get_rect()
self.high_score_rect.centerx = self.screen_rect.centerx
self.high_score_rect.top = self.score_rect.top
def check_high_score(self):
'''Check to see if there's a new high score'''
if self.stats.score > self.stats.high_score:
self.stats.high_score = self.stats.score
self.prep_high_score()
When i run alien_invasion, i get this error :
pygame 2.0.1 (SDL 2.0.14, Python 3.9.6)
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
File "C:\Users\basti\OneDrive\Documents\Python\Alien Invasion\Alien Invasion.py", line 321, in <module>
ai = AlienInvasion()
File "C:\Users\basti\OneDrive\Documents\Python\Alien Invasion\Alien Invasion.py", line 38, in __init__
self.sb = Scoreboard()
TypeError: __init__() missing 1 required positional argument: 'ai_game'
[Finished in 1.4s]
Could someone help me correct it ?
P.S. : Also, I don't understand why we use the self argument in self.ship = Ship(self) and self.alien = Alien(self)

Bullets wont show when fired... Attributes seems to show bullet is moving but wont show [duplicate]

This question already has answers here:
Why is nothing drawn in PyGame at all?
(2 answers)
Closed 1 year ago.
Below is the code... Bullet class is defined first, class is called in _fire_bullet, _update_screen, and _check_KEYDOWN. When spacebar is pressed the event handler should take in the event key, call _fire_bullet function where a bullet object is created and added to sprite list. Then fired and moves across screen. As of now its going to move the wrong direction but I will correct that issue easily when I can actually see the bullet.
#make a pygame window with a blue background
import pygame
import sys
from pygame.sprite import Sprite
class Bullet(Sprite):
""" A class to manage bullets fired from the ship """
def __init__(self, game):
""" create a bullet object at the ships current position """
super().__init__()
self.screen = game.screen
self.bullet_speed = 1.0
self.bullet_width = 300
self.bullet_height = 150
self.bullet_color = (0, 200, 200)
#create a bullet at rect (0,0) and the set the correct position
self.rect = pygame.Rect(0, 0, self.bullet_width, self.bullet_height)
self.rect.midright = game.rect.midright
#store the bullets position as a decimal value
self.y = float(self.rect.y)
self.x = float(self.rect.x)
def update(self):
""" move the bullet up the screen """
#update the decimal position of the bullet.
self.y -= self.bullet_speed
self.rect.x = self.x
#uipdate the rect position
self.rect.y = self.y
def draw_bullet(self):
""" draw the bullet to the screen """
pygame.draw.rect(self.screen, self.bullet_color, self.rect)
class Game:
""" a class the creates a window with a blue screen """
def __init__(self):
pygame.init()
#--------------------------------------------------------------------------------------------
#screen size, color, caption
self.screen = pygame.display.set_mode((1200,800)) #create attribute to hold display settings
self.bg_color = (250,250,250) #create attribute to hold RGB color (blue)
pygame.display.set_caption("Blue Screen")
#--------------------------------------------------------------------------------------------
#--------------------------------------------------------------------------------------------
#tank drawing
self.screen_rect = self.screen.get_rect() #get the screen rect dim
self.image = pygame.image.load('images/tank.bmp') #load the image from directory
self.rect = self.image.get_rect() #get the image rect dim
self.rect.center = self.screen_rect.center #store the screens center x/y coord
#tank movement
self.tank_moving_left = False
self.tank_moving_right = False
self.tank_moving_up = False
self.tank_moving_down = False
self.tank_speed = 1 #tank pixels
self.direction_right = self.image #holds right image
self.direction_left = pygame.transform.flip(self.image, True, False) #holds left image
#--------------------------------------------------------------------------------------------
self.bullets = pygame.sprite.Group()
def move(self):
""" move tnak tank_speed based on direction of movement (key pressed)
also detect collision """
if self.tank_moving_right and self.rect.right < self.screen_rect.right:
self.rect.x += self.tank_speed
if self.tank_moving_left and self.rect.left > self.screen_rect.left:
self.rect.x -= self.tank_speed
if self.tank_moving_down and self.rect.bottom < self.screen_rect.bottom:
self.rect.y += self.tank_speed
if self.tank_moving_up and self.rect.top > self.screen_rect.top:
self.rect.y -= self.tank_speed
def blitme(self):
""" draw the image of the tank """
self.screen.blit(self.image, self.rect)
def _update_screen(self):
""" update screen """
self.screen.fill(self.bg_color)
self.blitme()
pygame.display.flip()
for bullet in self.bullets.sprites():
bullet.draw_bullet()
print(bullet.rect.midright)
def _check_KEYDOWN(self, event):
""" when key is press either quit, or move direction of arrow pressed and flip image """
if event.key == pygame.K_q:
sys.exit()
elif event.key == pygame.K_RIGHT:
self.tank_moving_right = True
self.image = self.direction_right
elif event.key == pygame.K_LEFT:
self.tank_moving_left = True
self.image = self.direction_left
elif event.key == pygame.K_UP:
self.tank_moving_up = True
elif event.key == pygame.K_DOWN:
self.tank_moving_down = True
elif event.key == pygame.K_SPACE:
self._fire_bullet()
print(1)
def _check_KEYUP(self, event):
""" when key is let go stop moving """
if event.key == pygame.K_RIGHT:
self.tank_moving_right = False
elif event.key == pygame.K_LEFT:
self.tank_moving_left = False
elif event.key == pygame.K_UP:
self.tank_moving_up = False
elif event.key == pygame.K_DOWN:
self.tank_moving_down = False
def _fire_bullet(self):
""" create a bullet and add it to the bullets group """
new_bullet = Bullet(self)
self.bullets.add(new_bullet)
def run_game(self):
""" loops the game/ updates screen/ checks for key clicks"""
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
self._check_KEYDOWN(event)
elif event.type == pygame.KEYUP:
self._check_KEYUP(event)
self.move()
self.bullets.update()
self._update_screen()
if __name__ == '__main__':
a = Game()
a.run_game()
Your _update_screen() function is drawing your bullets after updating the display. The bullets then get overwritten next time _update_screen() is called when you fill the screen with the background color.
If you reorder your screen update function as follows you should be able to see your bullets:
def _update_screen(self):
""" update screen """
self.screen.fill(self.bg_color)
self.blitme()
for bullet in self.bullets.sprites():
bullet.draw_bullet()
print(bullet.rect.midright)
pygame.display.flip()
Also, you can create an image for your bullet by changing your initialization function:
…
#create a bullet at rect (0,0) and the set the correct position
self.image = pygame.Surface((self.bullet_width, self.bullet_height))
self.image.fill(self.bullet_color)
self.rect = self.image.get_rect()
Then you won't need a draw_bullet() function, you can replace the drawing of individual bullets in _update_screen() with self.bullets.draw(self.screen)

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

trying to get sprite to disappear from screen after certain amount of time

i am trying to get my explosion image to disappear after a bullet collision with an alien. i am able to get the explosion to appear when the collision happens but can't seem to get it to disappear afterwards. i would like the explosion image to disappear after maybe 1 second or so. i understand that it would possibly involve a game clock and a kill method? thank you.
import sys
import pygame
from settings import Settings
from ship import Ship
from bullet import Bullet
from alien import Alien
from pygame.sprite import Sprite
class AlienInvasion:
"""overall class to manage game assets and behavior"""
def __init__(self):
"""initialize that game and create game resources"""
pygame.init()
self.settings = Settings()
self.screen = pygame.display.set_mode(
(self.settings.screen_width, self.settings.screen_height))
pygame.display.set_caption("Alien Invasion")
self.ship = Ship(self)
self.bullets = pygame.sprite.Group()
self.aliens = pygame.sprite.Group()
self.all_sprites = pygame.sprite.Group()
self._create_fleet()
# set the background color
# set the background color
def run_game(self):
"""start the main loop for the game"""
while True:
self._check_events()
self.ship.update()
self._update_bullets()
self._update_aliens()
self._update_screen()
def _check_events(self):
"""respond to keypress 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):
"""respons to key presses"""
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_SPACE:
self._fire_bullet()
elif event.key == pygame.K_q:
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 _fire_bullet(self):
"""create a new bullet and add it to the bullet group"""
if len(self.bullets) < self.settings.bullets_allowed:
new_bullet = Bullet(self)
self.bullets.add(new_bullet)
def _update_bullets(self):
"""update positions of the bullets and get rid of old bullets"""
# update bullet position
self.bullets.update()
# get rid of bullets that have disappeared
for bullet in self.bullets.copy():
if bullet.rect.bottom <= 0:
self.bullets.remove(bullet)
collisions = pygame.sprite.groupcollide(self.bullets, self.aliens,
True, True)
for collision in collisions:
expl = Explosion(collision.rect.center)
self.all_sprites.add(expl)
def _update_aliens(self):
"""update the positions of all the aliens in the fleet"""
self._check_fleet_edges()
self.aliens.update()
def _create_fleet(self):
alien = Alien(self)
alien_place = alien.rect.x
alien_other_place = alien.rect.y
for row_number in range(4):
for alien_number in range(9):
alien = Alien(self)
alien.rect.x = alien_place + 110 * alien_number
alien.rect.y = alien_other_place + 120 * row_number
self.aliens.add(alien)
def _check_fleet_edges(self):
for alien in self.aliens:
if alien.check_edges():
self._change_fleet_direction()
break
def _change_fleet_direction(self):
for alien in self.aliens:
alien.rect.y += self.settings.fleet_drop_speed
self.settings.fleet_direction *= -1
def _update_screen(self):
"""update images on the screen and flip to the new screen"""
self.screen.fill(self.settings.bg_color)
self.ship.blitme()
for bullet in self.bullets:
bullet.draw_bullet()
self.aliens.draw(self.screen)
self.all_sprites.draw(self.screen)
pygame.display.flip()
class Explosion(Sprite):
def __init__(self, center):
super().__init__()
self.image = pygame.image.load('images/explo.bmp')
self.rect = self.image.get_rect()
self.rect.center = center
if __name__ == '__main__':
# make a game instance, and run the game
ai = AlienInvasion()
ai.run_game()
You have to add another group for the explosions and to add the new Explosion object to this group, too:
class AlienInvasion:
# [...]
def __init__(self):
# [...]
self.explosions = pygame.sprite.Group()
# [...]
def _update_bullets(self):
# [...]
for collision in collisions:
expl = Explosion(collision.rect.center)
self.explosions.add(expl)
self.all_sprites.add(expl)
Get the current time (pygame.time.get_ticks()) when the Explosion object is constructed and kill() the object in the update method after a certain time span:
class Explosion(Sprite):
def __init__(self, center):
super().__init__()
self.image = pygame.image.load('images/explo.bmp')
self.rect = self.image.get_rect()
self.rect.center = center
self.start_time = pygame.time.get_ticks()
def update(self):
current_time = pygame.time.get_ticks()
timespan = 1000 # 1000 milliseconds = 1 second
if current_time > self.start_time + timespan:
self.kill()
Do not forget to invoke self.explosions.update() in AlienInvasion._update_bullets:
class AlienInvasion:
# [...]
def _update_bullets(self):
# [...]
self.explosions.update()

Categories