Назначьте статическую маску движущейся поверхности с помощью PyGame

Я только вчера начал свой первый проект PyGame и не могу найти, как правильно использовать сущность Mask для применения на движущейся поверхности.

Я сделал специальный класс для анимированных поверхностей

class LabelObject():
    def __init__(self, surface, x, y, endX, speed, idleTime):
        self.surface = surface
        self.x = x
        self.y = y
        self.endX = endX
        self.speed = speed
        self.idleTime = idleTime
        self.alpha = 255
        self.timer_start = 0
        self.timer_end = 0
        self.pos = self.surface.get_rect(x=self.x,y=self.y)

    def move(self):
        self.timer_start += 1
        if self.timer_start > self.idleTime:
            if self.pos.right > self.endX:
                self.pos.x += self.speed
            elif self.pos.x < self.x:
                self.timer_end += 1
                if self.timer_end > self.idleTime:
                    self.alpha -= 25
                if self.timer_end > self.idleTime + 11:
                    self.pos = self.surface.get_rect(x=self.x, y=self.y)
                    self.timer_start = 0
                    self.timer_end = 0
                    self.alpha = 255
        self.surface.set_alpha(self.alpha)

Задача этого класса - проверить, превышает ли поверхность заданную область, и сдвинуть влево, чтобы иметь возможность полностью прочитать текст, отображаемый внутри нее.

В моем основном цикле я просто могу отобразить его так:

label = LabelObject(textSurface,20,10,100,-0.5,30)
while not over:
    for event in pygame.event.get():
         if event.type == pygame.QUIT
             over = True
    screen.fill((0,0,0))
    label.move()
    screen.blit(label.surface, label.pos)
    pygame.display.update()

Это работает нормально, но мне нужно наложить на него маску, которая не должна двигаться. В этом примере Rect маски будет (20, 10, 100-20, label.surface.get_height()). Я вижу несколько примеров маски в сети, но я не нашел способа использовать ее, когда маска статична, а поверхность движется.

РЕДАКТИРОВАТЬ: Я попытался использовать параметр области в функции blit, но есть что-то странное, область и движение поверхности не синхронизируются.

РЕДАКТИРОВАТЬ2: И, наконец, вот хорошая функция blit с опцией области. Просто нужно сделать блит со статической позицией и область с анимированной позицией:

self.screen.blit(label.surface, (label.x,label.y), area=pygame.Rect(label.x-label.pos.x, 0, label.endX-label.x, label.surface.get_height()))

person jbltx    schedule 26.12.2015    source источник
comment
если у вас есть self.pos (экземпляр pygame.Rect), вам не нужны self.x и self.y, потому что у вас есть self.pos.x, self.pos.y, self.pos.width, self.pos.right (вместо self.pos[0]+self.pos[2]), self.pos.center и т. д. Вы можете использовать get_rect(x=self.x, y=self.y) вместо get_rect().move(self.x, self.y)   -  person furas    schedule 26.12.2015
comment
вы можете использовать self.pos.x += self.speed вместо self.pos = self.pos.move(self.speed, 0)   -  person furas    schedule 26.12.2015
comment
@furas спасибо за комментарии, я разъясню свой класс вашим советом.   -  person jbltx    schedule 26.12.2015
comment
возможно вам понадобится pygame.Surface.subsurface(offset_x,....) с offset_x += speed, чтобы получить часть полного изображения   -  person furas    schedule 26.12.2015
comment
Я отредактировал свой вопрос, я протестировал опцию области из функции blit, что тоже могло бы быть хорошим способом сделать это, но область и движение поверхности не синхронизируются. Область тоже движется влево, но медленнее, чем поверхность. Это странно, потому что позиция x области связана с движущейся позицией x поверхности ...   -  person jbltx    schedule 26.12.2015
comment
Я считаю, что блит-позиция должна быть всегда одинаковой, и только область должна меняться. Я пытаюсь привести пример, чтобы это проверить.   -  person furas    schedule 26.12.2015


Ответы (1)


Я пытаюсь сделать полный рабочий пример с subsurface, чтобы отрезать видимую часть полного изображения. Rect (sub_image_rect) всегда одно и то же - рисовать в одном месте. Я меняю только смещение, чтобы отрезать разные части изображения.

Я использую текст и шрифт для создания изображения - и каждый может запустить его без собственных изображений.

