WebAssembly(3)-康威生命游戏案例-交互

康威生命游戏案例-交互和性能分析
本文是在上一节基础上的进一步完善,增加交互以及性能分析

1. 暂停和恢复游戏

可以手动控制运行和停止

1.1 index.html代码

加入了一个button

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello wasm-pack!</title>
<style>
body {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
</style>
</head>
<body>
<button id="play-pause">启/停</button>
<canvas id="game-of-life-canvas"></canvas>
<script src="./bootstrap.js"></script>
</body>
</html>

1.2 index.js代码

控制开关的逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import {Universe, Cell} from "wasm-game-of-life";
import {memory} from "wasm-game-of-life/wasm_game_of_life_bg"

const CELL_SIZE = 5;
const GRID_COLOR = "#CCCCCC";
const DEAD_COLOR = "#FFFFFF";
const ALIVE_COLOR = "#000000";
const universe = Universe.new();
const width = universe.width();
const height = universe.height();
const canvas = document.getElementById("game-of-life-canvas");
canvas.height = (CELL_SIZE + 1) * height + 1;
canvas.width = (CELL_SIZE + 1) * width + 1;

const ctx = canvas.getContext('2d');
let animationId = null;

function renderLoop() {
drawGrid();
drawCells();
universe.tick();
animationId = requestAnimationFrame(renderLoop);
}

function isPaused(){
return animationId === null;
}

const playPauseButton = document.getElementById("play-pause");
function play(){
playPauseButton.textContent = "⏸️";
renderLoop();
}
function pause(){
playPauseButton.textContent = "▶";
cancelAnimationFrame(animationId)
animationId = null
}

function drawGrid() {
ctx.beginPath();
ctx.strokeStyle = GRID_COLOR;
// Vertical lines.
for (let i = 0; i <= width; i++) {
ctx.moveTo(i * (CELL_SIZE + 1) + 1, 0);
ctx.lineTo(i * (CELL_SIZE + 1) + 1, (CELL_SIZE + 1) * height + 1);
}
// Horizontal lines.
for (let j = 0; j <= height; j++) {
ctx.moveTo(0, j * (CELL_SIZE + 1) + 1);
ctx.lineTo((CELL_SIZE + 1) * width + 1, j * (CELL_SIZE + 1) + 1);
}
ctx.stroke();
}

function getIndex(row, column) {
return row * width + column;
}

function drawCells() {
const cellsPtr = universe.cells();
const cells = new Uint8Array(memory.buffer, cellsPtr, width * height);
ctx.beginPath();
for (let row = 0; row < height; row++) {
for (let col = 0; col < width; col++) {
const idx = getIndex(row, col);
ctx.fillStyle = cells[idx] === Cell.Dead
? DEAD_COLOR
: ALIVE_COLOR;
ctx.fillRect(
col * (CELL_SIZE + 1) + 1,
row * (CELL_SIZE + 1) + 1,
CELL_SIZE,
CELL_SIZE
);
}
}
ctx.stroke();
}
window.requestAnimationFrame(renderLoop);
playPauseButton.addEventListener("click",function(){
if (isPaused()){
play();
}else{
pause();
}
})

2. 细胞点击变化

在上一节基础上
鼠标点击细胞,可以发生变化

2.1 lib.rs加入内容

可变换Cell:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Cell实现切换
impl Cell {
fn toggle(&mut self) {
*self = match *self {
Cell::Dead => Cell::Alive,
Cell::Alive => Cell::Dead,
}
}
}

//Universe中新增方法
pub fn toggle_cell(&mut self, row: u32, col: u32) {
let idx = self.get_index(row, col);
self.cells[idx].toggle();
}

2.2 index.js中加入交互

非重点,这里不讲解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
canvas.addEventListener("click", function()  {
const boundingRect = canvas.getBoundingClientRect();

const scaleX = canvas.width / boundingRect.width;
const scaleY = canvas.height / boundingRect.height;

const canvasLeft = (event.clientX - boundingRect.left) * scaleX;
const canvasTop = (event.clientY - boundingRect.top) * scaleY;

const row = Math.min(Math.floor(canvasTop / (CELL_SIZE + 1)), height - 1);
const col = Math.min(Math.floor(canvasLeft / (CELL_SIZE + 1)), width - 1);

universe.toggle_cell(row, col);

drawGrid();
drawCells();
});

总结

本文已编辑完毕

参考

[1] Wasm官方文档

  • Copyrights © 2017-2023 Jason
  • Visitors: | Views:

谢谢打赏~

微信