TypeError: start() takes 0 positional arguments but 1 was given - python

class mainmenu(object):
def __init__(self, screen):
pygame.init()
self.screen = screen
def button(self, rect, radius=0, action=None):
click = pygame.mouse.get_pressed()
if rect.collidepoint(pygame.mouse.get_pos()):
color = (141,182,205)
if click[0] == 1 and action != None:
action()
else:
color = (28,134,238)
pygame.draw.rect(self.screen, color, rect, border_radius = radius)
def menu(self):
screenw = self.screen.get_width()
screenh = self.screen.get_height()
mid_w = screenw/2
mid_h = screenh/2
btn_start = pygame.Rect(mid_w-150,mid_h*3/5,300,100)
self.button(btn_start, 50, self.start)
def start():
return 'start'
I don't give any arguments in start() but I catch this error
TypeError: start() takes 0 positional arguments but 1 was given

self.start() is shorthand for writing start(self). So you can't pass in a method that's bound to an object, you'll have to pass in a free function (or static method). All methods on a class expects the argument self (your start method shouldn't work).
class Example:
def method(self): # Takes `self` as parameter
pass
Instead, you must create a static method that doesn't take any parameters:
class Example:
#staticmethod
def my_static_method():
# Doesn't take `self` as parameter, which means you cannot use
# `self` in this method.
pass
or a free-standing function that's not bound to a class at all.
def my_function():
pass
These can be passed as functions that doesn't take any arguments.
In your specific case, you can make start a static method, as it doesn't use self, or a free function:
class MainMenu:
def __init__(self, screen):
pygame.init()
self.screen = screen
def button(self, rect, radius=0, action=None):
click = pygame.mouse.get_pressed()
if rect.collidepoint(pygame.mouse.get_pos()):
color = (141,182,205)
if click[0] == 1 and action != None:
action()
else:
color = (28, 134, 238)
pygame.draw.rect(self.screen, color, rect, border_radius=radius)
def menu(self):
screen_width = self.screen.get_width()
screen_height = self.screen.get_height()
mid_width = screen_width / 2
mid_height = screen_height / 2
btn_start = pygame.Rect(mid_width-150, mid_height*3/5, 300, 100)
# Do this to call the static method.
self.button(btn_start, 50, MainMenu.start)
# Or do this to call the free standing function.
self.button(btn_start, 50, start)
#staticmethod
def start():
return 'start'
def start():
return 'start'

Related

Why do I get "missing 1 required positional argument: 'self'"?

When I use in the program querauto_group.add(QuerWagen.create_querauto()) then I get the report
missing 1 required positional argument: 'self'. When I use querauto_group.add(player.create_querauto()) then the program works.
import pygame, sys
import random
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
def create_querauto(self):
ii=random.randrange(0,8)
img = pygame.image.load(f"Bilder/Gegenstaende/geg{ii}.png")
img = pygame.transform.scale(img,(100,25))
return QuerWagen(200,300,img)
class QuerWagen(pygame.sprite.Sprite):
def __init__(self, pos_x,pos_y,img):
super().__init__()
self.image=img
self.rect = self.image.get_rect(center = (pos_x,pos_y))
def update(self):
self.rect.x+=5
if self.rect.x > screen_width + 200:
self.kill()
def create_querauto(self):
ii=random.randrange(0,8)
img = pygame.image.load(f"Bilder/Gegenstaende/geg{ii}.png")
img = pygame.transform.scale(img,(100,25))
return QuerWagen(200,300,img)
pygame.init()
clock = pygame.time.Clock()
screen_width,screen_hight = (1200,800)
screen = pygame.display.set_mode((screen_width,screen_hight))
player = Player()
querauto_group = pygame.sprite.Group()
WECHSELBILD = pygame.USEREVENT + 1
pygame.time.set_timer(WECHSELBILD,1800)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type ==WECHSELBILD:
#querauto_group.add(QuerWagen.create_querauto())
querauto_group.add(player.create_querauto())
screen.fill((30,30,30))
querauto_group.draw(screen)
querauto_group.update()
pygame.display.flip()
clock.tick(30)
pygame.quit()
quit()
On both classes create_querauto is an instance method, meaning that the class needs to be instantiated in order to call the method.
That's why it is working with the player instance.
i.e.
class Player:
def create_querauto(self):
ii=random.randrange(0,8)
img = pygame.image.load(f"Bilder/Gegenstaende/geg{ii}.png")
img = pygame.transform.scale(img,(100,25))
return QuerWagen(200,300,img)
player_instance = Player()
player_instance.create_querauto() # This will work
Player.create_querauto() # This will throw the error you see above
If you would like to method to work without instantiating the class first you can define it as a static method, using the #staticmethod decorator
This would look like:
class QuerWagen(pygame.sprite.Sprite):
#staticmethod
def create_querauto():
ii=random.randrange(0,8)
img = pygame.image.load(f"Bilder/Gegenstaende/geg{ii}.png")
img = pygame.transform.scale(img,(100,25))
return QuerWagen(200,300,img)
Now you can call that function on the class directly like you were trying to do.
querwagen = QuerWagen.create_querauto() # works fine

