【Virtual World 02】两点一线!!!

这是纯前端手搓虚拟世界第二篇。

在上一篇里,我们已经成功搭好了项目的基础骨架,并实现了最基础的单位 ------ Point2D类。如果你是中途加入,点下面先补一下。

戳这里就可以【Virtual World 01】头脑热一把,带你手搓虚拟世界💪!

吐个槽

第一篇写得有点啰嗦,可能有人觉得我"明明是手搓虚拟世界,为啥从语文课开始讲起"😂。

这...总得有点仪式感嘛。

别急别急!

上代码!!!

来,直接在我们primitives文件夹中,定义一个segment类。

js 复制代码
// ./primitives/segment.js
export default class Segment {
  // p1 p2 传入Point类 
  constructor(p1, p2) {
    this.p1 = p1;
    this.p2 = p2;
  }
}

现在看过去,这个类依旧那么简单,但如果能跟到后面,你会发现---它是构建虚拟世界里所有「形状」的基础大到建筑、道路、地形轮廓,小到网格、辅助线,全都绕不开它。

打基础的时候就是这么简单,但往往复杂的东西就是简单东西堆砌的。知道1+1然后考上了清华的朋友一定会给我点个赞的。

骑驴看账本--走着瞧吧

两点一线

对于创建虚拟世界,我们打小就有理论基础的。这个我坚信。

你肯定还记得小学二年级的王老师曾告诉你,两点才能成一条线!!!

嗯,好,知识充,接下来动手实操了。技术点上,主要还依赖canvasgetContext("2d")。其中有moveTolineTo

在Segment类中填上如下代码:

js 复制代码
// ./primitives/segment.js
draw(ctx, { width = 2, color = "black" } = {}) {
    ctx.beginPath();  // 开始绘制
    ctx.lineWidth = width; // 设置线的宽度
    ctx.strokeStyle = color; // 设置线的颜色
    ctx.moveTo(this.p1.x, this.p1.y);
    ctx.lineTo(this.p2.x, this.p2.y);
    ctx.stroke();
}

代码很好理解,但我们可以靠想象力丰富下。

脑海中想一下你拿着笔,先移动笔到纸的某一点,然后下笔,手腕将笔移动到另一点,把笔拿开,线搞定!!

show一下,在/src/index.js中的display方法添加如下代码:

js 复制代码
 // 用于绘制所有图形
  display() {
    new Segment(new Point2D(200, 200),new Point2D(400, 400)).draw(this.ctx)
  }

嗯...万里长征第二步。

粗细是个问题(但先不急)

先说明下:

属性 说明
lineWidth Canvas 只是大致控制粗细,不是像 SVG 那样精确
strokeStyle 支持颜色、渐变等
高级需求 需要结合像素密度 / DPR 做适配

目前好只是基础几何阶段先不在乎这个。后面做 坐标系 + 视口缩放 的时候,我们再一起处理 DPI 适配和缩放视觉一致性。

至于曲线,先忘掉这回事吧。

装个X

老师常常告诫我们举一反三,嗯,这就来了。

我们目前两个类:

  • Point2D
  • Segment

但理论上,可以绘制任何几何图形了,这样,简简单单搞个分形树

还在在/src/index.js中的display方法中,添加上实验代码:

js 复制代码
 // 用于绘制所有图形
 const fractalTree = (p1, length, angle, depth, ctx) => {
      if (depth <= 0) return;

      const p2 = new Point2D(
        p1.x + Math.cos(angle) * length,
        p1.y + Math.sin(angle) * length
      );

      new Segment(p1, p2).draw(this.ctx);

      const nextLength = length * 0.7;

      fractalTree(p2, nextLength, angle - 0.5, depth - 1, ctx); // 左叉
      fractalTree(p2, nextLength, angle + 0.5, depth - 1, ctx); // 右叉
}

fractalTree(new Point2D(300, 500), 120, -Math.PI / 2, 10, this.ctx);

不出意外,艺术成分还得上几层楼。

今天就这样了!!!

相关推荐
css趣多多16 小时前
this.$watch
前端·javascript·vue.js
Code小翊16 小时前
JS语法速查手册,一遍过JS
javascript
子春一17 小时前
Flutter for OpenHarmony:构建一个 Flutter 天气卡片组件,深入解析动态 UI、响应式布局与语义化设计
javascript·flutter·ui
Remember_99317 小时前
Java 单例模式深度解析:设计原理、实现范式与企业级应用场景
java·开发语言·javascript·单例模式·ecmascript
写代码的【黑咖啡】17 小时前
Python 中的自然语言处理利器:NLTK
前端·javascript·easyui
可问春风_ren18 小时前
Vue3 入门详解:从基础到实战
开发语言·前端·javascript·vue.js·前端框架·ecmascript·edge浏览器
摘星编程18 小时前
用React Native开发OpenHarmony应用:NativeStack原生导航
javascript·react native·react.js
一起养小猫18 小时前
Flutter for OpenHarmony 实战:从零开发一款五子棋游戏
android·前端·javascript·flutter·游戏·harmonyos
想睡好18 小时前
ref和reactive
前端·javascript·vue.js
霁月的小屋18 小时前
React 闭包陷阱深度解析
前端·javascript·react.js