要获得“平滑”,您必须使用浮点值而不是整数值来计算敌人的位置和运动。
请注意,pygame.Rect 对象的位置和大小以整数形式存储。每次向位置添加移动时,都会丢失小数部分。这导致根本不执行一个方向上的小运动。如果将小于 0.5 (round) 的值添加到整数坐标,则位置将永远不会改变,即使超出帧也是如此。如果坐标是浮点值,那么位置的整数部分会在几帧后发生变化。
在Enemy类中添加位置属性(.pos):
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。例如:
self.pos[0] = self.pos[0] + self.move_x
self.rect.x = round(self.pos[0])
如果检测到碰撞,则属性.pos 必须通过属性.rect 的整数位置来纠正。例如:
if block_collide:
self.pos[0] = self.rect.x
您还需要创建对象属性属性self.move_x 和self.move_y,而不是类属性Enemy.move_x 和Enemy.move_y。
请注意,每个类型(calss)都有一个类属性,但每个对象(“敌人”)都有一个对象属性。每个敌人都必须有自己的运动矢量,否则最后一个敌人计算的运动将应用于所有敌人。这会导致敌人做出意想不到的移动。见Class Definition Syntax。
当然要循环移动敌人
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