JavaScript实现Penrose铺砌代码性能优化咨询
Penrose铺砌JavaScript代码优化方案
1. 预计算固定角度的三角函数值
Penrose铺砌依赖五边形相关的固定角度(36°、72°、108°等),提前计算并缓存这些角度的sin/cos值,彻底避免重复调用Math.sin()和Math.cos():
// 预计算核心角度的三角函数(弧度制) const ANGLE_36 = Math.PI / 5; const ANGLE_72 = 2 * Math.PI / 5; const SIN_36 = Math.sin(ANGLE_36); const COS_36 = Math.cos(ANGLE_36); const SIN_72 = Math.sin(ANGLE_72); const COS_72 = Math.cos(ANGLE_72); // 补全反向/补角的三角函数(直接复用已有值) const SIN_NEG_36 = -SIN_36; const COS_NEG_36 = COS_36; const SIN_108 = SIN_72; // sin(180-72)=sin72 const COS_108 = -COS_72; // cos(180-72)=-cos72
2. 用配置化替代冗余条件判断
把每种Tile的绘制规则、衍生逻辑封装到配置对象中,新增Tile只需扩展配置,无需修改大量if-else分支:
// Tile类型配置映射,统一管理绘制与衍生规则 const TILE_CONFIGS = { 'cyan-pentagon': { draw: (pos, size) => { const vertices = []; for (let i = 0; i < 5; i++) { const angle = i * ANGLE_72; vertices.push([ pos[0] + size * Math.cos(angle), pos[1] + size * Math.sin(angle) ]); } drawPolygon(vertices, 'cyan'); }, derivatives: [ { type: 'yellow-rhombus', offset: [size => size * COS_36, size => size * SIN_36], scale: 0.8 } ] }, 'gray-pentagon': { draw: (pos, size) => drawPolygon(getPentagonVertices(pos, size), 'gray'), derivatives: [ { type: 'red-pentagon', offset: [size => size * COS_72, size => size * SIN_72], scale: 0.6 }, { type: 'red-pentagon', offset: [size => size * COS_NEG_36, size => size * SIN_NEG_36], scale: 0.6 }, { type: 'half-star', offset: [() => 0, () => 0], scale: 1 } ] } // 新增Tile类型直接追加配置 }; // 通用Tile创建函数 function spawnTile(type, pos, size) { const config = TILE_CONFIGS[type]; if (!config) return; // 绘制当前Tile config.draw(pos, size); // 生成衍生Tile config.derivatives.forEach(deriv => { const derivPos = [ pos[0] + deriv.offset[0](size), pos[1] + deriv.offset[1](size) ]; spawnTile(deriv.type, derivPos, size * deriv.scale); }); } // 通用多边形顶点生成函数(复用逻辑) function getPentagonVertices(pos, size) { const vertices = []; for (let i = 0; i < 5; i++) { const angle = i * ANGLE_72; vertices.push([ pos[0] + size * Math.cos(angle), pos[1] + size * Math.sin(angle) ]); } return vertices; }
3. 精简变量与复用逻辑
- 用数组解构简化坐标传递,避免单独声明
x/y临时变量:
// 原写法 let x = pos[0]; let y = pos[1]; let newX = x * COS_36 - y * SIN_36; let newY = x * SIN_36 + y * COS_36; spawnTile('yellow-rhombus', [newX, newY], size); // 简化后 const [newX, newY] = rotatePoint(pos[0], pos[1], '36'); spawnTile('yellow-rhombus', [newX, newY], size);
- 封装通用坐标变换函数,避免重复编写旋转/平移代码:
function rotatePoint(x, y, angleKey) { const [sin, cos] = { '36': [SIN_36, COS_36], '-36': [SIN_NEG_36, COS_NEG_36], '72': [SIN_72, COS_72], '108': [SIN_108, COS_108] }[angleKey]; return [x * cos - y * sin, x * sin + y * cos]; }
4. 优化碰撞检测与数量统计
- 用全局
Map存储所有已生成的Tile,通过唯一ID避免重复创建,同时快速统计数量:
const activeTiles = new Map(); function spawnTile(type, pos, size) { // 生成唯一标识(可优化为更高效的哈希) const tileId = `${type}-${pos[0].toFixed(2)}-${pos[1].toFixed(2)}-${size.toFixed(2)}`; if (activeTiles.has(tileId)) return; // 碰撞检测:复用预计算的Tile边界 const bounds = getTileBounds(type, pos, size); for (const [, existingBounds] of activeTiles) { if (isOverlapping(bounds, existingBounds)) return; } // 绘制与衍生逻辑... activeTiles.set(tileId, bounds); } // 按类型统计Tile数量 function countTilesByType(type) { return Array.from(activeTiles.keys()).filter(id => id.startsWith(type)).length; }
- 预计算每种Tile的边界规则,避免每次碰撞检测时重新计算顶点:
function getTileBounds(type, pos, size) { // 根据Tile类型返回预定义的边界框(比如五边形的外接矩形) return { minX: pos[0] - size, maxX: pos[0] + size, minY: pos[1] - size, maxY: pos[1] + size }; } // 简化的轴对齐碰撞检测 function isOverlapping(b1, b2) { return b1.minX < b2.maxX && b1.maxX > b2.minX && b1.minY < b2.maxY && b1.maxY > b2.minY; }
5. 代码精简建议
- 移除未使用的变量,合并重复的逻辑片段;
- 用箭头函数简化简短的回调(比如配置中的
draw方法); - 把重复的顶点计算、颜色设置等逻辑抽成通用工具函数。
内容的提问来源于stack exchange,提问作者visionary
相关产品推荐
相关产品推荐

