Inherited __init__() function not working as intended - python

I was working on a game using the pygame library on Python. I basically defined a Character class from which the Knight class and Enemy class would inherit functions. Since both children classes use the same initialize functions, I defined the __init__() function under the parent class. However, I don't fully understand how it works and I'm getting the following error:
TypeError: __init__() takes 1 positional argument but 3 were given
Here's my code:
class Character():
def __init__(self, img, hitbox, vel, pos_x, pos_y):
self.img = img
self.hitbox = hitbox
self.vel = vel
self.pos_x = pos_x
self.pos_y = pos_y
def draw(self):
if self.right:
pygame.transform.flip(self.img, True, False)
win.blit(self.img, (self.pos_x, self.pos_y))
class Knight(Character):
def __init__(self):
Character.__init__(self)
def move(self):
if self.right:
if self.x + self.vel < win_width:
self.x += self.vel
if self.left:
if self.x - self.vel > 0:
self.x -= self.vel
main_plr = Knight("img", (19, 20), 5, 30, 20)

For a quick fix: just remove the __init__ method from Knight.
The error is raised because you create a Knight object with 6
arguments (self, "img", (19, 20), 5, 30, 20) whereas the __init__ method accepts only one (self).
So if your Knight objects do not have any additional attributes
compared to Character objects, it will be just fine to remove the
__init__ method. Now if you want your knight to have weapons, for
example, you will have to do something like that:
class Knight(Character):
def __init__(self, img, hitbox, vel, pos_x, pos_y, weapon):
super().__init__(img, hitbox, vel, pos_x, pos_y)
self.weapon = weapon
k = Knight("img", (19, 20), 5, 30, 20, "sword")
[Edit]
Additionaly, as suggested by #Matiiss, you can use *args to avoid
repeating all arguments of Character.__init__ in Knight.__init__.
One advantage, besides conciseness, is that you do not have to modify
Knight if you add attributes to your Character objects.
class Knight(Character):
def __init__(self, *args, weapon):
super().__init__(*args)
self.weapon = weapon
k = Knight("img", (19, 20), 5, 30, 20, weapon="sword")
But now the drawback is that you have to specify the weapon with
weapon="the-weapon", since it is now a keyword argument (placed
after *args).

As the error you are seeing says, your Knight constructor does not accept those arguments; if you are going to use that kind of inherited method extension, the class and subclass methods need to have matching argument signatures. It's also best to use super() to refer to the superclass rather than naming it explicitly.
The simplest way of handling this is to use *args and **kwargs, to concisely pass arguments that aren't needed by the subclass method to the superclass method, ie
class Character():
def __init__(self, img, hitbox, vel, pos_x, pos_y):
self.img = img
self.hitbox = hitbox
self.vel = vel
self.pos_x = pos_x
self.pos_y = pos_y
class Knight(Character):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def move(self):
if self.right:
if self.x + self.vel < win_width:
self.x += self.vel
if self.left:
if self.x - self.vel > 0:
self.x -= self.vel

Related

How do I fix TypeError: __init__() missing 1 required positional argument: 'y'

I'm currently trying to set up hitboxes for my characters but I can't seem to get rid of this error.
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
self.x = x
self.y = y
pygame.sprite.Sprite.__init__(self)
self.image = IronMan
self.rect = self.image.get_rect()
self.rect.y = 475
self.direction = 1
self.hitbox = (self.x + 20, self.y + 11, 28, 60)
def draw(self, win):
self.hitbox = (self.x + 20, self.y + 11, 28, 60)
pygame.draw.rect(win, (255, 0, 0), self.hitbox, 2)
When the code is ran Im faced with
TypeError: __init__() missing 1 required positional argument: 'y'
Looks like you didn't provide sufficient parameters when you created an instance of the class. There are 2 options to fix it.
Provide sufficient parameters when creating instance.
Example:
Mark = Player() # Error
Cindy = Player(1) # Error
James = Player(1, 2) # Good!
Since you specified _init_ method to take 2 arguments, you must provide 2 arguments when calling it.
Simply set a default value for the arguments.
You can do this by using '=' sign.
Example:
def __init__(self, x=0, y=0):
#blabla
Now, _init_ method will automatically initialize the arguments to 0, if it's not provided manually.
Mark = Player() # Mark.x=0, Mark.y=0
Cindy = Player(1) # Cindy.x=1, Cindy.y=0
James = Player(1, 2) # James.x=1, James.y=2

How to inherit specific variables from one class to another class?

