摘自:哈哈老师的日记
https://www.toutiao.com/a7051427670651077159
哈哈老师设计的程序,学习实践一下。
一、三点画圆
做一个圆形路径动画,给定起点和终点后,再自动计算一个运动幅度,使用复数求解函数,得到圆心坐标和半径值,然后就可以画出圆来。
二、动画
在屏幕中间随便点一些点,依次得到坐标值,三个点画一个小球,使经过这三个点。
在屏幕上随意点了5个点,生成了3个卫星。
![](https://img.haomeiwen.com/i17748967/8afa0b003fa347d6.gif)
三、源程序
# circlepath.py
from base import *
W,H = 1280,800
def get_circle(p1,p2,p3):
'''三点求圆,返回圆心和半径'''
x, y, z = p1[0]+p1[1]*1j, p2[0]+p2[1]*1j, p3[0]+p3[1]*1j
w = z-x
w /= y-x
c = (x-y)*(w-abs(w)**2)/2j/w.imag-x
return (-c.real,-c.imag),abs(c+x)
class CirclePath:
def __init__(self,center,r):
self.center = Vector2(center)
self.r = r
self.angle = 0
self.speed = 2
def draw(self,canvas):
self.angle += self.speed
pos = self.center + Vector2(self.r,0).rotate(self.angle)
pygame.draw.circle(canvas, (0,200,0),pos, 5)
points = []
circles = []
show_points = True # 显示点
def setup():
size(W,H)
def draw():
global show_points
for event in ctx.events:
if event.type == pygame.KEYDOWN:
if event.key == K_SPACE:
show_points = not show_points
if event.type == pygame.MOUSEBUTTONDOWN:
points.append(event.pos)
if len(points) >= 3:
c,r = get_circle(points[-3],points[-2],points[-1])
circles.append(CirclePath(c,r))
ctx.screen.fill((0,0,0,100))
if show_points:
for p in points:
pygame.draw.circle(ctx.screen, (100,100,0),p, 2)
for circle in circles:
circle.draw(ctx.screen)
run()
四、base.py
base.py 是哈哈老师封装的 pygame ,主要是为了仿 processing 的调用方式。
# base.py
import pygame
from pygame.locals import *
from pygame.math import Vector2
import sys,random,math,os
width,height = 1920,1080
pygame.init()
window = None
pygame.display.set_caption('测试')
clock = pygame.time.Clock()
running = True
class real_contex():
def __init__(self):
self.screen = None
x,y = pygame.mouse.get_pos()
self.mouseX = x
self.mouseY = y
self.fps = 60
def fill(self,color):
self.window.fill(0)
if self.screen is not None:
self.screen.fill(color)
def hsv_to_rgb(self,h,s,v,a=100):
'''颜色转换'''
c = pygame.Color(0,0,0,a)
c.hsva = (h,s,v,a)
return c
def setup(self):
pass
def draw(self):
pass
ctx = real_contex()
def size(w,h):
global width,height,window
width,height = w,h
if w == 1920 and h == 1080:
window = pygame.display.set_mode((width,height),FULLSCREEN)
else:
window = pygame.display.set_mode((width,height))
ctx.window = window
# ctx.screen = window.convert_alpha() # 支持透明度
ctx.screen = pygame.Surface((w,h), pygame.SRCALPHA)
ctx.width = width
ctx.height = height
ctx.rect = window.get_rect()
ctx.center = ctx.rect.center
def run():
global running,window
# 获取调用 run 函数的文件名
m_name = sys._getframe(1).f_code.co_filename
f_name = os.path.basename(m_name)
module_name = os.path.splitext(f_name)[0]
# print(f_name,module_name)
# 通过文件名加载为模块,并动态获取 setup 和 draw 方法
app_module = __import__(module_name)
m_dir = dir(app_module)
if 'setup' in m_dir:
ctx.setup = app_module.setup
if 'draw' in m_dir:
ctx.draw = app_module.draw
del m_dir
ctx.setup()
if window is None:
size(800,600)
while running:
ctx.events = pygame.event.get()
ctx.mouseX,ctx.mouseY = pygame.mouse.get_pos()
for evt in ctx.events:
if evt.type == QUIT:
pygame.quit()
sys.exit()
if evt.type == KEYDOWN:
if evt.key == K_ESCAPE:
pygame.quit()
sys.exit()
ctx.draw()
window.blit(ctx.screen,(0,0))
pygame.display.update()
clock.tick(ctx.fps)
网友评论