Чтобы получить "плавность", вам нужно вычислить позицию и движение противника с использованием значений с плавающей запятой, а не целых значений.
Обратите внимание, что позиция и размер объекта pygame.Rect
сохраняются как целые. Каждый раз, когда к позиции добавляется движение, дробная часть теряется. Это приводит к тому, что небольшие движения в направлении вообще не выполняются. Если к интегральной координате добавляется значение меньше 0,5 (round
), то положение никогда не изменится, даже за рамками. Если координата является значением с плавающей запятой, то через несколько кадров интегральная часть позиции изменится.
Добавить атрибут позиции (.pos) для класса Enemy
:
class Enemy(pygame.sprite.Sprite):
def __init__(self, x, y, speed, walls):
# [...]
self.pos = [x, y]
self.rect.y = y
self.rect.x = x
Измените позицию на атрибуте .pos
и обновите .rect
на .pos
. e.g.:
self.pos[0] = self.pos[0] + self.move_x
self.rect.x = round(self.pos[0])
Если было обнаружено столкновение, то атрибут .pos
должен быть исправлен с помощью целочисленной позиции в атрибуте .rect
. e.g.:
if block_collide:
self.pos[0] = self.rect.x
Далее вам нужно создать атрибуты атрибутов объекта self.move_x
и self.move_y
, а не атрибуты класса Enemy.move_x
и Enemy.move_y
.
Обратите внимание, что атрибут существует для каждого типа (calss) один раз, но атрибут объекта существует только один раз для каждого объекта («враг»). Каждый враг должен иметь свой собственный вектор движения, иначе движение, вычисленное последним врагом, будет применено ко всем врагам. Это заставляет врагов совершать неожиданные движения. См. Синтаксис определения класса .
Конечно, вы должны перемещать врагов в цикле
for e in enemy_list:
e.move(player)
Полный код класса Enemy
:
class Enemy(pygame.sprite.Sprite):
def __init__(self, x, y, speed, walls):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([20, 20])
self.image.fill(red)
self.rect = self.image.get_rect()
self.pos = [x, y]
self.rect.y = y
self.rect.x = x
self.move_x = 0
self.move_y = 0
self.speed = speed # speed of the enemy
self.walls = walls # walls for the collision test
def move(self, player):
dx, dy = player.rect.x - self.pos[0], player.rect.y - self.pos[1]
dist = math.hypot(dx, dy)
dx, dy = dx / dist, dy / dist
self.move_x = dx * min(dist, self.speed)
self.move_y = dy * min(dist, self.speed)
def update(self):
self.pos[0] = self.pos[0] + self.move_x
self.rect.x = round(self.pos[0])
block_collide = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_collide:
if self.move_x > 0:
self.rect.right = block.rect.left
else:
self.rect.left = block.rect.right
if block_collide:
self.pos[0] = self.rect.x
self.pos[1] = self.pos[1] + self.move_y
self.rect.y = round(self.pos[1])
block_collide = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_collide:
if self.move_y > 0:
self.rect.bottom = block.rect.top
else:
self.rect.top = block.rect.bottom
if block_collide:
self.pos[1] = self.rect.y