hookehuyr

feat(StarryBackground): 优化星星渲染效果并调整移动速度

添加预渲染星星纹理实现放射效果,改进星星大小随机分布
降低微信移动端星星移动速度系数从1.5到0.3
...@@ -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,20 +208,27 @@ const render = () => { ...@@ -168,20 +208,27 @@ 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
178 - const bg = context.createRadialGradient(star.x, star.y, 0, star.x, star.y, star.r); 215 + if (starTexture) {
179 - bg.addColorStop(0, `rgba(${props.starColor}, ${finalAlpha})`); 216 + // 使用预渲染的纹理绘制
180 - bg.addColorStop(1, `rgba(${props.starColor}, 0)`); 217 + context.globalAlpha = finalAlpha;
181 - context.fillStyle = bg; 218 + // star.r 作为大小的一半
182 - context.arc(star.x, star.y, star.r, 0, Math.PI * 2, true); 219 + context.drawImage(starTexture, star.x - star.r, star.y - star.r, star.r * 2, star.r * 2);
183 - context.fill(); 220 + context.globalAlpha = 1.0; // 恢复
184 - context.closePath(); 221 + } else {
222 + // 降级处理
223 + context.beginPath();
224 + const bg = context.createRadialGradient(star.x, star.y, 0, star.x, star.y, star.r);
225 + bg.addColorStop(0, `rgba(${props.starColor}, ${finalAlpha})`);
226 + bg.addColorStop(1, `rgba(${props.starColor}, 0)`);
227 + context.fillStyle = bg;
228 + context.arc(star.x, star.y, star.r, 0, Math.PI * 2, true);
229 + context.fill();
230 + context.closePath();
231 + }
185 } 232 }
186 233
187 animationFrameId = requestAnimationFrame(render); 234 animationFrameId = requestAnimationFrame(render);
......