Хитбокс с пиктограммами спрайтов - PullRequest
0 голосов
/ 31 мая 2018

Я сделал простую игру, где вы должны перепрыгивать через камни, движущиеся к вам.Проблема в том, что один из этих хитбоксов спрайтов не работает, даже если используется маска спрайтов.Спрайт игрока генерируется просто делением листа спрайта игрока на 4 столбца.Может там проблема в сокрытии?Картинки для программы: https://drive.google.com/drive/folders/1We6RDMs3Cwwprf1OY0ow9WCTHF9MHzne?usp=sharing

import pygame, os, random

pygame.init()

W, H = 800,600
HW, HH = W/2,H/2
AREA = W * H

WHITE = (255,255,255)
GREEN = (69,139,0)

FPS = 60

bg = pygame.image.load(os.path.join('Pildid', 'Taust3.png'))
bg = pygame.transform.scale(bg, (2000, 600))

DS = pygame.display.set_mode((W,H))
clock = pygame.time.Clock()


class Player(pygame.sprite.Sprite):
    def __init__(self, x, y, py, player, veerg, rida):
        super(Player,self).__init__()
        '''Mangija huppamine'''
        clock.tick(5)
        self.x = x
        self.y = y

        self.jumping = False
        self.platform_y = py
        self.velocity_index = 0

        '''Sprite sheet'''
        self.player = pygame.image.load(os.path.join('Pildid', 'karakter.png')).convert_alpha()#pildi uleslaadimine
        #self.player = pygame.transform.scale(self.player,(200,100)) 
        self.rect = self.player.get_rect()

        '''Sprite sheeti piltide jaotamine pikslite jargi'''
        self.veerg = veerg
        self.rida = rida
        self.kokku = veerg * rida

        self.rect = self.player.get_rect()
        L = self.veergL = self.rect.width/veerg
        K = self.weegK = self.rect.height/rida
        PL,PK = self.veergKeskel = (L/2,K/2)

        self.veerg = list([(index % veerg * L, int(index/veerg) * K,L,K )for index in range(self.kokku)])
        self.handle = list([ #pildi paigutamise voimalikud positsioonid
            (0, 0), (-PL, 0), (-L, 0),
            (0, -PK), (-PL, -PK), (-L, -PK),
            (0, -L), (-PL, -K), (-L, -K),])

        self.mask = pygame.mask.from_surface(self.player)

    def do_jumpt(self):
        '''Huppamine: kiirus, korgus, platvorm'''
        global velocity
        if self.jumping:
            self.y += velocity[self.velocity_index]
            self.velocity_index += 1
            if self.velocity_index >= len(velocity) - 1:
                self.velocity_index = len(velocity) - 1
            if self.y > self.platform_y:
                self.y = self.platform_y
                self.jumping = False
                self.velocity_index = 0



    def draw(self, DS,veergindex,x,y,handle=0):
        DS.blit(self.player,(self.x+self.handle[handle][0], self.y + self.handle[handle][1]),self.veerg[veergindex])

    def do(self):
        '''Funktsioonide kokkupanek'''
        self.do_jumpt()
        p.draw(DS,index%p.kokku,190, 359,4)

    def update(self):
        self.rect.center = self.x, self.y



def keys(player):
    keys = pygame.key.get_pressed()
    if keys[pygame.K_SPACE] or keys[pygame.K_UP] and player.jumping == False:
         player.jumping = True




class Obsticles(pygame.sprite.Sprite):
    '''Game obsticles: **'''
    #img = pygame.image.load(os.path.join('images', 'box.png'))
    def __init__(self, x, y):
        super(Obsticles,self).__init__()
        self.img = pygame.image.load(os.path.join('Pildid', 'kivi.png')).convert_alpha()
        self.img = pygame.transform.scale(self.img, (90,90))
        self.rect = self.img.get_rect(center=(x, y))
        self.x = x
        self.y = y
        self.mask = pygame.mask.from_surface(self.img)

    def draw(self, DS):
        '''Obsticle img blitting and hitbox'''
        DS.blit(self.img, (self.x, self.y))

    def update(self):
        if self.x < -64:  # Delete the obstacle.
            # `kill()` removes this obstacle sprite from all sprite groups.
            self.kill()

        self.x += speed  # Move the obstacle.
            # Update the rect because it's used to blit the
            # sprite and for the collision detection.
        self.rect.center = self.x, self.y

