❝
努力成为一个情绪价值的提供者
❞
大家好,我是「柒八九」。一个「专注于前端开发技术/Rust
及AI
应用知识分享」的Coder
。
前言
在上一篇Rust 编译为 WebAssembly 在前端项目中使用我们通过一个简单的Hello World
的 Demo
,讲述了如何将 Rust
编译为 WebAssembly
,并在前端项目中使用。
虽然,是一个Demo
;但是,我们由小见大,以点见面,分别描述了
Rust
如何编译为WebAssembly
WebAssembly
如何内嵌到JS
环境中WebAssembly
如何与JS
进行交互Rust
如何能被 JS 调用的原理分析web-sys
充当wasm-bindgen
的前端
在写完上篇文章中,总觉得如果只是一个Demo
的话,有点意犹未尽。我们想要在实际开发中使用WebAssembly
,总不能通过Rust
唤起类似alert
等前端唾手可得的功能。这就有点「脱裤子放屁」多此一举了。我们不能为了用而用。WebAssembly
在前端项目中,更多扮演的是「功能加速」的角色。也就是我们用了它是为了降本增效的。(不是降本增笑哈)。
并且,在之前的文章中,还有很多开发上的不足,比方说
- 缺少代码热更新
- 本地 dev 服务器(上一篇中,我们特意用了
Webpack
搭建了一个本地服务器) - 操作浏览器的
DOM
元素 - ...
所以,我们今天用一个功能更加丰富的例子(贪吃蛇游戏),来逐一解决上面的问题,并让大家真正的理解Rust
和JS
是如何更好的合作的。
我们的本文的内容,不是要写一个功能完备的贪吃蛇游戏,而是以这个例子来更加完善我们对Rust
/WebAssembly
/JS
之间的数据交互的理解。「重在过程」,当然结果也很可爱,我们会写一个简单版本的贪吃蛇小游戏。
本文的一些基础内容,不再做出过多解释,也就是说大家需要有一定的Rust
的基础和如何在浏览器中运行Rust
有一定的了解。(可以Rust 编译为 WebAssembly 在前端项目中使用)
好了,天不早了,干点正事哇。
我们能所学到的知识点
❝
- 前置知识点
- 项目初始化
- Rust 内部实现&原理
- 优化开发
- 效果展示
❞
1. 前置知识点
❝
「前置知识点」,只是做一个概念的介绍,不会做深度解释。因为,这些概念在下面文章中会有出现,为了让行文更加的顺畅,所以将本该在文内的概念解释放到前面来。「如果大家对这些概念熟悉,可以直接忽略」
同时,由于阅读我文章的群体有很多,所以有些知识点可能「我视之若珍宝,尔视只如草芥,弃之如敝履」。以下知识点,请「酌情使用」。❞
WebAssembly 是什么
这个问题,在之前也有过解释,参看浏览器第四种语言-WebAssembly
如何在 JS 中调用 WebAssembly
上文中多次提过,参看Rust 编译为 WebAssembly 在前端项目中使用
requestAnimationFrame
requestAnimationFrame
是为了「优化动画性能」而设计的。它会在浏览器下一次重绘之前调用注册的回调函数,以确保动画更新发生在浏览器执行下一帧之前。这样可以避免在浏览器不活跃或隐藏的标签页中执行不必要的动画更新,节省系统资源。从而利用浏览器的优化机制,提供更流畅的动画效果。
requestAnimationFrame
的回调函数会传递一个时间戳参数
,表示动画开始执行的时间。我们可以利用这个参数来计算动画的进度,从而实现更复杂的动画效果。
使用方法
function animate(timestamp) {
// 在这里执行动画更新
// 通过递归调用 requestAnimationFrame 来实现持续的动画
requestAnimationFrame(animate);
}
// 启动动画
requestAnimationFrame(animate);
示例
function animate(timestamp) {
// 在这里执行动画更新
// 例如:移动一个元素
const element = document.getElementById("animatedElement");
const speed = 0.1; // 移动速度
const timePassed = timestamp - startTime;
element.style.left = timePassed * speed + "px";
// 通过递归调用 requestAnimationFrame 来实现持续的动画
requestAnimationFrame(animate);
}
// 获取动画开始的时间戳
const startTime = performance.now();
// 启动动画
requestAnimationFrame(animate);
❝
尽管
requestAnimationFrame
会在下一帧前执行回调函数,但仍然可能以较高的频率调用。如果需要控制动画的帧率,可以使用其他手段来进行节流。❞
Clamped 类型处理图像相关
在 Rust
中,使用 wasm-bindgen
包的 Clamped
类型通常与 WebAssembly
和 JavaScript
的互操作性有关。特别是在处理图像数据时,Clamped
在 Rust
代码中起到了重要的作用。
用途
- 「Clamped Array(钳制数组)」:在
JavaScript
中,Clamped
通常与Uint8ClampedArray
相关联,这是一个处理「图像数据时常用的数组类型」。Uint8ClampedArray
用于「存储图像的像素数据」,其中每个像素的值被“钳制”在0 到 255
的范围内,这正是标准RGBA
颜色值的范围。 - 「图像处理」:在使用
WebAssembly
处理Canvas
或者其他图像数据时,Clamped
类型确保了像素值不会超出有效范围。这对于图像渲染非常重要,因为它保证了颜色数据的正确性和一致性。
工作原理
- 当我们在
Rust
中处理图像数据并准备将其传递给JavaScript
或者Web API
(例如Canvas
的API
)时,我们可能会使用一组像素数据。这些数据通常是一个字节数组,其中包含了图像的红色、绿色、蓝色和透明度(RGBA
)信息。 - 使用
Clamped
包装器(例如Clamped(&some_array)
)时,我们告诉wasm-bindgen
应该将这个数组视为一个Uint8ClampedArray
,并相应地处理它。这意味着当这个数组传递到JavaScript
环境时,任何超出0-255
范围的值都会被自动调整(钳制)到这个范围内。 - 在我们提供的代码示例中,
Clamped
被用来确保在创建ImageData
对象时,传递给它的像素数组符合 Web 标准,并能被正确地渲染到 Canvas 上。
❝
use wasm_bindgen::Clamped;
的用途是为了在Rust
和WebAssembly
中处理和传递图像数据时保证数据的正确性和一致性,特别是当这些数据需要与JavaScript
的Uint8ClampedArray
类型互操作时。❞
2. 项目初始化
首先,我们来创建一个Rust WebAssembly
项目
cargo new game --lib
这将创建一个包含基本项目结构的文件夹,其中包括一个 Cargo.toml
文件和一个 src
文件夹。
+-- Cargo.toml
+-- src
+-- lib.rs
创建前端目录结构
在此项目的根目录下手动新增三个文件:
index.html
(项目的入口文件)index.js
(逻辑的主入口)style.css
index.html
在里面其实没啥操作可言,就是将index.js
和style.css
按照资源类别引入。
然后,如果大家在用VSCode
编辑器的话,可以使用Emmet
命令,一键自动生成Html
基础文档。
具体操作步骤简单如喝水,在*.html
的空文件中,输入!
然后就会出现Emmet
的命令,然后选中对于的命令,按下Tab
键,就可以自动生成Html
文件了。
然后,在其内部引入我们定义的style.css
和index.js
。(下面的内容只展示了核心代码)
其中有一点,简单的解释一下,在处理index.js
时,我们将其放置到body
靠后的位置,这样做的目的是能够在页面充分渲染好时,才会进行对于事件的注册和触发。
<!DOCTYPE html>
<html lang="en-US">
<head>
<title>Game</title>
<!-- 引入样式信息 -->
<link rel="stylesheet" href="style.css" />
</head>
<body>
<!-- 注意这块,会将rust渲染的内容放置到canvas元素下 -->
<canvas id="canvas"></canvas>
<!-- 承接业务逻辑-->
<script type="module" src="index.js"></script>
</body>
</html>
style.css
在这个文件中,定义一下元素的样式信息。这就很简单了。我们就不过多解释了哈。
body {
text-align: center;
font-size: 18px;
margin: 0;
}
#canvas {
width: 320px;
height: 320px;
image-rendering: pixelated;
}
@media (min-width: 600px) {
#canvas {
width: 500px;
height: 500px;
}
}
有一点简单说一下:在#canvas
下有一个image-rendering: pixelated
pixelated
是一种特殊的图像渲染技术,它将图像呈现为「像素化」的样式,使图像看起来像是由像素点组成的。这种效果通常用于创造复古或像素风格的视觉效果。
index.js
index.js
作为逻辑入口
,它算是一个粘合剂,将WebAssembly
和JS
融合到一起,并且能够实现逻辑互通。
玩过贪吃蛇的同学都知道,小
标签:WebAssembly,游戏,Color,self,pub,Game,Coord,screen,Rust From: https://blog.51cto.com/front789/8727576