简体   繁体   English

为什么我的喷枪功能在pygame中不起作用?

[英]Why is my airbrush function not working in pygame?

I am creating a basic paint app and I want to create an airbrush function, and have other functions for different styles of brushes. 我正在创建一个基本的绘画应用程序,我想创建一个喷枪功能,并具有针对不同样式的画笔的其他功能。 Basically, the user clicks an icon to select the style of brush, and then when they click and hold over the canvas, the respective brush will paint on the canvas. 基本上,用户单击图标以选择画笔的样式,然后在单击并按住画布时,相应的画笔将在画布上进行绘制。 Here is my code: The main loop: 这是我的代码:主循环:

def paintScreen():
    intro = True
    gameDisplay.fill(cyan)
    message_to_screen('Welcome to PyPaint', black, -300, 'large')
    cur = pygame.mouse.get_pos()
    click = pygame.mouse.get_pressed()
    while intro:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

        pygame.draw.rect(gameDisplay, white, (50, 120, displayWidth - 100, displayHeight - 240))

        button('X', 20, 20, 50, 50, red, lightRed, action = 'quit')
        icon(airbrushIcon, white, 50, displayHeight - 101, 51, 51, white, grey, 'airbrush')
        icon(pencilIcon, white, 140, displayHeight - 101, 51, 51, white, grey, 'pencil')
        icon(calligraphyIcon, white, 230, displayHeight - 101, 51, 51, white, grey, 'calligraphy')
        pygame.display.update()
        if cur[0] > 50 < displayWidth - 50 and cur [1] > 120 < displayHeight - 120:
            if airbrush == True:
                airbrush()

the icon function: 图标功能:

def icon(icon, colour, x, y, width, height, inactiveColour, activeColour, action = None):
    cur = pygame.mouse.get_pos()
    click = pygame.mouse.get_pressed()
    if x + width > cur[0] > x and y + height > cur[1] > y:#if the cursor is over the button
        pygame.draw.rect(gameDisplay, activeColour, (x, y, width, height))
        gameDisplay.blit(icon, (x, y))
        if click[0] == 1 and action != None:
            if action == 'quit':
                pygame.quit()
                quit()
            elif action == 'pencil':
                pencil = True
                return pencil
            elif action == 'airbrush':
                airbrush = True
                return airbrush
            elif action == 'calligraphy':
                calligraphy = True
                return calligraphy
            elif action == 'erase':
                eraser = True
                return eraser
    else:
        pygame.draw.rect(gameDisplay, inactiveColour, (x, y, width, height))
        gameDisplay.blit(icon, (x, y))

the airbrush function: 喷枪功能:

def airbrush(brushSize = 3):
    airbrush = True
    cur = pygame.mouse.get_pos() #cur[0] is x location, cur[1] is y location
    click = pygame.mouse.get_pressed()
    while airbrush == True:
        if click[0] == True:
            if cur[0] > 50 < displayWidth - 50 and cur[1] > 120 < displayHeight - 120: #if the cursor is above the canvas
                #the area of the canvas is x(50, width-50) y(120, width-120)
                pygame.draw.circle(gameDisplay, black, (cur[0] + random.randrange(brushSize), cur[1] + random.randrange(brushSize)), random.randrange(1, 5))
                pygame.display.update()
            clock.tick(60)

What can I do to make the airbrush function work? 如何使喷枪功能起作用? When running the app, it doesn't return any errors, it just doesn't work at all 运行该应用程序时,它不会返回任何错误,而根本不起作用

Your code has several flaws: 您的代码有几个缺陷:

  • You mix up the business logic and the drawing, which clutters up your code. 您将业务逻辑和图形混合在一起,使代码混乱。 We'll fix it later 我们待会儿解决
  • In your icon function, you're setting local variables (like airbrush and pencil etc), which does not affect global variables with the same name. icon功能中,您正在设置局部变量(例如airbrushpencil等),该变量不会影响具有相同名称的全局变量。 Also you return their value after setting them and never use that value. 同样,您在设置它们后返回它们的值,并且永远不要使用该值。
  • If your airbrush function would be called, you could never leave that function, because there's no way to set airbrush to false 如果将调用airbrush功能,则永远都不能离开该功能,因为无法将airbrush设置为false
  • The function would also not work because you don't handle events in its loop, which would result in your window no longer responding once the event queue fills up 该函数也将不起作用,因为您无法在其循环中处理事件,这将导致事件队列填满后窗口不再响应

You should make use of polymorphism, something like this: 您应该使用多态,例如:

import pygame
import pygame.freetype
import random

def bresenham_line(start, end):
    x1, y1 = start
    x2, y2 = end
    dx = x2 - x1
    dy = y2 - y1
    is_steep = abs(dy) > abs(dx)
    if is_steep:
        x1, y1 = y1, x1
        x2, y2 = y2, x2
    swapped = False
    if x1 > x2:
        x1, x2 = x2, x1
        y1, y2 = y2, y1
        swapped = True
    dx = x2 - x1
    dy = y2 - y1
    error = int(dx / 2.0)
    ystep = 1 if y1 < y2 else -1
    y = y1
    points = []
    for x in range(x1, x2 + 1):
        coord = (y, x) if is_steep else (x, y)
        points.append(coord)
        error -= abs(dy)
        if error < 0:
            y += ystep
            error += dx
    if swapped:
        points.reverse()
    return points

