繁体   English   中英

Pygame 碰撞面具:精灵和地面

[英]Pygame collision masks: sprite and ground

我正在 pygame 中开发游戏。 我有一个角色精灵和一个地面,它们都是图像。 我想使用掩码检测这些对象之间的碰撞。 这是我的代码:

import pygame
import os
import sys
import time
import gradients


pygame.init()

#window size
screen_width = 1080
screen_height = 720
monitor_size = [pygame.display.Info().current_w, pygame.display.Info().current_h]

win = pygame.display.set_mode((screen_width, screen_height), pygame.RESIZABLE)
fullscreen = False
in_options = False


pygame.display.set_caption("Pokemon Firered")




#time for FPS management
clock = pygame.time.Clock()



class character(object):
    def __init__(self,x,y):
        self.left = [pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_1.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_2.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_3.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_4.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_5.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_6.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_7.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_8.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_9.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_10.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_11.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_12.png")).convert_alpha()]
        self.right = [pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_1.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_2.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_3.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_4.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_5.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_6.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_7.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_8.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_9.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_10.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_11.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_12.png")).convert_alpha()]

        self.x = x
        self.y = y
        self.is_right = False
        self.is_left = True
        self.is_jump = False
        self.velocity = 5
        self.walk_count = 0
        self.jump_count= 10
        self.latest_direction = "left"
        self.border = 1000
        if self.latest_direction == "left":
            self.mask = pygame.mask.from_surface(self.left[self.walk_count])
        if self.latest_direction == "right":
            self.mask = pygame.mask.from_surface(self.right[self.walk_count])

    def jump(self, win):
        neg = 1
        if self.jump_count >= -10:
            if self.jump_count < 0:
                neg = -1  
            self.y -= (self.jump_count**2)//2.5 * neg
            self.jump_count -= 1
        else:
            self.is_jump = False
            self.jump_count = 10

    def movement(self, win):
        keys = pygame.key.get_pressed() #keyboard input
        if keys[pygame.K_a] and self.x > -20:
            self.is_left = True
            self.is_right = False
            self.latest_direction = "left"
            self.x -= self.velocity
        elif keys[pygame.K_d] and self.x < self.border:
            self.is_left = False
            self.is_right = True
            self.latest_direction = "right"
            self.x += self.velocity
        else:
            self.is_left = False
            self.is_right = False
        if keys[pygame.K_SPACE] and self.x > 5:
            self.is_jump = True

        if self.is_jump:    
            self.jump(win)

    def draw(self, win):
        if self.walk_count + 1 >= 36:
            self.walk_count = 0
        if self.is_left:
            win.blit(self.left[self.walk_count//3], (self.x, self.y))
            self.walk_count += 1
        elif self.is_right:
            win.blit(self.right[self.walk_count//3], (self.x, self.y))
            self.walk_count += 1
        elif self.is_jump:
            if self.latest_direction == "left":
                win.blit(self.left[self.walk_count//3], (self.x, self.y))
            if self.latest_direction == "right":
                win.blit(self.right[self.walk_count//3], (self.x, self.y))
        else:
            if self.latest_direction == "left":
                win.blit(self.left[3], (self.x, self.y))
            if self.latest_direction == "right":
                win.blit(self.right[3], (self.x, self.y))



avatar = character(500, 350)

class controls_panel(object):
    #controls panel

class ground(object):
    def __init__(self):
        self.ground = pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Background", "ground.png")).convert_alpha()
        self.mask = pygame.mask.from_surface(self.ground)

    def draw(self, win):
        #ground
        ground_height = 502
        ground_width = 590
        repeat = screen_width//590+1
        for i in range(repeat):
            win.blit(self.ground, (0+590*i,ground_height))
            ground_width = 590*(i+1)


ground = ground()


def event_handling(win):
    global fullscreen
    global run
    global screen_width
    global in_options
    for event in pygame.event.get():
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_ESCAPE:
                run = False
        if event.type == pygame.VIDEORESIZE:
            if not fullscreen:
                screen = pygame.display.set_mode((event.w, event.h), pygame.RESIZABLE)
                avatar.border = event.w-75
                screen_width = event.w
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_f:
                fullscreen = not fullscreen
                if fullscreen:
                    screen = pygame.display.set_mode(monitor_size, pygame.FULLSCREEN)
                else:
                    screen = pygame.display.set_mode((screen.get_width(), screen.get_height()), pygame.RESIZABLE)
            if event.key == pygame.K_e:
                in_options = not in_options

#texts
font = pygame.font.SysFont(None, 25)
def print_text(msg, colour, cords):
    text = font.render(msg, True, colour)
    win.blit(text, cords)

def options(win):
    #options menu


def redraw_game_window():
    event_handling(win)
    #display background
    #win.fill(0)


    #win.fill(0)

    background_gradient = gradients.vertical([screen_width, screen_height], (209, 77, 135, 255), (249, 175, 88, 255))
    win.blit(background_gradient, (0,0))

    #ground
    ground.draw(win)

    if pygame.sprite.spritecollide(avatar, ground, False, pygame.sprite.collide_mask):
        print(True)

    #options
    if in_options:
     options(win)

    #ingame controls 
    controls_panel.input(win)

    #character
    avatar.movement(win)
    avatar.draw(win)

    pygame.display.update()

run = True
while run:
    clock.tick(36) #FPS rate
    redraw_game_window()




#Mainloop End 
pygame.quit()

它仍然很乱,因为我刚刚开始,我留下了一些不必要的部分以使其更清晰。 当我尝试检测 redraw_game_window() function 中的碰撞时,我收到以下错误消息:

回溯(最后一次调用):文件“c:/Users/Pc/Desktop/Python/Games/Game Engine/First Game.py”,第 234 行,在 redraw_game_window() 文件“c:/Users/Pc/Desktop/ Python/Games/Game Engine/First Game.py", line 215, in redraw_game_window if pygame.sprite.spritecollide(avatar, ground, False, pygame.sprite.collide_mask): 文件 "C:\Data\Users\Pc \Python\Python37\site-packages\pygame\sprite.py", line 1532, in spritecollide return [s for s in group if collided(sprite, s)] TypeError: 'ground' object is not iterable

我试过的:

  • 使用矩形作为掩码(产生相同的错误)

有谁知道我做错了什么?

------

更新的课程:

class character(pygame.sprite.Sprite):
    def __init__(self,x,y):
        pygame.sprite.Sprite.__init__(self)
        self.left = [pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_1.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_2.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_3.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_4.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_5.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_6.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_7.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_8.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_9.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_10.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_11.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Left", "left_12.png")).convert_alpha()]
        self.left_masks = []
        for i in range(len(self.left)):
            self.left_masks.append(pygame.mask.from_surface(self.left[i]))
        self.right = [pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_1.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_2.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_3.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_4.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_5.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_6.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_7.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_8.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_9.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_10.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_11.png")).convert_alpha(), pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Character\Right", "right_12.png")).convert_alpha()]
        self.right_masks = []
        for i in range(len(self.right)):
            self.right_masks.append(pygame.mask.from_surface(self.right[i]))

        self.max_frames = len(self.left)
        self.image = self.left[0]
        self.mask = self.left_masks[0]
        self.rect = self.image.get_rect()
        self.rect_center = (x, y)

        self.x = x
        self.y = y
        self.is_right = False
        self.is_left = True
        self.is_jump = False
        self.velocity = 5
        self.walk_count = 0
        self.jump_count= 10
        self.latest_direction = "left"
        self.border = 1000


    def jump(self, win):
        neg = 1
        if self.jump_count >= -10:
            if self.jump_count < 0:
                neg = -1  
            self.y -= (self.jump_count*self.jump_count//1.5)//2.5 * neg
            self.jump_count -= 1
        else:
            self.is_jump = False
            self.jump_count = 10

    def movement(self, win):
        keys = pygame.key.get_pressed() #keyboard input
        if keys[pygame.K_a] and self.x > -20:
            self.is_left = True
            self.is_right = False
            self.latest_direction = "left"
            self.x -= self.velocity
        elif keys[pygame.K_d] and self.x < self.border:
            self.is_left = False
            self.is_right = True
            self.latest_direction = "right"
            self.x += self.velocity
        else:
            self.is_left = False
            self.is_right = False
        if keys[pygame.K_SPACE] and self.x > 5:
            self.is_jump = True

        if self.is_jump:    
            self.jump(win)

    def draw(self, win):
        self.hand_left = [(self.x+43, self.y+82), (self.x+41, self.y+82), (self.x+40, self.y+82), (self.x+35, self.y+77), (self.x+33, self.y+74), (self.x+30, self.y+74)]
        self.hand_right = [(self.x+45, self.y+73)]

        center_point = self.rect_center

        if self.walk_count + 1 >= 36:
            self.walk_count = 0
        if self.is_left:
            win.blit(self.left[self.walk_count//3], (self.x, self.y))
            self.rect = self.left[self.walk_count//3]
            self.walk_count += 1
            #item
            win.blit(item_flask.image, (self.hand_left[self.walk_count//6]))
        elif self.is_right:
            win.blit(self.right[self.walk_count//3], (self.x, self.y))
            self.rect = self.left[self.walk_count//3]
            self.walk_count += 1
        elif self.is_jump:
            if self.latest_direction == "left":
                win.blit(self.left[self.walk_count//3], (self.x, self.y))
                self.rect = self.left[self.walk_count//3]
            if self.latest_direction == "right":
                win.blit(self.right[self.walk_count//3], (self.x, self.y))
                self.rect = self.left[self.walk_count//3]
        else:
            if self.latest_direction == "left":
                win.blit(self.left[3], (self.x, self.y))
                self.rect = self.left[self.walk_count//3]
            if self.latest_direction == "right":
                win.blit(self.right[3], (self.x, self.y))
                self.rect = self.left[self.walk_count//3]

        self.rect_center = center_point

        #pygame.draw.rect(win, (25, 25, 25), pygame.Rect(self.x+30, self.y+74, 10, 10))

avatar = character(500, 350)

class ground(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.ground = pygame.image.load(os.path.join("Desktop\Python\Games\Game Engine\Background", "ground.png")).convert_alpha()
        self.mask = pygame.mask.from_surface(self.ground)

    def draw(self, win):
        #ground
        ground_height = 502
        ground_width = 590
        win.blit(self.ground, (590/2, ground_height))

def redraw_game_window():
    event_handling(win)
    #display background                    


    background_gradient = gradients.vertical([screen_width, screen_height], (209, 77, 135, 255), (249, 175, 88, 255))
    win.blit(background_gradient, (0,0))

#COLLISION TESTING
    if pygame.sprite.spritecollide(avatar, ground, False, pygame.sprite.collide_mask):
        print(True)


    #ground
    ground.draw(win)



    #options
    if in_options:
     options(win)


    #character
    avatar.movement(win)
    avatar.draw(win)

    pygame.display.update()

run = True
while run:
    clock.tick(36) #FPS rate
    redraw_game_window()




#Mainloop End 
pygame.quit()

该代码在不是 PyGame 精灵的对象上使用 PyGame 精灵库 spritecollide() function。 如果您想制作自己的精灵,您应该添加和维护Rect对象以允许代码使用Rect.collide函数集。

但是将现有的类似精灵的对象转换为正式的 PyGame 精灵会更容易和更快。 这意味着继承基础Sprite class,并覆盖某些函数和成员变量。 使用 Sprite class 是(恕我直言)最简单和最好的前进方式

class CharacterSprite( pygame.sprite.Sprite ):
    def __init__(self, x, y, image_path ):
        pygame.sprite.Sprite.__init__( self )
        self.left_frames  = []
        self.left_masks   = []
        self.right_frames = []
        self.right_masks  = []
        # Load the walking animation
        for i in range( 4 ):
            image_name = "left_%1.png" % (i)
            image_path = os.path.join( image_path, image_name )
            self.left_frames.append( pygame.image.load( image_path ).convert_alpha() )
            self.left_masks.append( pygame.mask.from_surface( self.left_frames[-1] )
            image_name = "right_%1.png" % (i)
            image_path = os.path.join( image_path, image_name )
            self.right_frames.append( pygame.image.load( image_path ).convert_alpha() )
            self.right_masks.append( pygame.mask.from_surface( self.right_frames[-1] )
        self.max_frames  = len( self.left_frames )
        self.frame_count = 0
        self.image = self.left_frames[0]
        self.mask  = self.left_masks[0]
        self.rect  = self.image.get_rect()   # position is always maintained in the sprite.rect
        self.rect.center = ( x, y )
        # Various Stats
        self.is_left    = True
        self.is_jump    = False
        self.velocity   = 5


    def update( self ):
        """ Choose the correct animation frame to show """
        centre_point = self.rect.center
        if ( self.is_left ):
            self.image   = self.left_frames[ self.frame_count ]
            self.mask    = self.left_masks[ self.frame_count ]
        else:
            self.image   = self.right_frames[ self.frame_count ]
            self.mask    = self.right_masks[ self.frame_count ]
        self.rect        = self.image.get_rect()
        self.rect.center = centre_point

    def movement( self ):
        """ handle changes of movement an the animation """
        # handle the movement and animation
        keys = pygame.key.get_pressed() #keyboard input
        if ( keys[pygame.K_d] and self.rect.x < self.border ):  # RIGHT
            if ( self.is_left ):
                # turned to the right
                self.is_left = False
                self.frame_count = 0
            else:
                # continue right
                self.frame_count += 1
                if ( frame_count >= self.max_frames ):
                    frame_count = 0
            self.x += self.velocity
        elif ( keys[pygame.K_a] and self.rect x > -20 ):   # LEFT
            if ( self.is_left ):
                # continue left
                self.frame_count += 1
                if ( frame_count >= self.max_frames ):
                    frame_count = 0
            else:
                # turned to the left
                self.is_left = True
                self.frame_count = 0
            self.x -= self.velocity

为简洁起见,我没有转换跳转功能。 您还需要对平台进行类似的更改。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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