def redrawWindow():
    '''Obsticle loop'''
    for i in ob:
        i.draw(DS)

def text_objects(text, font):
    textSurface = font.render(text, True, WHITE)
    return textSurface, textSurface.get_rect()

def message_display(text):
    largeText = pygame.font.Font('freesansbold.ttf',60)
    TextSurf, TextRect = text_objects(text, largeText)
    TextRect.center = ((W/2),(H/4))
    DS.blit(TextSurf, TextRect)
    pygame.display.update()
    pygame.time.wait(3000)

def crash():
    message_display('Failed')


pygame.time.set_timer(pygame.USEREVENT+2, random.choice([2500, 3000, 1500]))

velocity = list([(i/ 1)-20 for i in range (0,60)])  #Huppe ulatus
index = 3

obsticles = Obsticles(832, 363)
p = Player(190, 359, 359, 'karakter.png', 4, 1)

all_sprites = pygame.sprite.Group(p, obsticles)
ob = pygame.sprite.Group(obsticles)

x = 0
x -= 1
speed = -5

running = True
while running:

    # ---Handle the events.---
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.USEREVENT+2:
            r = random.randrange(0, 2)
            if r == 0:
                obsticles = Obsticles(832, 363)
                # Add the obstacle to both groups.
                ob.add(obsticles)
                all_sprites.add(obsticles)


    speed += -0.008
    # ---Game logic.---
    all_sprites.update()

    collided = pygame.sprite.spritecollide(p, ob, True, 
    pygame.sprite.collide_mask)

    if collided:
        crash()

    index += 1
    # Background movement.

    back_x = x % bg.get_rect().width
    x -= 2
    # ---Draw everything.---
    DS.blit(bg, (back_x - bg.get_rect().width, 0))
    if back_x < W:
        DS.blit(bg, (back_x, 0))


    keys(p)
    p.do()
    redrawWindow()


    pygame.display.update()
    clock.tick(60)


pygame.quit()
quit()

1 Ответ

0 голосов
/ 31 мая 2018

Проблема в том, что вы используете исходное изображение для создания Player.mask.Получающаяся маска покрывает все четыре позы персонажа, поэтому даже если видна только одна из рамок листа спрайта, полное исходное изображение используется для обнаружения столкновения.Ваша маска выглядит как зеленая область на этой картинке:

pygame mask

Вы также должны использовать rect (то есть rect.topleft координаты) в качестве позиции блика, потому что этотакже используется для обнаружения столкновений (для определения местоположения маски).

У меня есть фиксированная, укороченная версия вашей программы, в которой я изменил несколько вещей, чтобы показать вам, как я могу решить проблему.Прежде всего, я загружаю лист спрайта и разрезаю его на несколько подповерхностей, затем я назначаю первую поверхность / изображение атрибуту self.image Player.Это изображение может быть использовано для создания rect и mask.

В методе update я увеличиваю frame_index и присваиваю текущему изображению self.image для анимации спрайта.Кстати, было бы неплохо создать отдельные маски для каждого изображения и поменять их местами во время анимации.(Я просто использую здесь первую маску, поскольку кадры анимации очень похожи.)

Обратите внимание, что если вы дадите своим спрайтам атрибуты image и rect, вы можете просто вызвать all_sprites.update(DS) Blit все изображения спрайтов на их соответствующих rects.

import random
import pygame


