__init__中的参数太多

时间:2017-01-24 23:07:35

标签: python pygame

我目前正在youtube上的视频'kidscancode'的帮助下编写一个平台游戏。到目前为止,我已经很顺利了,我收到了以下错误:

Traceback (most recent call last):
  File "D:\College\CS Project\Python Coding For Project New\Main.py", line 290, in <module>
    g.new()
  File "D:\College\CS Project\Python Coding For Project New\Main.py", line 84, in new
    Platform(self, *plat)
TypeError: __init__() takes 4 positional arguments but 6 were given

这是我的代码(分为3页,主页,精灵和设置):

>># The "new" section creates new objects that spawn into the game, such as the player's character.
    def new(self):
        # Start a new game
        # Sets player's starting score to 0.
        self.score = 0
        # We add a sprite group
        self.all_sprites = pg.sprite.Group()
        # A platforms group
        self.platforms = pg.sprite.Group()
        # A powerups group
        self.powerups = pg.sprite.Group()
        # A players group
        self.player = Player(self)
        >for plat in PLATFORM_LIST:
            # The next line takes the list platform on the settings page, and               explodes it, gathering each variable from inside the list (this is just a shorter way of coding it)
            Platform(self, *plat)


            # Implements music into the game:
            # The following line means that the music file is queued up and ready to play.
        pg.mixer.music.load(path.join(self.sound_dir, 'gba1complete.ogg'))
        self.run()

