在推上看到一張有意思的圖片,黑點(diǎn)在多個(gè)交叉的圓上做圓周運(yùn)動(dòng),看上去會(huì)有波浪的效果。我想這個(gè)Python的Pygame就可以實(shí)現(xiàn)啊。馬上動(dòng)手,下面是程序運(yùn)行的效果:

本文會(huì)從零開(kāi)始演示如何實(shí)現(xiàn)上述圖片效果,如果你對(duì)Python語(yǔ)言和Pygame很陌生,歡迎你光臨www.icoding.pub收看我的使用Python語(yǔ)言制作游戲視頻教程。這個(gè)教程面向初學(xué)者,教你在編寫游戲中學(xué)習(xí)Python語(yǔ)言。本文的內(nèi)容我也制作了視頻放在www.icoding.pub上,歡迎訪問(wèn)。
注意,本文的程序需用到笛卡爾坐標(biāo)系和三角函數(shù)。
Ok。首先你需要已經(jīng)安裝Python和Pygame。安裝過(guò)程我的視頻教程中有,此處略過(guò)。首先啟動(dòng)IDLE,啟動(dòng)新建文件,然后另存為,為你的文件起一個(gè)名字,記住擴(kuò)展名應(yīng)為.py,還要記住保存文件的目錄。
在新建文件中輸入以下內(nèi)容:
# 引入pygame和sys模塊
import pygame, sys
from pygame.locals import *
# 設(shè)置窗口寬度和高度
WIDTH = 500
HEIGHT = 400
# 設(shè)置圓半徑
RADIUS = 25
# 初始化pygame
pygame.init()
# 設(shè)置窗口與窗口標(biāo)題
windowSurface = pygame.display.set_mode((500,400),0,32)
pygame.display.set_caption('Circle')
# 設(shè)置顏色
BLACK = (0,0,0)
WHITE = (255,255,255)
# to do
# 事件循環(huán)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# 填充背景
windowSurface.fill(WHITE)
# 繪制窗口到屏幕上
pygame.display.update()
上面的代碼中,首先通過(guò)兩個(gè)import語(yǔ)句引入了需用到的pygame、sys模塊以及pygame的常量。pygame用于繪制圖形,sys用于結(jié)束程序。然后是pygme的初始化,任何使用pygame的程序都需要初始化。下面是設(shè)置窗口的尺寸和標(biāo)題,這個(gè)例子中設(shè)置的尺寸為寬度500、高度400。接下來(lái)設(shè)置了兩個(gè)顏色常量BLACK和WHITE,設(shè)置常量為了便于修改。最后進(jìn)入窗口事件監(jiān)聽(tīng)循環(huán),后面通過(guò)調(diào)用windowSurface的fill方法填充白色背景,接下來(lái)通過(guò)update刷新屏幕。
這是程序的整體結(jié)構(gòu),我們先在to do部分寫代碼。要在屏幕上畫圓,我們首先要確定圓的圓心。在to do下增加以下代碼:
xs = list(range(0, WIDTH + RADIUS, int(RADIUS*1.2)))
ys = list(range(0, HEIGHT + RADIUS, int(RADIUS*1.2)))
以上語(yǔ)句生成了x方向和y方向序列。注意,range的3個(gè)參數(shù),第一個(gè)表示起始,第二個(gè)表示結(jié)束,第三個(gè)表示步長(zhǎng)。第二個(gè)參數(shù)如果不加上RADIUS,窗口右邊和下邊的圓將顯示不完成。注意:這個(gè)程序的任何部分任何參數(shù)你都可以修改并運(yùn)行以查看效果。特別是第三個(gè)參數(shù),你可以調(diào)整這個(gè)數(shù)值查看生成圓的間距。
在程序windowSurface.fill(WHITE)下pygame.display.update上增加以下代碼,注意縮進(jìn)與二者相同:
for x in xs:
for y in ys:
pygame.draw.circle(windowSurface,BLACK,(x,y),RADIUS,1)
保存,運(yùn)行,會(huì)出現(xiàn)以下畫面:

下面的任務(wù)是繪制圓上的點(diǎn)。我們不能使用pygame的point,因?yàn)橐粋€(gè)像素的點(diǎn)太小了難以看清。我們?cè)诿總€(gè)圓的圓周上繪制circle對(duì)象,不過(guò)這個(gè)circle是實(shí)心的,半徑僅為幾個(gè)像素。問(wèn)題來(lái)了,我們知道了每個(gè)圓的圓心坐標(biāo)為(x,y),怎么確定圓周上點(diǎn)的坐標(biāo)呢?這就用到三角函數(shù)了。請(qǐng)看下圖:

