如何使我的矩形与旋转精灵一起旋转

时间:2021-01-08 02:40:26

标签: python pygame

所以我的矩形/弹丸旋转遇到了这个问题,我想要它,这样我的矩形/弹丸就会随着我的旋转精灵旋转,但我正在尝试的代码对我不起作用,我的代码我正在尝试给我这个错误。 'pygame.Surface' object has no attribute 'x' 我试过移动代码,我也试过更改代码,这样我就不会再出现错误了,我也尝试过使用命中框,但我仍然不断收到错误消息。这是我的两个精灵

enter image description here enter image description here

我正在尝试的代码

        self.dist = 100
        dx = self.pin.x + self.dist*math.cos(-self.pin.angle*(math.pi/180)) -65 # why offset needed ?
        dy = self.pin.y + self.dist*math.sin(-self.pin.angle*(math.pi/180)) -50 # why offset needed ?
        self.rect.topleft = (dx,dy)
        pygame.draw.rect(window,self.color,self.rect)

我的完整代码

import pygame,math,random
pygame.init()

# Windowing screen width and height
width = 500
height = 500
window = pygame.display.set_mode((width,height))

# Name of window
pygame.display.set_caption("Game")

# The Background
background = pygame.image.load("img/BG.png")


def blitRotate(surf, image, pos, originPos, angle):

    # calcaulate the axis aligned bounding box of the rotated image
    w, h         = image.get_size()
    sin_a, cos_a = math.sin(math.radians(angle)), math.cos(math.radians(angle)) 
    min_x, min_y = min([0, sin_a*h, cos_a*w, sin_a*h + cos_a*w]), max([0, sin_a*w, -cos_a*h, sin_a*w - cos_a*h])

    # calculate the translation of the pivot 
    pivot        = pygame.math.Vector2(originPos[0], -originPos[1])
    pivot_rotate = pivot.rotate(angle)
    pivot_move   = pivot_rotate - pivot

    # calculate the upper left origin of the rotated image
    origin = (pos[0] - originPos[0] + min_x - pivot_move[0], pos[1] - originPos[1] - min_y + pivot_move[1])

    # get a rotated image
    rotated_image = pygame.transform.rotate(image, angle)

    # rotate and blit the image
    surf.blit(rotated_image, origin)
    
