2009-02-28 22 views
11

Según lo veo, hay dos formas de manejar los eventos del mouse para dibujar una imagen.Cómo crear clones de MS Paint con Python y pygame

El primero es detectar cuando el mouse se mueve y dibujar una línea hacia donde se encuentra el mouse, se muestra here. Sin embargo, el problema con esto es que con un gran tamaño de pincel, aparecen muchas brechas entre cada "línea" que no es recta ya que está utilizando el tamaño de trazo de la línea para crear líneas gruesas.

La otra forma es dibujar círculos cuando el mouse se mueve como se muestra here. El problema con esto es que aparecen espacios entre cada círculo si el mouse se mueve más rápido de lo que la computadora detecta la entrada del mouse.

Aquí hay una captura de pantalla con mis problemas con ambos:

http://imgur.com/32DXN.jpg

¿Cuál es la mejor manera de implementar un cepillo como MS Paint, con un tamaño de pincel decentemente-grande sin huecos en la carrera del línea o no huecos entre cada círculo?

+0

No entiendo su problema con las líneas. ¿Estás hablando de la falta de endcaps, o ...? –

+0

Simplemente combine los dos. Líneas gruesas + círculos. –

+0

Aquí hay una captura de pantalla de mis problemas con ambos: http://imgur.com/32DXN Usar líneas gruesas y círculos parece que podría solucionar el problema, pero no suena muy elegante, así que pensaré en es más y lo uso como último recurso. – Johnston

Respuesta

13

¿Por qué no hacer las dos cosas?

Dibuja un círculo en cada punto final y una línea entre los dos.

EDIT rofl, simplemente no pude detenerme.

En realidad, usted no quiere usar pygame.draw.line porque hace trampa. Llena una fila o columna de 1 píxel de ancho (según el ángulo de ataque) de píxeles. Si va en un ángulo aproximadamente perpendicular, 0 grados o 90 grados, esto no es un problema, pero a los 45, notará una especie de efecto de frijol.

La única solución es dibujar un círculo a la distancia de cada píxel. Aquí ...

import pygame, random 

screen = pygame.display.set_mode((800,600)) 

draw_on = False 
last_pos = (0, 0) 
color = (255, 128, 0) 
radius = 10 

def roundline(srf, color, start, end, radius=1): 
    dx = end[0]-start[0] 
    dy = end[1]-start[1] 
    distance = max(abs(dx), abs(dy)) 
    for i in range(distance): 
     x = int(start[0]+float(i)/distance*dx) 
     y = int(start[1]+float(i)/distance*dy) 
     pygame.draw.circle(srf, color, (x, y), radius) 

try: 
    while True: 
     e = pygame.event.wait() 
     if e.type == pygame.QUIT: 
      raise StopIteration 
     if e.type == pygame.MOUSEBUTTONDOWN: 
      color = (random.randrange(256), random.randrange(256), random.randrange(256)) 
      pygame.draw.circle(screen, color, e.pos, radius) 
      draw_on = True 
     if e.type == pygame.MOUSEBUTTONUP: 
      draw_on = False 
     if e.type == pygame.MOUSEMOTION: 
      if draw_on: 
       pygame.draw.circle(screen, color, e.pos, radius) 
       roundline(screen, color, e.pos, last_pos, radius) 
      last_pos = e.pos 
     pygame.display.flip() 

except StopIteration: 
    pass 

pygame.quit() 
1

Para el primer problema, debe tener un fondo, incluso si es solo un color. Tuve el mismo problema con un juego de réplica pong que hice. Este es un ejemplo de un programa de dibujo réplica hice, a la izquierda haga clic para dibujar, haga clic derecho de borrar, haga clic en la imagen en color para elegir un color, y hasta botón para borrar la pantalla:

import os 
os.environ['SDL_VIDEO_CENTERED'] = '1' 
from pygamehelper import * 
from pygame import * 
from pygame.locals import * 
from vec2d import * 
from math import e, pi, cos, sin, sqrt 
from random import uniform 

class Starter(PygameHelper): 
    def __init__(self): 
     self.w, self.h = 800, 600 
     PygameHelper.__init__(self, size=(self.w, self.h), fill=((255,255,255))) 

     self.img= pygame.image.load("colors.png") 
     self.screen.blit(self.img, (0,0)) 

     self.drawcolor= (0,0,0) 
     self.x= 0 

    def update(self): 
     pass 

    def keyUp(self, key): 
     if key==K_UP: 
      self.screen.fill((255,255,255)) 
      self.screen.blit(self.img, (0,0)) 




    def mouseUp(self, button, pos): 
     pass 

    def mouseMotion(self, buttons, pos, rel): 
     if pos[1]>=172: 
      if buttons[0]==1: 
       #pygame.draw.circle(self.screen, (0,0,0), pos, 5) 
       pygame.draw.line(self.screen, self.drawcolor, pos, (pos[0]-rel[0], pos[1]-rel[1]),5)     
      if buttons[2]==1: 
       pygame.draw.circle(self.screen, (255,255,255), pos, 30) 
      if buttons[1]==1: 
       #RAINBOW MODE 
       color= self.screen.get_at((self.x, 0)) 
       pygame.draw.line(self.screen, color, pos, (pos[0]-rel[0], pos[1]-rel[1]), 5) 

       self.x+= 1 
       if self.x>172: self.x=0 

     else: 
      if pos[0]<172: 
       if buttons[0]==1: 
        self.drawcolor= self.screen.get_at(pos) 
        pygame.draw.circle(self.screen, self.drawcolor, (250, 100), 30) 

    def draw(self): 
     pass 
     #self.screen.fill((255,255,255)) 
     #pygame.draw.circle(self.screen, (0,0,0), (50,100), 20) 

s = Starter() 
s.mainLoop(40) 
2

No a actuar en cada paso de bucle puede mejorar la velocidad del dibujo (utilizando este código adaptado del anterior permite eliminar el problema de retraso en mi máquina)

import pygame, random 

screen = pygame.display.set_mode((800,600)) 

draw_on = False 
last_pos = (0, 0) 
color = (255, 128, 0) 
radius = 10 

def roundline(srf, color, start, end, radius=1): 
    dx = end[0]-start[0] 
    dy = end[1]-start[1] 
    distance = max(abs(dx), abs(dy)) 
    for i in range(distance): 
     x = int(start[0]+float(i)/distance*dx) 
     y = int(start[1]+float(i)/distance*dy) 
     pygame.display.update(pygame.draw.circle(srf, color, (x, y), radius)) 

try: 
    while True: 
     e = pygame.event.wait() 
     if e.type == pygame.QUIT: 
      raise StopIteration 
     if e.type == pygame.MOUSEBUTTONDOWN: 
      color = (random.randrange(256), random.randrange(256), random.randrange(256)) 
      pygame.draw.circle(screen, color, e.pos, radius) 
      draw_on = True 
     if e.type == pygame.MOUSEBUTTONUP: 
      draw_on = False 
     if e.type == pygame.MOUSEMOTION: 
      if draw_on: 
       pygame.display.update(pygame.draw.circle(screen, color, e.pos, radius)) 
       roundline(screen, color, e.pos, last_pos, radius) 
      last_pos = e.pos 
     #pygame.display.flip() 

except StopIteration: 
    pass 

pygame.quit()