为什么我的喷枪功能在 pygame 中不起作用? [英] Why is my airbrush function not working in pygame?

查看:33
本文介绍了为什么我的喷枪功能在 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()

图标功能:

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

喷枪功能:

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

推荐答案

你的代码有几个缺陷:

  • 您混淆了业务逻辑和绘图,这会弄乱您的代码.我们稍后会修复它
  • 在您的 icon 函数中,您正在设置局部变量(如 airbrushpencil 等),这不会影响全局变量同名.您也可以在设置它们后返回它们的值,并且永远不要使用该值.
  • 如果你的 airbrush 函数被调用,你永远不能离开那个函数,因为没有办法将 airbrush 设置为 false
  • 该函数也无法工作,因为您不在其循环中处理事件,这将导致一旦事件队列填满您的窗口就不再响应
  • 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. 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
  • 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()

在这个例子中,我们有一个 Brush 基类来处理图标的绘制并跟踪画笔的 active 状态,子类处理实图.

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.

通过这种方式,我们可以通过创建一个新类并实现 draw_to_canvas 函数来轻松添加新的画笔/工具.

This way, we can easily add new brushes/tools quite easily by creating a new class and implementing the draw_to_canvas function.

这篇关于为什么我的喷枪功能在 pygame 中不起作用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