【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);

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

今天就这样了!!!

相关推荐
qq_589666052 小时前
TypeScript 完整入门教程
前端·javascript·typescript
星栈独行4 小时前
翻完 Pi 源码:它和 Codex、Claude Code 有何不同
开发语言·javascript·人工智能·程序人生
落落Plus5 小时前
浏览器缓存机制详解
javascript·缓存·浏览器缓存
用户059540174466 小时前
LLM对话记忆测试踩坑实录:手工回归30分钟,自动化后2分钟发现3个隐藏Bug
前端·css
浅水壁虎7 小时前
vue基础(第二章 )
前端·javascript·vue.js
界面开发小八哥7 小时前
界面控件DevExtreme v26.1新版亮点——支持Angular 22
前端·javascript·angular.js·devexpress·ui开发·devextreme
mONESY8 小时前
React useState 核心原理与最佳实践:从异步更新到性能优化全解
javascript
腻害兔8 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:CRM 客户关系模块深度解析——从线索到回款,一套完整的 B2B 销售闭环是怎么搭的?
java·前端·javascript·vue.js·产品经理·ai编程
gis开发之家9 小时前
《Vue3 从入门到大神37篇》Vue3 源码详解(七):watch 与 watchEffect 源码对比——副作用是如何被追踪的?
javascript·前端框架·vue3·vue3源码
bloglin9999910 小时前
langchain 和 langgraph 和 react
javascript·react.js·langchain