# Player class
class Player:
    def __init__(self,x,y,width,height,color):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.color = color
        self.speed = 4
        self.cannon = pygame.image.load("img/Cannon.png")
        self.cannon = pygame.transform.scale(self.cannon,(self.cannon.get_width()//2, self.cannon.get_height()//2))
        self.rect = pygame.Rect(x,y,width,height)
        self.hitbox = (self.x,self.y,30,30)
        self.image = self.cannon
        self.rect  = self.image.get_rect(center = (self.x, self.y))
        self.look_at_pos = (self.x, self.y)

        self.isLookingAtPlayer = False
        self.look_at_pos = (x,y)

        self.angle = 0
    def get_rect(self):
        self.rect.topleft = (self.x,self.y)
        return self.rect
    def draw(self):
        self.rect.topleft = (self.x,self.y)
        pygame.draw.rect(window,self.color,self.hitbox)
    
        player_rect = self.cannon.get_rect(center = self.get_rect().center)
        player_rect.centerx -= 0
        player_rect.centery += 90
    
        # Another part of cannon rotating     
        dx = self.look_at_pos[0] - self.rect.centerx
        dy = self.look_at_pos[1] - self.rect.centery 
        
        angle = (180/math.pi) * math.atan2(-dy, dx) - 90
  
        gun_size = self.image.get_size()
        pivot_abs = player_rect.centerx, player_rect.top + 13
        pivot_rel = (gun_size[0] // 2, 105)
        
        pygame.draw.rect(window,self.color,self.rect)
        blitRotate(window, self.image,pivot_abs, pivot_rel, angle)

        
    def lookAt( self, coordinate ):
        self.look_at_pos = coordinate


        

# Players gun
class projectile(object):
    def __init__(self,x,y,dirx,diry,color):
        self.x = x
        self.y = y
        self.dirx = dirx
        self.diry = diry
        self.pin = pygame.image.load("img/Pin.png")
        self.pin = pygame.transform.scale(self.pin,(self.pin.get_width()//6, self.pin.get_height()//6))
        self.rect = self.pin.get_rect()
        self.topleft = ( self.x, self.y )
        self.speed = 10
        self.color = color
        self.hitbox = (self.x + 20, self.y, 30,40)
    def move(self):
        self.x += self.dirx * self.speed
        self.y += self.diry * self.speed
    def draw(self):
        self.rect.topleft = (round(self.x), round(self.y))
        
        window.blit(self.pin,self.rect)
        self.hitbox = (self.x + 20, self.y,30,30)

       # For rotating the the projectile
        self.dist = 100
        dx = self.pin.x + self.dist*math.cos(-self.pin.angle*(math.pi/180)) -65 # why offset needed ?
        dy = self.pin.y + self.dist*math.sin(-self.pin.angle*(math.pi/180)) -50 # why offset needed ?
        self.rect.topleft = (dx,dy)
        pygame.draw.rect(window,self.color,self.rect)


        


# The color white
white = (255,255,255)

# The xy cords, width, height and color of my classes[]

playerman = Player(350,385,34,75,white)



# This is where my balloons get hit by the bullet and disappers
# redrawing window
def redrawwindow():
    window.fill((0,0,0))

    # Drawing the window in
    window.blit(background,(0,0))

    # drawing the player in window
    playerman.draw()

    # Drawing the players bullet
    for bullet in bullets:
        bullet.draw()

# Frames for game
fps = 30
clock = pygame.time.Clock()
#projectile empty list
bullets = []
# main loop
run = True
while run:
    clock.tick(fps)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False


        if event.type == pygame.MOUSEBUTTONDOWN:

            if len(bullets) < 6700:
                mousex , mousey = pygame.mouse.get_pos()
                start_x , start_y = playerman.rect.x + 12, playerman.rect.y - 3
                mouse_x , mouse_y = event.pos
                dir_x , dir_y = mouse_x - start_x , mouse_y - start_y
                distance = math.sqrt(dir_x**2 + dir_y**2)
                if distance > 0:
                    new_bullet = projectile(start_x, start_y, dir_x/distance , dir_y/distance, (0,0,0))
                    bullets.append(new_bullet)

    for bullet in bullets[:]:
        bullet.move()
        if bullet.x < 0 or bullet.x > 900 or bullet.y < 0 or bullet.y > 900:
            bullets.pop(bullets.index(bullet))

    # gun rotation
    mousex, mousey = pygame.mouse.get_pos()
    if not playerman.isLookingAtPlayer:
        playerman.lookAt((mousex, mousey))

   
                    
    # telling game that key means when a key get pressed
    keys = pygame.key.get_pressed()

    # The player moving when the key a is pressed
    if keys[pygame.K_a] and playerman.x > playerman.speed:
        playerman.x -= playerman.speed

    # The player moving when the key d is pressed
    if keys[pygame.K_d] and playerman.x < 500 - playerman.width - playerman.speed:
        playerman.x += playerman.speed

    # Calling the redraw function
    redrawwindow()
    # updating game
    pygame.display.update()
# quiting the game
pygame.quit()


1 个答案:

答案 0 :(得分:0)

您已经在 projectile.move 方法中移动了图钉。在 projectile.draw 方法中,您只需旋转图钉。请参阅 How do I rotate an image around its center using PyGame?How to rotate an image(player) to the mouse direction?


class projectile(object):
    # [...]

    def draw(self):
        self.rect.center = (round(self.x), round(self.y))
        
        angle = math.degrees(math.atan2(-self.diry, self.dirx)) - 90
        rotated_pin = pygame.transform.rotate(self.pin, angle)
        rotated_rect = rotated_pin.get_rect(center = self.rect.center)

        pygame.draw.rect(window,self.color, rotated_rect)
        window.blit(rotated_pin, rotated_rect)
        self.hitbox = (self.x + 20, self.y,30,30)

您必须找到引脚的起始位置。销应该从吹管顶部的某个地方开始。向 get_pivot 类添加 Player 方法:

class Player:
    # [...]

    def get_pivot(self):
        player_rect = self.cannon.get_rect(center = self.get_rect().center)
        return player_rect.centerx, player_rect.top + 103

添加一个计算吹管角度的get_angle方法:

class Player:
    # [...]

    def get_angle(self):
        pivot_abs = self.get_pivot()
        dx = self.look_at_pos[0] - pivot_abs[0]
        dy = self.look_at_pos[1] - pivot_abs[1]
        return math.degrees(math.atan2(-dy, dx))

使用此方法计算吹管的顶部:

class Player:
    # [...]

    def get_top(self):
        pivot_x, pivot_y = self.get_pivot()
        angle = self.get_angle()
        length = 100
        top_x = pivot_x + length * math.cos(math.radians(angle))
        top_y = pivot_y - length * math.sin(math.radians(angle))
        return top_x, top_y

您还可以在 get_pivot 方法中使用 get_angledraw 方法:

class Player:
    # [...]

    def draw(self):
        self.rect.topleft = (self.x,self.y)
        pygame.draw.rect(window,self.color,self.hitbox)

        gun_size = self.image.get_size()
        pivot_abs = self.get_pivot()
        pivot_rel = (gun_size[0] // 2, 105)
        angle = self.get_angle() - 90
        
        pygame.draw.rect(window,self.color,self.rect)
        blitRotate(window, self.image,pivot_abs, pivot_rel, angle)

使用get_top设置引脚的起始位置:

mousex, mousey = pygame.mouse.get_pos()
start_x, start_y = playerman.get_top()
mouse_x, mouse_y = event.pos
dir_x, dir_y = mouse_x - start_x , mouse_y - start_y
distance = math.sqrt(dir_x**2 + dir_y**2)
if distance > 0:
    new_bullet = projectile(start_x, start_y, dir_x/distance, dir_y/distance, (0,0,0))
    bullets.append(new_bullet)

在吹管之前将销子拉入,使销子看起来像是从吹管中出来:

def redrawwindow():
    window.fill((0,0,0))

    # Drawing the window in
    window.blit(background,(0,0))

    # Drawing the players bullet
    for bullet in bullets:
        bullet.draw()

    # drawing the player in window
    playerman.draw()

完整示例:

import pygame,math,random
pygame.init()

# Windowing screen width and height
width = 500
height = 500
window = pygame.display.set_mode((width,height))

# Name of window
pygame.display.set_caption("Game")

# The Background
background = pygame.image.load("img/BG.png")


def blitRotate(surf, image, pos, originPos, angle):

    # calcaulate the axis aligned bounding box of the rotated image
    w, h         = image.get_size()
    sin_a, cos_a = math.sin(math.radians(angle)), math.cos(math.radians(angle)) 
    min_x, min_y = min([0, sin_a*h, cos_a*w, sin_a*h + cos_a*w]), max([0, sin_a*w, -cos_a*h, sin_a*w - cos_a*h])

    # calculate the translation of the pivot 
    pivot        = pygame.math.Vector2(originPos[0], -originPos[1])
    pivot_rotate = pivot.rotate(angle)
    pivot_move   = pivot_rotate - pivot

    # calculate the upper left origin of the rotated image
    origin = (pos[0] - originPos[0] + min_x - pivot_move[0], pos[1] - originPos[1] - min_y + pivot_move[1])

    # get a rotated image
    rotated_image = pygame.transform.rotate(image, angle)

    # rotate and blit the image
    surf.blit(rotated_image, origin)
    
# Player class
class Player:
    def __init__(self,x,y,width,height,color):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.color = color
        self.speed = 4
        self.cannon = pygame.image.load("img/Cannon.png")
        self.cannon = pygame.transform.scale(self.cannon,(self.cannon.get_width()//2, self.cannon.get_height()//2))
        self.rect = pygame.Rect(x,y,width,height)
        self.hitbox = (self.x,self.y,30,30)
        self.image = self.cannon
        self.rect  = self.image.get_rect(center = (self.x, self.y))
        self.look_at_pos = (self.x, self.y)

        self.isLookingAtPlayer = False
        self.look_at_pos = (x,y)

        self.angle = 0
    def get_rect(self):
        self.rect.topleft = (self.x,self.y)
        return self.rect

    def get_pivot(self):
        player_rect = self.cannon.get_rect(center = self.get_rect().center)
        return player_rect.centerx, player_rect.top + 103

    def get_angle(self):
        pivot_abs = self.get_pivot()
        dx = self.look_at_pos[0] - pivot_abs[0]
        dy = self.look_at_pos[1] - pivot_abs[1]
        return math.degrees(math.atan2(-dy, dx))

    def get_top(self):
        pivot_x, pivot_y = self.get_pivot()
        angle = self.get_angle()
        length = 100
        top_x = pivot_x + length * math.cos(math.radians(angle))
        top_y = pivot_y - length * math.sin(math.radians(angle))
        return top_x, top_y

    def draw(self):
        self.rect.topleft = (self.x,self.y)
        pygame.draw.rect(window,self.color,self.hitbox)

        gun_size = self.image.get_size()
        pivot_abs = self.get_pivot()
        pivot_rel = (gun_size[0] // 2, 105)
        angle = self.get_angle() - 90
        
        pygame.draw.rect(window,self.color,self.rect)
        blitRotate(window, self.image,pivot_abs, pivot_rel, angle)
        
    def lookAt( self, coordinate ):
        self.look_at_pos = coordinate


        

# Players gun
class projectile(object):
    def __init__(self,x,y,dirx,diry,color):
        self.x = x
        self.y = y
        self.dirx = dirx
        self.diry = diry
        self.pin = pygame.image.load("img/Pin.png")
        self.pin = pygame.transform.scale(self.pin,(self.pin.get_width()//6, self.pin.get_height()//6))
        self.rect = self.pin.get_rect()
        self.center = ( self.x, self.y )
        self.speed = 10
        self.color = color
        self.hitbox = (self.x + 20, self.y, 30,40)
    def move(self):
        self.x += self.dirx * self.speed
        self.y += self.diry * self.speed
    def draw(self):
        self.rect.center = (round(self.x), round(self.y))
        
        angle = math.degrees(math.atan2(-self.diry, self.dirx)) - 90
        rotated_pin = pygame.transform.rotate(self.pin, angle)
        rotated_rect = rotated_pin.get_rect(center = self.rect.center)

        pygame.draw.rect(window,self.color, rotated_rect)
        window.blit(rotated_pin, rotated_rect)
        self.hitbox = (self.x + 20, self.y,30,30)
        


# The color white
white = (255,255,255)

# The xy cords, width, height and color of my classes[]

playerman = Player(350,385,34,75,white)



# This is where my balloons get hit by the bullet and disappers
# redrawing window
def redrawwindow():
    window.fill((0,0,0))

    # Drawing the window in
    window.blit(background,(0,0))

    # Drawing the players bullet
    for bullet in bullets:
        bullet.draw()

    # drawing the player in window
    playerman.draw()

# Frames for game
fps = 30
clock = pygame.time.Clock()
#projectile empty list
bullets = []
# main loop
run = True
while run:
    clock.tick(fps)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False


        if event.type == pygame.MOUSEBUTTONDOWN:

            if len(bullets) < 6700:
                mousex, mousey = pygame.mouse.get_pos()
                start_x, start_y = playerman.get_top()
                mouse_x, mouse_y = event.pos
                dir_x, dir_y = mouse_x - start_x , mouse_y - start_y
                distance = math.sqrt(dir_x**2 + dir_y**2)
                if distance > 0:
                    new_bullet = projectile(start_x, start_y, dir_x/distance, dir_y/distance, (0,0,0))
                    bullets.append(new_bullet)

    for bullet in bullets[:]:
        bullet.move()
        if bullet.x < 0 or bullet.x > 900 or bullet.y < 0 or bullet.y > 900:
            bullets.pop(bullets.index(bullet))

    # gun rotation
    mousex, mousey = pygame.mouse.get_pos()
    if not playerman.isLookingAtPlayer:
        playerman.lookAt((mousex, mousey))

   
                    
    # telling game that key means when a key get pressed
    keys = pygame.key.get_pressed()

    # The player moving when the key a is pressed
    if keys[pygame.K_a] and playerman.x > playerman.speed:
        playerman.x -= playerman.speed

    # The player moving when the key d is pressed
    if keys[pygame.K_d] and playerman.x < 500 - playerman.width - playerman.speed:
        playerman.x += playerman.speed

    # Calling the redraw function
    redrawwindow()
    # updating game
    pygame.display.update()
# quiting the game
pygame.quit()