使用Pygame绘制对角椭圆

4

有没有简单的方法画与x轴和y轴不对齐的椭圆?我对pygame非常陌生,请见谅我的无知,但我找不到任何相关的东西。

如果不存在简单的方法,可以有人帮我想办法吗?除了在椭圆上生成许多点并绘制所有这些点之外,我还能怎么画它?

5个回答

3
你可以做到这一点。创建一个表面,将椭圆绘制到该表面上,然后旋转整个表面(椭圆在其上)。以下是我的测试代码:
import pygame, sys

screen = pygame.display.set_mode((1024, 640))

running = True

#let's create a surface to hold our ellipse:
surface = pygame.Surface((320, 240))

red = (180, 50, 50)
size = (0, 0, 300, 200)

#drawing an ellipse onto the 
ellipse = pygame.draw.ellipse(surface, red, size)

#new surface variable for clarity (could use our existing though)
#we use the pygame.transform module to rotate the original surface by 45°
surface2 = pygame.transform.rotate(surface, 45)

while running:
    screen.fill((255, 250, 200))
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
    screen.blit(surface2, (100, 100))
    pygame.display.update()

结果将是一个旋转的椭圆。可以使椭圆的“容器”透明。请查阅模块文档:

http://www.pygame.org/docs/ref/transform.html#pygame.transform.rotate

http://www.pygame.org/docs/ref/surface.html

希望能帮到你!

1

很遗憾,没有直接绘制旋转形状的方法。pygame.transform.rotate() 可以旋转一个 pygame.Surface 对象,但是你不能直接旋转一个形状。你需要在一个 Surface 上绘制该形状并旋转该 Surface

  1. 使用pygame.Surface对象创建一个逐像素Alpha格式的图形,并设置其大小。
  2. 在_Surface上绘制该图形。
  3. 以该图形为中心旋转Surface。参见如何使用PyGame将图像围绕其中心旋转?
  4. blit该带有该图形的Surface到目标Surface上。

编写一个函数来绘制旋转的图形:

def draw_ellipse_angle(surface, color, rect, angle, width=0):
    target_rect = pygame.Rect(rect)
    shape_surf = pygame.Surface(target_rect.size, pygame.SRCALPHA)
    pygame.draw.ellipse(shape_surf, color, (0, 0, *target_rect.size), width)
    rotated_surf = pygame.transform.rotate(shape_surf, angle)
    surface.blit(rotated_surf, rotated_surf.get_rect(center = target_rect.center))

最简单的例子:

import pygame

def draw_ellipse_angle(surface, color, rect, angle, width=0):
    target_rect = pygame.Rect(rect)
    shape_surf = pygame.Surface(target_rect.size, pygame.SRCALPHA)
    pygame.draw.ellipse(shape_surf, color, (0, 0, *target_rect.size), width)
    rotated_surf = pygame.transform.rotate(shape_surf, angle)
    surface.blit(rotated_surf, rotated_surf.get_rect(center = target_rect.center))

pygame.init()
window = pygame.display.set_mode((250, 250))
clock = pygame.time.Clock()

