How to move up and down - python

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)

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)

Attribute error in Python Crash course alien invasion project

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)

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__

sprite can't move python pygame

I just finished chapter 12 in python crash course and i want to add a little more feature for my python pygame code. I had succesfully added a rotation feature to make my ship facing the mouse, but my ship seems kinda stuck and does not want move. Please help!
here's my code
alien invasion.py
def main():
pygame.init()
setting = Settings()
screen = pygame.display.set_mode((setting.screen_width, setting.screen_height))
pygame.display.set_caption("Alien Invasion")
bullets = Group()
while True:
mouse_position = pygame.mouse.get_pos()
ship = Ship(screen,mouse_position)
gf.check_events(screen, ship, bullets)
ship.ship_movement()
gf.update_bullet(bullets)
gf.update_screen(setting, screen, ship, bullets)
ship.py
import pygame
import math
class Ship():
def __init__(self, screen,mouse_position):
# initialize the ship and set its starting position
self.screen = screen
# Load the ship image
self.image = pygame.image.load('images/ship.bmp')
self.rect = self.image.get_rect() # getting the image rectangle
self.screen_rect = screen.get_rect() # getting the screen rectangle
# 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
# if True then it'll move right/left
self.move_right = False
self.move_left = False
self.move_up = False
self.move_down = False
# set speed
self.set_speed = 1.5
# store the decimal value for the ship's center
self.center_x = float(self.rect.centerx)
self.center_y = float(self.rect.bottom)
# player rotation
self.mouse_position = mouse_position
self.angle = math.atan2(self.mouse_position[1] - (self.rect.centery), self.mouse_position[0] - (self.rect.centerx))
self.player_rotation = pygame.transform.rotate(self.image, -self.angle * 57.29 - 90)
self.new_playerpos = self.rect.centerx - self.player_rotation.get_rect().width / 2, self.rect.centery - self.player_rotation.get_rect().height / 2
def ship_movement(self):
if self.move_right and self.rect.right < self.screen_rect.right:
self.center_x += self.set_speed
if self.move_left and self.rect.left > 0:
self.center_x -= self.set_speed
if self.move_up and self.rect.top > self.screen_rect.top:
self.center_y -= self.set_speed
if self.move_down and self.rect.bottom < self.screen_rect.bottom:
self.center_y += self.set_speed
self.rect.centery = self.center_y - 30
self.rect.centerx = self.center_x
def blit_screen(self):
# Draw the ship at it's current location
self.screen.blit(self.player_rotation, self.new_playerpos)
# self.screen.blit(self.image, self.rect)
game functions.py
import pygame
from pygame.locals import *
import sys
from bullet import Bullet
def check_keydown_events(event,screen, ship, bullets):
if event.key == K_RIGHT or event.key == K_d:
ship.move_right = True
elif event.key == K_LEFT or event.key == K_a:
ship.move_left = True
elif event.key == K_UP or event.key == K_w:
ship.move_up = True
elif event.key == K_DOWN or event.key == K_s:
ship.move_down = True
elif event.key == K_SPACE:
fire_bullet(screen, ship, bullets)
def check_keyup_events(event, ship):
if event.key == K_RIGHT or event.key == K_d:
ship.move_right = False
elif event.key == K_LEFT or event.key == K_a:
ship.move_left = False
elif event.key == K_UP or event.key == K_w:
ship.move_up = False
elif event.key == K_DOWN or event.key == K_s:
ship.move_down = False
def fire_bullet(screen, ship, bullets):
# create new bullet and add it to the bullet group
new_bullet = Bullet(screen, ship)
if len(bullets) < new_bullet.bullet_limit:
bullets.add(new_bullet)
def check_events(screen, ship, bullets):
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
elif event.type == KEYDOWN:
check_keydown_events(event,screen, ship, bullets)
elif event.type == KEYUP:
check_keyup_events(event, ship)
def update_bullet(bullets):
# removing bullet that has already disapeared
bullets.update()
for bullet in bullets.copy():
if bullet.rect.bottom <= 0:
bullets.remove(bullet)
def update_screen(setting, screen, ship, bullets):
screen.fill(setting.bg_color)
for bullet in bullets.sprites():
bullet.draw_bullet()
ship.blit_screen()
pygame.display.flip()
The issue is that the Ship object is recreated in every frame at it's initial position. You have to create the instance of Ship before the main application loop:
def main():
# [...]
ship = Ship(screen,mouse_position) # <--- INSERT
while True:
# ship = Ship(screen,mouse_position) <--- DELETE
# [...]
The rotation of the ship has to be updated in the method ship_movement rather than the constructor:
def main():
# [...]
while True:
# [...]
mouse_position = pygame.mouse.get_pos()
ship.ship_movement(mouse_position)
# [...]
class Ship():
# [...]
def ship_movement(self, mouse_position):
if self.move_right and self.rect.right < self.screen_rect.right:
self.center_x += self.set_speed
if self.move_left and self.rect.left > 0:
self.center_x -= self.set_speed
if self.move_up and self.rect.top > self.screen_rect.top:
self.center_y -= self.set_speed
if self.move_down and self.rect.bottom < self.screen_rect.bottom:
self.center_y += self.set_speed
self.rect.centery = self.center_y - 30
self.rect.centerx = self.center_x
# player rotation
self.mouse_position = mouse_position
self.angle = math.atan2(self.mouse_position[1] - (self.rect.centery), self.mouse_position[0] - (self.rect.centerx))
self.player_rotation = pygame.transform.rotate(self.image, -self.angle * 57.29 - 90)
self.new_playerpos = self.rect.centerx - self.player_rotation.get_rect().width / 2, self.rect.centery - self.player_rotation.get_rect().height / 2

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

Categories

Resources