用 python 的柏林噪声库(noise)实现随机行走
柏林噪声太神奇了,最近在看一本 processing 的书,里面讲到随机行走,就想着能不能在 pygame 里实现,查了一通,发现案例很少,有个 noise 库,直接 pip install 还报错,需要编译环境。
在 CSDN 上找到一篇文章,《柏林噪声(Python)》,里面有相关的介绍和解决办法,根据自己的 windows 和 python 版本下载对应的 whl 文件,然后在下载目录下安装。
pip install noise-1.2.3-cp39-cp39-win_amd64.whl
关于 noise 的库,介绍文章好少,我也是简单了解一些,至少可以用了。
1、随机游走
核心代码如下,生成随机位置(x,y)
x_scale,y_scale,scale = W/2,H/2,512
seed_x,seed_y = random.random(),random.random()
px,py = random.randint(0,W),random.randint(0,H)
def random_pos():
'''生成随机位置'''
global px,py
px += 1
py += 1
x = int(W/2 - snoise2(px/scale,seed_y)*x_scale)
y = int(H/2 - snoise2(seed_x,py/scale)*y_scale)
return x,y
- snoise2() 返回的是一个 (-1,1)之间的数,所以要乘以长宽比例进行放大
- 用 W/2 和 H/2 减,是实现坐标变换,以屏幕中心为原点
- 我现在把 snoise2(x,y) 当一维噪声来调用,所以有一个参数要设置为常量
- scale 越大,随机数前后变化幅度越小,表现就越丝滑
完整代码:
import pygame
from pygame.locals import *
import random
from noise import snoise2
pygame.init()
screen = pygame.display.set_mode((0,0),FULLSCREEN) # Surface
W,H = screen.get_size()
canvas = screen.convert_alpha()
pygame.display.set_caption('my game')
x_scale,y_scale,scale = W/2,H/2,512
seed_x,seed_y = random.random(),random.random()
px,py = random.randint(0,100),random.randint(0,100)
def random_pos():
global px,py
px += 1
py += 1
x = int(W/2 - snoise2(px/scale,seed_y)*x_scale)
y = int(H/2 - snoise2(seed_x,py/scale)*y_scale)
return x,y
def draw_rect(x,y,width,height,alpha):
pygame.draw.rect(canvas,(0,255,0,alpha),(x,y,width,height),3)
def fill_rect(x,y,n):
wstep = W/n
hstep = H/n
sw = x / n
sh = y / n
sa = 200/n
for i in range(n+1,0,-1):
alpha = sa * i
draw_rect(x-i*sw,y-i*sh,i*wstep,i*hstep,alpha)
x0,y0 = W/2,H/2
n = 30
bright = n
time_count = 0
pygame.mouse.set_visible(False)
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
running = False
screen.fill(0)
canvas.fill((0,0,0,0))
# x0,y0 = pygame.mouse.get_pos()
x0,y0 = random_pos()
fill_rect(x0,y0,n)
screen.blit(canvas,(0,0))
pygame.display.update()
clock.tick(60)
pygame.quit()
效果图:
我用 imageio 生成的 gif,alpha 通道的信息没保存进去,有高手可以在评论里指点一下。
2、随机画线
把生成的随机点存到列表里,就可以随机画线了,效果就是文章最上面的图,我觉得可以用它生成无数 NFT。全屏运行时,笔走龙蛇,很有书法大师的范儿。。
import pygame
from pygame.locals import *
import random
from noise import snoise2
screen_size = W,H = 800,600
pygame.init()
# screen = pygame.display.set_mode((W,H)) # Surface
screen = pygame.display.set_mode((0,0),FULLSCREEN) # Surface
W,H = screen.get_size()
canvas = screen.convert_alpha()
pygame.display.set_caption('my game')
x_scale,y_scale,scale = W/2,H/2,512
seed_x,seed_y = random.random(),random.random()
lines = []
points = []
px,py = random.randint(0,W),random.randint(0,H)
def gen_point():
global px,py,points
for i in range(20):
px += 1
py += 1
x = int(W/2 - snoise2(px/scale,seed_y)*x_scale)
y = int(H/2 - snoise2(seed_x,py/scale)*y_scale)
points.append((x,y))
if len(points) >10 and (x,y) == points[0]:
lines.append(points)
points=[]
if len(points)>1000:
points.pop(0)
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
running = False
screen.fill(0)
canvas.fill((0,0,0,0))
if len(points)>1:
pygame.draw.lines(canvas,(0,255,0,255),False,points,3)
gen_point()
screen.blit(canvas,(0,0))
pygame.display.update()
clock.tick(60)
pygame.quit()
3、随机画圆
随机画圆,要用到 snoise3 通过变化 z 参数来获取圆周半径的变化,youtube 上有个 code challenge 专门讲了这个专题,我就不贴代码了。
闺女说我这个圆蠕动起来有点像史莱姆,我就简单封装了一下,写了个史莱姆的类,再加上随机游走,运行起来后,有点显微镜下观察细胞的感觉。
可惜,《黑客帝国4》不能在国内上映。