Python Forum
[PyGame] How would I make my position variable more accurate?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[PyGame] How would I make my position variable more accurate?
#1
Currently, I have a variable that is supposed to exit the program once the player reaches a certain point, but my collision detection system is "fake" in the sense that the player can still move a bit after the collision. This causes my position variable to be off. Does anyone know how to add my correction variable to my position variables?


import pygame

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 255, 255)
 
DISPLAY_WIDTH = 800
DISPLAY_HEIGHT = 600
gameDisplay = pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_HEIGHT))

def textObjects(text, font):
    textSurface = font.render(text, True, BLACK)
    return textSurface, textSurface.get_rect()
def messageDisplay(text):
    largeText = pygame.font.Font('freesansbold.ttf', 115)
    textSurf, textRect = textObjects(text, largeText)
    textRect.center = ((DISPLAY_WIDTH/2), (DISPLAY_HEIGHT/2))
    gameDisplay.blit(textSurf, textRect)

    
class Player(pygame.sprite.Sprite):
 
    def __init__(self):
 

        super().__init__()
 

        width = 100
        height = 150
        self.image = pygame.Surface([width, height])
        self.image.fill(RED)
 

        self.rect = self.image.get_rect()
 

        self.xVel = 0
        self.yVel = 0
 

        self.level = None
 
    def update(self):
        self.calc_grav()
 

        self.level.bgX += self.xVel
 
 

        correction = 0
        block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
        for block in block_hit_list:
            if self.xVel < 0:
                self.friction()
                correction = self.rect.right - block.rect.left
            elif self.xVel > 0:
                self.friction()
                correction = self.rect.left - block.rect.right

        if correction != 0:
            for block in self.level.platform_list:
                block.rect.x += correction

 
        self.rect.y += self.yVel
 

        block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
        for block in block_hit_list:
            if self.yVel > 0:
                self.rect.bottom = block.rect.top
            if self.yVel < 0:
                self.rect.top = block.rect.bottom
 

            self.yVel = 0
 
            if isinstance(block, MovingPlatform):
                self.level.bgX += block.xVel
 
    def calc_grav(self):
        
        if self.yVel == 0:
            self.yVel = 1
        else:
            self.yVel +=0.3
 
        if self.rect.y >= DISPLAY_HEIGHT - self.rect.height and self.yVel >= 0:
            self.yVel = 0
            self.rect.y = DISPLAY_HEIGHT - self.rect.height
        
 
    def jump(self):
        self.rect.y += 2
        platform_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
        self.rect.y -= 2
 

        if len(platform_hit_list) > 0 or self.rect.bottom >= DISPLAY_HEIGHT:
            self.yVel = -10
 
    def moveLeft(self):

        self.xVel = 10
 
    def moveRight(self):

        self.xVel = -10
 
    def friction(self):

        self.xVel = 0
 
 
class Platform(pygame.sprite.Sprite):
 
    def __init__(self, width, height):
        super().__init__()
 
        self.image = pygame.Surface([width, height])
        self.image.fill(GREEN)
 
        self.rect = self.image.get_rect()
 
 
class MovingPlatform(Platform):

    xVel = 0
    yVel = 0
 
    boundary_top = 0
    boundary_bottom = 0
    boundary_left = 0
    boundary_right = 0
 
    player = None
 
    level = None
 
    def update(self):
        self.rect.x += self.xVel
        correction = 0
        hit = pygame.sprite.collide_rect(self, self.player)
        if hit:
            if self.xVel < 0:
                self.player.friction()
                correction = self.player.rect.right - self.rect.left
            elif self.xVel > 0:
                self.player.friction()
                correction = self.player.rect.left - self.rect.right

        if correction != 0:
            for block in self.level.platform_list:
                block.rect.x += correction
            
 
        self.rect.y += self.yVel
 

        hit = pygame.sprite.collide_rect(self, self.player)
        if hit:
            if self.yVel < 0:
                self.player.rect.bottom = self.rect.top
            else:
                self.player.rect.top = self.rect.bottom
 
        if self.rect.bottom > self.boundary_bottom or self.rect.top < self.boundary_top:
            self.yVel *= -1
        cur_pos = self.rect.x
        if cur_pos < self.boundary_left or cur_pos > self.boundary_right:#<-- [b]HERE IS WHERE I NEED TO ADD[/b]
            self.xVel *= -1
 
 
class Level(object):
 
    def __init__(self, player):
        self.platform_list = pygame.sprite.Group()
        self.enemy_list = pygame.sprite.Group()
        self.player = player
         
        self.background = None
     

        self.bgX = 0
        self.level_limit = -1000 #<-- [b]HERE IS WHERE I NEED TO ADD[/b]
 
    def update(self):
        self.platform_list.update()
        self.enemy_list.update()
 
    def draw(self, screen):
 
        screen.fill(BLUE)
 

        self.platform_list.draw(screen)
        self.enemy_list.draw(screen)

        for platform in self.platform_list:
            platform.rect.x += self.player.xVel
 
        for enemy in self.enemy_list:
            enemy.rect.x += self.player.xVel
 
