为什么我的喷枪功能在 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()
图标功能:
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
函数中,您正在设置局部变量(如airbrush
和pencil
等),这不会影响全局变量同名.您也可以在设置它们后返回它们的值,并且永远不要使用该值. - 如果你的
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 (likeairbrush
andpencil
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 setairbrush
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屋!