This question already has answers here:
Why is nothing drawn in PyGame at all?
(2 answers)
Why is my PyGame application not running at all?
(2 answers)
Closed 1 year ago.
Hi I would be grateful for some help with why the bullets are not being fired, i followed all of the steps in the book and it doesn't work.
the bullet.py file is newly written, so is the "#bullet settings" in settings.py, and some parts have been added to alien_invasion.py. and in alien_invasion.py The "for bullet in self.bullets.sprites(): bullet.draw_bullet". isnt drawing any bullets?
alien_invasion.py
import sys
import pygame
from settings import Settings
from ship import Ship
from bullet import Bullet
class AlienInvasion:
def __init__(self):
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
#self.screen = pygame.display.set_mode((self.settings.screen_width, self.settings.screen_height))
pygame.display.set_caption("Alien Invasion")
self.bg_color = (0, 0, 50)
self.ship = Ship(self)
self.bullets = pygame.sprite.Group()
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."""
new_bullet = Bullet(self)
self.bullets.add(new_bullet)
def _check_keydown_events(self, event):
if event.key == pygame.K_RIGHT:
self.ship.rect2.x += 10
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_ESCAPE:
sys.exit()
elif event.key == pygame.K_SPACE:
self._fire_bullet()
def _update_screen(self):
"""update images on the screen, and flip to the new screen"""
def _check_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == pygame.KEYDOWN:
self._check_keydown_events(event)
if event.type == pygame.KEYUP:
self._check_keyup_events(event)
for bullet in self.bullets.sprites():
bullet.draw_bullet()
def run_game(self):
while True:
self._check_events()
self.ship.update()
self.bullets.update()
self._update_screen()
for bullet in self.bullets.sprites():
bullet.draw_bullet()
pygame.display.flip()
self.screen.fill(self.bg_color)
self.ship.blitme()
self.ship.blitme2()
if __name__ == '__main__':
ai = AlienInvasion()
ai.run_game()
settings.py
class Settings:
"""A class to store all settings for Alien Invasion."""
def __init__(self):
"""Initialize the game's settings."""
# Screen settings
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230, 230, 230)
#Ship settings
self.ship_speed = 15
#Bullet settings
self.bullet_speed = 1.0
self.bullet_width = 3
self.bullet_height = 15
self.bullet_color = (60, 60, 60)
bullet.py
import pygame
from pygame.sprite import Sprite
class Bullet(Sprite):
"""A class to manage blullets fired from the ship"""
def __init__(self, ai_game):
"""Create a bullet object at the ships current position."""
super().__init__()
self.screen = ai_game.screen
self.settings = ai_game.settings
self.color = self.settings.bullet_color
# Create a bullet rect at (0, 0) and then the correct position.
self.rect = pygame.Rect(0, 0, self.settings.bullet_width, self.settings.bullet_height)
self.rect.midtop = ai_game.ship.rect.midtop
# Store the bullets position as a decimal value.
self.y = float(self.rect.y)
def update(self):
""" Move the bullet up the screen."""
# Update the decimal position of the bullet.
self.y -= self.settings.bullet_speed
#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)
ship.py
import pygame
class Ship:
def __init__(self, ai_game):
self.screen = ai_game.screen
self.screen_rect = ai_game.screen.get_rect()
self.settings = ai_game.settings
self.image = pygame.image.load('C:/Users/Documents/Python Learning/python crash course lessons/Alien Invasion/ship.bmp')
self.image2 = pygame.image.load('C:/Users/Documents/Python Learning/python crash course lessons/Alien Invasion/ship1.bmp')
self.rect = self.image.get_rect()
self.rect2 = self.image2.get_rect()
self.rect.midbottom = self.screen_rect.midbottom
self.moving_right = False
self.moving_left = False
self.x = float(self.rect.x)
self.x2 = float(self.rect2.x)
def update(self):
"""Update the ships position based on the movement flagg."""
if self.moving_right == True:
self.rect2.x += 5
self.rect.x +=2
if self.moving_right and self.rect2.right < self.screen_rect.right:
self.x += self.settings.ship_speed
if self.moving_left == True:
self.rect2.x -= 5
self.rect.x -= 2
if self.moving_left and self.rect2.left > 0:
self.x -= self.settings.ship_speed
#Update rect object from self.x
self.rect2.x = self.x
#self.rect.x = self.x
def blitme(self):
self.screen.blit(self.image, self.rect)
def blitme2(self):
self.screen.blit(self.image2, self.rect2.move(0, 670))
You have to draw the bullets in the _update_screen method:
class AlienInvasion:
# [...]
def _update_screen(self):
for bullet in self.bullets.sprites():
bullet.draw_bullet()
You have to call _update_screen after clearing the screen and before updating the screen:
class AlienInvasion:
# [...]
def run_game(self):
while True:
self._check_events()
self.ship.update()
self.bullets.update()
self.screen.fill(self.bg_color)
self.ship.blitme()
self.ship.blitme2()
self._update_screen()
pygame.display.flip()
The start position of the bullets is wrong. Change the position in Bullet.__init__:
self.rect.midtop = ai_game.ship.rect.midtop
class Bullet(Sprite):
def __init__(self, ai_game):
# [...]
self.rect = pygame.Rect(0, 0, self.settings.bullet_width, self.settings.bullet_height)
self.rect.midtop = ai_game.ship.rect2.move(0, 670).midtop
Related
I can't get my ship to move after adding the ship speed in the settings. I identified that the problems has to do with the code self.rect.x = self.x under the Update method of the Ship class. If I comment it out, the ships is able to move, but when I uncomment the ship stops moving. Can't figure this problem out, followed the instructions of the book and don't know where I went wrong. Thank you.
import pygame
from settings import Settings
from ship import Ship
class AleinInvasion:
"""Overallclass to maange game assets and behavior."""
def __init__(self):
"""Intialize 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")
self.ship= Ship(self)
#Set background color
self.bg_color = self.settings.bg_color
def run_game(self):
"""Start the main loop for the game."""
while True:
self._check_events()
self.ship.update()
self._update_screen()
#make the most recenlty drawn screen visible
#pygame.display.flip()
def _check_events(self):
#watch for keyboard and moust 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):
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()
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 _update_screen(self):
"""Updates images on the screen, and flip to the new screen"""
self.screen.fill(self.settings.bg_color)
self.ship.blitme()
#make the most recenlty drawn screen visible
pygame.display.flip()
if __name__ == '__main__':
# Make a game instance, and run the game.
ai = AleinInvasion()
ai.run_game()
class Settings:
"""A class to store all settings for Alien Invasion."""
def __init__(self):
"""Initialize the game's settings."""
# Screen Settings
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230,230,230)
# Ship settings
self.ship_speed = 1.5
import pygame
class Ship:
"""A class to manage the ship"""
def __init__(self,ai_game):
""" Intialize the ship and set its starting postiion."""
self.screen = ai_game.screen
self.settings = ai_game.settings
self.screen_rect = ai_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 of the screen.
self.rect.midbottom = self.screen_rect.midbottom
# Store a decimal value for the ship's horizontal position.
self.x = float(self.rect.x)
#movement flag
self.moving_right = False
self.moving_left = False
def update(self):
"""Update the ship's postiion 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.rect.x += self.settings.ship_speed
if self.moving_left and self.rect.left > 0:
self.rect.x -= self.settings.ship_speed
#Update rect object 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)
I would very appreciate if someone could tell me how to fix this error:
AttributeError: 'AlienInvasion' object has no attribute '_check_events'
I am starting to learn python and I don't know how to solve this problem. This traceback happens whenever I try to run invasion.py
invasion.py:
import sys
import pygame
from settings import Settings
from ship import Ship
class AlienInvasion:
def __init__(self):
pygame.init()
self.settings = Settings()
self.screen = pygame.display.set_mode(
(self.settings.screen_width, self.settings.screen_height))
pygame.display.set_caption("Aliens is invading!")
self.ship = Ship(self)
self.bg_color = (230, 230, 230)
def run_game(self):
while True:
self._check_events()
self.ship.update()
self._update_screen()
def _check_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
self._check_keydown_events(event)
elif event.type == pygame.KEYUP:
self._check_keyup_events(event)
def _check_keydown_events(self, event):
if event.key == pygame.K_RIGHT:
self.ship.moving_right = True
elif event.key == pygame.K_LEFT:
self.ship.moving_left = True
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 _update_screen(self):
self.screen.fill(self.settings.bg_color)
self.ship.blitme()
pygame.display.flip()
if __name__ == '__main__':
ai = AlienInvasion()
ai.run_game()
settings.py:
class Settings:
def __init__(self):
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230, 230, 230)
self.ship_speed = 1.5
Ship.py:
import pygame
class Ship:
def __init__(self, ai_game):
self.screen = ai_game.screen
self.screen_rect = ai_game.screen.get_rect()
self.image = pygame.image.load('images/shipdos.bmp')
self.rect = self.image.get_rect()
self.rect.midbottom = self.screen_rect.midbottom
self.x = float(self.rect.x)
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
self.rect.x = self.x
def blitme(self):
self.screen.blit(self.image, self.rect)
Any feedback is appreciated!
It's hard to debug your code because it's poorly formatted, but:
it seems like your entire code base is incorrectly indented, also the function _update_screen(), which means it is defined inside _check_events() - if you remove one level of indentation of _update_screen() it should run without any errors. I would recommend using an IDE like PyCharm in order to help to catch those kind of errors. This is how your files should look like:
invasion.py
import sys
import pygame
from settings import Settings
from Ship import Ship
class AlienInvasion:
def __init__(self):
pygame.init()
self.settings = Settings()
self.screen = pygame.display.set_mode(
(self.settings.screen_width, self.settings.screen_height))
pygame.display.set_caption("Aliens is invading!")
self.ship = Ship(self)
self.bg_color = (230, 230, 230)
def run_game(self):
while True:
self._check_events()
self.ship.update()
self._update_screen()
def _check_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
self._check_keydown_events(event)
elif event.type == pygame.KEYUP:
self._check_keyup_events(event)
def _check_keydown_events(self, event):
if event.key == pygame.K_RIGHT:
self.ship.moving_right = True
elif event.key == pygame.K_LEFT:
self.ship.moving_left = True
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 _update_screen(self):
self.screen.fill(self.settings.bg_color)
self.ship.blitme()
pygame.display.flip()
if __name__ == '__main__':
ai = AlienInvasion()
ai.run_game()
settings.py
class Settings:
def __init__(self):
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230, 230, 230)
self.ship_speed = 1.5
Ship.py
import pygame
class Ship:
def __init__(self, ai_game):
self.screen = ai_game.screen
self.screen_rect = ai_game.screen.get_rect()
self.image = pygame.image.load('images/shipdos.bmp')
self.rect = self.image.get_rect()
self.rect.midbottom = self.screen_rect.midbottom
self.x = float(self.rect.x)
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
self.rect.x = self.x
def blitme(self):
self.screen.blit(self.image, self.rect)
I'm working through the book, following it step by step. The screen comes up, the ship .bmp shows up where it's supposed to. The problem is it doesn't move left or right, most of the time. When it does move, it only moves right, never left. It flies to the bottom right corner and just stays there. Not sure what is wrong with the code. Thanks in advance.
alien_invasion.py
import sys
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
#Initialize game and create a screeen 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)
#Start the main loop for the game.
while True:
gf.check_events(ship)
ship.update()
gf.update_screen(ai_settings, screen, ship)
#Redraw the screen during each pass through the loop.
screen.fill(ai_settings.bg_color)
ship.blitme()
# Watch for keyboard and mouse events.
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()
settings.py
class Settings():
"""A class to store all the settings for Alien Invasion."""
def __init__(self):
"""Initialize the game's settings."""
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (0,0, 90)
self.ship_speed_factor = 1.5
ship.py
import pygame
class Ship():
def __init__(self, ai_settings, screen):
"""Initialize the ship and set its starting position."""
self.screen = screen
# 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()
self.ai_settings = ai_settings
# 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 ship's center.
self.center = float(self.rect.centerx)
# Movement flag
self.moving_right = False
self.moving_left = False
def update(self):
"""Update the ship's position based on movement flags."""
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)
game_functions.py
import sys
import pygame
def check_keydown_events(event, ship):
"""Respond to keypresses."""
if event.key == pygame.K_RIGHT:
ship.moving_right = True
elif event.key == pygame.K_LEFT:
ship.moving_left = True
def check_keyup_events(event, ship):
"""Respond 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(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 update_screen(ai_settings, screen, ship):
"""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()
What I have found:
IndentationError: expected an indented block in (settings.py).
Wrong one (before):
class Settings():
"""A class to store all the settings for Alien Invasion."""
def __init__(self):
"""Initialize the game's settings."""
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (0,0, 90)
self.ship_speed_factor = 1.5
the right one (after)
class Settings():
#"""A class to store all the settings for Alien Invasion."""
def __init__(self):
# """Initialize the game's settings."""
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (0,0, 90)
self.ship_speed_factor = 1.5
In the update method of ship class, you wrote:
if self.moving_left and self.rect.left < 0:
self.center -= self.ai_settings.ship_speed_factor
It should be:
if self.moving_left and self.rect.left > 0:
self.center -= self.ai_settings.ship_speed_factor
Python Pygame issue in Alien Invasion game causing the game to keep crashing when trying to fire bullets. I just finished chapter 12 in Python Crash Course, and my ship wont fire bullets and the game crashed when pressing spacebar to fire bullets. Any help I can get in solving this issue is much appreciated. Attribute error is listed in title.
alien_invasion.py
import sys
import pygame
from settings import Settings
from ship import Ship
from bullet import Bullet
class AlienInvasion:
"""Overall class to manange game assests and behavior."""
def __init__(self):
"""Initialize the game, and create game resources."""
pygame.init()
self.settings = Settings()
self.screen = pygame.display.set_mode(
(self.settings.screen_width, self.settings.screen_height))
pygame.display.set_caption("Alien Invasion")
self.ship = Ship(self)
self.bullets = pygame.sprite.Group()
#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()
self.ship.update()
self._update_bullets()
self._update_screen()
# Get rid of bullets that have disappeared.
for bullet in self.bullets.copy():
if bullet.rect.bottom <= 0:
self.bullets.remove(bullet)
#print(len(self.bullets))
# Watch for keyboard and mouse events.
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# Redraw the screen during each pass through the loop.
self.screen.fill(self.settings.bg_color)
self.ship.blitme()
# Make the most recently drawn screen availible.
pygame.display.flip()
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)
#Move th ship to the right
self.ship.rect.x += 1
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()
def _check_keyup_events(self, event):
"""Responds to 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 new bullets group."""
if len(self.bullets) < self.settingsbullets_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.bottom <= 0:
self.bullets.remove(bullet)
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.sprites():
bullet.draw_bullet()
# Make the most recently drawn screen availible.
#pygame.display.flip()
if __name__ == '__main__':
# Make a game instance, and run the game.
ai = AlienInvasion()
ai.run_game()
bullet.py
import pygame
from pygame.sprite import Sprite
class Bullet(Sprite):
"""A class to manage bullets fired from a ship"""
def __init__(self, ai_game):
"""Create a bullet object at the ship's current position."""
super().__init__()
self.screen = ai_game.screen
self.settings = ai_game.settings
self.color = self.settings.bullet_color
# Create a bullet rect at (0, 0) and then set correct position.
self.rect = pygame.Rect(0, 0, self.settings.bullet_width,
self.settings.bullet_height)
self.rect.mid_top = ai_game.ship.rect.mid_top
# Store the bullet's position at a decimal value.
self.y = float(self.rect.y)
def update(self):
"""Move the bullet up the screen."""
# Update the decimal position of the bullet.
self.y -= self.settings.bullet_speed
# 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)
settings.py
class Settings:
"""A Class to store all settings for Alien Invasion."""
def __init__(self):
"""Initializing the game's settings."""
#Screen settings
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230, 230, 230)
#Ship settings
self.ship_speed = 1.5
#Bullet settings
self.bullet_speed = 1.0
self.bullet_width = 3
self.bullet_height = 15
self.bullet_color = (60, 60, 60)
self.bullets_allowed = 3
ship.py
import pygame
class Ship:
"""A class to manage the ship."""
def __init__(self, ai_game):
"""Initialize the ship and set its starting position."""
self.screen = ai_game.screen
self.settings = ai_game.settings
self.screen_rect = ai_game.screen.get_rect()
#Load the ship and imagine its rect.
self.image = pygame.image.load('images_ai/ship.bmp')
self.rect = self.image.get_rect()
#Start each new ship at the bottom of the screen.
self.rect.midbottom = self.screen_rect.midbottom
#Store a decimal value for the ship's horizontal position.
self.x = float(self.rect.x)
# Movement flags
self.moving_right = False
self.moving_left = False
def update(self):
"""Update the ship's position based on movement flags."""
# 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 blitme(self):
"""Draw the ship at its current location."""
self.screen.blit(self.image, self.rect)
The issue is caused by a typo. self.settingsbullets_allowed has to be self.settings.bullets_allowe
Trying to make a game where my catcher catches a baseball. If the baseball is caught, then a new baseball appears randomly at the top of the screen. I can't seem to move the catcher after the changes I've made. The game is made through python and pygame.
catch.py
import sys
import pygame
from pygame.sprite import Group
from settings import Settings
from catcher import Catcher
from baseball import Baseball
import game_functions as gf
def run_game():
"""Initializes the game, screen, and settings."""
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))
pygame.display.set_caption("Catch")
catcher = Group()
baseball = Group()
while True:
gf.check_events(catcher)
gf.update_catcher(ai_settings, screen, catcher)
gf.update_baseball(ai_settings, screen, catcher, baseball)
gf.update_screen(ai_settings, screen, catcher, baseball)
run_game()
baseball.py
import pygame
from pygame.sprite import Sprite
class Baseball(Sprite):
"""A class to represent a baseball."""
def __init__(self, ai_settings, screen):
super().__init__()
self.screen = screen
self.ai_settings = ai_settings
# Load the baseball image and set its rect attribute.
self.image = pygame.image.load('images/baseball.bmp')
self.rect = self.image.get_rect()
# Start each new baseball at a random position at the top of the screen.
self.rect.x = self.rect.width
self.rect.y = self.rect.height
# Store the alien's exact position.
self.x = float(self.rect.x)
self.y = float(self.rect.y)
def blitme(self):
"""Draw the baseball at tis current location."""
self.screen.blit(self.image, self.rect)
def update(self):
"""Dropping the baseball."""
self.y += self.ai_settings.baseball_drop_speed
self.rect.y = self.y
catcher.py
import pygame
from pygame.sprite import Sprite
class Catcher(Sprite):
def __init__(self, ai_settings, screen):
"""Initialize the catcher and set its starting position."""
super().__init__()
self.screen = screen
self.ai_settings = ai_settings
# Load the catcher image and get its rect.
self.image = pygame.image.load('images/catcher.bmp')
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
# Start each new catcher 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 catcher's center.
self.center = float(self.rect.centerx)
# Movement flags
self.moving_right = False
self.moving_left = False
def update(self, ai_settings, screen):
"""Update the catcher's position baed on the movement flag."""
# Update the catcher's center value, not the rect.
if self.moving_right and self.rect.right <= self.screen_rect.right:
self.center += self.ai_settings.catcher_speed_factor
if self.moving_left and self.rect.left >= 0:
self.center -= self.ai_settings.catcher_speed_factor
# Update rect object from self.center.
self.rect.centerx = self.center
def blitme(self):
"""Draw the catcher at its current location."""
self.screen.blit(self.image, self.rect)
game_functions.py
import sys
import pygame
from baseball import Baseball
from catcher import Catcher
from random import randint
def check_keydown_events(event, catcher):
"""Respond to keypresses."""
if event.key == pygame.K_RIGHT:
catcher.moving_right = True
elif event.key == pygame.K_LEFT:
catcher.moving_left = True
elif event.key == pygame.K_q:
sys.exit()
def check_keyup_events(event, catcher):
"""Respond to key releases."""
if event.key == pygame.K_RIGHT:
catcher.moving_right = False
elif event.key == pygame.K_LEFT:
catcher.moving_left = False
def check_events(catcher):
"""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, catcher)
elif event.type == pygame.KEYUP:
check_keyup_events(event, catcher)
def update_screen(ai_settings, screen, catcher, baseball):
"""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)
catcher.draw(screen)
baseball.draw(screen)
# Make the most recently drawn screen visible.
pygame.display.flip()
def update_baseball(ai_settings, screen, catcher, baseball):
"""Update the positions of the baseball and detect collisions."""
screen_rect = screen.get_rect()
baseball.update()
if len(baseball) == 0:
new_ball = Baseball(ai_settings, screen)
new_ball.x = randint(new_ball.rect.width, screen_rect.right - new_ball.rect.width)
new_ball.rect.x = new_ball.x
new_ball.y = new_ball.rect.height
new_ball.rect.y = new_ball.y
baseball.add(new_ball)
collisions = pygame.sprite.groupcollide(baseball, catcher, True, False)
def update_catcher(ai_settings, screen, catcher):
screen_rect = screen.get_rect()
catcher.update(ai_settings, screen)
if len(catcher) == 0:
new_catcher = Catcher(ai_settings, screen)
new_catcher.center = screen_rect.centerx
new_catcher.rect.centerx = new_catcher.center
new_catcher.rect.bottom = screen_rect.bottom
catcher.add(new_catcher)
settings.py
import pygame
class Settings():
"""Class to store settings."""
def __init__(self):
"""Initializes the game's settings."""
# Screen settings.
self.screen_width = 800
self.screen_height = 600
self.bg_color = (255, 255, 255)
# Ship settings.
self.catcher_speed_factor = 1.5
# Baseball settings.
self.baseball_drop_speed = float(1 / 2)
The issue is that catcher is an instance of Group rather than Catcher(Sprite):
catcher = Group()
while True:
check_events(catcher)
That causes that the attributes moving_right and moving_left are set to the Group object in check_keydown_events respectively check_keyup_events.
You have to change the attributes of the objects in the Group:
def check_keydown_events(event, catcher):
"""Respond to keypresses."""
if event.key == pygame.K_RIGHT:
for c in catcher:
c.moving_right = True
elif event.key == pygame.K_LEFT:
for c in catcher:
c.moving_left = True
elif event.key == pygame.K_q:
sys.exit()
def check_keyup_events(event, catcher):
"""Respond to key releases."""
if event.key == pygame.K_RIGHT:
for c in catcher:
c.moving_right = False
elif event.key == pygame.K_LEFT:
for c in catcher:
c.moving_left = False