在pygame中旋转矩形(不是图像)

问题描述 投票:0回答:10

在 pygame 中,我对程序中的所有矩形使用

pygame.draw.rect(screen, color, rectangle)
。我希望能够将这些矩形旋转到任何角度。我已经看到以下代码来旋转IMAGES,但我的问题是RECTANGLES

pygame.transform.rotate(image, angle)

但是我正在使用矩形,我没有可以旋转的图像或“表面”。当我尝试使用

旋转矩形时
rect = pygame.draw.rect(screen, self.color, self.get_rectang())
rotatedRect = pygame.transform.rotate(rect, self.rotation)
screen.blit(rotatedRect)

这会在 .rotate() 线上给出

TypeError: must be pygame.Surface, not pygame.Rect

我的问题是,如何在 pygame 中旋转 a 并显示矩形

(x,y,w,h)
,而不是图像。

这是“潜在重复”的链接帖子不是重复的。一个答案解释了旋转矩形的后果,另一个答案使用旋转图像的代码。

python rotation pygame rectangles
10个回答
8
投票
import pygame as py  

# define constants  
WIDTH = 500  
HEIGHT = 500  
FPS = 30  

# define colors  
BLACK = (0 , 0 , 0)  
GREEN = (0 , 255 , 0)  

# initialize pygame and create screen  
py.init()  
screen = py.display.set_mode((WIDTH , HEIGHT))  
# for setting FPS  
clock = py.time.Clock()  

rot = 0  
rot_speed = 2  

