PyGame exceptions and freezes when trying to render to window - python

Can someone tell me what's wrong with this Python code? I'm using Python 3.8.2.
This code is from the book Python Crash Course, 2nd Edition: A Hands-On, Project-Based Introduction to Programming. The original code uses pygame.display.flip() instead of pygame.display.update(), the original code will produce this error code: pygame.error: Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface
However, after I changed it to pygame.display.update(), it just freezes my PC with blank PyGame window.
import pygame
from settings import Settings
from ship import Ship
class AlienInvasion:
""" overall class to manage game assets and behavior."""
def __init__(self):
"""Initialize the game, and create game resources."""
pygame.init()
self.settings = Settings()
self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
self.settings.screen_width = self.screen.get_rect().width
self.settings.screen_height = self.screen.get_rect().height
pygame.display.set_caption("Alien Invasion")
self.ship = Ship(self)
def run_game(self):
"""Start the main loop for the game."""
while True:
self._check_events()
self.ship.update()
self._update_screen()
def _check_events(self):
"""respond to keyboard and mouse events."""
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
self._check_keydown_events(event)
elif event.type == pygame.KEYUP:
self._check_keyup_events(event)
elif event.type == pygame.K_q:
sys.exit()
def _check_keydown_events(self, event):
"""Respond to keypresses."""
if event.key == pygame.K_RIGHT:
self.ship.moving_right = True
if event.key == pygame.K_LEFT:
self.ship.moving_left = True
if event.key == pygame.K_UP:
self.ship.moving_up = True
if event.key == pygame.K_DOWN:
self.ship.moving_down = True
def _check_keyup_events(self, event):
"""Respond to key releases."""
if event.key == pygame.K_RIGHT:
self.ship.moving_right = False
if event.key == pygame.K_LEFT:
self.ship.moving_left = False
if event.key == pygame.K_UP:
self.ship.moving_up = False
if event.key == pygame.K_DOWN:
self.ship.moving_down = False
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()
pygame.display.update()
if __name__ == '__main__':
#make a game instance, and run the game.
ai = AlienInvasion()
ai.run_game()

You typed the program in incorrectly. I found the source code for the entire book at https://github.com/ehmatthes/pcc_2e and this particular example is https://github.com/ehmatthes/pcc_2e/blob/master/chapter_12/piloting_the_ship/alien_invasion.py
Your program runs the same way for me - I get a blank frozen screen too. As shown above, your program is ignoring the pygame.K_q keypress because you entered that line of code in the _check_events() function, instead of _check_keydown_events(). That's what's making it seem like your computer is frozen.
The author's source code on github (linked above) runs fine for me. I recommend you download or copy/paste that code instead of trying to type it in by hand.

Related

How to stop the music when the s key is pressed?

My program plays music when I press the space bar. How to stop music when the s key is pressed?
import pygame, sys
from pygame.locals import QUIT
def main():
pygame.init()
#Intalise
DISPLAYSURF = pygame.display.set_mode((400, 300))
pygame.display.set_caption('Drop Shadow!')
#load sound
beep_sound = pygame.mixer.Sound('Joy.wav')
#load music
pygame.mixer.music.load('Joy.wav')
# Game Clock
game_clock = pygame.time.Clock()
#Game Loop
running = True
while running:
#Update Section
#Update delta_time
delta_time = game_clock.tick(60) / 100
#Handle events
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
#play sound
pygame.mixer.Sound.play(beep_sound)
if event.key == pygame.K_p:
#play music
pygame.mixer.music.play(-1)
#Draw Section
DISPLAYSURF.fill((128, 128, 128))
pygame.display.flip()
if __name__ == "__main__":
main()
You can use the pygame.mixer.music.stop():
Stops the music playback if it is currently playing. endevent will be triggered, if set. It won't unload the music.
Conditionally call it in your event-loop when pygame.K_s is pressed, like so:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
#play sound
pygame.mixer.Sound.play(beep_sound)
if event.key == pygame.K_p:
#play music
pygame.mixer.music.play(-1)
if event.key == pygame.K_s:
#stop music
pygame.mixer.music.stop()

Spaceship image is failing to move. Is there an error in my code?

