图中同时渲染了十万个像素,没有明显掉帧
我对Pygame的印象一直是慢的扣脚的,直到前段时间看到了一段MandelBrot代码(源地址弄丢了)其中使用了这个功能:pygame.surfarray.make_surface()
这里可以直接把numpy阵列转换为pygame.surface,对比draw来说节省了大量算力
在运算物理效果的时候还可以使用numba即时编译,速度指数型上升。
这里粒子用了水粒子作为示范,原理十分简单,依次检测每个像素下方,左边,右边,如果像素为空则移动到临近像素。
代码见下
import pygame as pg
import random
import numpy as np
from numba import njit, prange@njit(cache=True)
def palette(im): # I snatched this from stack exchangeim = 255 * (im / im.max())w, h = im.shaperet = np.empty((w, h, 3), dtype=np.uint8)ret[:, :, 0] = ret[:, :, 1] = ret[:, :, 2] = imreturn ret@njit(cache=False,fastmath=False,nopython=True)
def frame_calculation(particles, pix_array):if len(particles) == 0:returnfor ob in particles:x=ob[0]y=ob[1]if y<1 or y>resH-1:continueif pix_array[y-1,x]==0:pix_array[y-1,x]=255pix_array[y,x] = 0ob[1] = y-1continueif x+1<resW:if pix_array[y, x+1] == 0:pix_array[y, x+1] = 255pix_array[y, x] = 0ob[0] = x + 1continueif x-1>0:if pix_array[y, x - 1] == 0:pix_array[y,x-1] = 255pix_array[y, x] = 0ob[0] = x - 1continuedef draw_on_array(x, y):global particlesglobal pix_arrayy_=resH-yif y_ < resH:for i in range(-1,1):for j in range(-1,1):pix_array[y_+i, x+j] = 255particles = np.vstack((particles, [x+i, y_+j]))# pix_array[y_,x] = 255# particles = np.vstack((particles, [x, y_]))resW,resH = [1050, 600]
pg.init()
pg.font.init()
screen = pg.display.set_mode((resW,resH))
l_mouse_clicked = False
pix_array = np.zeros((resH,resW),np.int32)
run = True
particles = np.array([[-1,-1]],np.int32)while run:screen.fill([0, 0, 0])x, y = 0,0for event in pg.event.get():if event.type == pg.QUIT:run = Falsepg.quit()if event.type == pg.MOUSEBUTTONDOWN:if event.button == 1:l_mouse_clicked = Trueif event.button == 3:print(len(particles))if event.type == pg.MOUSEBUTTONUP:if event.button == 1:l_mouse_clicked = Falseif l_mouse_clicked:x, y = pg.mouse.get_pos()draw_on_array(x,y)frame_calculation(particles, pix_array)pixel_surface = pg.surfarray.make_surface(palette(pix_array))pixel_surface = pg.transform.rotate(pixel_surface,90)screen.blit(pixel_surface, [0, 0])pg.display.flip()