我正在尝试创建一种画笔功能,以一种书法风格的画笔在画布上绘制,一种方法薄,另一种方法厚。现在,可以实际绘制笔迹,但是代码运行得不够快,并且实际的线条一直在切割(如gif所示)。
这是我现在的代码:
import pygame
import os
import random
from pygame.locals import *
flags = DOUBLEBUF
pygame.init()
pygame.event.set_allowed([QUIT])
current_path = os.path.dirname(__file__) #The directory the main file is in
iconPath = os.path.join(current_path, 'images') #The icon folder path
displayWidth = 1280
displayHeight = 720
gameDisplay = pygame.display.set_mode((displayWidth, displayHeight), flags)
gameDisplay.set_alpha(None)
pygame.display.set_caption('PyPaint')
black = (0, 0, 0)
white = (255, 255, 255)
grey = (200, 200, 200)
cyan = (0, 200, 255)
green = (0, 150, 0)
lightGreen = (0, 255, 0)
red = (150, 0, 0)
lightRed = (255, 0, 0)
smallfont = pygame.font.SysFont("arial", 40)
medfont = pygame.font.SysFont("arial", 60)
largefont = pygame.font.SysFont("arial", 80)
airbrushIcon = pygame.image.load(os.path.join(iconPath, "airbrush.png"))
pencilIcon = pygame.image.load(os.path.join(iconPath, "pencil.png"))
calligraphyIcon = pygame.image.load(os.path.join(iconPath, "calligraphy.png"))
eraserIcon = pygame.image.load(os.path.join(iconPath, "eraser.png"))
clock = pygame.time.Clock()
FPS = 60
airbrushMode = False
calligraphyMode = False
eraserMode = False
def paintScreen():
global airbrushMode
global calligraphyMode
global eraserMode
airbrushMode = False
paint = True
gameDisplay.fill(cyan)
message_to_screen('Welcome to PyPaint', black, -300, 'large')
click = pygame.mouse.get_pressed()
pygame.draw.rect(gameDisplay, white, (50, 120, displayWidth - 100, displayHeight - 240))
while paint:
cur = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
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')
icon(eraserIcon, white, 320, displayHeight - 101, 51, 51, white, grey, 'eraser')
pygame.draw.rect(gameDisplay, cyan, (0, 120, 50, displayHeight - 100))#to clean up the left border of the canvas
pygame.draw.rect(gameDisplay, cyan, (displayWidth - 50, 120, 50, displayHeight - 100))#to clean up the right border of the canvas
pygame.draw.rect(gameDisplay, cyan, (0, displayHeight - 120, displayWidth, 20))#to clean up the bottom of the canvas
pygame.draw.rect(gameDisplay, cyan, (0, 100, displayWidth, 20))#to clean up the top of the canvas
if airbrushMode == True:
airbrush()
elif calligraphyMode == True:
calligraphy()
elif eraserMode == True:
eraser()
pygame.display.update()
def icon(icon, colour, x, y, width, height, inactiveColour, activeColour, action = None):
global airbrushMode
global calligraphyMode
global eraserMode
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 clicked
if action == 'quit':
pygame.quit()
quit()
elif action == 'pencil':
pencilMode = True
airbrushMode = False
calligraphyMode = False
eraserMode = False
elif action == 'airbrush':
airbrushMode = True
calligraphyMode = False
pencilMode = False
eraserMode = False
elif action == 'calligraphy':
calligraphyMode = True
airbrushMode = False
pencilMode = False
eraserMode = False
elif action == 'eraser':
eraserMode = True
airbrushMode = False
pencilMode = False
calligraphyMode = False
else:
pygame.draw.rect(gameDisplay, inactiveColour, (x, y, width, height))
gameDisplay.blit(icon, (x, y))
def button(text, 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:
pygame.draw.rect(gameDisplay, activeColour, (x, y, width, height))
if click[0] == 1 and action != None:
if action == 'quit':
pygame.quit()
quit()
else:
pygame.draw.rect(gameDisplay, inactiveColour, (x, y, width, height))
text_to_button(text, black, x, y, width, height)
def text_to_button(msg, colour, buttonx, buttony, buttonwidth, buttonheight, size = 'small'):
textSurf, textRect = text_objects (msg, colour, size)
textRect.center = ((buttonx + (buttonwidth/2)), buttony + (buttonheight/2))
gameDisplay.blit(textSurf, textRect)
def message_to_screen(msg, colour, y_displace = 0, size = 'small'):
textSurf, textRect = text_objects (msg, colour, size)
textRect.center = (displayWidth / 2), (displayHeight / 2) + y_displace
gameDisplay.blit(textSurf, textRect)
def airbrush(brushSize = 3):
cur = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if cur[0] >= 50 and cur[0] <= displayWidth - 50 and cur[1] >= 120 and cur[1] <= displayHeight - 120:
if click[0] == 1:
pygame.draw.circle(gameDisplay, black, (cur[0] + random.randrange(-brushSize * 2, brushSize * 2), cur[1] + random.randrange(-brushSize * 2, brushSize * 2)), random.randrange(1, brushSize * 2))
def calligraphy(brushSize = 3):
cur = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if cur[0] >= 50 and cur[0] <= displayWidth - 50 and cur[1] >= 120 and cur[1] <= displayHeight - 120:#if cursor is on the canvas
if click[0] == 1:
pygame.draw.rect(gameDisplay, black, (cur[0] - brushSize / 2, cur[1] - brushSize / 4, brushSize, brushSize * 3))
def eraser(brushSize = 3):
cur = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if cur[0] >= 50 and cur[0] <= displayWidth - 50 and cur[1] >= 120 and cur[1] <= displayHeight - 120:#if cursor is on the canvas
if click[0] == 1:
pygame.draw.rect(gameDisplay, white, (cur[0] - brushSize / 2, cur[1] - brushSize / 2, brushSize * 6, brushSize * 6))
def text_objects(text, colour, size):
if size == 'small':
textSurface = smallfont.render (text, True, colour)
elif size == 'medium':
textSurface = medfont.render (text, True, colour)
elif size == 'large':
textSurface = largefont.render (text, True, colour)
return textSurface, textSurface.get_rect()
paintScreen()
我尝试将clock.tick()
添加到几个不同的函数中,以尝试尽可能快地运行它,但仍然采用相同的方法。我什至在更新,更快的计算机上对其进行了测试,并且没有区别,这意味着问题出在python而不是计算机内。如何允许pygame在2点之间的线上绘制所有点?
答案 0 :(得分:1)
我使用注释中的方法创建了最小的工作示例。
我记得上一个点(或无)在新点和上一个点之间绘制缺失点。
我计算出我必须添加多少点
steps = max(abs(x-prev_x), abs(y-prev_y))
和点之间的距离
dx = (x - prev_x)/steps
dy = (y - prev_y)/steps
然后我可以循环绘制缺失点
for _ in range(steps):
prev_x += dx
prev_y += dy
pygame.draw.circle(display, BLACK, (round(prev_x - 5), round(prev_y - 5)), 10)
完整代码
import pygame
# --- constants --- (uppercase)
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
WIDTH = 800
HEIGHT = 600
FPS = 60
# --- functions --- (lowercase)
def airbrush(brushSize = 3):
global prev_x
global prev_y
click = pygame.mouse.get_pressed()
if click[0] == 1:
x, y = pygame.mouse.get_pos()
if x >= 0 and x <= WIDTH and y >= 0 and y <= HEIGHT0:
pygame.draw.circle(display, BLACK, (x - 5, y - 5), 10)
# if there is previous point then draw missing points
if prev_x is not None:
diff_x = x - prev_x
diff_y = y - prev_y
steps = max(abs(diff_x), abs(diff_y))
# skip if distance is zero (error: dividing by zero)
if steps > 0:
dx = diff_x / steps
dy = diff_y / steps
for _ in range(steps):
prev_x += dx
prev_y += dy
pygame.draw.circle(display, BLACK, (round(prev_x - 5), round(prev_y - 5)), 10)
prev_x = x # remeber previous point
prev_y = y # remeber previous point
else:
prev_x = None # there is no previous point
prev_y = None # there is no previous point
# --- main ---
pygame.init()
display = pygame.display.set_mode((WIDTH, HEIGHT), pygame.DOUBLEBUF)
prev_x = None # at start there is no previous point
prev_y = None # at start there is no previous point
display.fill(WHITE)
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
airbrush()
pygame.display.update()
clock.tick(FPS)
如果您删除行
prev_x = x
prev_y = y
那么您将获得版本而不会丢失任何点。