Advertisement

"self" not defined

Started by May 27, 2017 10:58 AM
3 comments, last by Alberth 7 years, 6 months ago

Hi everyone I'm trying to make my first game using pygame and I was wondering if anyone could help me. I get an error in Main() saying that "classes.classprotagonist.motion()" needs argument 'self'. When I comply with this it gives another error saying 'self' is not defined. I'm stuck since

Main.py.

-------------------------------------------------------------------------------------------------------------

import pygame, sys
import classes
pygame.init()
WIDTH,HEIGHT = 1920 ,900
screen = pygame.display.set_mode((WIDTH,HEIGHT),0,32)
clock = pygame.time.Clock()
FPS = 30
protagonist= classes.classprotagonist(0 ,HEIGHT-150, 150 ,150, "imagesgame/protagonist3.png")
while True:
##PROCESSES
for event in pygame.event.get(): ## for game to close properly
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
keys = pygame.key.get_pressed() ##assigning keys
if keys[pygame.K_d]:
protagonist.velx = 5
elif keys [ pygame.K_a]:
protagonist.velx = -5
else:
protagonist.velx = 0
##LOGIC
classes.classprotagonist.motion() ##HERE'S WHERE I GET THE ERROR
##DRAW
screen.fill((255,255,255)) ##setting screen white and drawing
classes.BaseClass.allsprites.draw(screen)
pygame.display.flip()
clock.tick (FPS)
------------------------------------------------------------------------------------------------------------------------------------------------
classes.py
-------------------------------------------------------------------------------------------------------------------------------------------------
import pygame
##creating BaseClass
class BaseClass(pygame.sprite.Sprite):
allsprites = pygame.sprite.Group()
def __init__( self ,x,y,width,height,image_string):
pygame.sprite.Sprite.__init__(self)
BaseClass.allsprites.add(self)
self.image = pygame.image.load(image_string)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.width = width
self.height = height
class classprotagonist(BaseClass): ##creating protagonist class inheriting BaseClass
List = pygame.sprite.Group()
def __init__(self,x,y,width,height,image_string):
BaseClass.__init__(self,x,y,width,height,image_string)
classprotagonist.List.add(self) ##add all bugs to this list when theyre created
self.velx = 0
def motion(self):
self.rect.x += self.velx
This is not a Game Design topic. Moving to a programming forum.

-- Tom Sloper -- sloperama.com

Advertisement

Quoting some relevant lines from your code:


protagonist= classes.classprotagonist(0 ,HEIGHT-150, 150 ,150, "imagesgame/protagonist3.png")
wihle True:
    ....
    classes.classprotagonist.motion()

Not sure how much you understand of classes, but "classes.classprotagonist" is a class. It's like a template, a sort of empty form with checkmarks and dotted lines, so you can check-off common things, and write lines of text at the indicated places.

In particular, the class is not "live", it contains no data like a filled-in form. To make a "live" version of the template you make a xerox-copy of it, and you it hand over to the person that should fill it with checkmarks and lines of text. In Programming, it's called "instantiating a class". The result is called "an object". The object has the same shape as the class, but it's meant for filling with data.

You instantiate the "classes.classprotagonist" class in the first line that I quoted, giving it values that match with the __init__ function in the class.

The created object is assigned to the "protagonist" variable. The name "self" in the class refers to such an object, ie it points to the object that stores the actual data.

The "classes.classprotagonist.motion()" calls the function "motion" in the class. If you compare the class definition with how you call it, you see it's missing a 'self' argument. The template says you need one, and in the call you provide none. This is why Python refuses to perform the call, it's missing the object with data.

There are two ways out of this, a nice theoretical one, and a much more practical one. First the theoretical one:


classes.classprotagonist.motion(protagonist)

I copied your line, and add the object as argument. I supplied a "self" for the call, and now it will work.

The more practical one uses the fact that the "protagonist" is created from the class. It has everything that the class has, including the "motion" function. In other words, there is no need to go through "classes.classprotagonist", as "protagonist" already has the function. That leads to


protagonist.motion()

From the object, I call the "motion" function, and since I use the object to reach the function, the object inserts itself as first argument, so I don't need to supply it. Neat eh?

Quoting some relevant lines from your code:


protagonist= classes.classprotagonist(0 ,HEIGHT-150, 150 ,150, "imagesgame/protagonist3.png")
wihle True:
    ....
    classes.classprotagonist.motion()

Not sure how much you understand of classes, but "classes.classprotagonist" is a class. It's like a template, a sort of empty form with checkmarks and dotted lines, so you can check-off common things, and write lines of text at the indicated places.

In particular, the class is not "live", it contains no data like a filled-in form. To make a "live" version of the template you make a xerox-copy of it, and you it hand over to the person that should fill it with checkmarks and lines of text. In Programming, it's called "instantiating a class". The result is called "an object". The object has the same shape as the class, but it's meant for filling with data.

You instantiate the "classes.classprotagonist" class in the first line that I quoted, giving it values that match with the __init__ function in the class.

The created object is assigned to the "protagonist" variable. The name "self" in the class refers to such an object, ie it points to the object that stores the actual data.

The "classes.classprotagonist.motion()" calls the function "motion" in the class. If you compare the class definition with how you call it, you see it's missing a 'self' argument. The template says you need one, and in the call you provide none. This is why Python refuses to perform the call, it's missing the object with data.

There are two ways out of this, a nice theoretical one, and a much more practical one. First the theoretical one:


classes.classprotagonist.motion(protagonist)

I copied your line, and add the object as argument. I supplied a "self" for the call, and now it will work.

The more practical one uses the fact that the "protagonist" is created from the class. It has everything that the class has, including the "motion" function. In other words, there is no need to go through "classes.classprotagonist", as "protagonist" already has the function. That leads to


protagonist.motion()

From the object, I call the "motion" function, and since I use the object to reach the function, the object inserts itself as first argument, so I don't need to supply it. Neat eh?learnedmorewi

omg I learned more with your reply than all the hours I spent learning objects and classes...THANKSS!

I did sneakily use a lot of words that only make sense after you spent those hours reading about objects and classes :)

This topic is closed to new replies.

Advertisement