Pygame + 精灵旋转不居中
Pygame + Sprite rotation not staying centered
几天来我一直在努力解决这个问题。我正在尝试在其中心轴上旋转一个精灵,并且一直在参考之前关于同一问题的 post:
How do I rotate an image around its center using Pygame?
我使用的代码与之前 post 中描述的代码完全相同,并且还利用了 image_clean 属性,以便在连续旋转时不扭曲图像。当我尝试旋转我的精灵时,图像的中心在两点之间来回摆动。
def rotate_center(image, angle):
"""rotate a Surface, maintaining position."""
loc = image.get_rect().center #rot_image is not defined
rot_img = pg.transform.rotate(image, angle)
print('')
print('>>> before: ' + str(rot_img.get_rect().center))
rot_img.get_rect().center = loc
print('>>> after: ' + str(rot_img.get_rect().center))
return rot_img
打印语句验证行:
rot_sprite.get_rect().center = loc
似乎没有将 loc
值分配给图像中心。输出总是这样:
>>> before: (32, 32)
>>> after: (32, 32)
>>> before: (37, 37)
>>> after: (37, 37)
>>> before: (41, 41)
>>> after: (41, 41)
>>> before: (43, 43)
>>> after: (43, 43)
>>> before: (45, 45)
>>> after: (45, 45)
>>> before: (45, 45)
>>> after: (45, 45)
>>> before: (43, 43)
>>> after: (43, 43)
>>> before: (41, 41)
>>> after: (41, 41)
>>> before: (37, 37)
>>> after: (37, 37)
我一直希望中心位于 (32, 32)(我相信)。任何帮助将不胜感激。
代码:
def main():
pg.init()
# Screen Setup
size = (SCREEN_WIDTH, SCREEN_HEIGHT)
screen = pg.display.set_mode(size)
screen_flags = screen.get_flags()
pg.display.set_caption(GAME_NAME)
done = False
clock = pg.time.Clock()
# SPRITE GROUPS
all_sprites = pg.sprite.Group()
turrets = pg.sprite.Group()
turret = Tower2((SCREEN_WIDTH/2, SCREEN_HEIGHT/2))
turrets.add(turret)
all_sprites.add(turret)
# -------- Main Program Loop -----------
while not done:
# Process Incoming Events
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
if event.type == pg.KEYDOWN:
if event.key == pg.K_q:
done = True
if event.key == pg.K_f:
if screen_flags & pg.FULLSCREEN == False:
screen_flags |= pg.FULLSCREEN
pg.display.set_mode(size, screen_flags)
else:
screen_flags ^= pg.FULLSCREEN
pg.display.set_mode(size, screen_flags)
turret.angle += 10
turret.image = rotate_center(turret.image_clean, turret.angle)
screen.fill(WHITE)
all_sprites.draw(screen)
pg.display.flip()
clock.tick(15)
pg.quit()
class Tower2(pg.sprite.Sprite):
def __init__(self, pos, image, tRange, attackSpeed=1):
super().__init__()
self.image = image
self.image_clean = image
self.rect = self.image.get_rect()
self.rect.center = pos
self.range = tRange
self.attackSpeed = attackSpeed
self.lastAttack = time.time()
self.angle = 0
def __iter__(self):
return self
def canAttack(self):
if time.time() - self.lastAttack > self.attackSpeed:
return True
else:
return False
def rotate(self):
pass
def update(self):
self.angle += 10
self.image = pg.transform.rotate(self.image_clean, self.angle)
self.image.get_rect().center = self.image_clean.get_rect().center
class Turret1(Tower2):
def __init__(self, pos):
TOWER_WIDTH = 64
TOWER_HEIGHT = 64
INIT_RANGE = 200
INIT_RATE = 1
SPEED = 1
tower_img = pg.image.load('imgs/test_rotate.png')
tower_img = pg.transform.scale(tower_img, (TOWER_WIDTH, TOWER_HEIGHT))
super().__init__(pos, tower_img, INIT_RANGE, SPEED)
不要一直使用 get_rect()
- 它总是会创建新矩形,并且您会在这个新矩形中更改位置,而不是在原始矩形中。稍后您会再次获得新的矩形来显示位置。
除了图像不保持位置你必须得到一次矩形并用它来保持位置。
loc = image.get_rect().center
rot_img = pg.transform.rotate(image, angle)
# get rectangle and keep it
rot_img_rect = rot_img.get_rect()
# change position in rectangle
rot_img_rect.center = loc
# display position
print('>>> after: ', rot_img_rect.center)
# return image and position in `rot_img_rect`
return rot_img, rot_img_rect
您还必须传递精灵的矩形,因为它保存了精灵的实际位置,然后将中心坐标传递给 .get_rect
或将它们分配给新的矩形 center
.如果你只是调用 .get_rect()
,你会得到一个左上坐标为 (0, 0) 的矩形。
def rotate_center(image, rect, angle):
"""Rotate a Surface, maintaining position."""
rot_img = pg.transform.rotate(image, angle)
# Get a new rect and pass the center position of the old
# rect, so that it rotates around the center.
rect = rot_img.get_rect(center=rect.center)
return rot_img, rect # Return the new rect as well.
# In the main while loop.
turret.angle += 10
# Also pass the turret's rect which holds the position of the sprite.
image, rect = rotate_center(turret.image_clean, turret.rect, turret.angle)
turret.image = image # Assign the new image.
turret.rect = rect # Assign the new rect.
您也可以在精灵的 update
方法中执行此操作:
import pygame as pg
WHITE = pg.Color('white')
class Tower2(pg.sprite.Sprite):
def __init__(self, pos, tRange=1, attackSpeed=1):
super().__init__()
self.image = your_image
self.image_clean = self.image
self.rect = self.image.get_rect()
self.rect.center = pos
self.angle = 0
def update(self):
self.angle += 10
self.image = pg.transform.rotate(self.image_clean, self.angle)
self.rect = self.image.get_rect(center=self.rect.center)
def main():
pg.init()
SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480
size = (SCREEN_WIDTH, SCREEN_HEIGHT)
screen = pg.display.set_mode(size)
done = False
clock = pg.time.Clock()
all_sprites = pg.sprite.Group()
turret = Tower2((SCREEN_WIDTH/2, SCREEN_HEIGHT/2))
all_sprites.add(turret)
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
all_sprites.update()
screen.fill(WHITE)
all_sprites.draw(screen)
pg.display.flip()
clock.tick(15)
main()
pg.quit()
几天来我一直在努力解决这个问题。我正在尝试在其中心轴上旋转一个精灵,并且一直在参考之前关于同一问题的 post:
How do I rotate an image around its center using Pygame?
我使用的代码与之前 post 中描述的代码完全相同,并且还利用了 image_clean 属性,以便在连续旋转时不扭曲图像。当我尝试旋转我的精灵时,图像的中心在两点之间来回摆动。
def rotate_center(image, angle):
"""rotate a Surface, maintaining position."""
loc = image.get_rect().center #rot_image is not defined
rot_img = pg.transform.rotate(image, angle)
print('')
print('>>> before: ' + str(rot_img.get_rect().center))
rot_img.get_rect().center = loc
print('>>> after: ' + str(rot_img.get_rect().center))
return rot_img
打印语句验证行:
rot_sprite.get_rect().center = loc
似乎没有将 loc
值分配给图像中心。输出总是这样:
>>> before: (32, 32)
>>> after: (32, 32)
>>> before: (37, 37)
>>> after: (37, 37)
>>> before: (41, 41)
>>> after: (41, 41)
>>> before: (43, 43)
>>> after: (43, 43)
>>> before: (45, 45)
>>> after: (45, 45)
>>> before: (45, 45)
>>> after: (45, 45)
>>> before: (43, 43)
>>> after: (43, 43)
>>> before: (41, 41)
>>> after: (41, 41)
>>> before: (37, 37)
>>> after: (37, 37)
我一直希望中心位于 (32, 32)(我相信)。任何帮助将不胜感激。
代码:
def main():
pg.init()
# Screen Setup
size = (SCREEN_WIDTH, SCREEN_HEIGHT)
screen = pg.display.set_mode(size)
screen_flags = screen.get_flags()
pg.display.set_caption(GAME_NAME)
done = False
clock = pg.time.Clock()
# SPRITE GROUPS
all_sprites = pg.sprite.Group()
turrets = pg.sprite.Group()
turret = Tower2((SCREEN_WIDTH/2, SCREEN_HEIGHT/2))
turrets.add(turret)
all_sprites.add(turret)
# -------- Main Program Loop -----------
while not done:
# Process Incoming Events
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
if event.type == pg.KEYDOWN:
if event.key == pg.K_q:
done = True
if event.key == pg.K_f:
if screen_flags & pg.FULLSCREEN == False:
screen_flags |= pg.FULLSCREEN
pg.display.set_mode(size, screen_flags)
else:
screen_flags ^= pg.FULLSCREEN
pg.display.set_mode(size, screen_flags)
turret.angle += 10
turret.image = rotate_center(turret.image_clean, turret.angle)
screen.fill(WHITE)
all_sprites.draw(screen)
pg.display.flip()
clock.tick(15)
pg.quit()
class Tower2(pg.sprite.Sprite):
def __init__(self, pos, image, tRange, attackSpeed=1):
super().__init__()
self.image = image
self.image_clean = image
self.rect = self.image.get_rect()
self.rect.center = pos
self.range = tRange
self.attackSpeed = attackSpeed
self.lastAttack = time.time()
self.angle = 0
def __iter__(self):
return self
def canAttack(self):
if time.time() - self.lastAttack > self.attackSpeed:
return True
else:
return False
def rotate(self):
pass
def update(self):
self.angle += 10
self.image = pg.transform.rotate(self.image_clean, self.angle)
self.image.get_rect().center = self.image_clean.get_rect().center
class Turret1(Tower2):
def __init__(self, pos):
TOWER_WIDTH = 64
TOWER_HEIGHT = 64
INIT_RANGE = 200
INIT_RATE = 1
SPEED = 1
tower_img = pg.image.load('imgs/test_rotate.png')
tower_img = pg.transform.scale(tower_img, (TOWER_WIDTH, TOWER_HEIGHT))
super().__init__(pos, tower_img, INIT_RANGE, SPEED)
不要一直使用 get_rect()
- 它总是会创建新矩形,并且您会在这个新矩形中更改位置,而不是在原始矩形中。稍后您会再次获得新的矩形来显示位置。
除了图像不保持位置你必须得到一次矩形并用它来保持位置。
loc = image.get_rect().center
rot_img = pg.transform.rotate(image, angle)
# get rectangle and keep it
rot_img_rect = rot_img.get_rect()
# change position in rectangle
rot_img_rect.center = loc
# display position
print('>>> after: ', rot_img_rect.center)
# return image and position in `rot_img_rect`
return rot_img, rot_img_rect
您还必须传递精灵的矩形,因为它保存了精灵的实际位置,然后将中心坐标传递给 .get_rect
或将它们分配给新的矩形 center
.如果你只是调用 .get_rect()
,你会得到一个左上坐标为 (0, 0) 的矩形。
def rotate_center(image, rect, angle):
"""Rotate a Surface, maintaining position."""
rot_img = pg.transform.rotate(image, angle)
# Get a new rect and pass the center position of the old
# rect, so that it rotates around the center.
rect = rot_img.get_rect(center=rect.center)
return rot_img, rect # Return the new rect as well.
# In the main while loop.
turret.angle += 10
# Also pass the turret's rect which holds the position of the sprite.
image, rect = rotate_center(turret.image_clean, turret.rect, turret.angle)
turret.image = image # Assign the new image.
turret.rect = rect # Assign the new rect.
您也可以在精灵的 update
方法中执行此操作:
import pygame as pg
WHITE = pg.Color('white')
class Tower2(pg.sprite.Sprite):
def __init__(self, pos, tRange=1, attackSpeed=1):
super().__init__()
self.image = your_image
self.image_clean = self.image
self.rect = self.image.get_rect()
self.rect.center = pos
self.angle = 0
def update(self):
self.angle += 10
self.image = pg.transform.rotate(self.image_clean, self.angle)
self.rect = self.image.get_rect(center=self.rect.center)
def main():
pg.init()
SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480
size = (SCREEN_WIDTH, SCREEN_HEIGHT)
screen = pg.display.set_mode(size)
done = False
clock = pg.time.Clock()
all_sprites = pg.sprite.Group()
turret = Tower2((SCREEN_WIDTH/2, SCREEN_HEIGHT/2))
all_sprites.add(turret)
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
all_sprites.update()
screen.fill(WHITE)
all_sprites.draw(screen)
pg.display.flip()
clock.tick(15)
main()
pg.quit()