pygame.init()
FPS = 60
DS = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
PLAYER_SHEET = pygame.image.load('karakter.png').convert_alpha()
# Cut the sprite sheet and append the subsurfaces to this list.
PLAYER_IMAGES = []
width = PLAYER_SHEET.get_width() / 4
height = PLAYER_SHEET.get_height()
for x in range(4):
    PLAYER_IMAGES.append(PLAYER_SHEET.subsurface(x*width, 0, width, height))


class Player(pygame.sprite.Sprite):
    def __init__(self, x, y, py):
        super(Player,self).__init__()
        self.x = x
        self.y = y

        self.jumping = False
        self.platform_y = py
        self.velocity_index = 0
        self.velocity = list([(i/ 1)-20 for i in range (0,60)])

        self.frame_index = 0
        self.image = PLAYER_IMAGES[self.frame_index]
        self.rect = self.image.get_rect()
        self.mask = pygame.mask.from_surface(self.image)

    def do_jump(self):
        if self.jumping:
            self.y += self.velocity[self.velocity_index]
            self.velocity_index += 1
            if self.velocity_index >= len(self.velocity) - 1:
                self.velocity_index = len(self.velocity) - 1
            if self.y > self.platform_y:
                self.y = self.platform_y
                self.jumping = False
                self.velocity_index = 0

    def update(self):
        self.rect.center = self.x, self.y
        self.do_jump()
        # Update the animation frame.
        self.frame_index += 1
        self.frame_index %= len(PLAYER_IMAGES) * 7  # * 7 to slow it down.
        # Swap the image.
        self.image = PLAYER_IMAGES[self.frame_index//7]  # // 7 to slow it down.


def keys(player):
    keys = pygame.key.get_pressed()
    if keys[pygame.K_SPACE] or keys[pygame.K_UP] and player.jumping == False:
         player.jumping = True


class Obstacle(pygame.sprite.Sprite):
    """Game Obstacle."""

    def __init__(self, x, y):
        super(Obstacle,self).__init__()
        self.image = pygame.Surface((90, 90), pygame.SRCALPHA)
        self.image.fill((100, 150, 0))
        self.image = pygame.transform.scale(self.image, (90,90))
        self.rect = self.image.get_rect(center=(x, y))
        self.x = x
        self.y = y
        self.mask = pygame.mask.from_surface(self.image)

    def update(self):
        if self.x < -64:
            self.kill()

        self.x += speed
        self.rect.center = self.x, self.y


pygame.time.set_timer(pygame.USEREVENT+2, random.choice([2500, 3000, 1500]))
index = 3

obstacle = Obstacle(832, 363)
player = Player(190, 359, 359)

all_sprites = pygame.sprite.Group(player, obstacle)
obstacles = pygame.sprite.Group(obstacle)
speed = -5

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.USEREVENT+2:
            r = random.randrange(0, 2)
            if r == 0:
                obstacle = Obstacle(832, 363)
                # Add the obstacle to both groups.
                obstacles.add(obstacle)
                all_sprites.add(obstacle)

    keys(player)

    # ---Game logic.---
    speed += -0.008

    all_sprites.update()

    collided = pygame.sprite.spritecollide(player, obstacles, True,
        pygame.sprite.collide_mask)

    if collided:
        print('crash')

    index += 1

    # ---Draw everything.---
    DS.fill((30, 30, 30))
    all_sprites.draw(DS)

    # Here I draw the outline (points) of the player's mask.
    px, py = player.rect.topleft
    for point in player.mask.outline(8):
        x, y = point[0] + px, point[1] + py
        pygame.draw.circle(DS, (250, 250, 0), (x, y), 2)

    pygame.draw.rect(DS, (0, 0, 250), player.rect, 1)
    # Draw the outlines of the obstacles.
    for obstac in obstacles:
        pygame.draw.rect(DS, (150, 250, 0), obstac.rect, 1)
        ox, oy = obstac.rect.topleft
        for point in obstac.mask.outline(6):
            pygame.draw.circle(DS, (250, 0, 0), (point[0]+ox, point[1]+oy), 2)

    pygame.display.update()
    clock.tick(60)


pygame.quit()
...