I am using a book called Python Crash Course by Eric Matthes. A part of the book deals with python code projects and I started coding for an Alien Invasion Game. I attached the code written so far for the game to work but whenever I run the code, the spaceship does not move regardless of whether I press my keyboard's right or left key. I have ran the code several times but my editor doesn't indicate that there are errors. Is there something I need to fix in my code? I would greatly appreciate it if someone knows how to fix this.
Alien_invasion.py code:
import sys
import pygame
from settings import Settings
from ship import Ship
class AlienInvasion:
"""Overall class to manage game assets 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)
# 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_screen()
# Redraw the screen during each pass through the loop.
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:
if event.key == pygame.K_RIGHT:
self.ship.moving_right = True
elif event.key == pygame.K_LEFT:
self.ship.moving_left = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
self.ship.moving_right = False
elif event.key == pygame.K_LEFT:
self.ship.moving_left = False
# Move the ship to the right.
self.ship.rect.x += 1
def _update_screen(self):
"""Update images on the screen, and flip to the new screen."""
self.screen.fill(self.settings.bg_color)
self.ship.blitme()
pygame.display.flip()
if __name__ == '__main__':
# Make a game instance, and run the game.
ai = AlienInvasion()
ai.run_game()
Ship.py code:
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.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()
# Movement flags
self.moving_right = False
self.moving_left = False
def update(self):
"""Update the ship's position based on the movement flag."""
if self.moving_right:
self.rect.x += 1
if self.moving_left:
self.rect.x -= 1
# Start each new ship at the bottom center of the screen.
self.rect.midbottom = self.screen_rect.midbottom
def blitme(self):
"""Draw the ship at its current location."""
self.screen.blit(self.image, self.rect)
Settings.py code:
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)
I got the code working, it was a typo error.
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if **event.key** == pygame.K_RIGHT:
self.ship.moving_right = True
elif **event.key** == pygame.K_LEFT:
self.ship.moving_left = True
elif event.type == pygame.KEYUP:
if **event.key** == pygame.K_RIGHT:
self.ship.moving_right = False
elif **event.key** == pygame.K_LEFT:
self.ship.moving_left = False
Earlier I coded event.type instead of event.key
The code is working now, will continue working on the project.

Python - Options for accessing class attributes/methods from other classes while keeping classes encapsulated?

I'm teaching myself python and am working on a space invaders clone. Pretty much everything is working as I want it to. But I'm also trying to teach myself good principles of object-oriented design.
I have one class AlienInvasion that initializes a bunch of game objects and runs the while loop for the game (it currently also does some other things that should probably be in their own classes). When I create each object I pass it the AlienInvasion object so that each class can get access to objects that it needs to interact with. For example here is a class that checks for and responds to events:
import sys
import pygame
class EventHandler:
def __init__(self, ai_game):
"""Initialize attributes."""
self.ai_game = ai_game
self.settings = ai_game.settings
self.display = ai_game.display
self.stats = ai_game.stats
self.sb = ai_game.sb
self.ship = ai_game.ship
def check_events(self):
"""Respond to keypresses and mouse events."""
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.sb.record_high_score()
sys.exit()
elif event.type == pygame.KEYDOWN:
self._check_keydown_events(event)
elif event.type == pygame.KEYUP:
self._check_keyup_events(event)
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = pygame.mouse.get_pos()
self._check_button(mouse_pos)
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:
self.ai_game.quit()
elif event.key == pygame.K_SPACE:
self.ship.fire_bullet()
elif event.key == pygame.K_e and not self.stats.game_active:
self.settings.set_difficulty(self.settings.easy)
self.ai_game.start_game()
elif event.key == pygame.K_n and not self.stats.game_active:
self.settings.set_difficulty(self.settings.normal)
self.ai_game.start_game()
elif event.key == pygame.K_h and not self.stats.game_active:
self.settings.set_difficulty(self.settings.hard)
self.ai_game.start_game()
def _check_keyup_events(self, event):
"""Respond to key releases."""
if event.key == pygame.K_RIGHT:
self.ship.moving_right = False
elif event.key == pygame.K_LEFT:
self.ship.moving_left = False
def _check_button(self, mouse_pos):
"""Set the difficulty setting."""
if self.display.easy_button.rect.collidepoint(mouse_pos):
self.settings.set_difficulty(self.settings.easy)
self.ai_game.start_game()
elif self.display.normal_button.rect.collidepoint(mouse_pos):
self.settings.set_difficulty(self.settings.normal)
self.ai_game.start_game()
elif self.display.hard_button.rect.collidepoint(mouse_pos):
self.settings.set_difficulty(self.settings.hard)
self.ai_game.start_game()
elif self.display.quit_button.rect.collidepoint(mouse_pos):
self.ai_game.quit()
The initialization method consists entirely of setting up attributes referencing objects from ai_game (the AlienInvasion class) so that EventHandler can tell each object when it needs to do in response to an event. This is how I've been handling all object interactions. The AlienInvasion class 'knows' about all the different objects and allows each object to interact with other objects via the sorts of attributes you see above in the EventHandler.
I'm interested in learning how to make my code more maintainable. I've spent the last few days looking for an answer. I haven't seen anything that explains how I should be handling object interactions (or, more accurately, I haven't seen anything that I recognized as something I could/should apply here to minimize how much each object 'knows' about the other objects).
You can see the full code at https://github.com/nmoore32/Space-Invaders-Clone