# The next run function is the start of my game loop.
    def run(self):
        # Game Loop
        #Plays music:
        #music.play() would normally only play the music track once, however there is a loop option. The -1 value means infinitely loop the track, which is what I want to happen.
        pg.mixer.music.play(loops=-1)
        self.playing = True
        while self.playing:
            # This will start the clock when the player starts playing
            self.clock.tick(FPS)
            self.events()
            self.update()
            self.draw()
            #Music ends, fadeout instead of stop (milliseconds)
        pg.mixer.music.fadeout(3000)
    def update(self):
        # Game Loop - Update
        self.all_sprites.update()
        # The following initiates a collision check for the player's character:
        # Checks if player hits a platform - only if falling (y velocity is above 0)
        if self.player.vel.y > 0:
            hits = pg.sprite.spritecollide(self.player, self.platforms, False)
            if hits:
                # Line below says that we are only going to snap to the platform if our feet are higher than the platform.
                # REVISIT
                # REVISIT
                # REVISIT
                # REVISIT
                # REVISIT
                # The following mini section explains how I prevented overlapping snaps causing problems.
                lowest = hits[0]
                # We then compare the other hits
                for hit in hits:
                    # See if any are lower than the first:
                    if hit.rect.bottom > lowest.rect.centery:
                        lowest = hit
                if self.player.pos.x < lowest.rect.right + 10 and \
                self.player.pos.x > lowest.rect.left -10:

                    if self.player.pos.y < lowest.rect.centery:
                    # If the player has collided with an object, then we want the player to stop falling in the y direction at that point.
                        self.player.pos.y = lowest.rect.top
                    # The next line sets the character's velocity to 0, so they do not carry on falling through the object at all. This allows us to run along it also.
                        self.player.vel.y = 0
                        self.player.jumping = False
        # If the player reaches right 1/4 of the screen
        if self.player.rect.right >= WIDTH -400  :
            # The next line moves the camera as the player moves (by the same velocity)
            self.player.pos.x -= (self.player.vel.x)
            # Next few lines move all of the platforms in the platform list on the settings page.
            for plat in self.platforms:
                # The next line means that the platforms stay behind once the player has moved.
                plat.rect.x -= (self.player.vel.x)

                # The next iteration loop is very similar to the previous one, however it works for the left side of the screen.
        if self.player.rect.right <= WIDTH -700  :
            # Here we set our boundary to the left (WIDTH - 700).
            self.player.pos.x -= (self.player.vel.x)
            # Then we move the platforms forwards, so we can retrace our steps in a level.
            for plat in self.platforms:
                plat.rect.x -= (self.player.vel.x)
                if plat.rect.right <= WIDTH - 10000:
                    plat.kill()

        # If the player dies:
        # If the player hits the bottom of the screen:
        if self.player.rect.bottom > HEIGHT:
            # Next loop scrolls platforms upwards when player falls off the map to make the game more realistic.
            for sprite in self.all_sprites:
                # We do not want to scroll the platforms at a constant speed, as this is not realistic, however we want to set a max number, and using the max function here means we pick the max number between the player's vel and 10.
                sprite.rect.y -= max(self.player.vel.y, 10)
                # The next two lines kill all sprites when they reache the bottom of the screen.
                if sprite.rect.bottom < 0:
                    sprite.kill()
                    # The next line ends the game when the legnth of the platforms is zero, as we have gotten rid of them all.
        if len(self.platforms) == 0:
                # The next line lets the game know that the player's character is dead, and therefore ends the game session.
            self.playing = False

    def events(self):
        # Game Loop - events
        for event in pg.event.get():
            # check for closing window
            if event.type == pg.QUIT:
                if self.playing:
                    self.playing = False
                self.running = False
                # Below is an IF loop that determines if the player's character should be jumping or not.
            if event.type == pg.KEYDOWN:
                # First we establish that a key is being pressed, and then identify if it is the spacebar (or jump button)
                if event.key == pg.K_SPACE:
                    self.player.jump()



    def draw(self):
        # Game Loop - draw
        self.screen.fill(CYAN)
        self.all_sprites.draw(self.screen)
        self.draw_text(str(self.score), 22, BLACK, WIDTH / 2, 15)
        # *after* drawing everything, flip the display
        pg.display.flip()

    def show_start_screen(self):
        # game splash/start screen
        #Loads music again, can use a different track
        pg.mixer.music.load(path.join(self.sound_dir, 'gba1complete.ogg'))
        pg.mixer.music.play(loops=-1)
        # Fill the start screen background colour as brown to match our survival theme
        self.screen.fill(BROWN)
        # We display our string for 'TITLE', then choose font size, colour and choose where to display it on the screen.
        self.draw_text(TITLE, 48, WHITE, WIDTH / 2, HEIGHT / 4)
        # We display some information on how to play the game to the user
        self.draw_text("A and D Keys to move, Spacebar to jump!", 24, WHITE, WIDTH /2, HEIGHT / 2)
        # We tell the user how to initiate the game
        self.draw_text("Press any key to play", 24, WHITE, WIDTH / 2, HEIGHT * 3 / 4)
        # We display the high score on the starting screen:
        self.draw_text("High Score: " + str(self.highscore), 22, BROWN, WIDTH / 2, 15)

        # We flip the display so that the user actually sees this taking place
        pg.display.flip()
        self.wait_for_key()
        # This time I want to music to stop immediately.
        pg.mixer.music.stop

    def show_go_screen(self):
        # game over/continue
        if not self.running:
            # Return meaning end the function
            return
        # music
        pg.mixer.music.load(path.join(self.sound_dir, 'gba1complete.ogg'))
        pg.mixer.music.play(loops=-1)
            # Choose a background colour for the end screen
        self.screen.fill(BROWN)
        # Display game over
        self.draw_text("Game Over", 48, WHITE, WIDTH / 2, HEIGHT / 4)
        # Display the users score
        self.draw_text("Score: " + str(self.score), 24, WHITE, WIDTH /2, HEIGHT / 2)
        # Tell them how to restart the game
        self.draw_text("Press any key to play again", 24, WHITE, WIDTH / 2, HEIGHT * 3 / 4)
        # The following small section of code determines what message the player recieves - whether the player gets congratulated or commiserations.
        if self.score > self.highscore:
            self.highscore = self.score
            # The following line explains to the player that they have just got a new high score:
            self.draw_text("New High Score!", 22, BROWN, WIDTH / 2, HEIGHT / 2 + 40)
            with open(path.join(self.dir, HS_FILE), 'w') as f:
                # Then we write over the high score file and save it as a string because it is a text file.
                f.write(str(self.score))
        # Following line shows what happens if the player does not get a high score (displays current high score).
        else:
            self.draw_text("High Score: " + str(self.highscore), 22, BROWN, WIDTH / 2, HEIGHT / 2 + 40)
        # Enable the user to see this
        pg.display.flip()
        # Tells the program to stop and waits for the player to input a key to continue
        self.wait_for_key()

        pg.mixer.music.stop

        # The following method can be used in both show_start_screen and show_go_screen (end screen) to make the game wait for the player to press a key.
    def wait_for_key(self):
        # We set a variable to true.
        waiting = True
        # Then we create a while loop so that we can choose when the game waits and when the game continues.
        while waiting:
            # The next line chooses to run the start/end screen at the chosen FPS. We have defined FPS in the settings page so I will use this.
            self.clock.tick(FPS)
            for event in pg.event.get():
                if event.type == pg.QUIT:
                    # To leave this screen when the player presses QUIT, we end our loop
                    waiting = False
                    # Then because we want our whole program to end, we also need to set running to false.
                    self.running = False
                    # Any other key on the keyboard
                if event.type == pg.KEYUP:
                    waiting = False

    #The following method shows the text in my game.
    def draw_text(self, text, size, colour, x, y):
        # The next line gets the font object.
        font = pg.font.Font(self.font_name, size)
        # Next we render a surface for the font to be displayed on.
        # The 'True' value is my choice of whether to use anti-aliasing or not, I chose true as I believe it will make my game look smoother.
        text_surface = font.render(text, True, colour)
        # Then we generate a rectangle to help us generate it on the screen.
        text_rect = text_surface.get_rect()
        # Next we place it
        text_rect.midtop = (x, y)
        # Then we blit it onto the screen
        self.screen.blit(text_surface, text_rect)
