Rect, который отличается по размеру от изображения - PullRequest
0 голосов
/ 27 сентября 2019

Я хотел попробовать что-то новое и нашел этот учебник в Интернете.Я использовал его и немного подправил.Моя цель - создать клона Zelda, что означает, что моя игра будет основана на Tile

Теперь для решения проблемы.Все мои спрайты не в соотношении 1: 1.Размер прямоугольника, который я создал, равен TILESIZE * TILESIZE (= 64 высоты, 64 ширины).

Теперь прямоугольник прилипает к вершине:

enter image description here

но мне нужно, чтобы он придерживался нижнего центра моего спрайта:

enter image description here

для обнаружения столкновений.

Я пробовал множество способов и спрашивал своих коллег, но они также не могут помочь мне.

class Player(pg.sprite.Sprite):
    def __init__(self, game, x, y):
        self.groups = game.all_sprites
        pg.sprite.Sprite.__init__(self, self.groups)
        self.images = []

        def addImage(image):
            self.images.append(load_image(path.join(img_folder, "zelda_green", image)))
            print(self.images[-1].get_size())
            scale = TILESIZE/self.images[-1].get_width()
            #print(tuple([scale*x for x in self.images[-1].get_size()]))
            print(scale)
            self.images[-1] = pg.transform.scale(self.images[-1], tuple([int(scale*x) for x in self.images[-1].get_size()]))

        addImage("walk1.png")
        addImage("walk2.png")
        addImage("walk3.png")
        addImage("walk4.png")
        addImage("walk5.png")
        addImage("walk6.png")
        addImage("walk7.png")
        addImage("walk8.png")
        addImage("walk9.png")
        addImage("walk10.png")

        self.index = 0
        self.image = self.images[self.index]
        self.rect = pg.Rect(0, 0, TILESIZE, TILESIZE)
        self.game = game
        self.vel = vec(0,0)
        self.pos = vec(x,y) * TILESIZE
        self.vx, self.vy = 0,0
        self.x = x * TILESIZE
        self.y = y * TILESIZE

    def get_keys(self):
        self.vel = vec(0,0)
        keys = pg.key.get_pressed()
        if keys[pg.K_LEFT] or keys[pg.K_a]:
            self.vel.x = -PLAYER_SPEED
        if keys[pg.K_RIGHT] or keys[pg.K_d]:
            self.vel.x = PLAYER_SPEED
        if keys[pg.K_UP] or keys[pg.K_w]:
            self.vel.y = -PLAYER_SPEED
        if keys[pg.K_DOWN] or keys[pg.K_s]:
            self.vel.y = PLAYER_SPEED
        if self.vel.x != 0 and self.vy != 0:
            self.vel.x *= 0.7071
            self.vel.y *= 0.7071

    def move(self, dx=0, dy=0):
        if not self.collide_with_walls(dx, dy):
            self.x += dx
            self.y += dy

    def collide_with_walls(self, dir):     
        if dir == 'x':
            hits = pg.sprite.spritecollide(self, self.game.walls, False)
            if hits:
                if self.vel.x > 0:
                    self.pos.x = hits[0].rect.left - self.rect.width
                if self.vel.x < 0:
                    self.pos.x = hits[0].rect.right
                self.vel.x = 0
                self.rect.x = self.pos.x
        if dir == 'y':
            hits = pg.sprite.spritecollide(self, self.game.walls, False)
            if hits:
                if self.vel.y > 0:
                    self.pos.y = hits[0].rect.top - self.rect.height
                if self.vel.y < 0:
                    self.pos.y = hits[0].rect.bottom
                self.vel.y = 0
                self.rect.y = self.pos.y

    def update(self):
        global initTime
        frameTime = time.time() - initTime

        if frameTime >= 0.075:
            initTime = time.time()
            self.index += 1
        if self.index >= len(self.images):
            self.index = 0
        self.image = self.images[self.index]
        self.get_keys()
        self.pos += self.vel * self.game.dt
        self.rect.x = self.pos.x
        self.collide_with_walls('x')
        self.rect.y = self.pos.y
        self.collide_with_walls('y')

1 Ответ

0 голосов
/ 27 сентября 2019

Вы можете отделить Rect, который используется для рисования от фактического обнаружения столкновения.Если вы посмотрите на функцию pygame.sprite.spritecollide () , вы увидите параметр с именем collided:

Аргумент с коллизиями - это функция обратного вызова, используемая для вычисления, еслидва спрайта сталкиваются.он должен принимать два спрайта в качестве значений и возвращать значение bool, указывающее, сталкиваются ли они.Если коллизия не передана, все спрайты должны иметь значение «прямоугольник», представляющее собой прямоугольник области спрайтов, который будет использоваться для расчета коллизии.

Pygame уже поставляется с несколькими функциями, которыеВы можете использовать для обнаружения столкновений:

collide_rect, collide_rect_ratio, collide_circle,
collide_circle_ratio, collide_mask

collide_rect по умолчанию.

Вы можете использовать collide_mask для идеального столкновения пикселей, или вы можете предоставить свою собственную функцию.

Если вы хотите просто «переместить» Rect для обнаружения столкновения, как вы сказали в своем комментарии, вы можетедать вашим спрайтам секунду Rect, которая находится внизу вашего изображения, что-то вроде этого:

class Sprite(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface((64, 80))
        self.image.fill((0, 200, 200))

        self.rect = pygame.Rect(0, 0, 64, 64)
        # some drawing for demonstration
        pygame.draw.rect(self.image, (255, 0, 0), self.rect, 2)

        self.collision_rect = self.rect.copy()
        self.collision_rect.bottom = self.image.get_rect().bottom
        pygame.draw.rect(self.image, (255, 255, 0), self.collision_rect, 2)

, затем создайте функцию для передачи в качестве аргумента collided, который использует этот новый атрибут collision_rect:

def collide_collision_rect(left, right):
    return left.collision_rect.colliderect(right.collision_rect)

и при вызове spritecollide передайте функцию в качестве последнего аргумента:

pg.sprite.spritecollide(self, self.game.walls, False, collide_collision_rect)

Вы должны убедиться, что все ваши спрайты имеют атрибут collision_rect или первый check, если переданные спрайты имеют атрибут collision_rect и возвращаются к rect, если их нет.Кроме того, при изменении атрибута rect обязательно обновите также атрибут collision_rect.

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

class Sprite(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface((64, 80))
        self.image.fill((0, 200, 200))

        self.rect = pygame.Rect(0, 0, 64, 64)
        pygame.draw.rect(self.image, (255, 0, 0), self.rect, 2)

        self.diff = self.image.get_rect().height - self.rect.height

def collide_collision_rect(left, right):
    return left.rect.move(0, left.diff).colliderect(right.rect.move(0, right.diff))
...