我正在try 将这篇Daniel Shiffman教程从p5js转换到没有库的HTML5画布:


var angle;
var axiom = "F";
var sentence = axiom;
var len = 100;

var rules = [];
rules[0] = {
  a: "F",
  b: "FF+[+F-F-F]-[-F+F+F]"
}

function generate() {
  len *= 0.5;
  var nextSentence = "";
  for (var i = 0; i < sentence.length; i++) {
    var current = sentence.charAt(i);
    var found = false;
    for (var j = 0; j < rules.length; j++) {
      if (current == rules[j].a) {
        found = true;
        nextSentence += rules[j].b;
        break;
      }
    }
    if (!found) {
      nextSentence += current;
    }
  }
  sentence = nextSentence;
  createP(sentence);
  turtle();

}

function turtle() {
  background(51);
  resetMatrix();
  translate(width / 2, height);
  stroke(255, 100);
  for (var i = 0; i < sentence.length; i++) {
    var current = sentence.charAt(i);

    if (current == "F") {
      line(0, 0, 0, -len);
      translate(0, -len);
    } else if (current == "+") {
      rotate(angle);
    } else if (current == "-") {
      rotate(-angle)
    } else if (current == "[") {
      push();
    } else if (current == "]") {
      pop();
    }
  }
}

function setup() {
  createCanvas(400, 400);
  angle = radians(25);
  background(51);
  createP(axiom);
  turtle();
  var button = createButton("generate");
  button.mousePressed(generate);
}

这是我的代码,它有一个问题,我无法调试...当我运行下面的代码时,我得到了这棵树的开头,并显示了一条错误消息,提示我更改Rotate(-this.Angel)来调用上下文.但是当我解决这个问题时,树消失了&amp;"BuildFlower()"函数中的矩形出现了……为什么会发生这种情况?:/:

broken lsystems tree

我的代码是:

const init = () => {
  const html = document.getElementsByTagName("html").item(0),
    canvas = document.getElementsByTagName("canvas").item(0),
    c = canvas.getContext("2d");

  let flower;
  const gui = new dat.GUI();

  function line(x1, y1, x2, y2, color) {
    c.strokeStyle = color;
    c.beginPath();
    c.moveTo(x1, y1);
    c.lineTo(x2, y2);
    c.stroke();
  }

  class Flower {
    constructor(x, y, size) {
      this.x = x;
      this.y = y;
      this.size = size;

      this.angle = (Math.PI / 180) * 25;
      this.axiom = "F";
      this.sentence = this.axiom;
      this.len = 100;
      this.rules = [];
      this.rules[0] = {
        a: "F",
        b: "FF+[+F-F-F]-[-F+F+F]",
      };
    }

    generateLSystem() {
      this.len *= 0.5;
      let nextSentence = "";
      for (let i = 0; i < this.sentence.length; i++) {
        let current = this.sentence.charAt(i);
        let found = false;
        for (let j = 0; j < this.rules.length; j++) {
          if (current == this.rules[j].a) {
            found = true;
            nextSentence += this.rules[j].b;
            break;
          }
        }
        if (!found) {
          nextSentence += current;
        }
      }
      this.sentence = nextSentence;
      this.turtle();
    }

    turtle() {
      c.resetTransform();
      c.translate(100, getResolution().h);

      for (let i = 0; i < this.sentence.length; i++) {
        let current = [this.sentence.charAt(i)];

        if (current == "F") {
          line(0, 0, 0, -this.len);
          c.translate(0, -this.len);
        } else if (current == "+") {
          c.rotate(this.angle);
        } else if (current == "-") {
          // WHEN I CHANGE THE LINE BELOW TO (`c.rotate`) THE ENTIRE THING DISAPPEARS.
          rotate(-this.angle);
        } else if (current == "[") {
          current.push();
        } else if (current == "]") {
          current.pop();
        }
      }
    }

    buildFlower() {
      c.beginPath();
      c.rect(
        getResolution().w / 2 - this.size / 2,
        getResolution().h / 2 - this.size / 2,
        this.size,
        this.size
      );
      c.stroke();
    }
  }

  const resize = () => {
    canvas.width = w = window.innerWidth;
    canvas.height = h = window.innerHeight;
    console.log(`screen resolution: ${w}px × ${h}px`);
  };

  const getResolution = () => {
    return { w: canvas.width, h: canvas.height };
  };

  const setup = () => {
    c.clearRect(0, 0, getResolution().w, getResolution().h);
    flower = new Flower(getResolution().w, getResolution().h, 200);
    flower.generateLSystem();
    gui.add(flower, "size", 0, 200);
    gui.add(flower, "axiom");
  };

  setup();

  const draw = (t) => {
    c.fillStyle = "rgba(255, 255, 255, .5)";
    c.fillRect(0, 0, w, h);

    window.requestAnimationFrame(draw);
  };

  let w,
    h,
    last,
    i = 0,
    start = 0;

  window.removeEventListener("load", init);
  window.addEventListener("resize", resize);
  resize();
  window.requestAnimationFrame(draw);
};

window.addEventListener("load", init);

我已经try 了几个小时,但似乎无法调试:/

推荐答案

一般建议:在小Sprint中工作,并频繁运行代码以验证其行为是否如预期的那样.这里的代码似乎是在几次长时间的冲刺中构建起来的,在此过程中没有对每个组件进行太多验证.这显然导致了复杂性的积累,导致了混乱和微妙的错误.

尽量避免过早的抽象,比如过多的函数和类,直到代码正常工作.在这一点上,正确的抽象和切入点将显而易见.

此外,只要核心逻辑正常工作,就可以引入"花哨"式的外围功能,从而最大限度地减少问题空间.当基本绘图失败时,诸如图形用户界面、调整大小、RAF循环等功能就会阻碍进度.将这些添加到基本的绘图作品之后.