Attribute Error: Sideways shooter object has not attribute! Python Crash Course 2nd Edition

New to Python and have left myself stumped for a few hours. I am trying to follow the examples in the book Python Crash Course. Im at the last part of trying to make bullets shoot across the screen but i come with the AttributeError when trying to define the limits of the game screen the bullet can travel before being deleted, in the '_update_bullets' method. I have tried using self.screen_rect but that also brings up an AttributeError.
import sys
import pygame
from gun import Gun
from bullets import Bullet
class SidewaysShooter:
#Game board
def __init__(self):
#Initializes game and resources.
pygame.init()
self.screen = pygame.display.set_mode((1200, 500))
pygame.display.set_caption("Sideways Shooter")
self.gun = Gun(self)
self.bullets = pygame.sprite.Group()
#set background color
self.bg_color = (153, 72, 141)
def run_game(self):
#Start the main loop for the game
while True:
self._check_events()
self.gun.update ()
self._update_bullets()
self._update_screen()
def _check_events(self):
#Watch for keyboard and mounse events.
for event in pygame.event.get():
if event.type == pygame.QUIT:
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_UP:
self.gun.moving_up = True
elif event.key == pygame.K_DOWN:
self.gun.moving_down = True
elif event.key == pygame.K_SPACE:
self._fire_bullet()
elif event.key == pygame.K_q:
pygame.quit()
sys.exit()
def _check_keyup_events(self, event):
if event.key == pygame.K_UP:
self.gun.moving_up = False
if event.key == pygame.K_DOWN:
self.gun.moving_down = 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 _update_bullets(self):
"""Update the position of the bullets and get rid of old bullets."""
#Update bullets position
self.bullets.update()
#Get rid of bullets that have disappeared.
for bullet in self.bullets.copy():
if bullet.rect.left >= self.screen_right:
self.bullets.remove(bullet)
def _update_screen(self):
#Update images on a screen and flip to a new screen
self.screen.fill(self.bg_color)
self.gun.blitme()
for bullet in self.bullets.sprites():
bullet.draw_bullet()
pygame.display.flip()
if __name__== '__main__':
#MAke a game instance, and run the game.
ai = SidewaysShooter()
ai.run_game()
'''
You get the attribute error because there is no "screen_right"-Attribute defined (in your example).
You need to inizialize it as a Int, to have access to it in all of the objects functions it needs to be in your "__init__(self)" function.
Example:
def __init__(self):
#Initializes game and resources.
pygame.init()
self.display_width = 1200 # The size of the screen should be defined
self.display_height = 500 # Now you can use it when you create the screen.
self.screen = pygame.display.set_mode((self.display_width, self.display_height))
pygame.display.set_caption("Sideways Shooter")
self.gun = Gun(self)
self.bullets = pygame.sprite.Group()
#set background color
self.bg_color = (153, 72, 141)
self.screen_right = self.display_width # This is the position of the right side of the screen, 0 would be the left side

Frogger game using pygame: frog is not drawn on the window

this is how my code looks like. I suppose to draw frog on the window and make a movement. I suppose this should work, but , but the code doesn't even get to the mainRun event part. How should I fix it?
### Run Game
class MainRun(object):
# init function to initialize all the class
def __init__(self):
self.frog = Frog()
def run(self):
print("a")
while True:
print("b")
self.frog.draw(window)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
frog.move("left")
if event.key == pygame.K_RIGHT:
frog.move("right")
if event.key == pygame.K_UP:
frog.move("up")
if event.key == pygame.K_DOWN:
frog.move("down")
# add player updates here
self.frog.draw(window)
pygame.display.update()
windowClock.tick(60)
window.fill(white)
if __name__ == __main__:
MainRun()
You just instantiation your class.If you want to run the method run.Should add code after 'main':
if __name__ == '__main__':
m = MainRun()
m.run()

Categories