# define a surface (RECTANGLE)  
image_orig = py.Surface((100 , 100))  
# for making transparent background while rotating an image  
image_orig.set_colorkey(BLACK)  
# fill the rectangle / surface with green color  
image_orig.fill(GREEN)  
# creating a copy of orignal image for smooth rotation  
image = image_orig.copy()  
image.set_colorkey(BLACK)  
# define rect for placing the rectangle at the desired position  
rect = image.get_rect()  
rect.center = (WIDTH // 2 , HEIGHT // 2)  
# keep rotating the rectangle until running is set to False  
running = True  
while running:  
    # set FPS  
    clock.tick(FPS)  
    # clear the screen every time before drawing new objects  
    screen.fill(BLACK)  
    # check for the exit  
    for event in py.event.get():  
        if event.type == py.QUIT:  
            running = False  

    # making a copy of the old center of the rectangle  
    old_center = rect.center  
    # defining angle of the rotation  
    rot = (rot + rot_speed) % 360  
    # rotating the orignal image  
    new_image = py.transform.rotate(image_orig , rot)  
    rect = new_image.get_rect()  
    # set the rotated rectangle to the old center  
    rect.center = old_center  
    # drawing the rotated rectangle to the screen  
    screen.blit(new_image , rect)  
    # flipping the display after drawing everything  
    py.display.flip()  

py.quit()  

7
投票

请参阅此处的第二个答案:围绕另一个点旋转一个点(2D)

我认为矩形的方向只能是水平或垂直的。您需要定义角并旋转它们,然后在它们之间绘制和填充。

另一种方式是上课

class myRect(pygame.Surface):
    def __init__(self, parent, xpos, ypos, width, height):
      super(myRect, self).__init__(width, height)
      self.xpos = xpos
      self.ypos = ypos
      self.parent = parent

    def update(self, parent):
      parent.blit(self, (self.xpos, self.ypos))

    def rotate(self, angle):
      #(your rotation code goes here)

并使用它,这样您就可以使用变换函数来旋转它。


1
投票

快速替换的更复杂版本,您可以在其中为矩形定义任意旋转中心点 - 甚至在其外部(在 python3 中测试):

    def rectRotated( surface, color, pos, fill, border_radius, rotation_angle, rotation_offset_center = (0,0), nAntialiasingRatio = 1 ):
        """
        - rotation_angle: in degree
        - rotation_offset_center: moving the center of the rotation: (-100,0) will turn the rectangle around a point 100 above center of the rectangle,
                                             if (0,0) the rotation is at the center of the rectangle
        - nAntialiasingRatio: set 1 for no antialising, 2/4/8 for better aliasing
        """
        nRenderRatio = nAntialiasingRatio
        
        sw = pos[2]+abs(rotation_offset_center[0])*2
        sh = pos[3]+abs(rotation_offset_center[1])*2

        surfcenterx = sw//2
        surfcentery = sh//2
        s = pg.Surface( (sw*nRenderRatio,sh*nRenderRatio) )
        s = s.convert_alpha()
        s.fill((0,0,0,0))
        
        rw2=pos[2]//2 # halfwidth of rectangle
        rh2=pos[3]//2

        pg.draw.rect( s, color, ((surfcenterx-rw2-rotation_offset_center[0])*nRenderRatio,(surfcentery-rh2-rotation_offset_center[1])*nRenderRatio,pos[2]*nRenderRatio,pos[3]*nRenderRatio), fill*nRenderRatio, border_radius=border_radius*nRenderRatio )
        s = pygame.transform.rotate( s, rotation_angle )        
        if nRenderRatio != 1: s = pygame.transform.smoothscale(s,(s.get_width()//nRenderRatio,s.get_height()//nRenderRatio))
        incfromrotw = (s.get_width()-sw)//2
        incfromroth = (s.get_height()-sh)//2
        surface.blit( s, (pos[0]-surfcenterx+rotation_offset_center[0]+rw2-incfromrotw,pos[1]-surfcentery+rotation_offset_center[1]+rh2-incfromroth) )
        

1
投票

您无法旋转由

pygame.draw.rect
绘制的矩形。您必须创建一个透明的
pygame.Surface
并旋转 Surface:

rect_surf = pygame.Surface((widht, height), pygame.SRCLAPHA)
rect_surf.fill(color)

请参阅如何使用 PyGame 围绕其中心旋转图像?,以旋转 Surface


1
投票

我创建了一个课程来为你处理轮换...
扩展自 Ashish 的设计

from pygame import Surface, transform
from consts import screen


class BaseEntity:
    def __init__(self, x: int, y: int):
        self.x = x
        self.y = y


class Rectangle(BaseEntity):
    def __init__(self, x: int, y: int, width: int, height: int, color: tuple):
        super().__init__(x, y)
        self.width = width
        self.height = height
        self.color = color
        self.rotatation = 0

        # the rectangle is a surface itself
        self.surface = Surface((width, height))
        self.surface.set_colorkey((0, 0, 0))
        self.surface.fill(color)
        self.rect = self.surface.get_rect()

    def display(self, angle=None):
        # updating values
        self.surface.fill(
            self.color
        )  # refill the surface color if you change it somewhere in the program
        self.rect = self.surface.get_rect()
        self.rect.center = (self.x, self.y)

        # renderer
        if angle is not None:
            self.rotatation = angle

        old_center = self.rect.center
        new = transform.rotate(self.surface, self.rotatation)
        self.rect = new.get_rect()
        self.rect.center = old_center
        screen.blit(new, self.rect)

1
投票

使用一些三角函数和 polygon 函数,我可以绘制一个旋转的矩形。

import math
import pygame.draw


def draw_rectangle(x, y, width, height, color, rotation=0):
    """Draw a rectangle, centered at x, y.

    Arguments:
      x (int/float):
        The x coordinate of the center of the shape.
      y (int/float):
        The y coordinate of the center of the shape.
      width (int/float):
        The width of the rectangle.
      height (int/float):
        The height of the rectangle.
      color (str):
        Name of the fill color, in HTML format.
    """
    points = []

    # The distance from the center of the rectangle to
    # one of the corners is the same for each corner.
    radius = math.sqrt((height / 2)**2 + (width / 2)**2)

    # Get the angle to one of the corners with respect
    # to the x-axis.
    angle = math.atan2(height / 2, width / 2)

    # Transform that angle to reach each corner of the rectangle.
    angles = [angle, -angle + math.pi, angle + math.pi, -angle]

    # Convert rotation from degrees to radians.
    rot_radians = (math.pi / 180) * rotation

    # Calculate the coordinates of each point.
    for angle in angles:
        y_offset = -1 * radius * math.sin(angle + rot_radians)
        x_offset = radius * math.cos(angle + rot_radians)
        points.append((x + x_offset, y + y_offset))

    pygame.draw.polygon(screen, color, points)

https://replit.com/@TimSwast1/RotateARectanlge?v=1


0
投票

快速替换基本 pygame 函数添加旋转:

def rectRotated( surface, color, pos, fill, border_radius, angle ):
    """
    - angle in degree
    """
    max_area = max(pos[2],pos[3])
    s = pg.Surface((max_area,max_area))
    s = s.convert_alpha()
    s.fill((0,0,0,0))
    pg.draw.rect(s, color,(0,0,pos[2],pos[3]),fill, border_radius=border_radius)
    s = pygame.transform.rotate(s,angle)
    surface.blit( s, (pos[0],pos[1]) )

0
投票

此代码模拟旋转的矩形落向地面。我在我的一款游戏中使用了它,让背景看起来很棒

import pygame
import random

class Square(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super(Square, self).__init__()

        self.win = win
        self.color = (128, 128, 128)
        self.speed = 3
        self.angle = 0

        self.side = random.randint(15, 40)

        self.surface = pygame.Surface((self.side, self.side), pygame.SRCALPHA)
        self.surface.set_colorkey((200,200,200))
        self.rect = self.surface.get_rect(center=(x, y))

    def update(self, win):
        center = self.rect.center
        self.angle = (self.angle + self.speed) % 360
        image = pygame.transform.rotate(self.surface , self.angle)
        self.rect = image.get_rect()
        self.rect.center = center

        self.rect.y += 1.5

        if self.rect.top >= HEIGHT:
            self.kill()

        pygame.draw.rect(self.surface, self.color, (0,0, self.side, self.side), 4)
        win.blit(image, self.rect)

if __name__ == '__main__':
    pygame.init()
    SCREEN = WIDTH, HEIGHT = 288, 512
    win = pygame.display.set_mode(SCREEN, pygame.NOFRAME)

    clock = pygame.time.Clock()
    FPS = 60
    count = 0

    square_group = pygame.sprite.Group()

    running = True
    while running:
        win.fill((200,200,200))

        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    running = False

        count += 1
        if count % 100 == 0:
            x = random.randint(40, WIDTH-40)
            y = 0
            square = Square(x, y)
            square_group.add(square)
            count = 0

        square_group.update(win)

        pygame.draw.rect(win, (30,30,30), (0, 0, WIDTH, HEIGHT), 8)
        clock.tick(FPS)
        pygame.display.update()
pygame.quit()

这是输出,但它不是 gif

现在,如果您想要颜色填充的矩形而不是仅带边框的矩形,请在第 31 行更新此行

pygame.draw.rect(self.surface, self.color, (0,0, self.side, self.side))

如果你不想让矩形掉下来注释第26行


0
投票

简洁快速的绘制旋转矩形的函数。使用 NumPy

    def rectRotated(self, surface, rect, color, rotation):
        """
        Draws a rotated Rect.
        surface: pygame.Surface
        rect: pygame.Rect
        color: pygame.Color
        rotation: float (degrees)
        return: np.ndarray (vertices)
        """
        # calculate the rotation in radians
        rot_radians = -rotation * pi / 180

        # calculate the points around the center of the rectangle, taking width and height into account
        angle = atan2(rect.height / 2, rect.width / 2)
        angles = [angle, -angle + pi, angle + pi, -angle]
        radius = sqrt((rect.height / 2)**2 + (rect.width / 2)**2)

        # create a numpy array of the points
        points = np.array([
            [rect.x + radius * cos(angle + rot_radians), rect.y + radius * sin(angle + rot_radians)]
            for angle in angles
        ])

        # draw the polygon
        pygame.draw.polygon(surface, color, points)

        # return the vertices of the rectangle
        return points

0
投票

您可以使用 numpy 中的旋转矩阵来旋转多边形:

# create polygon (a triangle)
polygon = np.array([(0,-20),(10,20),(-10,20)])

# create rotation matrix
sin, cos = np.sin(angle), np.cos(angle)
rotation_matrix = np.array([(cos, -sin),(sin, cos)])

# apply rotation matrix
rotated_polygon = ship @ rot_matrix

# draw result
pygame.draw.polygon(window, (0,255,0), rotated_polygon.tolist())

Pygame 不接受 numpy 数组,但 numpy tolist() 方法会对其进行转换。

如果要将多边形移动到窗口中的另一个位置:

location = (50,50)
pygame.draw.polygon(window, (0,255,0), (rotated_polygon+location).tolist())
© www.soinside.com 2019 - 2024. All rights reserved.