用 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》不能在国内上映。

相关文章

学会这个Python编程范式,让你的代码质量提升10倍!

函数式编程作为一种重要的编程范式,强调使用函数来解决问题,避免改变状态和可变数据。在Python这门多范式编程语言中,函数式编程的概念和技术正在被越来越多的开发者所接受和应用。不可变性作为函数式编程的...

Python 基础:如何编写阶乘程序

什么是阶乘,你为什么应该关心?如果你是 Python 新手,你可能已经听说过“阶乘”这个术语。但它是怎么回事,为什么它很重要呢?一个数的阶乘(表示为n!)就是从 1 到n所有正整数的乘积。例如:5!...

OpenAI久违发了篇「正经」论文:线性布局实现高效张量计算

机器之心报道编辑:PandaOpenAI 发论文的频率是越来越低了。如果你看到了一份来自 OpenAI 的新 PDF 文件,那多半也是新模型的系统卡或相关增补文件或基准测试,很少有新的研究论文。至于原...

8.Python趣味数学笔记:点积和叉积

向量相乘分为:点积(例如:)和叉积(例如:),对于数来说,这些符号意思都是表示数字相乘,但是对于向量来说,却表示完全不同的操作。点积点积(也叫内积)是对两个向量的运算,返回一个标量。点积适用于二维、三...

零基础Python完全自学教程14:Python中的序列知识详解

欢迎你来到站长学堂,学习站长在线出品的在线课程《零基础Python完全自学教程》今天给大家分享的是第14课《Python中的序列知识详解》。本节课主要内容有:序列索引、序列切片、序列相加、序列相乘、序...