Reputation: 69
I am trying to use the draw method to update the screen in pygame.
However I get the following error when I run my program:
➜ Stars python3 stars.py
pygame 2.0.1 (SDL 2.0.14, Python 3.9.6)
Traceback (most recent call last):
File "/Users/Desktop/python/Stars/stars.py", line 93, in <module>
st.run_game()
File "/Users/Desktop/python/Stars/stars.py", line 31, in run_game
self._update_screen()
File "/Users/Desktop/python/Stars/stars.py", line 84, in _update_screen
star_draw.draw(self.screen)
TypeError: draw() missing 1 required positional argument: 'surface'
My program consists of three python files: stars.py, star.py, and settings.py.
stars.py contains the Stars class which manages the 'game'.
star.py contains the Star class which manages a single star.
settings.py contains the Settings class which manages the screen settings.
stars.py:
import sys
import pygame
from settings import Settings
from star import Star
# Make a grid of stars appear on the screen
# /images/star.bmp
# A class to manage a star
class Stars:
"""Overall class to manage the game."""
def __init__(self):
"""Initialize the game and create game resources."""
# Initialize pygame.
pygame.init()
# Make an instance of the Settings class and assign it.
self.settings = Settings()
# Make a screen with dimensions defined in the settings module.
self.screen = pygame.display.set_mode(
(self.settings.screen_width, self.settings.screen_height))
# Set a caption on the pygame.
pygame.display.set_caption("Stars")
# Create a group for the stars.
self.stars = pygame.sprite.Group()
# Add an attribute that is a method to create stars.
self._create_stars()
self.star = Star(self)
def run_game(self):
"""Start the main loop for the game."""
while True:
self._check_events()
self._update_screen()
def _check_events(self):
"""Respond to keypresses and mouse events."""
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
self._check_keydown_events(event)
def _check_keydown_events(self, event):
"""Respond to keypresses."""
if event.key == pygame.K_q:
sys.exit()
def _create_stars(self):
"""Create a sky full of stars."""
# Create a star and find the number of stars in a row.
# Spacing between each star is equal to two star widths.
star = Star(self)
star_width, star_height = star.rect.size
available_space_x = self.settings.screen_width - (star_width)
number_stars_x = available_space_x // (2 * star_width)
# Determine the number of rows of stars that fit on the screen.
# Fill most of the screen with stars.
available_space_y = (self.settings.screen_height - (2 * star_height))
number_rows = available_space_y // (2 * star_height)
# Fill the sky with stars.
# For every row in the total amount of rows.
for row_number in range(number_rows):
# For every star in the total amount of stars.
for star_number in range(number_stars_x):
# Call _create_star with the loops as arguments.
self._create_star(star_number, row_number)
def _create_star(self, star_number, row_number):
"""Create a star and place it in the row."""
star = Star(self)
star_width, star_height = star.rect.size
star.x = star_width + (2 * star_width) * star_number
star.rect.x = star.x
star.rect.y = star.rect.height + (2 * star.rect.height) * row_number
# Add the star to the group stars.
self.stars.add(star)
def _update_screen(self):
"""Update images on the screen, and flip to the new screen."""
# Redraw the screen during each pass through the loop.
self.screen.fill(self.settings.bg_color)
# Draw the star on the screen
self.star.draw(self.screen)
# Make the most recently drawn screen visible.
pygame.display.flip()
if __name__ == '__main__':
# Make a game instance, and run the game.
st = Stars()
st.run_game()
star.py:
import pygame
from pygame.sprite import Sprite
class Star(pygame.sprite.Sprite):
"""A class to manage a single star."""
def __init__(self, star_game):
"""Initialize the star and set it's starting position."""
super().__init__()
self.screen = star_game.screen
# Load the star image and set its rect attribute.
self.image = pygame.image.load('images/star.bmp')
self.rect = self.image.get_rect()
# Start each new star near the top left of the screen.
self.rect.x = self.rect.width
self.rect.y = self.rect.height
# Store the star's exact vertical position.
self.y = float(self.rect.y)
self.draw = pygame.sprite.Group.draw
settings.py:
class Settings:
"""A class to store all settings for the star game."""
def __init__(self):
"""Initialize the game's settings."""
# Screen settings
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (50, 50, 50)
Upvotes: 2
Views: 177
Reputation: 211176
pygame.sprite.Group.draw
is a method. It must be called with an instance of pygame.sprite.Group
.
pygame.sprite.Group.draw()
and pygame.sprite.Group.update()
are methods which are provided by pygame.sprite.Group
.
The former delegates the to the update
method of the contained pygame.sprite.Sprite
s - you have to implement the method. See pygame.sprite.Group.update()
:
Calls the
update()
method on all Sprites in the Group [...]
The later uses the image
and rect
attributes of the contained pygame.sprite.Sprite
s to draw the objects - you have to ensure that the pygame.sprite.Sprite
s have the required attributes. See pygame.sprite.Group.draw()
:
Draws the contained Sprites to the Surface argument. This uses the
Sprite.image
attribute for the source surface, andSprite.rect
. [...]
Remove the line self.draw = pygame.sprite.Group.draw
it is misleading. The Star
object doesn't need a draw
method, because it's drawn by the Group.
Just call:
self.stars.draw(self.screen)
Method _update_screen
:
class Stars:
# [...]
def _update_screen(self):
"""Update images on the screen, and flip to the new screen."""
# Redraw the screen during each pass through the loop.
self.screen.fill(self.settings.bg_color)
# Draw the star on the screen
self.stars.draw(self.screen) # <--
# Make the most recently drawn screen visible.
pygame.display.flip()
Upvotes: 1