background = pygame.Surface(window.get_size())
ts, w, h, c1, c2 = 50, *window.get_size(), (160, 160, 160), (192, 192, 192)
tiles = [((x*ts, y*ts, ts, ts), c1 if (x+y) % 2 == 0 else c2) for x in range((w+ts-1)//ts) for y in range((h+ts-1)//ts)]
for rect, color in tiles:
    pygame.draw.rect(background, color, rect)

angle = 0
run = True
while run:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    window.blit(background, (0, 0))
    draw_ellipse_angle(window, (0, 0, 255), (25, 75, 200, 100), angle, 5)
    angle += 1
    pygame.display.flip()

pygame.quit()
exit()

0
如果有人好奇如何使用旋转的椭圆来画“花”,以下内容可能会对此有所帮助。
def flower(width: int, color: tuple, edges: bool=False):
    W, H = width, width
    # create a flower surface with an alpha channel on which to draw 
    # the petals
    flower = pygame.Surface((W, H), pygame.SRCALPHA, 32).convert_alpha()
    R = flower.get_rect()
    cx, cy = R.center
    # assuming petal height should be half their width
    petal_size = (width//2, width//4)
    pw, ph = petal_size
    radius = pw/2
    center_radius = width//10
    center_color = (255-color[0], 255-color[1], 255-color[2])

    def draw_petal(S, x, y, w, h, angle):
        # Create surface for drawing an individual petal
        surface = pygame.Surface((w, h), pygame.SRCALPHA, 32).convert_alpha()
        # Draw the un-rotated petal
        pygame.draw.ellipse(surface, color, (0, 0, w, h), 0)
        if edges:
            pygame.draw.ellipse(surface, BLACK, (0, 0, w, h), 1)

        # Create a new surface with the petal rotated by angle
        rot_surface = pygame.transform.rotate(surface, angle)
        # Need center of rotated surface to blit (draw) the rotated
        # petal at the given (x, y) coordinate
        rcx, rcy = rot_surface.get_rect().center
        # Draw the center of the rotated petal at (x, y)
        S.blit(rot_surface, (x - rcx, y - rcy))

    # Petals are drawn at diagonals first, then the horizontal petals,
    # then the vertical petals
    angles = [
        45, 135, 225, 315,      # diagonals
        0, 180,                 # horizontal
        90, 270                 # vertical
    ]
    for a in angles:
        # placing petal centers onto circle of radius (petal_width/2)
        x, y = map(int, (
            radius*math.cos(math.radians(a)), radius*math.sin(math.radians(a))
        ))
        draw_petal(flower, cx+x, cy+y, pw, ph, -a)
    # draw flower center (don't remember what it's called)
    pygame.draw.circle(flower, center_color, (cx, cx), center_radius)
    if edges:
        pygame.draw.circle(flower, BLACK, (cx, cx), center_radius, 1)

    def draw_flower(S, x, y, flower=flower):
        S.blit(flower, (x - cx, y - cy))
    return draw_flower

使用此代码:

import math
import pygame

BLACK    = (   0,   0,   0)
GREEN    = (   0, 255,   0)
RED      = ( 255,   0,   0)

pygame.init()

size = (800, 800)
SW, SH = size
screen = pygame.display.set_mode(size)

pygame.display.set_caption("Flower Demo")

done = False
clock = pygame.time.Clock()

# insert above flower code

draw_green_flower = flower(100, GREEN)
draw_red_flower = flower(100, RED)
try:
    while not done:

        for event in pygame.event.get(): 
            if event.type == pygame.QUIT:
                done = True 
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    done = True 

        screen.fill(WHITE)

        draw_green_flower(screen, SW/2,SH/2)
        draw_red_flower(screen, SW/2-100,SH/2-100)

        pygame.display.flip()

        clock.tick(60)

finally:
    pygame.quit()

0
如果有人需要的话,我写了一个函数,可以让你在任意两点A和B之间绘制椭圆。
虽然不是最优雅的数学方法,但它确实有效!请参见下面的示例:
import pygame
import math


def draw_ellipse(A, B, width, color, line):
    """
    draws ellipse between two points
    A = start point (x,y)
    B = end point (x,y)
    width in pixel
    color (r,g,b)
    line thickness int, if line=0 fill ellipse
    """
    # point coordinates
    xA, yA = A[0], A[1]
    xB, yB = B[0], B[1]
    # calculate ellipse height, distance between A and B
    AB = math.sqrt((xB - xA)**2 + (yB - yA)**2)

    # difference between corner point coord and ellipse endpoint
    def sp(theta):
        return abs((width / 2 * math.sin(math.radians(theta))))

    def cp(theta):
        return abs((width / 2 * math.cos(math.radians(theta))))

    if xB >= xA and yB < yA:
        # NE quadrant
        theta = math.degrees(math.asin((yA - yB) / AB))
        xP = int(xA - sp(theta))
        yP = int(yB - cp(theta))
    elif xB < xA and yB <= yA:
        # NW
        theta = math.degrees(math.asin((yB - yA) / AB))
        xP = int(xB - sp(theta))
        yP = int(yB - cp(theta))
    elif xB <= xA and yB > yA:
        # SW
        theta = math.degrees(math.asin((yB - yA) / AB))
        xP = int(xB - sp(theta))
        yP = int(yA - cp(theta))
    else:
        # SE
        theta = math.degrees(math.asin((yA - yB) / AB))
        xP = int(xA - sp(theta))
        yP = int(yA - cp(theta))

    # create surface for ellipse
    ellipse_surface = pygame.Surface((AB, width), pygame.SRCALPHA)
    # draw surface onto ellipse
    pygame.draw.ellipse(ellipse_surface, color, (0, 0, AB, width), line)
    # rotate ellipse
    ellipse = pygame.transform.rotate(ellipse_surface, theta)
    # blit ellipse onto screen
    screen.blit(ellipse, (xP, yP))


screen = pygame.display.set_mode((1000, 1000))

running = True
while running:
    screen.fill((255, 250, 200))

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()

    draw_ellipse((500, 500), (420, 350), 100, (0, 255, 0), 5)
    draw_ellipse((400, 600), (700, 280), 80, (255, 0, 0), 5)
    draw_ellipse((260, 190), (670, 440), 50, (0, 0, 255), 5)

    pygame.display.update()

-2

我不懂Python或Pygame,但根据您正在构建的内容,可能更容易使用像PC和Mac上的Inkscape或iPad上的Inkpad这样的程序制作图像。 这两个应用程序都可以让您制作对角椭圆,然后将其导出为.png文件并在代码中使用它。 再次强调,是否能够这样做实际取决于您对椭圆的使用方法。


这并不完全符合我的要求,因为我想在游戏中实际操纵形状和尺寸。不过,是否有一种方法可以扭曲圆形或其他的东西,从而实现斜椭圆?然后也许图片的想法就能奏效了。 - davik
再次抱歉,我不懂Python,但我猜你可能是用类似ellipse(x,y,w,l)的函数绘制椭圆。也许可以先绘制出圆的上下左右四个点,然后在每两个点之间绘制一条曲线?这样只需四个点,就可以移动和调整圆形了。 - jrohanian
想一想,我认为jrohanian的想法可以通过使用draw.arc函数在PyGame中实现:http://www.pygame.org/docs/ref/draw.html#pygame.draw.arc - Patric Hartmann
1
是的。我没有任何知识,但我做到了。 - jrohanian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接