Attribute error in Python Crash course alien invasion project - python

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)

Related

Can't get ship to move after modifying ship speed in alien invasion

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)

Why are bullets not firing from ship? [duplicate]

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

Python Crash Course Alien Invasion | AttributeError: 'Bullet' object has no attribute 'speed_factor'

I am doing Python Crash Course Alien invasion and when I test this code, an error pops out saying that "Bullet" has no object "speed_factor"
I've been trying for so long to find out why, checked multiple times the code and even compared it to other codes, but it all seems fine.
The game 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(screen, ai_settings)
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)
gf.check_events(ship, screen, ship, bullets)
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()
pygame.display.flip()
run_game()
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 = 2
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, screen, ai_settings):
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):
self.screen.blit(self.image, self.rect)
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.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()
Error log:
File "C:\Users\user\Desktop\alien invasion\bullet.py", line 17, in update
self.y -= self.speed_factor
AttributeError: 'Bullet' object has no attribute 'speed_factor'
I would really appreciate any kind of help as this is driving me crazy.
In the __init__ of your Bullet class, you're setting self.ship_speed_factor but in its update method you're trying to do self.y -= self.speed_factor.
I guess you're just using a wrong field name, in which case you should do either of:
replace self.y -= self.speed_factor with self.y -= self.ship_speed_factor in update
replace self.ship_speed_factor = ... with self.speed_factor = ... in __init__

Ship not moving, python crash course chapter 12

The ship won't move, but it doesn't return errors.
This is really frustrating.
alien_invasion.py
import sys
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))
pygame.display.set_caption("Alien Invasion")
ship = Ship(ai_settings, screen)
while True:
gf.check_events(ship)
ship.update()
gf.update_screen(ai_settings, screen, ship)
pygame.display.flip()
run_game()
game_functions.py
import sys
import pygame
def check_events(ship):
for event in pygame.event.get():
if event == pygame.QUIT:
sys.exit()
elif event == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
ship.moving_right = True
elif event.key == pygame.K_LEFT:
ship.moving_left = False
elif event == 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, screen, ship):
screen.fill(ai_settings.bg_colour)
ship.blitme()
settings.py
class Settings():
def __init__(self):
#screen stuff
self.screen_width = 1000
self.screen_height = 750
self.bg_colour = (0, 0, 0)
self.ship_speed_factor = 1.5
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('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)
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)
Also, here is ship.bmp
event is an object, the type of the event is stored in the attribute .type. Thus you have to evaluate if event.type == ...: rather than if event == ...::
(See pygame.event)
def check_events(ship):
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
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

How to move up and down