画布上的画消失的主要原因是在setup()之后调用了resize().当您调整画布大小时,它会将其擦除干净.在您最初拨打resize()电话后拨打setup():

window.removeEventListener("load", init);
window.addEventListener("resize", resize);
resize(); // <-- wipes the screen
setup();  // <-- draw after resize
window.requestAnimationFrame(draw);

您会看到一个部分图形显示,因为您的崩溃阻止了resize()的执行.这应该是一个重要的调试提示:绘制后的一些代码一定会清除它.


从P5的push()pop()到HTML5画布的转换似乎不正确:

} else if (current == "[") {
  current.push();
} else if (current == "]") {
  current.pop();
}

current是一个数组,但我们不想把它搞乱.我们应该推送和弹出画布上下文,而不是array.这些调用是HTML5中的context.save()context.restore():

} else if (current === "[") {
  c.save();
} else if (current === "]") {
  c.restore();
}

一个奇怪的设计 Select 是:

let current = [this.sentence.charAt(i)];

if (current == "F") {

在这里,您创建了一个包含一个元素的数组,然后使用强制将其与字符串进行比较.始终使用===,不要创建不必要的单元素数组:

// use const instead of let and [i] instead of charAt(i)
const current = this.sentence[i];

if (current === "F") {

我可以进一步分析设计并进行全面的重写/代码审查,但我将把它留在这里,只是为了让您再次行动起来,而不是重复这一点:

const init = () => {
  const html = document.getElementsByTagName("html").item(0),
    canvas = document.getElementsByTagName("canvas").item(0),
    c = canvas.getContext("2d");

  let flower;
//  const gui = new dat.GUI();

  function line(x1, y1, x2, y2, color) {
    c.strokeStyle = color;
    c.beginPath();
    c.moveTo(x1, y1);
    c.lineTo(x2, y2);
    c.stroke();
  }

  class Flower {
    constructor(x, y, size) {
      this.x = x;
      this.y = y;
      this.size = size;

      this.angle = (Math.PI / 180) * 25;
      this.axiom = "F";
      this.sentence = this.axiom;
      this.len = 50;
      this.rules = [];
      this.rules[0] = {
        a: "F",
        b: "FF+[+F-F-F]-[-F+F+F]",
      };
    }

    generateLSystem() {
      this.len *= 0.5;
      let nextSentence = "";
      for (let i = 0; i < this.sentence.length; i++) {
        let current = this.sentence[i];
        let found = false;
        for (let j = 0; j < this.rules.length; j++) {
          if (current == this.rules[j].a) {
            found = true;
            nextSentence += this.rules[j].b;
            break;
          }
        }
        if (!found) {
          nextSentence += current;
        }
      }
      this.sentence = nextSentence;
      this.turtle();
    }

    turtle() {
      c.resetTransform();
      c.translate(100, getResolution().h);

      for (let i = 0; i < this.sentence.length; i++) {
        const current = this.sentence[i];

        if (current === "F") {
          line(0, 0, 0, -this.len);
          c.translate(0, -this.len);
        } else if (current === "+") {
          c.rotate(this.angle);
        } else if (current === "-") {
          c.rotate(-this.angle);
        } else if (current === "[") {
          c.save();
        } else if (current === "]") {
          c.restore();
        }
      }
    }

    buildFlower() {
      c.beginPath();
      c.rect(
        getResolution().w / 2 - this.size / 2,
        getResolution().h / 2 - this.size / 2,
        this.size,
        this.size
      );
      c.stroke();
    }
  }

  const resize = () => {
    canvas.width = w = window.innerWidth;
    canvas.height = h = window.innerHeight;
    console.log(`screen resolution: ${w}px × ${h}px`);
  };

  const getResolution = () => {
    return { w: canvas.width, h: canvas.height };
  };

  const setup = () => {
    c.clearRect(0, 0, getResolution().w, getResolution().h);
    flower = new Flower(getResolution().w, getResolution().h, 200);
    flower.generateLSystem();
    //gui.add(flower, "size", 0, 200);
    //gui.add(flower, "axiom");
  };

  const draw = (t) => {
    c.fillStyle = "rgba(255, 255, 255, .5)";
    c.fillRect(0, 0, w, h);

    window.requestAnimationFrame(draw);
  };

  let w,
    h,
    last,
    i = 0,
    start = 0;

  window.removeEventListener("load", init);
  window.addEventListener("resize", resize);
  resize();
  setup();
  window.requestAnimationFrame(draw);
};

window.addEventListener("load", init);
<canvas></canvas>

Javascript相关问答推荐

如何修复我的数据表,以使stateSave正常工作?

当使用';字母而不是与';var#39;一起使用时,访问窗口为什么返回未定义的?

如何在不影响隐式类型的情况下将类型分配给对象?

Use Location位置成员在HashRouter内为空

Puppeteer上每页的useProxy返回的不是函数/构造函数

搜索功能不是在分页的每一页上进行搜索

如何确保预订系统跨不同时区的日期时间处理一致?

未捕获的运行时错误:调度程序为空

FireBase云函数-函数外部的ENV变量

在不扭曲纹理的情况下在顶点着色器中旋转UV

Jexl to LowerCase()和Replace()

在GraphQL解析器中修改上下文值

rxjs在每次迭代后更新数组的可观察值

将字体样式应用于material -UI条形图图例

如果查询为空,则MongoDB将所有文档与$in匹配

在执行console.log(new X())时记录一个字符串

递归地将JSON对象的内容上移一级

JavaScript structuredClone在Chrome/Edge中获得了非法调用,但在NodeJS中没有

JS函数返回未定义的值,即使返回值有效

如何在使用会话时防止争用情况?