settings does not have attribute blit

I am currently learning python from the book 'Python Crash Course'.

In the book I am currently on a project called Alien Invasion. I am running into a problem in the game after I tried to add the ability for the ship to gain speed the longer you press the button. It says that the settings() does not have the attribute 'blit' (when it calls the blitme function to draw the ship in the game).

My code is split into multiple modules which I have included below.

All modules are .py.

alieninvasionbase:

import sys                                               
import pygame
from settings import *
from ship import *
from gamef import *

def start_game():
        pygame.init()
    ai_settings = settings()
    screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))
    pygame.display.set_caption("Space Wars")
    ship = Ship(ai_settings, screen)
    while True:
        ship.update() 
        check_events(ship)
        us(ai_settings,screen,ship)

start_game()

game.py:

import sys
import ship
import pygame
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
def us(self,ai_settings,screen,ship):
    self.screen.fill(ai_settings.bg_color)
    self.ship.blitme()                              
    self.pygame.display.flip()
check_events(ship)

ship.py:

import pygame
import sys
class Ship():
    def __init__(self,screen,ai_settings):
        self.screen = screen
        self.ai_settings = ai_settings
        self.image = pygame.image.load('images/spaceship.bmp')
        self.rect = self.image.get_rect()
        self.screen_rect = self.image.get_rect()
        self.screen_rect.centerx = self.screen_rect.centerx
        self.rect.bottom = self.screen_rect.bottom
        self.moving_right = False
        self.moving_left = False

    def update(self):
        if self.moving_right == True:
            self.rect.centerx += 1
        if self.moving_left == True:
            self.rect.centerx += -1
    def blitme(self):
        self.screen.blit(self.image,self.rect)

settings.py:

import pygame

import sys
import ship
class settings():
    def __init__(self):
        self.screen_width = 1200
        self.screen_height = 800 
        self.bg_color = (0,0,0)

Upvotes: 0

Views: 126

Answers (1)

Gino Mempin
Gino Mempin

Reputation: 29608

The us method in game.py is not an instance method since it's not part of a class, so it does not need the self parameter. See What is the purpose of the word 'self', in Python?.

def us(self,ai_settings,screen,ship):
    self.screen.fill(ai_settings.bg_color)
    self.ship.blitme()                              
    self.pygame.display.flip()

Remove self and just use the 3 parameters directly.

def us(ai_settings,screen,ship):
    screen.fill(ai_settings.bg_color)
    ship.blitme()                              
    pygame.display.flip()

I think it would be better to make check_events and us instance methods of Ship, since you pass ship as a parameter anyway, and also all Ship instances already has a copy of screen and ai_settings.

Another problem I see is that you mixed-up the arguments to Ship. The class __init__ methods accept screen and ai_settings, in that specific order:

def __init__(self,screen,ai_settings):  # <--- look at the input order
    self.screen = screen
    self.ai_settings = ai_settings

But you instantiate a ship like this:

ship = Ship(ai_settings, screen)        # <--- the order here is incorrect

Notice the order is incorrect. So in __init__, the 1st argument ai_settings gets assigned to self.screen and the 2nd argument screen gets assigned to self.ai_settings. The order is important for positional arguments of a function, Python does not check the variable name.

That will lead to the error you mentioned here:

def blitme(self):
    self.screen.blit(self.image,self.rect)

Because, in effect, self.screen is actually the settings instance ai_settings. You can check that by printing-out type(self.screen). It is the same as:

ai_settings = settings()  # instantiated in `start_game`
ai_settings.blit(...)     # inside `Ship#blitme`

and the settings class does not have the blit attribute.

Upvotes: 1

Related Questions