設(shè)圓半徑為r,圓心坐標(biāo)(x_0,y_0),圓周上點(diǎn)的坐標(biāo)(小圓的圓心)為(x_1,y_1),點(diǎn)與圓心連線與X軸夾角為a,則x_1 = x_0 + r * cosa,y_1 = y_0 + r * sina。不熟悉三角函數(shù)的同學(xué)自行搜索補(bǔ)習(xí)一下。
我們先設(shè)角度為0。因?yàn)橐玫饺呛瘮?shù),我們要引入math庫(kù),在from pygame.locals import *下增加一行:
import math
還要設(shè)置點(diǎn)的半徑,在RADIUS = 25下增加一行:
POINT_RADIUS = 3
還需要設(shè)置角度變量,在 xs = ...上增加一行:
angle = 0
然后在pygame.draw.circle...下增加相同縮進(jìn)的以下3行:
x_point = x + RADIUS * (math.cos(angle))
y_point = y + RADIUS * (math.sin(angle))
pygame.draw.circle(windowSurface,BLACK,(int(x_point), int(y_point)), POINT_RADIUS)
前兩行是設(shè)置點(diǎn)的坐標(biāo),第三行繪制點(diǎn)?,F(xiàn)在,保存,運(yùn)行,會(huì)出現(xiàn)以下畫面:

試試將angle變量的值分別改為math.pi / 2, math.pi, math.pi * 3 / 2, math.pi *2等運(yùn)行,看看點(diǎn)會(huì)出現(xiàn)在什么位置,并想想為什么。
下面,我們要寫讓點(diǎn)移動(dòng)的代碼了。首先在程序首部import部分最后增加一行:
import time
我們要使用time的sleep函數(shù)控制程序的刷新時(shí)間,否則因?yàn)橛?jì)算機(jī)運(yùn)行太快,畫面閃爍得看不清。在第二個(gè)pygame.draw.cirlce下增加一行,注意縮進(jìn)與for x in xs:相同:
angle += 0.2
我們讓程序每刷新一次,角度增加0.2。在程序末尾pygame.display.update()下增加相同縮進(jìn)的一行:
time.sleep(0.02)
讓程序20毫秒刷新1次。保存,運(yùn)行。

貌似還不錯(cuò),但沒(méi)有期望的波浪的效果。要想得到那種效果,需要每一行的點(diǎn)的位置有輕微的差別,我們需要為每一行圓周上的點(diǎn)設(shè)置不同的起始角度?,F(xiàn)在,在ys = list(range(0...下增加以下內(nèi)容:
angles = {}
for y in ys:
angles[y] = angle
angle += 0.5
我們建立了一個(gè)angles字典變量,用于存儲(chǔ)每一行(對(duì),每一行,因?yàn)槊恳恍械?code>y值相同)的角度,而每一行的角度比上一行多0.5。循環(huán)代碼塊的x_point=...和y_point-...修改為:
x_point = x + RADIUS * (math.cos(angles[y]))
y_point = y + RADIUS * (math.sin(angles[y]))
我們還要在每個(gè)while循環(huán)里增加每行點(diǎn)的角度,在pygame.display.update()上增加一行相同縮進(jìn)的內(nèi)容:
for y in ys:
angles[y] += 0.05
保存,運(yùn)行。

以下是全部代碼:
# 引入pygame和sys模塊
import pygame, sys
import math
from pygame.locals import *
import time
WIDTH = 500
HEIGHT = 400
RADIUS = 25
POINT_RADIUS = 3
# 初始化pygame
pygame.init()
# 設(shè)置窗口與窗口標(biāo)題
windowSurface = pygame.display.set_mode((WIDTH,HEIGHT),0,32)
pygame.display.set_caption('Circle')
# 設(shè)置顏色
BLACK = (0,0,0)
WHITE = (255,255,255)
angle = 0
# to do
xs = list(range(0, WIDTH + RADIUS, int(RADIUS*1.2)))
ys = list(range(0, HEIGHT + RADIUS, int(RADIUS*1.2)))
angles = {}
for y in ys:
angles[y] = angle
angle += 0.5
# 事件循環(huán)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
windowSurface.fill(WHITE)
for x in xs:
for y in ys:
pygame.draw.circle(windowSurface,BLACK,(x,y),RADIUS,1)
x_point = x + RADIUS * (math.cos(angles[y]))
y_point = y + RADIUS * (math.sin(angles[y]))
pygame.draw.circle(windowSurface,BLACK,(int(x_point), int(y_point)), POINT_RADIUS)
for y in ys:
angles[y] += 0.05
# 繪制窗口到屏幕上
pygame.display.update()
time.sleep(0.02)
OK。我已將本文寫代碼過(guò)程錄制為視頻并配有講解,如果你對(duì)本文內(nèi)容有不清楚的地方,可以光臨www.icoding.pub收看。