pythonpygamegravity

How to make gravity function in pygame?


I was trying to create a simple physics system in pygame. My main goal was to add a Y gravity function that would move the player when activated. I have tried several times to make it work, but I guess I am missing something.

Here is the code:

class Physic:
    def __init__(self, color, master, type, sizeX, sizeY, pos=[0,0]):
        self.master = master
        self.color = color
        self.type = type
        self.sizeX = sizeX
        self.sizeY = sizeY
        self.x = pos[0]
        self.y = pos[1]

        self.moveX = 0
        self.moveY = 0

        self.create_Object()


    def create_Object(self):
        if self.type == 'rect':
            self.rect()

    def rect(self):
        return pygame.draw.rect(self.master, self.color, (self.x, self.y, self.sizeX, self.sizeY))

    def drag(self):
        for event in pygame.event.get():
            if event.type == pygame.mouse.get_pressed()[0]:
                self.x = pygame.mouse.get_pos()

    def add_gravity(self):
        self.moveY += 3.2
        self.update_pos()

    def update_pos(self):
        self.y += self.moveY
        self.x += self.moveX

In the main script I put this:

def game():
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()


        screen.fill(WHITE)

        player = object.Physic(BLUE, screen, 'rect', 50, 50, [POS[0], POS[1]])
        player.add_gravity()

        # platform = object.rect(screen, RED, [30, 30], 100, 30)

        # physics.add_collider(player, platform, POS[0])

        pygame.display.update()


game()

Do you know what I am missing?


Solution

  • Your big problem is that you are recreating the player every pass inside the main loop and so it looks like it is frozen in place.

    You also need to have a limit on the frame rate so that you control the speed of the game and therefor can properly set the acceleration per frame.

    There are a some other minor things that needed to be fixed to run this. I tried to change the minimum possible to run it, since the point was to fix the error rather than rewrite it on you. Obviously I had to add some wrapper code around it

    Try this slightly adjusted version:

    #!/usr/bin/env python
    
    import traceback
    import pygame
    import sys
    
    FRAME_RATE = 60
    GRAVITY = 32
    
    SCREEN_SIZE = (600, 800)
    
    WHITE = pygame.Color("white")
    BLUE = pygame.Color("blue")
    
    POS = (100, 600)
    
    class Physic:
        def __init__(self, color, master, type, sizeX, sizeY, pos=(0,0)):
            self.master = master
            self.color = color
            self.type = type
            self.sizeX = sizeX
            self.sizeY = sizeY
            self.x = pos[0]
            self.y = pos[1]
    
            self.moveX = 0
            self.moveY = 0
    
            self.create_Object()
    
    
        def create_Object(self):
            if self.type == 'rect':
                self.draw()
    
        def draw(self):
            return pygame.draw.rect(self.master, self.color, (self.x, self.y, self.sizeX, self.sizeY))
    
        def drag(self):
            for event in pygame.event.get():
                #if event.type == pygame.mouse.get_pressed()[0]:    <--- remove this
                if event.type == pygame.MOUSEBUTTONDOWN:
                    self.x = pygame.mouse.get_pos()
    
        def add_gravity(self):
            self.moveY += GRAVITY / FRAME_RATE
            self.update_pos()
    
        def update_pos(self):
            self.y += self.moveY
            self.x += self.moveX
    
    def game():
        
        pygame.init()
        screen = pygame.display.set_mode(SCREEN_SIZE)
    
        clock = pygame.time.Clock()
        
        player = Physic(BLUE, screen, 'rect', 50, 50, POS)
        # I added this to illustrate the gravity better ... going up and down
        player.moveY = -25
        player.moveX = 2
    
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    return
    
    
            screen.fill(WHITE)
    
            player.add_gravity()
    
            player.draw()
    
            # platform = object.rect(screen, RED, [30, 30], 100, 30)
    
    
            # physics.add_collider(player, platform, POS[0])
    
            pygame.display.update()
    
            clock.tick(FRAME_RATE)
    
    
    
    def main():
        
        try:
            game()
    
        except Exception as ex:
            print(traceback.format_exc())
            raise
    
        finally:
            # game exit cleanup stuff
            pygame.quit()
    
    
    if __name__ == '__main__':
        main()
    
    

    An issue that I want to point out though it is not affecting this code here. You should not use an immutable object (like a list) as an default when defining an optional/named argument in a method. I.e. in the Physic __init__() I changed pos=[0,0] to pos=(0,0). Not a big deal here, but can cause really odd bugs if you had assigned it to a var, then tried to change it. It will have effects on other instances of the object because they actually share the default initialization object and if it gets modified by one of them it happens in all of them!