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

时间:2019-02-19 02:22:02

标签: python python-3.x pygame

我正在创建一个基本的绘画应用程序,我想创建一个喷枪功能,并具有用于不同样式的画笔的其他功能。基本上,用户单击图标以选择画笔的样式,然后在单击并按住画布时,相应的画笔将在画布上进行绘制。这是我的代码: 主循环:

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)

如何使喷枪功能起作用?在运行该应用程序时,它不会返回任何错误,而根本不起作用

1 个答案:

答案 0 :(得分:1)

您的代码有几个缺陷:

  • 您将业务逻辑和图形混合在一起,使代码混乱。我们待会儿会解决
  • icon函数中,您正在设置局部变量(例如airbrushpencil等),这不会影响具有相同名称的全局变量。同样,您在设置它们后返回它们的值,并且永远不要使用该值。
  • 如果将调用您的airbrush函数,则永远都不会离开该函数,因为无法将airbrush设置为false
  • 该函数也将不起作用,因为您无法在其循环中处理事件,这将导致事件队列填满后窗口不再响应

您应该利用多态性,例如:

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

enter image description here

在此示例中,我们有一个Brush基类,它处理图标的绘制并跟踪笔刷的active状态,而子类则处理实际的绘制。

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