class Brush(pygame.sprite.Sprite):
    def __init__(self, pos, font, canvas, tmpcanvas, icon, brushes, offset):
        super().__init__(brushes)
        self.image = pygame.Surface((32, 32))
        self.image.fill(pygame.Color('grey'))
        font.render_to(self.image, (8, 7), icon)
        self.other_image = self.image.copy()
        pygame.draw.rect(self.other_image, pygame.Color('red'), self.other_image.get_rect(), 3)
        self.rect = self.image.get_rect(topleft=pos)
        self.active = False
        self.canvas = canvas
        self.tmpcanvas = tmpcanvas
        self.brushes = brushes
        self.offset = offset
        self.mouse_pos = None

    def translate(self, pos):
        return pos[0] - self.offset[0], pos[1] - self.offset[1]

    def draw_to_canvas(self):
        pass

    def flip(self):
        self.active = not self.active
        self.image, self.other_image = self.other_image, self.image        

    def update(self, events):
        for e in events:
            if e.type == pygame.MOUSEBUTTONDOWN and self.rect.collidepoint(e.pos):
                for brush in self.brushes:
                    if brush.active:
                        brush.flip()
                self.flip()

        self.mouse_pos = self.translate(pygame.mouse.get_pos())
        if self.active:
            self.draw_to_canvas()

class Pencil(Brush):
    def __init__(self, pos, font, canvas, tmpcanvas, brushes, offset):
        super().__init__(pos, font, canvas, tmpcanvas, 'P', brushes, offset)
        self.prev_pos = None

    def draw_to_canvas(self):
        pressed = pygame.mouse.get_pressed()
        if pressed[0] and self.prev_pos:
            pygame.draw.line(self.canvas, pygame.Color('red'), self.prev_pos, self.mouse_pos)
        self.prev_pos = self.mouse_pos

class Calligraphy(Brush):
    def __init__(self, pos, font, canvas, tmpcanvas, brushes, offset):
        super().__init__(pos, font, canvas, tmpcanvas, 'C', brushes, offset)
        self.prev_pos = None

    def draw_to_canvas(self):
        pressed = pygame.mouse.get_pressed()
        if pressed[0] and self.prev_pos:
            for x, y in bresenham_line(self.prev_pos, self.mouse_pos):
                pygame.draw.rect(self.canvas, pygame.Color('orange'), (x, y, 5, 15))
        self.prev_pos = self.mouse_pos 

class Airbrush(Brush):
    def __init__(self, pos, font, canvas, tmpcanvas, brushes, offset):
        super().__init__(pos, font, canvas, tmpcanvas, 'A', brushes, offset)

    def draw_to_canvas(self):
        pressed = pygame.mouse.get_pressed()
        if pressed[0]:
            pygame.draw.circle(self.canvas, pygame.Color('green'), 
            (self.mouse_pos[0] + random.randrange(-13, 13), self.mouse_pos[1] + random.randrange(-13, 13)), 
            random.randrange(1, 5))

class LineTool(Brush):
    def __init__(self, pos, font, canvas, tmpcanvas, brushes, offset):
        super().__init__(pos, font, canvas, tmpcanvas, 'L', brushes, offset)
        self.start = None

    def draw_to_canvas(self):
        pressed = pygame.mouse.get_pressed()
        if pressed[0]:
            if not self.start:
                self.start = self.mouse_pos
            pygame.draw.line(self.tmpcanvas, pygame.Color('yellow'), self.start, self.mouse_pos)
        else:
            if self.start:
                pygame.draw.line(self.canvas, pygame.Color('yellow'), self.start, self.mouse_pos)
                self.start = None

class Clear(Brush):
    def __init__(self, pos, font, canvas, tmpcanvas, brushes, offset):
        super().__init__(pos, font, canvas, tmpcanvas, '*', brushes, offset)

    def draw_to_canvas(self):
        pressed = pygame.mouse.get_pressed()
        if pressed[0]:
            self.canvas.fill((1, 1, 1))
            self.flip()

def main():
    pygame.init()
    screen = pygame.display.set_mode((500, 500))
    sprites = pygame.sprite.Group()
    clock = pygame.time.Clock()

    font = pygame.freetype.SysFont(None, 26)
    offset = 0, 50
    canvas = pygame.Surface((500, 450))
    canvas.set_colorkey((1,1,1))
    canvas.fill((1,1,1))
    tmpcanvas = canvas.copy()

    x=10
    for tool in (Pencil, Calligraphy, Airbrush, LineTool, Clear):
        tool((x, 10), font, canvas, tmpcanvas, sprites, offset)
        x+= 40

    while True:
        events = pygame.event.get()
        for e in events:
            if e.type == pygame.QUIT:
                return
        tmpcanvas.fill((1, 1, 1))
        sprites.update(events)
        screen.fill((30, 30, 30))
        screen.blit(canvas, offset)
        screen.blit(tmpcanvas, offset)
        sprites.draw(screen)
        pygame.display.update()
        clock.tick(60)

if __name__ == '__main__':
    main()

在此处输入图片说明

In this example, we have a Brush base class that handles drawing of the icon and keeping track of the active -state of the brush, and the subclasses handle the actual drawing. 在此示例中,我们有一个Brush基类,该基类处理图标的绘制并跟踪画笔的active状态,而子类则处理实际的绘制。

This way, we can easily add new brushes/tools quite easily by creating a new class and implementing the draw_to_canvas function. 这样,我们可以通过创建一个新类并实现draw_to_canvas函数,轻松地轻松添加新的画笔/工具。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM