Learning about multiple arguments in a function

Hey all,

Fresh n00b here. I’ve been playing around with some tutorials on how to make a 2D game, and I’m trying to dive a little bit deeper into the physics of character movement. First, I reckon I’l post what I have, then ask my question.

import pygame
from pygame.locals import *


pygame.init()

clock = pygame.time.Clock()
fps = 60
player_speed = 3
walk_acc = 0
run_acc = 0



screen_width = 700
screen_height = 700

screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption('Platformer')

#define game variables
tile_size = 35


#load images
sun_img = pygame.image.load('img/sun.png')
bg_img = pygame.image.load('img/sky.png')
class Player():
    def __init__(self, x, y):
        self.images_right = []
        self.images_left = []
        self.index = 0
        self.counter = 0
        for num in range(1, 5):
            img_right = pygame.image.load(f'img/guy{num}.png')
            img_right = pygame.transform.scale(img_right, (28, 56))
            img_left = pygame.transform.flip(img_right, True, False)
            self.images_right.append(img_right)
            self.images_left.append(img_left)
        self.image = self.images_right[self.index]    
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.vel_y = 0
        self.jumped = False
        self.direction = 1
        
    def update(self, walk_acc, run_acc):
        dx = 0
        dy = 0
        walk_cooldown = 4

    
        #get keypresses
        key = pygame.key.get_pressed()       
        if self.rect.bottom < screen_height - tile_size:
            self.jumped = True
        if key[pygame.K_SPACE] and self.jumped == False:
            self.vel_y = -15
            self.jumped = True 
        if key[pygame.K_SPACE] == False:
            self.jumped = False    
        if key[pygame.K_LEFT] and self.direction == 1:
            walk_cooldown = 0
        if key[pygame.K_RIGHT] and self.direction == -1:   
            walk_cooldown = 0         
        if key[pygame.K_LEFT]:
            walk_acc += 1
            if walk_acc > 3:
                walk_acc = 3
            if key[pygame.K_LSHIFT] and key[pygame.K_LEFT]:
                run_acc += 1
                if run_acc > 7:
                    run_acc = 7      
            dx -= player_speed + walk_acc + run_acc
            self.counter +=1
            self.direction = -1
        if key[pygame.K_RIGHT]:
            walk_acc += 1
            if walk_acc > 3:
                walk_acc = 3
            if key[pygame.K_LSHIFT] and key[pygame.K_RIGHT]:
                run_acc += 1
                if run_acc > 7:
                    run_acc = 7       
            dx += player_speed + walk_acc + run_acc
            self.counter += 1
            self.direction = 1
        if key[pygame.K_LSHIFT] == False and key[pygame.K_RIGHT] == False and key[pygame.K_LEFT] == False:
                walk_acc -= 1
                run_acc -= 1
                if walk_acc < 0:
                    walk_acc = 0
                if run_acc < 0:
                    run_acc = 0             
        if key[pygame.K_LEFT] == False and key[pygame.K_RIGHT] == False:
            self.counter = 0
            self.index = 0
            if self.direction == 1:    
                self.image = self.images_right[self.index]
            if self.direction == -1:    
                self.image = self.images_left[self.index]
        if key[pygame.K_LEFT] == True and key[pygame.K_RIGHT] == True:
            self.counter = 0
            self.index = 0
            if self.direction == 1:    
                self.image = self.images_right[self.index]
            if self.direction == -1:    
                self.image = self.images_left[self.index]                

        #handle animations
        if self.counter > walk_cooldown:
            self.counter = 0
            self.index += 1
            if self.index >= len(self.images_right):
                self.index = 0
            if self.direction == 1:    
                self.image = self.images_right[self.index]
            if self.direction == -1:    
                self.image = self.images_left[self.index]    

        #add gravity
        self.vel_y += 1
        if self.vel_y > 10:
            self.vel_y = 10
        dy += self.vel_y

        #check for collision


        #update player coordinates
        self.rect.x += dx
        self.rect.y += dy

        if self.rect.bottom > screen_height - tile_size:
            self.rect.bottom = screen_height - tile_size
            dy = 0
            



        #draw player onto screen
        screen.blit(self.image, self.rect) 
        print(walk_acc)
        print(run_acc)
        return walk_acc
        return run_acc   

class World():
    def __init__(self, data):
        self.tile_list = []

        #load images
        dirt_img = pygame.image.load('img/dirt.png')
        grass_img = pygame.image.load('img/grass.png')

        row_count = 0
        for row in data:
            col_count = 0
            for tile in row:
                if tile == 1:
                    img = pygame.transform.scale(dirt_img, (tile_size, tile_size))
                    img_rect = img.get_rect()
                    img_rect.x = col_count * tile_size
                    img_rect.y = row_count * tile_size
                    tile = (img, img_rect)
                    self.tile_list.append(tile)
                if tile == 2:
                    img = pygame.transform.scale(grass_img, (tile_size, tile_size))
                    img_rect = img.get_rect()
                    img_rect.x = col_count * tile_size
                    img_rect.y = row_count * tile_size
                    tile = (img, img_rect)
                    self.tile_list.append(tile)    
                col_count += 1
            row_count += 1  

    def draw(self):
        for tile in self.tile_list:
            screen.blit(tile[0], tile[1])
                          

world_data =[
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
]


player = Player(70, screen_height - 91)
world = World(world_data)


run = True
while run:
    clock.tick(fps)
    screen.blit(bg_img, (0, 0))
    screen.blit(sun_img, (100, 75))

    world.draw()
    
    walk_acc = player.update(walk_acc, run_acc)
    run_acc = player.update(walk_acc, run_acc)
    
    for event in pygame.event.get():
        key = pygame.key.get_pressed() 
        if event.type == pygame.QUIT:
            run = False
    pygame.display.update()        

pygame.quit()

Hopefully that formatted correctly. So my question is this:

Initially I had the update function only take two arguments, self and acc (acceleration). In my game loop, I had acc = player.update(acc) and with a few tweaks, everything worked fine. I would press LSHIFT and acc would increment, and decrement when it was not held. Now that there are 3 args for update, I’m not quite sure of the syntax of the stuff that I have in the main game loop.

I know this code probably looks really ugly, but, it’s a start. Any pointers? Basically I’m trying to increment walk_acc and run_acc using the update function.

Fresh n00b here. I’ve been playing around with some tutorials on how to
make a 2D game, and I’m trying to dive a little bit deeper into the
physics of character movement. First, I reckon I’l post what I have,
then ask my question.

Hopefully that formatted correctly. So my question is this:

BTW, Apparently “```py” gets nice syntax highlighting (there are 3
backticks there, in case this gets mangled). But the formatting looked
fine to me (reading the post via email).

Initially I had the update function only take two arguments, self and
acc (acceleration). In my game loop, I had acc = player.update(acc) and
with a few tweaks, everything worked fine. I would press LSHIFT and acc
would increment, and decrement when it was not held. Now that there are
3 args for update, I’m not quite sure of the syntax of the stuff that I
have in the main game loop.

Looks fine to me. With a class method defined as:

class Player:
    def method(self, blah,blah,...):

when you call it with an instance:

player.method(1,2,3)

it implicitly takes “player” and supplied it as “self” in the method. So
if you defined the method with 3 arguments (self,walk_acc,run_acc) then
you call it with 2 arguments:

player.update(walk_acc,run_acc)

Also, note that Python, if you get the number of arguments wrong, python
will complain that “update” expects 3 arguments but got (whatever).
because the method itself has 3 parameters. You call it with 2 (one
fewer).

I know this code probably looks really ugly, but, it’s a start. Any
pointers? Basically I’m trying to increment walk_acc and run_acc using
the update function.

Does it work? Looks ok to me.

That said, I’ll insert a few random comments in the code below. But it
basicly looks good to me.

class Player():

You don’t need the brackets if there are no superclasses.

def update(self, walk_acc, run_acc):
dx = 0
dy = 0
walk_cooldown = 4

   #get keypresses
   key = pygame.key.get_pressed()
   if self.rect.bottom < screen_height - tile_size:
       self.jumped = True
   if key[pygame.K_SPACE] and self.jumped == False:
       self.vel_y = -15
       self.jumped = True
   if key[pygame.K_SPACE] == False:
       self.jumped = False
   if key[pygame.K_LEFT] and self.direction == 1:

Purely style, but I would write this as:

if self.direction == 1 and key[pygame.K_LEFT]:

in that I’d be thinking “here is code for direction=1”: if K_LEFT: do
this.

       walk_cooldown = 0
   if key[pygame.K_RIGHT] and self.direction == -1:
       walk_cooldown = 0
   if key[pygame.K_LEFT]:
       walk_acc += 1
       if walk_acc > 3:
           walk_acc = 3

You can shorten this to:

walk_acc = min(walk_acc + 1, 3)

There’s a bultin max() as well.

       if key[pygame.K_LSHIFT] and key[pygame.K_LEFT]:

You don’t need and “key[pygame.K_LEFT]” here - you’re inside that test
already, so it must be true.

   if key[pygame.K_LSHIFT] == False and key[pygame.K_RIGHT] == 
   False and key[pygame.K_LEFT] == False:

We don’t test “key[pygame.K_LSHIFT==False” in Python, rather “not
key[pygame.K_LSHIFT]”. So if not this and not that and not the_other.

           walk_acc -= 1
           run_acc -= 1
           if walk_acc < 0:
               walk_acc = 0
           if run_acc < 0:
               run_acc = 0
   if key[pygame.K_LEFT] == False and key[pygame.K_RIGHT] == False:
       self.counter = 0
       self.index = 0
       if self.direction == 1:
           self.image = self.images_right[self.index]
       if self.direction == -1:
           self.image = self.images_left[self.index]
   if key[pygame.K_LEFT] == True and key[pygame.K_RIGHT] == True:

Again, “if key[pygame.K_LEFT] and key[pygame.K_RIGHT]”.

       self.counter = 0
       self.index = 0
       if self.direction == 1:
           self.image = self.images_right[self.index]
       if self.direction == -1:
           self.image = self.images_left[self.index]

   #handle animations
   if self.counter > walk_cooldown:
       self.counter = 0
       self.index += 1
       if self.index >= len(self.images_right):
           self.index = 0
       if self.direction == 1:
           self.image = self.images_right[self.index]
       if self.direction == -1:
           self.image = self.images_left[self.index]

   #add gravity
   self.vel_y += 1
   if self.vel_y > 10:
       self.vel_y = 10

You can use min() again here.

Otherwise it all looks quite good.

Cheers,
Cameron Simpson cs@cskk.id.au