如何使用Python和pygame创建MS Paint clone
在我看来,有两种方法可以处理鼠标事件来绘制图片 第一个是检测鼠标何时移动,并绘制鼠标所在位置的直线,如图所示。但是,问题在于,如果笔刷尺寸较大,则由于使用线的笔划尺寸创建粗线,因此在不直的每条“线”之间会出现许多间隙 另一种方法是在鼠标移动时绘制圆,如图所示。问题是,如果鼠标移动速度超过计算机检测到的鼠标输入速度,则每个圆之间都会出现间隙 以下是我在这两方面的问题的截图: 实现MS Paint这样的画笔的最佳方法是什么,画笔大小适中,线条笔划中没有间隙,或者每个圆之间没有间隙?为什么不两者都做 在每个端点处画一个圆,并在两者之间画一条线 编辑罗夫,就是无法阻止自己 实际上,您不想使用如何使用Python和pygame创建MS Paint clone,python,mouse,pygame,draw,paint,Python,Mouse,Pygame,Draw,Paint,在我看来,有两种方法可以处理鼠标事件来绘制图片 第一个是检测鼠标何时移动,并绘制鼠标所在位置的直线,如图所示。但是,问题在于,如果笔刷尺寸较大,则由于使用线的笔划尺寸创建粗线,因此在不直的每条“线”之间会出现许多间隙 另一种方法是在鼠标移动时绘制圆,如图所示。问题是,如果鼠标移动速度超过计算机检测到的鼠标输入速度,则每个圆之间都会出现间隙 以下是我在这两方面的问题的截图: 实现MS Paint这样的画笔的最佳方法是什么,画笔大小适中,线条笔划中没有间隙,或者每个圆之间没有间隙?为什么不两者都做
pygame.draw.line
,因为它会作弊。它填充1像素宽的像素行或像素列(取决于攻角)。如果你以一个大致垂直的角度,0度或90度,这不是问题,但在45度,你会注意到一种弦豆效应
唯一的解决办法是在每个像素的距离上画一个圆。这里
import pygame, random
screen = pygame.display.set_mode((800,600))
draw_on = False
last_pos = (0, 0)
color = (255, 128, 0)
radius = 10
def roundline(srf, color, start, end, radius=1):
dx = end[0]-start[0]
dy = end[1]-start[1]
distance = max(abs(dx), abs(dy))
for i in range(distance):
x = int( start[0]+float(i)/distance*dx)
y = int( start[1]+float(i)/distance*dy)
pygame.draw.circle(srf, color, (x, y), radius)
try:
while True:
e = pygame.event.wait()
if e.type == pygame.QUIT:
raise StopIteration
if e.type == pygame.MOUSEBUTTONDOWN:
color = (random.randrange(256), random.randrange(256), random.randrange(256))
pygame.draw.circle(screen, color, e.pos, radius)
draw_on = True
if e.type == pygame.MOUSEBUTTONUP:
draw_on = False
if e.type == pygame.MOUSEMOTION:
if draw_on:
pygame.draw.circle(screen, color, e.pos, radius)
roundline(screen, color, e.pos, last_pos, radius)
last_pos = e.pos
pygame.display.flip()
except StopIteration:
pass
pygame.quit()
对于第一个问题,你需要有一个背景,即使它只是一种颜色。我做的一个复制品乒乓球游戏也有同样的问题。这是我制作的复制绘制程序的一个示例,左键单击绘制,右键单击擦除,单击彩色图像选择颜色,向上按钮清除屏幕:
import os
os.environ['SDL_VIDEO_CENTERED'] = '1'
from pygamehelper import *
from pygame import *
from pygame.locals import *
from vec2d import *
from math import e, pi, cos, sin, sqrt
from random import uniform
class Starter(PygameHelper):
def __init__(self):
self.w, self.h = 800, 600
PygameHelper.__init__(self, size=(self.w, self.h), fill=((255,255,255)))
self.img= pygame.image.load("colors.png")
self.screen.blit(self.img, (0,0))
self.drawcolor= (0,0,0)
self.x= 0
def update(self):
pass
def keyUp(self, key):
if key==K_UP:
self.screen.fill((255,255,255))
self.screen.blit(self.img, (0,0))
def mouseUp(self, button, pos):
pass
def mouseMotion(self, buttons, pos, rel):
if pos[1]>=172:
if buttons[0]==1:
#pygame.draw.circle(self.screen, (0,0,0), pos, 5)
pygame.draw.line(self.screen, self.drawcolor, pos, (pos[0]-rel[0], pos[1]-rel[1]),5)
if buttons[2]==1:
pygame.draw.circle(self.screen, (255,255,255), pos, 30)
if buttons[1]==1:
#RAINBOW MODE
color= self.screen.get_at((self.x, 0))
pygame.draw.line(self.screen, color, pos, (pos[0]-rel[0], pos[1]-rel[1]), 5)
self.x+= 1
if self.x>172: self.x=0
else:
if pos[0]<172:
if buttons[0]==1:
self.drawcolor= self.screen.get_at(pos)
pygame.draw.circle(self.screen, self.drawcolor, (250, 100), 30)
def draw(self):
pass
#self.screen.fill((255,255,255))
#pygame.draw.circle(self.screen, (0,0,0), (50,100), 20)
s = Starter()
s.mainLoop(40)
导入操作系统
os.environ['SDL\u VIDEO\u CENTERED']=“1”
从pygamehelper导入*
从pygame导入*
从pygame.locals导入*
从vec2d导入*
从数学输入e,pi,cos,sin,sqrt
从随机导入制服
类启动程序(PygameHelper):
定义初始化(自):
self.w,self.h=800600
PygameHelper.\uuuuu初始化(self,size=(self.w,self.h),fill=((255255)))
self.img=pygame.image.load(“colors.png”)
自屏幕blit(self.img,(0,0))
self.drawcolor=(0,0,0)
self.x=0
def更新(自我):
通过
def keyUp(自动,钥匙):
如果key==K_UP:
自我筛选填充((255255))
自屏幕blit(self.img,(0,0))
def鼠标(自身、按钮、位置):
通过
def mouseMotion(self、按钮、pos、rel):
如果位置[1]>=172:
如果按钮[0]==1:
#pygame.draw.circle(self.screen,(0,0,0),位置5)
pygame.draw.line(self.screen,self.drawcolor,pos,(pos[0]-rel[0],pos[1]-rel[1]),5)
如果按钮[2]==1:
pygame.draw.circle(self.screen,(255255),位置30)
如果按钮[1]==1:
#彩虹模式
color=self.screen.get_at((self.x,0))
pygame.draw.line(自我屏幕,颜色,位置,(位置[0]-rel[0],位置[1]-rel[1]),5)
self.x+=1
如果self.x>172:self.x=0
其他:
如果pos[0]在每个循环步骤中不闪烁可以提高绘图速度(使用从上一个代码改编的代码可以消除我的机器上的滞后问题)
这是马修的一个简化版本,不幸的是它无法运行
移动鼠标时,pygame.MOUSEMOTION
事件将添加到事件队列中,其中包含位置和相对移动。您可以使用这些来计算上一个位置,然后将这两点传递给pygame.draw.line
pygame.MOUSEMOTION
事件还有一个buttons
属性,可用于检查当前按下的鼠标按钮
import os
import random
import pygame as pg
class App:
def __init__(self):
os.environ['SDL_VIDEO_CENTERED'] = '1'
pg.init()
self.w, self.h = 800, 600
self.screen = pg.display.set_mode((self.w, self.h))
self.screen.fill(pg.Color('white'))
self.clock = pg.time.Clock()
self.drawcolor = (0, 0, 0)
def mainloop(self):
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
return
elif event.type == pg.MOUSEBUTTONDOWN:
if event.button == 2: # Color picker (middle mouse button).
self.drawcolor = self.screen.get_at(pos)
# Pick a random color.
# self.drawcolor = [random.randrange(256) for _ in range(3)]
elif event.type == pg.MOUSEMOTION:
pos, rel = event.pos, event.rel
if event.buttons[0]: # If the left mouse button is down.
# Draw a line from the pos to the previous pos.
pg.draw.line(self.screen, self.drawcolor, pos, (pos[0]-rel[0], pos[1]-rel[1]), 5)
elif event.buttons[2]: # If the right mouse button is down.
# Erase by drawing a circle.
pg.draw.circle(self.screen, (255, 255, 255), pos, 30)
pg.display.flip()
self.clock.tick(30)
if __name__ == '__main__':
app = App()
app.mainloop()
pg.quit()
我制作了一个更有效的圆线函数
import pygame as pg,random,math
screen = pg.display.set_mode((800,600))
draw_on = False
last_pos = (0, 0)
color = (255, 128, 0)
radius = 10
def roundline(srf, color, start, end, radius=1):
pg.display.update([drawline(srf,color,start,end,radius),
pg.draw.circle(srf, color, end, radius),
pg.draw.circle(srf, color, start, radius)])
def drawline(srf, color,start,end,width):
v=(start[0]- end[0],start[1]- end[1])
betrag=width/math.sqrt(v[0]*v[0]+v[1]*v[1])
v_=(v[1]*betrag,-betrag*v[0])
return pg.draw.polygon(srf, color,(
(int(start[0]+v_[0]),int(start[1]+v_[1])),
(int(start[0]-v_[0]),int(start[1]-v_[1])),
(int(end[0]-v_[0]),int(end[1]-v_[1])),
(int(end[0]+v_[0]),int(end[1]+v_[1]))
))
try:
while True:
e = pg.event.wait()
if e.type == pg.QUIT:
raise StopIteration
elif e.type == pg.MOUSEBUTTONDOWN:
color = (random.randrange(256), random.randrange(256), random.randrange(256))
#pg.draw.circle(screen, color, e.pos, radius)
draw_on = True
start=e.pos
elif e.type == pg.MOUSEBUTTONUP:
draw_on = False
elif e.type == pg.MOUSEMOTION:
if draw_on:
roundline(screen, color, e.pos, last_pos, radius)
last_pos = e.pos
elif e.type == pg.MOUSEWHEEL:
radius=max(1,radius+e.y)
finally:
pg.quit()
我不明白你的线路问题。你是说没有端盖,还是…?把两者结合起来。粗线+圆。这是我两者问题的截图:使用粗线和圆似乎可以解决问题,但听起来不太优雅,所以我会再考虑一下,并将其作为最后的手段。+1因为我必须实现一个。。。啊!
import pygame as pg,random,math
screen = pg.display.set_mode((800,600))
draw_on = False
last_pos = (0, 0)
color = (255, 128, 0)
radius = 10
def roundline(srf, color, start, end, radius=1):
pg.display.update([drawline(srf,color,start,end,radius),
pg.draw.circle(srf, color, end, radius),
pg.draw.circle(srf, color, start, radius)])
def drawline(srf, color,start,end,width):
v=(start[0]- end[0],start[1]- end[1])
betrag=width/math.sqrt(v[0]*v[0]+v[1]*v[1])
v_=(v[1]*betrag,-betrag*v[0])
return pg.draw.polygon(srf, color,(
(int(start[0]+v_[0]),int(start[1]+v_[1])),
(int(start[0]-v_[0]),int(start[1]-v_[1])),
(int(end[0]-v_[0]),int(end[1]-v_[1])),
(int(end[0]+v_[0]),int(end[1]+v_[1]))
))
try:
while True:
e = pg.event.wait()
if e.type == pg.QUIT:
raise StopIteration
elif e.type == pg.MOUSEBUTTONDOWN:
color = (random.randrange(256), random.randrange(256), random.randrange(256))
#pg.draw.circle(screen, color, e.pos, radius)
draw_on = True
start=e.pos
elif e.type == pg.MOUSEBUTTONUP:
draw_on = False
elif e.type == pg.MOUSEMOTION:
if draw_on:
roundline(screen, color, e.pos, last_pos, radius)
last_pos = e.pos
elif e.type == pg.MOUSEWHEEL:
radius=max(1,radius+e.y)
finally:
pg.quit()