Pygame returning locking error during blitting

I am trying to make a 2D game in pygame, and have a camera class that has a surface attribute, and each time the cameras get updated their surface is updated. All graphics are blitted to game.worldSurface, and then the main camera take a picture of that and blits it to the display surface. However, when using other cameras, i am unable to blit to the worldsurface and get a locking error. i have tried .unlock(). what could be causing this?
import pygame
import pickle
class Tileset:
def __init__(self, location):
pass
class Tilemap:
def __init__(self):
pass
class Collisionmap(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
class Player(pygame.sprite.Sprite):
def __init__(self, spritesheet):
super().__init__()
self.spritesheet = pygame.image.load(spritesheet)
self.x = 0
self.y = 0
def draw(self, surface):
surface.blit(self.spritesheet, (self.x, self.y))
class Mob(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
class Camera:
def __init__(self):
self.x = 0
self.y = 0
self.width = 100
self.height = 100
self.surface = pygame.Surface((self.width, self.height))
def moveToSprite(self, sprite):
self.x = sprite.rect.centerx - WIDTH // 2
self.y = sprite.rect.centery - HEIGHT // 2
def update(self, world):
self.surface = world.subsurface((self.x, self.y, self.width, self.height))
class Level:
def __init__(self, terrarin, collision, mobs):
self.terrain = terrain
self.collision = collision
self.mobs = mobs
class Game:
def __init__(self):
pygame.init()
self.DISPLAYSURF = pygame.display.set_mode((0, 0))
self.mainCamera = Camera()
self.mainCamera.width = self.DISPLAYSURF.get_width()
self.mainCamera.height = self.DISPLAYSURF.get_height()
self.otherCameras = []
self.worldSurface = pygame.Surface((10000, 10000))
self.player = Player("marioSS.jpg")
self.otherCameras.append(Camera())
self.run()
def run(self):
while True:
for event in pygame.event.get():
pass
self.earlyUpdate()
self.update()
self.lateUpdate()
self.graphicsUpdate()
def update(self):
pass
def earlyUpdate(self):
pass
def lateUpdate(self):
pass
def graphicsUpdate(self):
for each in self.otherCameras:
each.update(self.worldSurface)
self.player.draw(self.worldSurface)
self.otherCameras[0].surface.unlock()
self.worldSurface.unlock()
self.worldSurface.blit(self.otherCameras[0].surface, (100, 100)) ##Error here
self.mainCamera.update(self.worldSurface)
self.DISPLAYSURF.blit(self.mainCamera.surface, (0, 0))
pygame.display.update()
x = Game()
Problem makes world.subsurface() in Camera.update()
It doesn't copy data from world to surface but it assigns access to original world. And later you have: camera.surface keeps access to world, and blit try to copy from camera.surface to world - so finally it tries to copy from world to world. And maybe it locks it.
But if in Camera.update() you use .copy()
self.surface = world.subsurface((self.x, self.y, self.width, self.height)).copy()
or blit it
self.surface.blit(world.subsurface((self.x, self.y, self.width, self.height)), (0,0))
then it works.
DOC: subsurface
subsurface(Rect) -> Surface
Returns a new Surface that shares its pixels with its new parent.

Python Pyglet Using External Fonts For Labels

I'm working on a project at the moment and I have been trying to change the fonts of the labels in the pyglet library to fonts that I found online but I couldn't get it to work. I tried searching online for an hour now and nothing seems to be working. Added some code for reference:
font.add_file('ZukaDoodle.ttf')
ZukaDoodle = font.load('ZukaDoodle.ttf', 16)
PlayLabel = pyglet.text.Label('Go', font_name='ZukaDoodle', font_size=100, x=window.width // 2,
y=window.height - 450, anchor_x='center', anchor_y='center',
batch=buttons_batch,
color=(0, 0, 0, 1000), width=250, height=130)
So the error is pretty simple. The loaded font-name is not ZukaDoodle, it's Zuka Doodle with a space. Here's a working executable sample:
from pyglet import *
from pyglet.gl import *
font.add_file('ZukaDoodle.ttf')
ZukaDoodle = font.load('ZukaDoodle.ttf', 16)
key = pyglet.window.key
class main(pyglet.window.Window):
def __init__ (self, width=800, height=600, fps=False, *args, **kwargs):
super(main, self).__init__(width, height, *args, **kwargs)
self.x, self.y = 0, 0
self.keys = {}
self.mouse_x = 0
self.mouse_y = 0
self.PlayLabel = pyglet.text.Label('Go', font_name='Zuka Doodle', font_size=100,
x=self.width // 2,
y=self.height - 450,
anchor_x='center', anchor_y='center',
color=(255, 0, 0, 255),
width=250, height=130)
self.alive = 1
def on_draw(self):
self.render()
def on_close(self):
self.alive = 0
def on_mouse_motion(self, x, y, dx, dy):
self.mouse_x = x
def on_key_release(self, symbol, modifiers):
try:
del self.keys[symbol]
except:
pass
def on_key_press(self, symbol, modifiers):
if symbol == key.ESCAPE: # [ESC]
self.alive = 0
self.keys[symbol] = True
def render(self):
self.clear()
self.PlayLabel.draw()
## Add stuff you want to render here.
## Preferably in the form of a batch.
self.flip()
def run(self):
while self.alive == 1:
self.render()
# -----------> This is key <----------
# This is what replaces pyglet.app.run()
# but is required for the GUI to not freeze
#
event = self.dispatch_events()
if __name__ == '__main__':
x = main()
x.run()
The key difference here is font_name='Zuka Doodle'.
Also, the alpha channel usually doesn't need to be higher than 255 since that's the max value of a colored byte, so unless you're using 16-bit color representation per channel, 255 will be the maximum value.

Pass an __init__ value from a higher class into a subclass requiring that same argument

I am creating a small game that creates a tower.
The tower has two components, the base and the gun. In order to do so I am trying to pass the value of self.x into the __init__ function of a subclass. I will further add an update() function once I have a solution.
Here is my code. (Poorly formatted and incomplete... sorry!)
import pygame
from math import atan2
screen = pygame.display.set_mode((800, 800))
pygame.display.set_caption('Foongus v0.1')
pygame.init()
class home_base:
def __init__(self, x, y):
class base:
def __init__(self, x, y):
self.image = pygame.image.load('base.png')
screen.blit(self.image, (x, y))
class gun:
def __init__(self, x, y):
self.image = pygame.image.load('gun.png')
screen.blit(self.image, (x, y))
home = home_base(300, 300)
while True:
screen.fill((0,0,0))
pygame.display.update()
The following code should help guide you in the direction you should be going:
import math
import pygame
def main():
screen = pygame.display.set_mode((800, 800))
pygame.display.set_caption('Foondus v0.1')
pygame.init()
home = HomeBase(300, 300, screen)
while True:
screen.fill((0, 0, 0))
pygame.display.update()
class HomeBase:
def __init__(self, x, y, screen):
self.x, self.y, self.screen = x, y, screen
self.base_image = pygame.image.load('base.png')
self.gun_image = pygame.image.load('gun.png')
self.screen.blit(self.base_image, (self.x, self.y))
self.screen.blit(self.gun_image, (self.x, self.y))
if __name__ == '__main__':
main()
you wouldn't usually define a class inside the __init__ method of another class. instead, I would do something along these lines:
class A(object):
def __init__(self, instance_classB):
# here self is an instance of A and instance_classB an instance of B
pass
class B(object):
def __init__(self):
# self is the newly created instance of B
self._instance_classA = A(self)
# create an instance of B - calls B.__init__ on the new instance
b = B()
that way, you have instances of class B have a reference to an instance of class A in self._instance_classA, where each instance of class A has a backwards reference to the instance of class B it belongs to passed into the constructor.

pyglet: changing the image of a sprite instance when pressing a button

This code displays the image assassin1.png on a black background. As soon as I press the key the image moves to the right and stops moving as soon as I release the key.
As soon as I press the key it should also change to the image assassin2.png and when I release the key it should change back to assassin1.png.
This code however never displays the assassin2.png image while moving. Why is this so and how can I fix this?
import pyglet
class Assassin(pyglet.sprite.Sprite):
def __init__(self, batch, img):
pyglet.sprite.Sprite.__init__(self, img, x = 50, y = 30)
def stand(self):
self.img = pyglet.image.load("assassin1.png")
return self
def move(self):
self.img = pyglet.image.load('assassin2.png')
return self
class Game(pyglet.window.Window):
def __init__(self):
pyglet.window.Window.__init__(self, width = 315, height = 220)
self.batch_draw = pyglet.graphics.Batch()
self.player = Assassin(batch = self.batch_draw, img = pyglet.image.load("assassin1.png"))
self.keys_held = []
self.schedule = pyglet.clock.schedule_interval(func = self.update, interval = 1/60.)
def on_draw(self):
self.clear()
self.batch_draw.draw()
self.player.draw()
def on_key_press(self, symbol, modifiers):
self.keys_held.append(symbol)
if symbol == pyglet.window.key.RIGHT:
self.player = self.player.move()
print "The 'RIGHT' key was pressed"
def on_key_release(self, symbol, modifiers):
self.keys_held.pop(self.keys_held.index(symbol))
self.player = self.player.stand()
print "The 'RIGHT' key was released"
def update(self, interval):
if pyglet.window.key.RIGHT in self.keys_held:
self.player.x += 50 * interval
if __name__ == "__main__":
window = Game()
pyglet.app.run()
I looked at the pyglet's source code and i think the problem is here:
self.img = pyglet.image.load(...
The image is stored in self.image variable, not self.img. So changing to:
self.image = pyglet.image.load(...
should update the image that the sprite is using.

Categories