I'm trying to make a ship for alien invaders move up and down but can't seem to make it properly work without messing something up.
With my code below what would I need to add?
alien_invasion.py:
import sys
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
#Initialize pygame, settings, and screen object
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode(
(ai_settings.screen_width, ai_settings.screen_height))
pygame.display.set_caption("Alien Invasion")
#Draw the ship
ship = Ship(ai_settings, screen)
#Start the main loop for the game.
while True:
#Watch for keyboard and mouse events
gf.check_events(ship)
ship.update()
gf.update_screen(ai_settings, screen, ship)
run_game()
ship.py:
import pygame
class Ship():
def __init__(self, ai_settings, screen):
"""Initialize teh ship and set its starting position"""
self.screen = screen
self.ai_settings = ai_settings
#Load teh ship image and get its rect
self.image = pygame.image.load('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 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 postion based on the movement flag"""
# 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)
game_fuction.py:
import sys
import pygame
def check_keydown_events(event, ship):
"""Responds 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):
"""Respoinds 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()
settings.py:
class Settings():
"""A Class to store all settings for ALein INvasion"""
def __init__(self):
"""Initialize the game's settings"""
#screen settings
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (255,255,255)
# Ship Settings
self.ship_speed_factor = 1.5
This is a project from Python Crash Course.
This certain project says
Make a game that begins with a rocket in the center of the screen.
Allow the player to move the rocket up, down, left, or right using the
four arrow keys. Make sure the rocket never moves beyond any edge or
the screen.
I haven't typed this in to check, but I have solved similar problems/projects in pygame. It looks like you need to modify the code in two places:
1) Catch the events of pressing the down key and the up keys.
This is probably something like:
# from your game_function.py
def check_keydown_events(event, ship):
"""Responds to keypresses"""
if event.key == pygame.K_RIGHT:
ship.moving_right = True
elif event.key == pygame.K_LEFT:
ship.moving_left = True
elif event.key == pygame.K_DOWN:
ship.moving_down = True
elif event.key == pygame.K_UP:
ship.moving_up = True
def check_keyup_events(event, ship):
"""Respoinds to key releases"""
if event.key == pygame.K_RIGHT:
ship.moving_right = False
elif event.key == pygame.K_LEFT:
ship.moving_left = False
elif event.key == pygame.K_DOWN:
ship.moving_down = False
elif event.key == pygame.K_UP:
ship.moving_up = False
2) Your original ship class to process the actual movement.
This should look something like:
# Movement flag
self.moving_right = False
self.moving_left = False
self.moving_down = False
self.moving_up = False
def update(self):
"""Update the ship's postion based on the movement flag"""
# 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
if self.moving_down and self.rect.bottom > self.screen_rect.bottom:
self.center -= self.ai_settings.ship_speed_factor
if self.moving_up and self.rect.top < self.screen_rect.top:
self.center -= self.ai_settings.ship_speed_factor
# Update rect object from self.center - might need to be changed now to handle
# movement in two directions properly.
if self.moving_up or self.moving_down:
self.rect.centery = self.center
if self.moving_left or self.moving_right:
self.rect.centerx = self.center
Ok, I've cracked it - this solution is now working:
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 = (255,255,255)
# Ship Settings
ship_speed_factor = 1.5
game_functions.py
import sys
import pygame
def check_keydown_events(event, ship):
"""Responds to keypresses"""
if event.key == pygame.K_RIGHT:
ship.moving_right = True
elif event.key == pygame.K_LEFT:
ship.moving_left = True
elif event.key == pygame.K_DOWN:
ship.moving_down = True
elif event.key == pygame.K_UP:
ship.moving_up = True
def check_keyup_events(event, ship):
"""Responds to key releases"""
if event.key == pygame.K_RIGHT:
ship.moving_right = False
elif event.key == pygame.K_LEFT:
ship.moving_left = False
elif event.key == pygame.K_DOWN:
ship.moving_down = False
elif event.key == pygame.K_UP:
ship.moving_up = False
def check_events(ship):
"""Respond to keypresses and mouse events."""
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
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()
ship.py
import pygame
class Ship:
def __init__(self, ai_settings, screen):
"""Initialize teh 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('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 ship's x and y center.
self.centerx = float(self.rect.centerx)
self.centery = float(self.rect.centery)
# Movement flag
self.moving_right = False
self.moving_left = False
self.moving_down = False
self.moving_up = False
def update(self):
"""Update the ship's postion based on the movement flag"""
# Update the ship's center value, not the rect.
if self.moving_right and self.rect.right < self.screen_rect.right:
self.centerx += self.ai_settings.ship_speed_factor
if self.moving_left and self.rect.left > 0:
self.centerx -= self.ai_settings.ship_speed_factor
if self.moving_down and self.rect.bottom < self.screen_rect.bottom:
self.centery += self.ai_settings.ship_speed_factor
if self.moving_up and self.rect.top > self.screen_rect.top:
self.centery -= self.ai_settings.ship_speed_factor
# Update rect object from self.center - might need to be changed now to handle
# movement in two directions properly.
if self.moving_up or self.moving_down:
self.rect.centery = self.centery
if self.moving_left or self.moving_right:
self.rect.centerx = self.centerx
def blitme(self):
"""Draw the ship at its current location"""
self.screen.blit(self.image, self.rect)
alien_invasion.py
import sys
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
#Initialize pygame, settings, and screen object
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode(
(ai_settings.screen_width, ai_settings.screen_height))
pygame.display.set_caption("Alien Invasion")
#Draw the ship
ship = Ship(ai_settings, screen)
#Start the main loop for the game.
while True:
#Watch for keyboard and mouse events
gf.check_events(ship)
ship.update()
gf.update_screen(ai_settings, screen, ship)
run_game()
Actually, all I did was to implement all of the changes that I described and eliminate a few basic errors in layout/syntax. Note that I added a better quit function to close the graphics canvas when you click the red button.
If this solution also works for you then please mark it as the answer so that I can get enough reputation here on stack flow.
I know this is an old question, but it was top result when I ran into the same problem. Just want to show how I ended up doing it.
alien_invasion.py keydown and keyup check events:
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_d:
self.ship.moving_right = True
elif event.key == pygame.K_LEFT:
self.ship.moving_left = True
elif event.key == pygame.K_a:
self.ship.moving_left = True
elif event.key == pygame.K_UP:
self.ship.moving_up = True
elif event.key == pygame.K_DOWN:
self.ship.moving_down = True
elif event.key == pygame.K_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_d:
self.ship.moving_right = False
elif event.key == pygame.K_LEFT:
self.ship.moving_left = False
elif event.key == pygame.K_a:
self.ship.moving_left = False
elif event.key == pygame.K_UP:
self.ship.moving_up = False
elif event.key == pygame.K_DOWN:
self.ship.moving_down = False
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 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
self.rect.center = self.screen_rect.center
# store a decimal value for the ship's horizontal position
self.x = float(self.rect.x)
self.y = float(self.rect.y)
# movement flag
self.moving_right = False
self.moving_left = False
self.moving_up = False
self.moving_down = False
def update(self):
"""update the ship's position on the movement flag"""
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
if self.moving_up and self.rect.top > 0:
self.y -= self.settings.ship_speed
if self.moving_down and self.rect.bottom < self.screen_rect.bottom:
self.y += self.settings.ship_speed
# update rect object from self.x
self.rect.x = self.x
self.rect.y = self.y
def blitme(self):
"""draw the ship at its current location"""
self.screen.blit(self.image, self.rect)
I added the moving_up and moving_down plus had to add the self.rect.y for the y axis.
The ship cannot move past the top of the screen or the bottom.
Hope this helps anyone who googled the same question.
I have written a runnable solution for 2nd edition of the book.
alien_invasion.py as below:
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('Alien Invasion')
self.ship = Ship(self)
def run_game(self):
while True:
self._check_event()
self.ship.update()
self._update_screen()
pygame.display.flip()
def _check_event(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_event(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_UP:
self.ship.moving_up = True
elif event.key == pygame.K_DOWN:
self.ship.moving_down = True
elif event.key == pygame.K_q:
sys.exit()
def _check_keyup_event(self, event):
if event.key == pygame.K_RIGHT:
self.ship.moving_right = False
elif event.key == pygame.K_LEFT:
self.ship.moving_left = False
elif event.key == pygame.K_DOWN:
self.ship.moving_down = False
elif event.key == pygame.K_UP:
self.ship.moving_up = False
def _update_screen(self):
self.screen.fill(self.settings.bg_color)
self.ship.blitme()
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.settings = ai_game.settings
self.screen_rect = ai_game.screen.get_rect()
self.image = pygame.image.load('images/ship.bmp')
self.rect = self.image.get_rect()
self.rect.midbottom = self.screen_rect.midbottom
self.x = float(self.rect.x)
self.y = float(self.rect.y)
self.moving_right = False
self.moving_left = False
self.moving_up = False
self.moving_down = 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
if self.moving_up and self.rect.top > self.screen_rect.top:
self.y -= self.settings.ship_speed
if self.moving_down and self.rect.bottom < self.screen_rect.bottom:
self.y += self.settings.ship_speed
self.rect.x = self.x
self.rect.y = self.y
def blitme(self):
self.screen.blit(self.image, self.rect)

Categories

Resources