在 JavaScript 中用海龟图形概念绘图

做者:javascript

翻译:疯狂的技术宅css

原文:slicker.me/javascript/…html

未经容许严禁转载前端

我曾经用 Python 海龟图形生成过这个图像,并有用 JavaScript 复制它的强烈冲动。java

对于那些不熟悉海龟图形的人来讲,这是一个使用虚拟“海龟”绘制图形的概念,当海龟四处移动时,它的尾巴会在屏幕上留下痕迹。海龟有几个简单的命令:向前/向后移动 x 步,向左/向右转 x 度等。编程

因此例如这个序列:canvas

  • 前进100步
  • 向左转90度
  • 前进100步
  • 向左转90度
  • 前进100步
  • 向左转90度
  • 前进100步

会画一个正方形。每次移动后,乌龟的位置和方向都会更新,下一步移动将相对于以前的位置。有点相似于Canvas Path(你能够有一系列的 lineTo),但 Path 只能使用笛卡尔坐标(x 和 y)而不是方向(左/右/前/后)。前端工程化

若是海龟朝北开始,左转 90 度它将指向西。再左 90 度会指向南等。数组

能够在 Logo(自20世纪60年代)和 Python 中使用海龟图形,但不能在 JavaScript 中使用。函数

但真的是这样吗?我忽然意识到 context.rotate 基本上模仿 “左转/右转”,而 context.translatemoveTo/drawTo 结合起来就像“前进/后退”同样。

这绝对不是一种优雅或可扩展的图形编程方式 —— 有点像用蚯蚓绑鞋子:它看起来很酷,但只适用于某些条件。这些只是个人奇怪代码集中的另外一个小发明。若是你玩真正的海龟图形,我建议你使用提供这种功能的 JS 库、Python 或 Logo。或者至少先建立移动和旋转海龟的功能,以便使你的代码可读。

个人第一反应是建立一个具备本身的坐标和方向的海龟对象,而后使用 trig 函数计算移动,可是 rotate/translate 解决方案确定更有趣,并容许我几乎逐行翻译 Python 程序:

首先,让咱们看一下 rotate 和 translate 方法的工做原理。他们基本上改变了坐标系:

  • rotate 旋转一个角度
  • translate 经过向量移动它

It's easiest to see it in an example: 经过下面这个例子中最容易理解:

img

<html>
<style> body { background-color: black;} </style>
<body>
  <canvas id='myCanvas' width='800' height='600'></canvas>
  <script> function line(x1, y1, x2, y2) { context.beginPath(); context.moveTo(x1, y1); context.lineTo(x2, y2); context.stroke(); } function drawAxles() { line(-length, 0, length, 0); // x axis line(length * .9, length * .1, length, 0); line(length * .9, -length * .1, length, 0); line(0, -length, 0, length); // y axis line(-length * .1, length * .9, 0, length); line(length * .1, length * .9, 0, length); } let length = 100; let canvas = document.getElementById('myCanvas'); let context = canvas.getContext('2d'); context.strokeStyle = 'white'; drawAxles(); context.translate(length * 3, length); context.strokeStyle = 'blue'; drawAxles(); context.rotate(Math.PI / 8); context.strokeStyle = 'red'; drawAxles(); context.translate(3 * length, 0); context.strokeStyle = 'green'; drawAxles(); </script>
</body>
复制代码

左上角的白色(半)箭头是 HTML5 Canvas 的标准初始 X(水平)和 Y 轴(垂直)。注意,Y 轴指向下方 —— 与你在学校学到的笛卡尔坐标系相反。

轴的负部分位于屏幕以外。

如今咱们用 translate 来向右和向下移动坐标系 —— 也就是这些蓝色箭头。

接下来,咱们将坐标系旋转几度并绘制红色箭头。请注意,原点(0, 0)仍然与蓝色原点位于同一位置。

最后,咱们将系统在 x 轴上移动并将其绘制为绿色。请注意,上一步的轮换仍然适用。

如今让咱们看看原始 Python 代码的 JavaScript 版本:

<html>
<style> body { background-color: black;} </style>
<canvas id='myCanvas' width='800' height='600'></canvas>
  <body>
    <script> let colors = ['red', 'purple', 'blue', 'green', 'orange', 'yellow']; let canvas = document.getElementById('myCanvas'); let context = canvas.getContext('2d'); context.scale(.3, .3); context.translate(canvas.width, canvas.height); for (let i = 0; i < 360; i++) { context.strokeStyle = colors[i % 6]; context.lineWidth = i / 100 + 1; context.beginPath(); context.moveTo(0, 0); context.lineTo(0, i); context.stroke(); context.translate(0, i); context.rotate(-59 * (2 * Math.PI / 360)); } </script>
  </body>
</canvas>
复制代码

在第[11]行中,我缩小了图像。不然若是我保留原始的 Python 维度,它将会很是大。

[12] 将“海龟”移到画布的右下角。

[13-22] 绘制螺旋的主循环

[14]经过颜色数组([8])循环

[15]随着螺旋的增加改变线宽。它几乎不可见。

[16-20] 经过 i 步长向前移动海龟。 [16-19] 画线,[20] 移动海龟。因此咱们首先绘制线,并在过后更新“海龟”的位置。

当海龟离开中心时,线的长度变长。

[21] 将海龟旋转 59 度。负号只是为了保持螺旋方向。

如今让咱们把螺旋旋转一下。只需几行代码就能够改变海龟转动的角度。我使用正弦函数[10]来实现,但若是你不是三角函数的粉丝,也能够使用不一样的公式。甚至像 let rotation = counter / speed; 这样简单的东西产生有趣的结果(确保根据本身的喜爱调整 [32] 中的速度)。

<html>
<style> body { background-color: black;} </style>
<body>
  <canvas id='myCanvas' width='800' height='600'></canvas>
    <script> function animate() { let rotation = (2 * Math.sin(counter / (3.14 * speed))); context.setTransform(scale, 0, 0, scale, canvas.width / 2, canvas.height / 2); context.clearRect(-canvas.width / 2, -canvas.height, canvas.width, canvas.height *2); for (let i = 0; i < 360; i++) { context.strokeStyle = colors[i % 6]; context.lineWidth = i / 100 + 1; context.beginPath(); context.moveTo(0, 0); context.lineTo(0, i); context.stroke(); context.translate(0, i); context.rotate((-60 + rotation) * 2 * Math.PI / 360); } window.requestAnimationFrame(animate); counter++; } let colors = ['red', 'purple', 'blue', 'green', 'orange', 'yellow']; let canvas = document.getElementById('myCanvas'); let context = canvas.getContext('2d'); let counter = 0; let scale = .3; let speed = 20; animate(); </script>
  </canvas>
</body>
复制代码

如下这些参源能够帮你了解更多图形学方面的东西:

Optical illusion (18 lines)

Spinning squares - visual effect (25 lines)

Oldschool fire effect (20 lines)

Fireworks (60 lines)

Animated fractal (32 lines)

Minesweeper game (100 lines)

Physics engine for beginners

Physics engine - interactive sandbox

Physics engine - silly contraption

Starfield (21 lines)

Yin Yang with a twist (4 circles and 20 lines)

Tile map editor (70 lines)

Sine scroller (30 lines)

Interactive animated sprites

Image transition effect (16 lines)

Wholla lotta quadratic curves (50 lines)

Your first program in JavaScript: you need 5 minutes and a notepad

欢迎关注前端公众号:前端先锋,领取前端工程化实用工具包。

相关文章
相关标签/搜索