Question

Comme je le vois, il y a deux façons de gérer les événements de la souris pour dessiner une image.

La première consiste à détecter le moment où la souris passe et tracer une ligne à l'endroit où la souris est représenté ici . Cependant, le problème est que, avec une grande taille du pinceau, de nombreuses lacunes apparaissent entre chaque « ligne » qui ne sont pas directement car il utilise la taille de la course de la ligne pour créer des lignes épaisses.

L'autre façon consiste à dessiner des cercles lorsque la souris se déplace comme cela est montré ici . Le problème est que semblent écarts entre chaque cercle si la souris se déplace plus vite que l'ordinateur détecte une 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 de la ligne ou pas d'espace entre chaque cercle?

Était-ce utile?

La solution

Pourquoi ne pas faire les deux?

Tracer un cercle au niveau de chaque point d'extrémité et une ligne entre les deux.

EDIT rofl, ne pouvait pas me arrêter.

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

La seule solution est de tracer 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()

Autres conseils

Non blitting à chaque étape de la boucle peut améliorer la vitesse du dessin (en utilisant ce code adapté de la précédente permet de retirer problème de retard 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()

Pour le premier problème, vous devez avoir un arrière-plan, même si son juste une couleur. J'ai eu le même problème avec un jeu de pong réplique je l'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)

Voici une version simplifiée du exemple qui est malheureusement pas runnable.

Lorsque la souris est déplacée, les événements de pygame.MOUSEMOTION sont ajoutés à la file d'attente qui contient la position et le mouvement relatif. Vous pouvez les utiliser pour calculer la position précédente, puis passer les deux points à pygame.draw.line.

événements pygame.MOUSEMOTION ont également un attribut buttons que vous pouvez utiliser pour vérifier quel bouton souris est actuellement vers le bas.

import os
import random

import pygame as pg


class App:

    def __init__(self):
        os.environ['SDL_VIDEO_CENTERED'] = '1'
        pg.init()
        self.w, self.h = 800, 600
        self.screen = pg.display.set_mode((self.w, self.h))
        self.screen.fill(pg.Color('white'))
        self.clock = pg.time.Clock()
        self.drawcolor = (0, 0, 0)

    def mainloop(self):
        while True:
            for event in pg.event.get():
                if event.type == pg.QUIT:
                    return
                elif event.type == pg.MOUSEBUTTONDOWN:
                    if event.button == 2:  # Color picker (middle mouse button).
                        self.drawcolor = self.screen.get_at(pos)
                        # Pick a random color.
                        # self.drawcolor = [random.randrange(256) for _ in range(3)]
                elif event.type == pg.MOUSEMOTION:
                    pos, rel = event.pos, event.rel
                    if event.buttons[0]:  # If the left mouse button is down.
                        # Draw a line from the pos to the previous pos.
                        pg.draw.line(self.screen, self.drawcolor, pos, (pos[0]-rel[0], pos[1]-rel[1]), 5)
                    elif event.buttons[2]:  # If the right mouse button is down.
                        # Erase by drawing a circle.
                        pg.draw.circle(self.screen, (255, 255, 255), pos, 30)

            pg.display.flip()
            self.clock.tick(30)


if __name__ == '__main__':
    app = App()
    app.mainloop()
    pg.quit()
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top