>g = Game()
g.show_start_screen()
while g.running:
    g.new()
    g.show_go_screen()
pg.quit()

精灵:

>import pygame as pg
from Settings import *
# This allows pygame to access vectors.
vec = pg.math.Vector2

# Technically this is not a sprite, but it is another class to define so:
class Spritesheet:
    # Utility class for loading and parsing (reading through the data file, understanding what it means) spritesheets
    # We will only need to pass it the filename
    def __init__(self, filename):
        # Here we load the spritesheet's filename and convert it
        self.spritesheet = pg.image.load(filename).convert()

        # The following function lets us pick an image from the spritesheet.
    def get_image(self, x, y, width, height):
        # First we make a surface to put the image on:
        image = pg.Surface((width, height))
        # image.blit - Blit it onto this image # (self.spritesheet, - We take this spritesheet
        #(0, 0), - Blit it at this location # (x, y, width, height)) - Choose this chunk
        image.blit(self.spritesheet, (0, 0), (x, y, width, height))
        # Then we return the image
        # Below I will scale my image so that the character is the correct size for the game, as initially it was far too large.
        # The double slash rounds the number to the nearest integer, so there are no errors.
        image = pg.transform.scale(image, (width // 2, height // 2))
        return image
# The following section creates the image/character model e.g. size etc.
class Player(pg.sprite.Sprite):
    # The use of 'game' in the parameter below means that the player knows about the variables from the 'main page'.
    def __init__(self, game):
        # Adds the player class to the group.
        self.groups = game.all_sprites
        # Here we set up the Sprite object.
        pg.sprite.Sprite.__init__(self, self.groups)
        # The line below is a 'copy' or a referance that the player class can use so that it knows about the game.
        self.game = game
        # The following line lets the game know whether the player is walking.
        self.walking = False
        # The following line lets the game know whether the player is jumping.
        self.jumping = False
        # The following line asks the game what frame is currently playing.
        self.current_frame = 0
        # The following variable keeps track of what time we made the last change, as each frame would be too fast, (60 per second!)
        self.last_update = 0
        # We choose for the player's image to be at the forefront, rather than the background.
        # The load_images method is called shortly after this section of code.
        self.load_images()
        self.image = self.standing_frames[0]
        # The line below removes the unwanted border around the player's character.
        self.image.set_colorkey(BLACK)
        self.rect = self.image.get_rect()
        # For example, the next line determines where the center of the rectangle that we have just created is, so that the game knows how to affect movement/hitboxes for the player's character.
        self.rect.center = (WIDTH / 2, HEIGHT /2)
        self.pos = vec(WIDTH / 2, HEIGHT / 2)
        self.vel = vec(0, 0)
        self.acc = vec(0, 0)

        # The following method load_images allows me to load all of the frames that are used for the character's animation.
    def load_images(self):
        # I start with the two standing frames:
        self.standing_frames = [self.game.spritesheet.get_image(614, 1063, 120, 191),
                                self.game.spritesheet.get_image(690, 406, 120, 201)]
        for frame in self.standing_frames:
            frame.set_colorkey(BLACK)
        # Now I am going to assign my two walking frames for walking right:
        self.walk_frames_r = [self.game.spritesheet.get_image(678, 860, 120, 201),
                              self.game.spritesheet.get_image(692, 1458, 120, 207)]
        # Now walk frames for the left direction:
        self.walk_frames_l = []
        # Now we will append the right ones to the left facing lists, and flip them:
        for frame in self.walk_frames_r:
            frame.set_colorkey(BLACK)
        # Here the true and false represent whether I want a horizontal flip and then a vertical flip.
            self.walk_frames_l.append(pg.transform.flip(frame, True, False))
        # Now the jumping frame:
        self.jump_frame = self.game.spritesheet.get_image(382, 763, 150, 181)
        self.jump_frame.set_colorkey(BLACK)

        # The following is a jump function that allows the player to gain velocity in the upwards direction.
    def jump(self):
        # The line below makes the character collide with the platform, however there is no drawing so the player doesn't see this.
        self.rect.x += 1
        # The next line initiates the collision, as we have  done before. We collide the character with the game's platforms.
        hits = pg.sprite.spritecollide(self, self.game.platforms, False)
        # The following line means that our character is moved back up 3 spaces. The player never sees this because no drawing of it is done.
        self.rect.x -= 3
        # The next few lines mean that if there is collision, we can jump.
        if hits:
            # Now we play the jump sound at the same time as jumping:
            self.game.jump_sound.play()


        # The value below is the strength of the jump.
            self.vel.y = -PLAYER_JUMP

       # The next section creates player movement. E.g. when certain keys are pressed, the character moves in the corresponding direction.
    def update(self):
        # The following method animates and handles which frame we want to use:
        self.animate()

        # Below I have set vertical acceleration (gravity) to the variable PLAYER_GRAV, which can be found in the Settings page, allowing the character to fall.
        self.acc = vec(0, PLAYER_GRAV)
        keys = pg.key.get_pressed()
        # Here, if the left key is pressed, the player will move left and so on.
        if keys[pg.K_a]:
            self.acc.x = -PLAYER_ACC
        if keys[pg.K_d]:
            self.acc.x = PLAYER_ACC

        # Applies friction by reducing acceleration
        # By adding .x after self.acc and self.vel, gravity is allowed to work properly as we can speed up faster in the y direction.
        self.acc.x += self.vel.x * PLAYER_FRICTION
        # Equations of motion
        self.vel += self.acc
        # The following two lines mean that if we are moving less than 0.1 of a pixel per tick, the player's velocity will get set to 0. This is so that our walking animations stop when we are standing still.
        if abs(self.vel.x) < 0.1:
            # Velocity is set to 0.
            self.vel.x = 0
        self.pos += self.vel + 0.5 * self.acc
        #Wrap around the sides of the screen
        if self.pos.x > WIDTH:
            self.pos.x = 0
        if self.pos.x < 0:
            self.pos.x = WIDTH

        # The next line lets the game know that I want the center of the player's character to be considered the center of the screen.
        self.rect.midbottom = self.pos

     # The recently referred to animate method is used:
    def animate(self):
        # Find out how many ticks have occured since the game was opened:
        now = pg.time.get_ticks()

        # The following small section determines if the player is standing still or not.
        # Is the player still?
        if self.vel.x != 0:
            # If they are not still, then walking is true.
            self.walking = True
        else:
            # If they are still, then walking is false.
            self.walking = False

        # Show Walk Animation:
        if self.walking:
            # here we set the frequency of the occuring updates (milliseconds)
            if now - self.last_update > 100:
                # We call for an update
                self.last_update = now
                # We almost copy what we used for the update loop below
                self.current_frame = (self.current_frame + 1) % len(self.walk_frames_l)
                # We set the bottom of the sprite to the right location whilst we are walking
                bottom = self.rect.bottom
                # Before  we set the image for the next frame, we decide if we are walking left or right:
                if self.vel.x > 0:
                    # If our velocity is more than 0, we are clearly moving right
                    self.image = self.walk_frames_r[self.current_frame]
                else:
                    # If our velocity is less than 0, we are clearly moving left
                    self.image = self.walk_frames_l[self.current_frame]
                    # We request our new rectangle to find the bottom of the character with
                self.rect = self.image.get_rect()
                # We then set the bottom of the character's hitbox again.
                self.rect.bottom = bottom

        # If the player is idle, we want to display the standing frame:
        if not self.jumping and not self.walking:
            # The following is in milliseconds, and determines the time lapse since the last update:
            if now - self.last_update > 280:
                # We call for an update to occur now:
                self.last_update = now
                # Now we change the current frame.
                self.current_frame = (self.current_frame + 1) % len(self.standing_frames)
                # The bottom variable holds where the bottom of our player's rectangle needs to be.
                bottom = self.rect.bottom
                self.image = self.standing_frames[self.current_frame]
                # the following line gets the new rectangle for the new frame we switched to.
                self.rect = self.image.get_rect()
                # the next line keeps the 'bottom' variable that we had for the last frame.
                self.rect.bottom = bottom

 # The next class defines all of the platforms in the game.
class Platform(pg.sprite.Sprite):
    # The next line shows how when we want to create a new platform object, we will give it a x and a y coordinate, along with a width and a height.
    def __init__(self, game, x, y):
        # Adds the platform class to the group.
        self.groups = game.all_sprites, game.platforms
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        # First, we create the image.
        self.image = pg.Surface((w, h))
        # Hext, we choose a colour for the platform.
        self.image.fill(BROWN)
        # We make it a rectangular shape.
        self.rect = self.image.get_rect()
        # Then we place it at it's predetermined coordinates.
        self.rect.x = x
        self.rect.y = y

 #Powerups class
class Pow(pg.sprite.Sprite):
    # I pass the class 'self', 'game' and 'plat'.
    def __init__(self, game, plat):
        # I create my list of groups:
        self.groups = game.all_sprites, game.powerups
        # I then initialise them (including groups):
        pg.sprite.Sprite.__init__(self, self.groups)
        # The following line allows me to use 'game'
        self.game = game
        # The following line allows me to use 'plat'
        self.plat = plat
        # Now we need different types of platforms.
        # The first type I am creating is called 'boost', it will shoot the player upwards a litte bit.
        self.type = choice(['boost'])
        # This is the art that will be used for my 'boost' powerup.
        self.image = self.game.spritesheet.get_image(820, 1805, 71, 70)
        self.image.set_colorkey(BLACK)
        self.rect = self.image.get_rect()
        # The following line sets the powerup's location to the center of the platform.
        self.rect.centerx = self.plat.rect.centerx

        self.rect.bottom = self.plat.rect.top - 5


    def update(self):

        self.rect.bottom = self.plat.rect.top -5

        if not self.game.platforms.has(self.plat):
            # If this loop returns false, we will delete the powerup as well.
       self.kill()

设置:

>TITLE = "Survival Game"
WIDTH = 1000
HEIGHT = 800
FPS = 60

HS_FILE = "highscore.txt"


PLAYER_ACC = 0.5
PLAYER_FRICTION = -0.12


PLAYER_GRAV = 0.3
PLAYER_JUMP = 10
FONT_NAME = 'Echelon'
SPRITESHEET = "spritesheet_jumper.png"

# Starting platforms
# The following list includes all the platforms I am going to be using in my game, and each platform takes in four values each. The x and y coordinates, and also the height and width of the platforms themselves.
# (x, y, Width, Height)
PLATFORM_LIST = [
                # Floor platforms
                (0, HEIGHT - 40, WIDTH + 500, 40),
                (2200, HEIGHT - 40, WIDTH + 100, 40),
                (4000, HEIGHT - 40, WIDTH + 100, 40),
                (6000, HEIGHT - 40, WIDTH + 100, 40),

                # Starting 3 platforms
                 (650, HEIGHT - 125, WIDTH - 600, 20),
                 (650, HEIGHT - 250, WIDTH - 600, 20),
                 (650, HEIGHT - 375, WIDTH - 600, 20),
                 # Middle Layer of short platforms
                 (1100, HEIGHT - 250, WIDTH - 800, 30),
                 (1500, HEIGHT - 250, WIDTH - 800, 30),
                 (2000, HEIGHT - 250, WIDTH - 800, 30),
                 (2500, HEIGHT - 250, WIDTH - 800, 30),
                 (3000, HEIGHT - 250, WIDTH - 800, 30),
                 (3500, HEIGHT - 250, WIDTH - 800, 30),

                 # Lower Layer of short platforms
                 (1175, HEIGHT - 180, WIDTH - 800, 30),
                 (1575, HEIGHT - 180, WIDTH - 800, 30),
                 (2075, HEIGHT - 180, WIDTH - 800, 30),
                 (2575, HEIGHT - 180, WIDTH - 800, 30),
                 (3075, HEIGHT - 180, WIDTH - 800, 30),
                 (3575, HEIGHT - 180, WIDTH - 800, 30),

                 # Upper Layer of short platforms
                 (1150, HEIGHT - 320, WIDTH - 800, 30),
                 (1550, HEIGHT - 320, WIDTH - 800, 30),
                 (2050, HEIGHT - 320, WIDTH - 800, 30),
                 (2550, HEIGHT - 320, WIDTH - 800, 30),
                 (3050, HEIGHT - 320, WIDTH - 800, 30),
                 (3550, HEIGHT - 320, WIDTH - 800, 30),

                 # In between platforms (Lowest)
                 (1250, HEIGHT - 115, WIDTH - 800, 30),
                 (1750, HEIGHT - 115, WIDTH - 800, 30),
                 (2250, HEIGHT - 115, WIDTH - 800, 30),
                 (2750, HEIGHT - 115, WIDTH - 800, 30),
                 (3250, HEIGHT - 115, WIDTH - 800, 30),
                 (3750, HEIGHT - 115, WIDTH - 800, 30)

                 ]


WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
CYAN = (0, 255, 255)
BROWN = (200, 140, 101)

我注意到当我从中删除self参数时 PLATFORM_LIST:             Platform(self, *plat), 该错误变成了有5个参数(而不是6个)的事实,其中只有4个。

1 个答案:

答案 0 :(得分:2)

您必须将参数(game, x, y)传递给Platform构造函数。

*plat似乎是四个元素,而不是(x,y)对,因此您的错误显示为6

  • self(默认情况下已通过)
  • game
  • 再加上4个元素

这是相关代码

# (x, y, Width, Height)
PLATFORM_LIST = [
                # Floor platforms
                (0, HEIGHT - 40, WIDTH + 500, 40),
    ...
]

...

class Platform(pg.sprite.Sprite):
    def __init__(self, game, x, y):
        # ...

...        

for plat in PLATFORM_LIST:
    Platform(self, *plat)