简体   繁体   中英

Clipping through platforms in Pygame (Python 3.4)

I'm making a simple platformer, and all seems to be working, however if I stand on one of my platforms for a few seconds, I'll suddenly clip through it.

If someone could take a look at my code and tell me where I'm going wrong, that would be nice.

import pygame
from random import randint

#initialize pygame - required for the module to begin working
pygame.init()

#define several basic colors for use in the form of tuples
WHITE = 255, 255, 255
BLACK = 0, 0, 0,
RED = 255, 0, 0
GREEN = 0, 255, 0
BLUE = 0, 0, 255

#define screen size as a tuple
screen_size = 500, 500
#open a window using screen size as parameters
screen = pygame.display.set_mode(screen_size)
#set a caption for the window
pygame.display.set_caption("Shooter Game")

#set a boolean as a condition for our loop
done = False
#set a clock to control frames per second
clock = pygame.time.Clock()

#define pygame groups to hold sprites
block_list = pygame.sprite.Group()
player_list = pygame.sprite.Group()

def build_level(level):
    for platform in level:
        block = Block(platform[0], platform[1])
        block.rect.x = platform[2]
        block.rect.y = platform[3]
        block_list.add(block)

#define a class for blocks
class Block(pygame.sprite.Sprite):
    #set the initialization function which takes color and size
    def __init__(self, width, height):
        #call the __init__ function of the parent Sprite class
        super().__init__()
        #define variables from parameters
        self.width = width
        self.height = height

        #create a surface to draw on
        self.image = pygame.Surface([width, height])
        self.image.fill(BLUE)
        #fill in that surface

        #create a rectangle out of the image so it can be moved around
        self.rect = self.image.get_rect()

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

        self.color = color

        self.change_x = 0
        self.change_y = 0

        self.image = pygame.Surface([16, 48])
        self.image.fill(color)

        self.rect = self.image.get_rect()

    def go_left(self):
        self.change_x = -3
    def go_right(self):
        self.change_x = 3
    def jump(self):
        self.rect.y += 2
        block_hit_list = pygame.sprite.spritecollide(self, block_list, False)
        self.rect.y -= 2

        if len(block_hit_list) > 0:
            self.change_y = -10

    def stop(self):
        self.change_x = 0
    def gravity(self):
        if self.change_y == 0:
            self.change_y = 1
        else:
            self.change_y += 0.35
    def update(self):
        self.gravity()

        self.rect.x += self.change_x
        block_hit_list = pygame.sprite.spritecollide(self, block_list, False)
        for block in block_hit_list:
            if self.change_x > 0:
                self.rect.right = block.rect.left
            elif self.change_x < 0:
                self.rect.left = block.rect.right

        self.rect.y += self.change_y
        block_hit_list = pygame.sprite.spritecollide(self, block_list, False)
        for block in block_hit_list:
            if self.change_y > 0:
                self.rect.bottom = block.rect.top
                print("collision")
            elif self.change_y < 0:
                self.rect.top = block.rect.bottom
                print("smollision")



player = Player(WHITE)
player.rect.x, player.rect.y = 100, 300
player_list.add(player)


#width, height, x, y
build_level([[300, 20, 100, 450], [200, 20, 150, 360]])

#loop continues as long as done is false
while not done:
    #every time there is an event, run it through this for loop
    for event in pygame.event.get():
        #if you click quit, exit the loop
        if event.type == pygame.QUIT:
            done = True
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_a:
                player.go_left()
            elif event.key == pygame.K_d:
                player.go_right()
            elif event.key == pygame.K_SPACE:
                player.jump()
        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_a or event.key == pygame.K_d:
                player.stop()
    #set a blank canvas to draw up
    screen.fill(BLACK)


    player_list.update()
    player_list.draw(screen)
    block_list.draw(screen)


    #display all the things put onto the screen
    pygame.display.flip()
    #set the game to 60 frames per second
    clock.tick(120)

You need to set change_y to 0 every time collision or smollision happens:

for block in block_hit_list:
    if self.change_y > 0:
        self.rect.bottom = block.rect.top
        self.change_y = 0
    elif self.change_y < 0:
        self.rect.top = block.rect.bottom
        self.change_y = 0

Explanation: if you don't do it change_y is constantly getting bigger and it becomes so big pygame.sprite.spritecollide doesn't detect collision.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM