将基于功能的草图对象转向

Turning a function based sketch object oriented

我正在尝试 Dan Shiffman's prime spiral program 并使其面向对象。

我正在将所有变量放入构造函数并将函数制作成方法来封装它们。

但是代码的 OOP 版本不会在屏幕上绘制超过 1 个三角形。我不明白为什么会出现问题,因为我将所有变量和函数都包含在 primeSpiral class.

的范围内

没有 classes

的工作代码

let x, y;
let step = 1;
let stepSize = 20;
let numSteps = 1;
let state = 0;
let turnCounter = 1;
let offset = 0;

function setup() {
  createCanvas(900, 900);
  background(0);
  const cols = width / stepSize;
  const rows = height / stepSize;

  x = width / 2;
  y = height / 2;

  for (let i = 0; i < 500; i++) {
    noStroke();
    primeSpiral(20, 1)
    primeSpiral(30, 200)
    incrementStep();
  }
}

function incrementStep() {
  switch (state) {
    case 0:
      x += stepSize;
      break;
    case 1:
      y -= stepSize;
      break;
    case 2:
      x -= stepSize;
      break;
    case 3:
      y += stepSize;
      break;
  }

  if (step % numSteps == 0) {
    state = (state + 1) % 4;
    turnCounter++;
    if (turnCounter % 2 == 0) {
      numSteps++;
    }
  }
  step++;


}

function primeSpiral(offset, color) {
  if (!isPrime(step + offset)) {
    //might put something here

  } else {
    let r = stepSize * 0.5;
    fill(color, 99, 164);
    push();
    translate(x, y);
    rotate(-PI / 4);
    triangle(-r, +r, 0, -r, +r, +r);
    pop();
  }
}

function isPrime(value) {
  if (value == 1) return false;
  for (let i = 2; i <= sqrt(value); i++) {
    if (value % i == 0) {
      return false;
    }
  }
  return true;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.js"></script>

与 classes:

let stepSize = 20;

function setup() {
  createCanvas(900, 900);
  background(0);
  const cols = width / stepSize;
  const rows = height / stepSize;
  x = width / 2;
  y = height / 2;
  background(0);
  prime = new PrimeSpiral(0, 0, 2, stepSize, 1, 0) //: x,y,offset,color
}

function draw() {
  prime.walk();
}

class PrimeSpiral {
  constructor(x, y, number) {
    this.x = x;
    this.y = y;
    this.number = number;
    this.stepSize = 20;
    this.numSteps = 1;
    this.state = 0;
    this.turnCounter = 1;
  }

  walk() {
    if (!this.isPrime(this.number)) {
      console.log(this.succes);
    } else {
      let r = stepSize * 0.5;
      fill(color, 99, 164);
      push();
      translate(x, y);
      rotate(-PI / 4);
      triangle(-r, +r, 0, -r, +r, +r);
      pop();
      this.incrementStep()
    }
  }

  isPrime(value) {
    if (value == 1) return false;
    for (let i = 2; i <= Math.sqrt(value); i++) {
      if (value % i == 0) {
        return false;
      }
    }
    return true;
  }

  incrementStep() {
    switch (this.state) {
      case 0:
        this.x += this.stepSize;
        break;
      case 1:
        this.y -= this.stepSize;
        break;
      case 2:
        this.x -= this.stepSize;
        break;
      case 3:
        this.y += this.stepSize;
        break;
    }

    if (this.step % this.numSteps == 0) {
      this.state = (this.state + 1) % 4;
      this.turnCounter++;
      if (this.turnCounter % 2 == 0) {
        this.numSteps++;
      }
    }
    this.step++;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.js"></script>

有时候你需要放慢速度才能走得更快:)

我的直觉是,您可能会尝试一次性编写 class,不要放慢速度并一次测试一个函数以确保没有错误。

以下是一些主要错误:

  • 您忘记在构造函数中将 step 属性 添加到 class (this.step = 1;)。在 incrementStep() this.step 中,undefined 递增,导致 NaN 丢弃其余部分(例如状态等)
  • 你离开 stepSize 主要作为全局变量,但也使用 this.stepSize:尽量避免歧义并使用其中之一(我建议使用 this.stepSize,因为它允许多个实例具有独立的步长)
  • 在步行中你仍在使用 translate(x, y);,而你的意思可能是 translate(this.x, this.y);

这是一个应用了上述注释的版本(如果 x,y 超出屏幕边界,则可选择不再递增或绘制三角形):

let spiral1;
let spiral2;

function setup() {
  createCanvas(900, 900);
  background(0);
  noStroke();
  // instantiate spirals here so width, height set
  spiral1 = new PrimeSpiral(20, 1);
  spiral2 = new PrimeSpiral(30, 200);
}

function draw(){
  spiral1.walk();
  spiral2.walk();
}

class PrimeSpiral{
  
  constructor(offset, color){
    this.x = width / 2;
    this.y = height / 2;
    this.step = 1;
    this.stepSize = 20;
    this.numSteps = 1;
    this.state = 0;
    this.turnCounter = 1;
    this.offset = offset;
    this.color = color;
  }
  
  incrementStep() {
    switch (this.state) {
      case 0:
        this.x += this.stepSize;
        break;
      case 1:
        this.y -= this.stepSize;
        break;
      case 2:
        this.x -= this.stepSize;
        break;
      case 3:
        this.y += this.stepSize;
        break;
    }

    if (this.step % this.numSteps == 0) {
      this.state = (this.state + 1) % 4;
      this.turnCounter++;
      if (this.turnCounter % 2 == 0) {
        this.numSteps++;
      }
    }
    this.step++;
  }
  
  walk(){
    // optional, early exit function if we're offscreen
    if(this.x < 0 || this.x > width) return;
    if(this.y < 0 || this.y > height) return;
    
    if (!isPrime(this.step + this.offset)) {
      //console.log('not prime:', step + offset);
    } else {
      let r = this.stepSize * 0.5;
      fill(this.color, 99, 164);
      push();
      translate(this.x, this.y);
      rotate(-PI / 4);
      triangle(-r, +r, 0, -r, +r, +r);
      pop();
    }
    this.incrementStep();
  }
  
}

function isPrime(value) {
  if (value == 1) return false;
  for (let i = 2; i <= sqrt(value); i++) {
    if (value % i == 0) {
      return false;
    }
  }
  return true;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js"></script>