feat(StarryBackground): 优化星星渲染效果并调整移动速度
添加预渲染星星纹理实现放射效果,改进星星大小随机分布 降低微信移动端星星移动速度系数从1.5到0.3
Showing
1 changed file
with
52 additions
and
5 deletions
| ... | @@ -38,7 +38,7 @@ const props = defineProps({ | ... | @@ -38,7 +38,7 @@ const props = defineProps({ |
| 38 | // 星星移动速度系数 (值越大移动越快) | 38 | // 星星移动速度系数 (值越大移动越快) |
| 39 | starSpeed: { | 39 | starSpeed: { |
| 40 | type: Number, | 40 | type: Number, |
| 41 | - default: isWxMobile ? 1.5 : 0.1 | 41 | + default: isWxMobile ? 0.3 : 0.1 |
| 42 | }, | 42 | }, |
| 43 | // 流星速度 - 水平分量 (负值向左,正值向右) | 43 | // 流星速度 - 水平分量 (负值向左,正值向右) |
| 44 | meteorVx: { | 44 | meteorVx: { |
| ... | @@ -75,18 +75,58 @@ let context = null; | ... | @@ -75,18 +75,58 @@ let context = null; |
| 75 | let width = 0; | 75 | let width = 0; |
| 76 | let height = 0; | 76 | let height = 0; |
| 77 | let stars = []; | 77 | let stars = []; |
| 78 | +let starTexture = null; // 预渲染的星星纹理 | ||
| 78 | let animationFrameId = null; | 79 | let animationFrameId = null; |
| 79 | let meteorTimeoutId = null; | 80 | let meteorTimeoutId = null; |
| 80 | let meteorIndex = -1; // 当前流星的索引 | 81 | let meteorIndex = -1; // 当前流星的索引 |
| 81 | 82 | ||
| 83 | +// 创建星星纹理(放射效果) | ||
| 84 | +const createStarTexture = () => { | ||
| 85 | + const canvas = document.createElement('canvas'); | ||
| 86 | + canvas.width = 32; | ||
| 87 | + canvas.height = 32; | ||
| 88 | + const ctx = canvas.getContext('2d'); | ||
| 89 | + const center = 16; | ||
| 90 | + const radius = 16; | ||
| 91 | + | ||
| 92 | + // 1. 核心发光 (径向渐变) | ||
| 93 | + const gradient = ctx.createRadialGradient(center, center, 0, center, center, radius); | ||
| 94 | + gradient.addColorStop(0, `rgba(${props.starColor}, 1)`); | ||
| 95 | + gradient.addColorStop(0.2, `rgba(${props.starColor}, 0.8)`); | ||
| 96 | + gradient.addColorStop(0.5, `rgba(${props.starColor}, 0.1)`); | ||
| 97 | + gradient.addColorStop(1, `rgba(${props.starColor}, 0)`); | ||
| 98 | + ctx.fillStyle = gradient; | ||
| 99 | + ctx.beginPath(); | ||
| 100 | + ctx.arc(center, center, radius, 0, Math.PI * 2); | ||
| 101 | + ctx.fill(); | ||
| 102 | + | ||
| 103 | + // 2. 十字星芒 (模拟放射效果) | ||
| 104 | + ctx.strokeStyle = `rgba(${props.starColor}, 0.9)`; | ||
| 105 | + ctx.lineWidth = 1; // 细线条 | ||
| 106 | + ctx.beginPath(); | ||
| 107 | + // 横向光芒 | ||
| 108 | + ctx.moveTo(center - radius, center); | ||
| 109 | + ctx.lineTo(center + radius, center); | ||
| 110 | + // 纵向光芒 | ||
| 111 | + ctx.moveTo(center, center - radius); | ||
| 112 | + ctx.lineTo(center, center + radius); | ||
| 113 | + ctx.stroke(); | ||
| 114 | + | ||
| 115 | + return canvas; | ||
| 116 | +}; | ||
| 117 | + | ||
| 82 | // 初始化星星 | 118 | // 初始化星星 |
| 83 | const initStars = () => { | 119 | const initStars = () => { |
| 84 | stars = []; | 120 | stars = []; |
| 121 | + starTexture = createStarTexture(); // 生成纹理 | ||
| 122 | + | ||
| 85 | for (let i = 0; i < props.starCount; i++) { | 123 | for (let i = 0; i < props.starCount; i++) { |
| 86 | stars.push({ | 124 | stars.push({ |
| 87 | x: Math.round(Math.random() * width), | 125 | x: Math.round(Math.random() * width), |
| 88 | y: Math.round(Math.random() * height), | 126 | y: Math.round(Math.random() * height), |
| 89 | - r: Math.random() * 3, | 127 | + // 增加星星大小的随机性:范围 [2, 12] (因为使用纹理绘制,这里的r代表缩放基准) |
| 128 | + // 较小的星星居多,较大的星星较少 | ||
| 129 | + r: Math.random() < 0.9 ? Math.random() * 2 + 1 : Math.random() * 6 + 4, | ||
| 90 | ra: Math.random() * 0.01, | 130 | ra: Math.random() * 0.01, |
| 91 | alpha: Math.random(), | 131 | alpha: Math.random(), |
| 92 | vx: Math.random() * props.starSpeed - props.starSpeed / 2, | 132 | vx: Math.random() * props.starSpeed - props.starSpeed / 2, |
| ... | @@ -168,13 +208,19 @@ const render = () => { | ... | @@ -168,13 +208,19 @@ const render = () => { |
| 168 | } | 208 | } |
| 169 | 209 | ||
| 170 | // 绘制星星 | 210 | // 绘制星星 |
| 171 | - context.beginPath(); | ||
| 172 | - | ||
| 173 | // 叠加闪烁效果:使用正弦波在基础 alpha 上叠加快速变化 | 211 | // 叠加闪烁效果:使用正弦波在基础 alpha 上叠加快速变化 |
| 174 | - // Date.now() 产生时间变化,i 作为相位偏移,* 0.005 控制闪烁频率 | ||
| 175 | const twinkle = Math.abs(Math.sin(Date.now() * 0.006 + i)); | 212 | const twinkle = Math.abs(Math.sin(Date.now() * 0.006 + i)); |
| 176 | const finalAlpha = Math.min(1, Math.max(0, star.alpha * (0.5 + 0.5 * twinkle))); | 213 | const finalAlpha = Math.min(1, Math.max(0, star.alpha * (0.5 + 0.5 * twinkle))); |
| 177 | 214 | ||
| 215 | + if (starTexture) { | ||
| 216 | + // 使用预渲染的纹理绘制 | ||
| 217 | + context.globalAlpha = finalAlpha; | ||
| 218 | + // star.r 作为大小的一半 | ||
| 219 | + context.drawImage(starTexture, star.x - star.r, star.y - star.r, star.r * 2, star.r * 2); | ||
| 220 | + context.globalAlpha = 1.0; // 恢复 | ||
| 221 | + } else { | ||
| 222 | + // 降级处理 | ||
| 223 | + context.beginPath(); | ||
| 178 | const bg = context.createRadialGradient(star.x, star.y, 0, star.x, star.y, star.r); | 224 | const bg = context.createRadialGradient(star.x, star.y, 0, star.x, star.y, star.r); |
| 179 | bg.addColorStop(0, `rgba(${props.starColor}, ${finalAlpha})`); | 225 | bg.addColorStop(0, `rgba(${props.starColor}, ${finalAlpha})`); |
| 180 | bg.addColorStop(1, `rgba(${props.starColor}, 0)`); | 226 | bg.addColorStop(1, `rgba(${props.starColor}, 0)`); |
| ... | @@ -183,6 +229,7 @@ const render = () => { | ... | @@ -183,6 +229,7 @@ const render = () => { |
| 183 | context.fill(); | 229 | context.fill(); |
| 184 | context.closePath(); | 230 | context.closePath(); |
| 185 | } | 231 | } |
| 232 | + } | ||
| 186 | 233 | ||
| 187 | animationFrameId = requestAnimationFrame(render); | 234 | animationFrameId = requestAnimationFrame(render); |
| 188 | }; | 235 | }; | ... | ... |
-
Please register or login to post a comment