2016-07-01 14 views
1

Ich versuche, einen einfachen Kreis-Timer in Python mit Pygame zu programmieren. Im Moment sieht es wie folgt aus: TimerAnti-aliased Arc Pygame

Wie Sie sehen können, die blaue Linie sehr wellig ist und darin weißen Punkten. Ich erreiche diese blaue Linie mit der Funktion pygame.draw.arc(), aber sie ist nicht geglättet und sieht schlecht aus. Ich möchte, dass es Anti-Aliased, aber Gfxdraw-Modul, die mich dies erreichen lassen sollte, unterstützt keine Auswahl der Lichtbogenbreite. Hier ist Code-Schnipsel:

pygame.draw.arc(screen, blue, [center[0] - 120, center[1] - 120, 240, 240], pi/2, pi/2+pi*i*koef, 15) 
pygame.gfxdraw.aacircle(screen, center[0], center[1], 105, black) 
pygame.gfxdraw.aacircle(screen, center[0], center[1], 120, black) 

Antwort

0

Ich bin nicht bekannt, dass pygame Funktion, die dieses Problem lösen würde, was bedeutet, Sie im Grunde um eine Lösung zu programmieren selbst (oder etwas anderes als pygame verwenden), da draw als du gebrochen‘ Ve notiert und gfxdraw wird Ihnen nicht die Dicke geben.

Ein sehr hässlich aber einfache Lösung ist es, mehrmals über die Bogensegmente zu zeichnen, immer leicht verschoben, um die fehlenden Lücken zu "füllen". Dies wird noch einige Aliasing an dem sehr vor dem Timer Bogen verlassen, aber der Rest wird ausgefüllt werden.

import pygame 
from pygame.locals import * 
import pygame.gfxdraw 
import math 

# Screen size 
SCREEN_HEIGHT = 350 
SCREEN_WIDTH = 500 

# Colors 
BLACK = (0, 0, 0) 
WHITE = (255, 255, 255) 
GREY = (150, 150, 150) 
RED = (255,0,0) 


# initialisation 
pygame.init() 
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) 
done = False 
clock = pygame.time.Clock() 

# We need this if we want to be able to specify our 
# arc in degrees instead of radians 
def degreesToRadians(deg): 
    return deg/180.0 * math.pi 

# Draw an arc that is a portion of a circle. 
# We pass in screen and color, 
# followed by a tuple (x,y) that is the center of the circle, and the radius. 
# Next comes the start and ending angle on the "unit circle" (0 to 360) 
# of the circle we want to draw, and finally the thickness in pixels 
def drawCircleArc(screen,color,center,radius,startDeg,endDeg,thickness): 
    (x,y) = center 
    rect = (x-radius,y-radius,radius*2,radius*2) 
    startRad = degreesToRadians(startDeg) 
    endRad = degreesToRadians(endDeg) 

    pygame.draw.arc(screen,color,rect,startRad,endRad,thickness) 


# fill screen with background 
screen.fill(WHITE) 
center = [150, 200] 
pygame.gfxdraw.aacircle(screen, center[0], center[1], 105, BLACK) 
pygame.gfxdraw.aacircle(screen, center[0], center[1], 120, BLACK) 

pygame.display.update() 

step = 10 
maxdeg = 0 

while not done: 
    for event in pygame.event.get(): 
     if event.type == pygame.QUIT: 
      done = True 

    maxdeg = maxdeg + step 
    for i in range(min(0,maxdeg-30),maxdeg): 
     drawCircleArc(screen,RED,(150,200),119,i+90,max(i+10,maxdeg)+90,14) 
     #+90 will shift it from starting at the right to starting (roughly) at the top 
    pygame.display.flip() 

    clock.tick(2) # ensures a maximum of 60 frames per second 

pygame.quit() 

Bitte beachte, dass ich degreesToRadians und drawCircleArc von https://www.cs.ucsb.edu/~pconrad/cs5nm/08F/ex/ex09/drawCircleArcExample.py

ich dies im Allgemeinen nicht kopiert haben empfehlen Lösung, aber es könnte in einer Prise tun.

+0

Das sieht viel besser aus, ist aber immer noch nicht perfekt. Ich werde versuchen zu googlen oder über andere mögliche Lösungen nachzudenken –

+1

Einfacher Weg, wenn Sie pygame verwenden müssen, wäre es, es einfach in einem Grafikprogramm zu tun und die Counterschritte von einem Spritesheet zu blit. Wenn Sie nur eine Handvoll Orte benötigen, ist ein handgeschriebener Hack wahrscheinlich nicht die Mühe wert. – Isa

+1

Warum nicht das nächste Segment zeichnen und dann eine Flutfüllung anwenden? –

0

Kleine ASCII-Art-Stil-Demo von einem Waldbrand-Algorithmus, die ich in Python geschrieben haben:

import sys 

class Canvas: 
    def __init__(self): 
     self.rows=10 
     self.columns=10 
     self.cells = {(r,c):None for r in range(1,self.rows+1) for c in range(1,self.columns+1)} 
     for i in range(3,6): 
      self.cells[(i,5)] = 1 
      self.cells[(i,8)] = 1 
     for i in range(5,8): 
      self.cells[(3,i)] = 1 
      self.cells[(6,i)] = 1 

    def display(self): 
     for i in range(1,self.rows): 
      for j in range(1,self.columns): 
       sys.stdout.write("*" if self.cells[(i,j)] else " ") 
      sys.stdout.write("\n") 


    def fill(self, x, y, t): 
     if not self.cells[(x,y)]: 
      to_fill = [(x,y)] 
      while to_fill: 
       # pick a point from the queue 
       x,y = to_fill.pop() 
       # change color if possible 
       self.cells[(x,y)] = t 

       # now the neighbours x,y +- 1 
       for delta_x in range(-1,2): 
        xdx = x+delta_x 
        if xdx > 0 and xdx < self.columns+1: 
         for delta_y in range(-1,2): 
          ydy = y+delta_y 
          # avoid diagonals 
          if (delta_x == 0)^(delta_y == 0): 
           if ydy > 0 and ydy < self.rows+1: 
            # valid x+delta_x,y+delta_y 
            # push in queue if no color 
            if not self.cells[(xdx,ydy)]: 
             to_fill.append((xdx,ydy)) 

c = Canvas() 
c.display() 
c.fill(4,6,2) 
c.display() 
So

im Grunde ist es eine leere Leinwand schafft, in eine Art von hässlichen hohlen Rechteck zieht (erste Zeichnung) führt flood fill und gefüllte Rechteck zieht wieder:

**** 
    * * 
    * * 
    *** 





    **** 
    **** 
    **** 
    *** 

Beim Start, könnte man einfach die 2 Linien ziehen, um die Zone zu begrenzen, und die flood fill Methode übergibt x nennen, y von einem Punkt in der Zone.

Dann für die nächsten Füllungen, zeichnen Sie einfach die nächste Zeile und wiederholen.