2009-02-28 13 views
11

Comme je le vois, il existe deux façons de gérer les événements de la souris pour dessiner une image. Le premier est de détecter quand la souris se déplace et tracer une ligne à l'endroit où se trouve la souris, comme illustré here. Cependant, le problème avec ceci est qu'avec une grande taille de pinceau, de nombreux espaces apparaissent entre chaque "ligne" qui n'est pas droite puisqu'il utilise la taille de trait de la ligne pour créer des lignes épaisses.Comment créer un clone MS Paint avec Python et pygame

L'autre façon consiste à dessiner des cercles lorsque la souris se déplace comme indiqué here. Le problème avec ceci est que des espaces apparaissent entre chaque cercle si la souris se déplace plus vite que l'ordinateur ne détecte l'entrée de la souris.

Voici une capture d'écran avec mes problèmes à la fois:

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

Quelle est la meilleure façon de mettre en œuvre un pinceau comme MS Paint de, avec une taille de pinceau décemment grande sans lacunes dans la course du ligne ou pas d'espaces entre chaque cercle?

+0

Je ne comprends pas votre problème avec les lignes. Parlez-vous du manque d'embouts, ou ...? –

+0

Il suffit de combiner les deux. Lignes épaisses + cercles. –

+0

Voici une capture d'écran de mes problèmes avec les deux: http://imgur.com/32DXN En utilisant à la fois les lignes épaisses et les cercles semblent comme cela pourrait résoudre le problème, mais il ne semble pas très élégant, donc je vais penser à C'est un peu plus et l'utiliser en dernier recours. – Johnston

Répondre

13

Pourquoi ne pas faire les deux? Dessinez un cercle à chaque extrémité et une ligne entre les deux.

EDIT rofl, juste ne pouvait pas m'arrêter.

En fait, vous ne voulez pas utiliser pygame.draw.line car il triche. Il remplit une ligne ou une colonne de 1 pixel de large (en fonction de l'angle d'attaque) des pixels. Si vous allez à un angle à peu près perpendiculaire, 0 deg ou 90 deg, ce n'est pas un problème, mais à 45, vous remarquerez une sorte d'effet de haricot de ficelle.

La seule solution consiste à dessiner un cercle à la distance de chaque pixel. Ici ...

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

Pour le premier problème, vous avez besoin d'un fond, même si c'est juste une couleur. J'ai eu le même problème avec un jeu de réplique de pong que j'ai fait. Voici un exemple d'un programme de peinture réplique que j'ai fait, à gauche cliquez pour dessiner, clic droit pour effacer, cliquez sur l'image couleur pour choisir une couleur, et jusqu'à bouton pour effacer l'écran:

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

Non blitting à chaque étape de boucle peut améliorer la vitesse du dessin (en utilisant ce code adapté de la précédente permettre de supprimer le problème de décalage sur ma machine)

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()