import pygame

# --- constants ---

BLACK = (  0,  0,  0)
RED   = (255,  0,  0)

# --- classes ---

class Label():

    def __init__(self, text, x, y, width):

        font = pygame.font.SysFont(None, 35)

        # generate full image
        self.image = font.render(text, True, RED)
        self.rect = self.image.get_rect(x=x, y=y)

        self.width = width
        self.speed = 1

        # offset of visible part
        self.offset_x = 0
        self.max_offset_x = self.rect.width - self.width

        # visible part of image
        self.sub_image = self.image.subsurface((self.offset_x,0), (self.width, self.rect.height))
        self.sub_image_rect = self.sub_image.get_rect(x=x, y=y)


    def move(self):

        # change offset
        self.offset_x += self.speed

        # change move direction
        if self.offset_x < 0:
            self.offset_x = 0
            self.speed = -self.speed
        elif self.offset_x > self.max_offset_x:
            self.offset_x = self.max_offset_x
            self.speed = -self.speed

        print self.offset_x, self.max_offset_x
        # visible part of image
        self.sub_image = self.image.subsurface((self.offset_x, 0),(self.width, self.rect.height))

    def draw(self, surface):
        surface.blit(self.sub_image, self.sub_image_rect)

# --- main ---

pygame.init()
screen = pygame.display.set_mode((800,600))

label = Label("Hello World of Python and Pygame!", 100, 100, 200)

# --- mainloop ---

fps = pygame.time.Clock()
running = True

while running:

    # --- events ---

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if event.key ==  pygame.K_ESCAPE:
                running = False

    # --- updates ---

    label.move()

    # --- draws ---

    screen.fill(BLACK)

    label.draw(screen)

    fps.tick(25)
    pygame.display.flip()

# --- the end ---

pygame.quit()

РЕДАКТИРОВАТЬ: Я сделал пример с area в blit. Поменял всего 3 строчки - см. # changed в коде

import pygame

# --- constants ---

BLACK = (  0,  0,  0)
RED   = (255,  0,  0)

# --- classes ---

class Label():

    def __init__(self, text, x, y, width):

        font = pygame.font.SysFont(None, 35)

        # generate full image
        self.image = font.render(text, True, RED)
        self.rect = self.image.get_rect(x=x, y=y)

        self.width = width
        self.speed = 1

        # offset of visible part
        self.offset_x = 0
        self.max_offset_x = self.rect.width - self.width

        # visible part of image as 'rect' - 'width' is always the same
        self.sub_image_rect = self.image.get_rect(x=0, width=self.width) # changed

    def move(self):

        # change offset
        self.offset_x += self.speed

        # change move direction
        if self.offset_x < 0:
            self.offset_x = 0
            self.speed = -self.speed
        elif self.offset_x > self.max_offset_x:
            self.offset_x = self.max_offset_x
            self.speed = -self.speed

        # visible part of image - change only `x` 
        self.sub_image_rect.x = self.offset_x  # changed

    def draw(self, surface):
        surface.blit(self.image, self.rect, area=self.sub_image_rect)  # changed

# --- main ---

pygame.init()
screen = pygame.display.set_mode((800,600))

label = Label("Hello World of Python and Pygame!", 100, 100, 200)

# --- mainloop ---

fps = pygame.time.Clock()
running = True

while running:

    # --- events ---

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if event.key ==  pygame.K_ESCAPE:
                running = False

    # --- updates ---

    label.move()

    # --- draws ---

    screen.fill(BLACK)

    label.draw(screen)

    fps.tick(25)
    pygame.display.flip()

# --- the end ---

pygame.quit()
person furas    schedule 26.12.2015
comment
Я принимаю ваш ответ, даже если я, наконец, воспользовался опцией площади. Всегда приятно знать несколько способов что-то сделать. Что касается области, в которой вы тоже были правы, мне просто пришлось заменить label.pos.x на label.x, чтобы сделать блит статическим, и это работает как шарм. Еще раз спасибо;) - person jbltx; 26.12.2015
comment
Я тоже сделал пример с area - потому что никогда раньше не использовал area. - person furas; 26.12.2015
comment
Да, спасибо, если вы хотите увидеть мой примерный код, он есть на Github;) github.com/jbltx/PyAudioTFT < / а> - person jbltx; 26.12.2015