Processing中如何用递归函数创建对象实现平滑随机运动?
问题排查与正确实现方案
问题核心
你手动实现了4层滑动平均(每层用100长度数组做均值)的平滑高斯随机运动,但尝试用递归Generator类重构时,递归仅执行一次,无法复现手动效果。
错误原因分析
- 实例频繁新建丢失状态:递归时每次新建
Generator实例,导致每层滑动平均的数组历史状态无法持续维护——滑动平均需要复用同一个数组保存历史值,每次新建实例都会重置数组,完全失去平滑效果。 - 递归逻辑错误:递归调用
n.gen(output)后直接返回0,没有将递归得到的最终结果返回,导致最终只返回了第一层的计算值。 - 求和变量未重置:
output作为类成员变量,每次调用gen()时未重置为0,会累积之前的求和结果,导致均值计算完全错误。 generations变量未定义:类内未定义该变量,依赖全局变量的设计既不严谨也容易出错。
正确实现方案
采用链式Generator实例替代递归(更直观易维护),每个实例维护自己的滑动数组,实现多层平滑的串联调用。
修正后的Generator类
class Generator { float[] array; int windowSize; // 滑动窗口大小,替代全局elements // 构造函数传入窗口大小 Generator(int windowSize) { this.windowSize = windowSize; array = new float[windowSize]; } // 单次滑动平均计算,返回当前均值 float process(float input) { // 数组元素后移 for (int i = windowSize - 1; i > 0; i--) { array[i] = array[i - 1]; } // 新值放入数组头部 array[0] = input; // 计算均值(每次计算前重置sum) float sum = 0; for (float val : array) { sum += val; } return sum / windowSize; } }
主代码重构
float y; int windowSize = 100; // 创建4层Generator实例,对应手动实现的4层平滑 Generator gen1, gen2, gen3, gen4; void setup() { size(800, 800); frameRate(120); y = 0; // 初始化4层滑动平均生成器 gen1 = new Generator(windowSize); gen2 = new Generator(windowSize); gen3 = new Generator(windowSize); gen4 = new Generator(windowSize); } void draw() { translate(width/2, height/2); background(0); stroke(255); line(-width/2, 0, width/2, 0); // 链式调用实现4层平滑 float raw = randomGaussian(); float smooth1 = gen1.process(raw); float smooth2 = gen2.process(smooth1); float smooth3 = gen3.process(smooth2); float finalSmooth = gen4.process(smooth3); // 圆形运动逻辑 noStroke(); ellipse(0, y, 20, 20); float speed = 20; y += finalSmooth * speed; if (y < -height/2 || y > height/2) { y = 0; } }
方案优势
- 每个
Generator实例独立维护滑动数组,持续保留历史值,完美复现手动实现的滑动平均逻辑。 - 链式调用替代递归,逻辑清晰,扩展方便(新增平滑层数只需新增实例并加入调用链)。
- 每次计算均值时重置sum,避免累积错误。
- 窗口大小通过构造函数传入,类的独立性更强,不依赖全局变量。
内容的提问来源于stack exchange,提问作者firewall
相关产品推荐
相关产品推荐

