我正在尝试使精灵向播放器旋转,但是旋转位置不合适。这是video of the behaviour。
我不确定如何解决此问题,
#-------------------------------- enemy shoots left and right
shotsright = pygame.image.load("canss.png")
class enemyshoot:
def __init__(self,x,y,height,width,color):
self.x = x
self.y =y
self.height = height
self.width = width
self.color = color
self.rect = pygame.Rect(x,y,height,width)
self.health = 10
self.hitbox = (self.x + -20, self.y + 30, 31, 57)
#-------------------------------------------------------
# Make a Reference Copy of the bitmap for later rotation
self.shootsright = pygame.image.load("canss.png")
self.shootsright = pygame.transform.scale(self.shootsright,(self.shootsright.get_width()-150,self.shootsright.get_height()-150))
self.image = self.shootsright
self.rect = self.image.get_rect()
self.position = pygame.math.Vector2( (200, 180) )
self.isLookingAtPlayer = False
def draw(self):
self.rect.topleft = (self.x,self.y)
window.blit(self.image, self.rect)
self.hits = (self.x + 20, self.y, 28,60)
pygame.draw.rect(window, (255,0,0), (self.hitbox[0], self.hitbox[1] - 60, 100, 10)) # NEW
pygame.draw.rect(window, (0,255,0), (self.hitbox[0], self.hitbox[1] - 60, 100 - (5 * (10 - self.health)), 10))
self.hitbox = (self.x + 200, self.y + 200, 51, 65)
def lookAt( self, coordinate ):
# Rotate image to point in the new direction
delta_vector = coordinate - self.position
radius, angle = delta_vector.as_polar()
self.image = pygame.transform.rotate(self.shootsright, -angle)
# Re-set the bounding rectangle and position since
# the dimensions and centroid will have (probably) changed.
current_pos = self.rect.center
self.rect = self.image.get_rect()
self.rect.center = current_pos
black = (0,0,0)
enemyshooting = []
platformGroup = pygame.sprite.Group
platformList = []
level = [" p p p p p ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",]
for iy, row in enumerate(level):
for ix, col in enumerate(row):
if col == "p":
new_platforms = enemyshoot(ix*10, iy*50, 10,10,(255,255,255))
enemyshooting.append(new_platforms)
这是旋转部分
class enemyshoot:
def __init__(self,x,y,height,width,color):
# [................]
#-------------------------------------------------------
# Make a Reference Copy of the bitmap for later rotation
self.shootsright = pygame.image.load("canss.png")
self.shootsright = pygame.transform.scale(self.shootsright,(self.shootsright.get_width()-150,self.shootsright.get_height()-150))
self.image = self.shootsright
self.rect = self.image.get_rect()
self.position = pygame.math.Vector2( (200, 180) )
def lookAt( self, coordinate ):
# Rotate image to point in the new direction
delta_vector = coordinate - pygame.math.Vector2(self.rect.center)
radius, angle = delta_vector.as_polar()
self.image = pygame.transform.rotate(self.shootsright, -angle)
# Re-set the bounding rectangle and position since
# the dimensions and centroid will have (probably) changed.
current_pos = self.rect.center
self.rect = self.image.get_rect()
self.rect.center = current_pos
在这里我调用LookAt
函数面对播放器:
# so instead of this
for enemyshoot in enemyshooting:
if not enemyshoot.isLookingAtPlayer:
enemyshoot.lookAt((playerman.x, playerman.y))
旋转位置不合适,我不知道如何解决它。我正在尝试使大炮的嘴朝玩家旋转,因为那是子弹的发源地。
答案 0 :(得分:1)
self.position
已在构造函数中设置,但未更新。使用self.rect.center
计算方向向量:
delta_vector = coordinate - pygame.math.Vector2(self.rect.center)
使用math.atan2
计算旋转角度:
(请参见How do I make my player rotate towards mouse position?)
angle = (180 / math.pi) * math.atan2(-delta_vector.x, -delta_vector.y)
在draw
中设置矩形位置需要旋转lookAt
中的子画面。请注意旋转的矩形的大小被放大。参见How do I rotate an image around its center using Pygame?。
我建议在lookAt
中设置查找位置,并在draw
中计算旋转后的图像:
class enemyshoot:
def __init__(self,x,y,height,width,color):
# [...]
self.look_at_pos = (x, y)
def draw(self):
self.rect = self.shootsright.get_rect(topleft = (self.x, self.y))
dx = self.look_at_pos[0] - self.rect.centerx
dy = self.look_at_pos[1] - self.rect.centery
angle = (180 / math.pi) * math.atan2(-dx, -dy)
self.image = pygame.transform.rotate(self.shootsright, angle)
self.rect = self.image.get_rect(center = self.rect.center)
window.blit(self.image, self.rect)
self.hits = (self.x + 20, self.y, 28,60)
pygame.draw.rect(window, (255,0,0), (self.hitbox[0], self.hitbox[1] - 60, 100, 10)) # NEW
pygame.draw.rect(window, (0,255,0), (self.hitbox[0], self.hitbox[1] - 60, 100 - (5 * (10 - self.health)), 10))
self.hitbox = (self.x + 200, self.y + 200, 51, 65)
def lookAt(self, coordinate):
self.look_at_pos = coordinate
答案 1 :(得分:1)
我同意@ Rabbid76在上述答案中所说的一切。
我怀疑您的问题的一部分可能是位图的“人类可读”部分未围绕位图的centroid居中。因此,当旋转时,它通过弧形“扫掠”,而不是“围绕自身”旋转。 (保持中心坐标是保持对象的质心平稳旋转的重要步骤。
考虑两个位图(右图在左上角有一个大的3/4透明部分):
两者均绕其质心旋转,但由于第二张图像上的可见部分未居中,因此旋转异常。
因此,请确保您的实际位图位于其内部居中。
参考代码:
import pygame
import random
# Window size
WINDOW_WIDTH = 800
WINDOW_HEIGHT = 400
WINDOW_SURFACE = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
DARK_BLUE = ( 3, 5, 54 )
class RotationSprite( pygame.sprite.Sprite ):
def __init__( self, image, x, y, ):
pygame.sprite.Sprite.__init__(self)
self.original = image
self.image = image
self.rect = self.image.get_rect()
self.rect.center = ( x, y )
# for maintaining trajectory
self.position = pygame.math.Vector2( ( x, y ) )
self.velocity = pygame.math.Vector2( ( 0, 0 ) )
def lookAt( self, co_ordinate ):
# Rotate image to point in the new direction
delta_vector = co_ordinate - self.position
radius, angle = delta_vector.as_polar()
self.image = pygame.transform.rotozoom( self.original, -angle, 1 )
# Re-set the bounding rectagle
current_pos = self.rect.center
self.rect = self.image.get_rect()
self.rect.center = current_pos
### initialisation
pygame.init()
pygame.mixer.init()
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), WINDOW_SURFACE )
pygame.display.set_caption( "Rotation Example" )
### Missiles!
rotation_sprites = pygame.sprite.Group()
rotation_image1 = pygame.image.load( 'rot_offcentre_1.png' )
rotation_image2 = pygame.image.load( 'rot_offcentre_2.png' )
rotation_sprites.add( RotationSprite( rotation_image1, WINDOW_WIDTH//3, WINDOW_HEIGHT//2 ) )
rotation_sprites.add( RotationSprite( rotation_image2, 2*( WINDOW_WIDTH//3 ), WINDOW_HEIGHT//2 ) )
### Main Loop
clock = pygame.time.Clock()
done = False
while not done:
# Handle user-input
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
done = True
elif ( event.type == pygame.MOUSEBUTTONUP ):
# On mouse-click
pass
# Record mouse movements for positioning the paddle
mouse_pos = pygame.mouse.get_pos()
for m in rotation_sprites:
m.lookAt( mouse_pos )
rotation_sprites.update()
# Update the window, but not more than 60 FPS
window.fill( DARK_BLUE )
rotation_sprites.draw( window )
pygame.display.flip()
# Clamp FPS
clock.tick_busy_loop(60)
pygame.quit()