class Level_01(Level):
 
    def __init__(self, player):
 

        Level.__init__(self, player)
 
        self.level_limit = -1500 #<-- [b]HERE IS WHERE I NEED TO ADD[/b]
 

        level = [[210, 70, 500, 500],
                 [210, 70, 800, 400],
                 [210, 70, 1000, 500],
                 [210, 70, 1120, 280],
                 ]
 

        for platform in level:
            block = Platform(platform[0], platform[1])
            block.rect.x = platform[2]
            block.rect.y = platform[3]
            block.player = self.player
            self.platform_list.add(block)
 

        block = MovingPlatform(100, 40)
        block.rect.x = 1350
        block.rect.y = 280
        block.boundary_left = 1350
        block.boundary_right = 1600
        block.xVel = -1
        block.player = self.player
        block.level = self
        self.platform_list.add(block)
 
 
class Level_02(Level):
 
    def __init__(self, player):
 
        Level.__init__(self, player)
 
        self.level_limit = -1500#<-- [b]HERE IS WHERE I NEED TO ADD[/b]
 

        level = [[210, 70, 500, 550],
                 [210, 70, 800, 400],
                 [210, 70, 1000, 500],
                 [210, 70, 1120, 280],
                 ]
 

        for platform in level:
            block = Platform(platform[0], platform[1])
            block.rect.x = platform[2]
            block.rect.y = platform[3]
            block.player = self.player
            self.platform_list.add(block)
 
        block = MovingPlatform(70, 70)
        block.rect.x = 1500
        block.rect.y = 300
        block.boundary_top = 100
        block.boundary_bottom = 550
        block.yVel = -1
        block.player = self.player
        block.level = self
        self.platform_list.add(block)
 
 
def main():
    pygame.init()
 

    size = [DISPLAY_WIDTH, DISPLAY_HEIGHT]
    screen = pygame.display.set_mode(size)
 
    pygame.display.set_caption("Platformer with moving platforms")
 
    player = Player()
 
    level_list = []
    level_list.append(Level_01(player))
    level_list.append(Level_02(player))
 
    current_level_no = 0
    current_level = level_list[current_level_no]
 
    active_sprite_list = pygame.sprite.Group()
    player.level = current_level
 
    player.rect.x = 350
    player.rect.y = DISPLAY_HEIGHT - player.rect.height
    active_sprite_list.add(player)
 

    done = False
 

    clock = pygame.time.Clock()
 
    # -------- Main Program Loop -----------
    while not done:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done = True
 
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    player.moveLeft()
                if event.key == pygame.K_RIGHT:
                    player.moveRight()
                if event.key == pygame.K_UP:
                    player.jump()
 
            if event.type == pygame.KEYUP:
                if event.key == pygame.K_LEFT and player.xVel > 0:
                    player.friction()
                if event.key == pygame.K_RIGHT and player.xVel < 0:
                    player.friction()
 
        active_sprite_list.update()
 
        current_level.update()
 

        current_position = current_level.bgX 
        if current_position < current_level.level_limit:#<-- [b]HERE IS WHERE I NEED TO ADD[/b]
            if current_level_no < len(level_list)-1:
                player.rect.x = 350
                current_level_no += 1
                current_level = level_list[current_level_no]
                player.level = current_level
            else:

                done = True
 

        current_level.draw(screen)
        active_sprite_list.draw(screen)
 

        clock.tick(60)
 

        pygame.display.flip()
 
    pygame.quit()
 
if __name__ == "__main__":
    main()
I've added "here is where I need to add" to where I need to add it
Reply
#2
What you have works. Add this line to your loop:
print(current_position,current_level.level_limit)
You go to the right, it hits the limit and the level changes. As for your position changing when it shouldn't, that's the exact same problem you had with platform collision. If you don't fix that properly, you'll have this problem with everything you add to the game.

The solution is to have a proper move function with a collision check. As I said last time, you are just going to keep replacing one bug with another.

What did you want to trigger the program to end?
Reply
#3
The problem is that if you go to a block and repeatedly press the right or left arrow keys it messes up the level ending point, so you could theoretically finish a level just by running into a block repeatedly
Reply
#4
(Dec-30-2019, 09:39 PM)HelpMEE Wrote: The problem is that if you go to a block and repeatedly press the right or left arrow keys it messes up the level ending point, so you could theoretically finish a level just by running into a block repeatedly

Exactly. You need to check to see if you are hitting a block BEFORE you change the current_position. The solution is exactly the same as when you asked about colliding with platforms last time. This is the same problem as then and the same solution as then. The internet is awash with pygame platformer tutorials and examples. If you insist on writing a game differently than everyone else and not having proper collision detection, you'll have problems every step along the way and your program will break whenever you want to change something.

The problem isn't your current_position variable, it's your approach. It's a safe bet you've spent way more time on finding temporary "fixes" than it would take to do it right. Especially at a beginner level, the answer to "how to do something?" is "the way that it's been done". It's why tutorials are a standard method and it's the experts that write the books. You aren't trying to do anything new.


"In order to break the rules, you must first know why they are rules"
- Every expert on everything ever.
Reply
#5
If you copy and paste this one file and run it, it will show you a basic platofrmer with moving platforms example. You can look through the code. I would strictly follow this process to have the most ease at programming platforms.
Recommended Tutorials:
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [split] Accurate Clicks Per Second Hamti 5 3,958 Sep-06-2022, 07:14 AM
Last Post: zackwang
  [split] Accurate Clicks Per Second kathyalex 4 3,156 Feb-16-2021, 04:27 PM
Last Post: SheeppOSU
  Accurate Clicks Per Second JudyLarose 8 9,366 Feb-10-2021, 03:00 AM
Last Post: deanhystad

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020