I'm making a game in python using the pygame module and I wish to inherit one specific variable from one class to another class, but have no clue how. I have tried super() but it has not worked, however, me being a novice may just mean I did it wrong so please do not discount that as a possibility if it works.
I have listed which variable I wish inherited in the code below as well.
Here's my relevant code below:
Class I want to inherit FROM:
class player():
def __init__(self, x, y, width, height, walkCount):
self.x = x
self.y = y
self.width = width
self.height = height
self.vel = 15
self.lastDirection = "right" or "left" or "up" or "down" #<--- variable I want to inherit
self.walkCount = walkCount
def drawCharacter(self, window):
dest = (self.x, self.y)
if self.walkCount + 1 >= 30:
self.walkCount = 0
if self.lastDirection == "left":
window.blit(protagL[0], dest)
elif self.lastDirection == "right":
window.blit(protagR[0], dest)
elif self.lastDirection == "up":
window.blit(protagU[0], dest)
elif self.lastDirection == "down":
window.blit(protagD[0], dest)
Class that I want to receive the inheritance:
class projectile(player):
def __init__(self, x, y, direction, travelCount):
self.x = x
self.y = y
self.direction = direction
self.vel = 20 * direction
self.travelCount = travelCount
def drawBullet(self, window):
dest = (self.x, self.y)
if self.travelCount + 1 >= 15:
self.walkCount = 0
if lastDirection == "right" or "left": # <--- I Want to call lastDirection variable here
if self.travelCount < 15:
window.blit(bulletsP[self.travelCount//3], dest) #dest)
self.travelCount += 1
self.x += self.vel
Any help would be greatly appreciated, thank you.
You have to invoke the constructor of the base class. See super():
class projectile(player):
def __init__(self, x, y, direction, travelCount):
super().__init__(x, y, 10, 10, travelCount)
# [...]
Note the arguments for width and height are unclear in you example, so I've exemplarily used (10, 10).

Positional argument is said to be missing but is given, what is wrong?

I'm using pygame and have created a class called Entity and a Subclass Player. The class Entity requires an argument "pos", which is always just "pos", because the value for it is created in the init.
class Entity(pygame.sprite.Sprite):
def __init__(self, color, stype, pos, *groups):
super().__init__(*groups)
self.image = stype
try:
self.image.fill(color)
except:
pass
self.image.convert()
self.rect = self.image.get_rect(topleft=pos)
def update(self, dt, events):
pass
class Player(Entity):
def __init__(self, platforms, pos, *groups):
super().__init__((pygame.image.load("lemon.png")), pos)
self.vel = pygame.Vector2((0, 0))
self.onGround = False
self.platforms = platforms
self.speed = 8
self.jump_strength = 10
However when I try to run the code it gives me this error:
TypeError: init() missing 1 required positional argument: 'pos'
Why only two arguments pass here:
super().__init__((pygame.image.load("lemon.png")), pos)
But the constructor of Entity requires at least 3:
def __init__(self, color, stype, pos, *groups)
I don't know your problem well, but this could be a solution:
super().__init__(color=None, stype=(pygame.image.load("lemon.png")), pos=pos)

Ways to reach variables from one class to another class?

I'm trying to create a basic game, but I'm fairly new to the python programming scene. I've come across a problem where with two classes (a player and enemy class), I want to access class variables like health from the player and enemy, and vice versa. What are some ways of doing this?
Here's the code to better emphasize what I'm asking:
class Player(object):
def __init__(self, image):
self.x = 100
self.y = 240
self.health = 30
self.defense = 25
self.image = image
self.black = (0, 0, 0)
self.draw()
def draw(self):
screen.blit(self.image, (self.x, self.y))
line = pygame.draw.rect(screen, self.black, (80, 300, 100, 5))
def attack(self):
pass
class Enemy(object):
def __init__(self, image):
self.x = 480
self.y = 240
self.health = 20
self.defense = 15
self.image = image
self.black = (0, 0, 0)
self.draw()
def draw(self):
screen.blit(self.image, (self.x, self.y))
line = pygame.draw.rect(screen, self.black, (460, 300, 100, 5))
def attack(self):
pass
Basically, I don't understand how I can take something like the "self.health" from one class, and easily access it from the other class. I've tried some methods of using return methods etc., but I'm curious if there are any simple ways to do this. Help is appreciated!
This code creates a class, and in the special __init__ method, it assigns values to various member variables.
class Player(object):
def __init__(self, image):
self.x = 100
self.y = 240
self.health = 30
self.defense = 25
self.image = image
self.black = (0, 0, 0)
self.draw()
These member variables are also called properties in Python. If you have a reference to a Player instance (an instance of the Player class):
p = Player()
You can access the properties all you like:
print(p.health)
Perhaps you need some kind of "main loop" or controller class that has access to players and enemies and can set their properties accordingly:
class MainLoop(object):
def __init__(self):
self.player_1 = Player()
self.enemy_1 = Enemy()
def run(self):
if fight(): # fight() is some function of your game
self.player_1.health -= 10
self.enemy_1.health -= 20

Using pygame.Surface.blit inside class

I can call my class only one time.
My code is:
class fish:
def __init__(self, x, y, image, speed):
self.x = x
self.y = y
self.image = image
self.speed = speed
def be(self):
screen.blit(self.image, (self.x, self.y))
self.x -= self.speed
if boot.x+36 > self.x and boot.x < self.x+5:
if boot.y+34 > self.y and boot.y < self.y+5:
boot.live -= 1
boot.x = 100
boot.y = 460
fishes = []
fishes.append(fish(900, 300, fish_1, 1))
And when I call 'fish' object inside or outside the game loop(fishes.append(fish(900, 300, fish_1, 1))
I got Error:
TypeError: 'fish' object is not callable
My first guess is that you have a fish variable somewhere down in your code. Rename the class to Fish as well as the constructor call to Fish(900, 300, fish_1, 1) and it should be fine.

Categories