今天有位群友遇到一个流行拖尾的特效,实现的方法有很多,也可以直接让PE和UI直接实现,但是我们Html5 Canvas也可以实现,在本文中,我们将通过一个简单的HTML5 Canvas动画项目,介绍如何绘制动态五角星并为它们添加拖尾效果。通过这一过程,我们不仅能实现星星的动态运动,还能看到它们留下一条渐变消失的轨迹,创造出令人惊叹的星空效果。
一、HTML结构
HTML文档的结构非常简洁,主要包含了一个canvas
元素,它用于呈现所有的绘图内容。我们将通过JavaScript来操作这个canvas
,并动态更新其中的图形。
xml
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Star with Trail</title>
<style>
body, html {
margin: 0;
height: 100%;
overflow: hidden;
}
canvas {
display: block;
background: black;
}
</style>
</head>
<body>
<canvas id="starCanvas"></canvas>
</body>
</html>
二、Canvas设置与样式
首先,我们为canvas
设置了一个全屏大小,使其填充整个浏览器窗口。通过window.innerWidth
和window.innerHeight
获取窗口的宽高,确保动画在不同屏幕上都能完整显示。
ini
const canvas = document.getElementById("starCanvas");
const ctx = canvas.getContext("2d");
// 设置画布大小
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
为了确保背景是黑色的,同时避免滚动条出现,我们在CSS中做了如下样式调整:
css
body, html {
margin: 0;
height: 100%;
overflow: hidden;
}
canvas {
display: block;
background: black;
}
三、五角星绘制函数
在这个动画中,我们使用了一个drawStar
函数来绘制五角星。五角星是通过计算五个顶点位置来绘制的,顶点之间的角度是固定的。函数接受四个参数:x
(星星的X坐标),y
(Y坐标),radius
(星星的半径),color
(星星的颜色)。
ini
function drawStar(x, y, radius, color) {
const spikes = 5; // 五个尖刺
const step = Math.PI / spikes;
const rotation = (Math.PI / 2) * 3; // 初始旋转角度
const outerRadius = radius;
const innerRadius = radius / 2;
ctx.beginPath();
ctx.moveTo(x, y - outerRadius);
for (let i = 0; i < spikes; i++) {
ctx.lineTo(
x + Math.cos(rotation + step * i) * outerRadius,
y + Math.sin(rotation + step * i) * outerRadius,
);
ctx.lineTo(
x + Math.cos(rotation + step * i + step / 2) * innerRadius,
y + Math.sin(rotation + step * i + step / 2) * innerRadius,
);
}
ctx.closePath();
ctx.fillStyle = color;
ctx.fill();
}
四、星星对象与轨迹
为了使星星具有动态效果,我们创建了一个Star
类,包含了星星的位置、大小、速度以及其轨迹。星星会随时间不断更新其位置,并在其移动的过程中留下轨迹。
轨迹的消失效果通过记录每个轨迹点的时间戳来实现,随着时间的推移,轨迹的透明度会逐渐减小,直到完全消失。
kotlin
class Star {
constructor(x, y, size, speedX, speedY) {
this.x = x;
this.y = y;
this.size = size;
this.speedX = speedX;
this.speedY = speedY;
this.trail = []; // 存储轨迹
this.trailLifetime = 1000; // 轨迹存活时间 3 秒
}
// 绘制星星和轨迹
draw() {
// 添加新的轨迹点
this.trail.push({ x: this.x, y: this.y, time: Date.now() });
// 清除已过期的轨迹点
this.trail = this.trail.filter((point) => Date.now() - point.time < this.trailLifetime);
// 绘制轨迹点
for (let i = 0; i < this.trail.length; i++) {
const trailPoint = this.trail[i];
const alpha = 1 - (Date.now() - trailPoint.time) / this.trailLifetime; // 轨迹的透明度随时间变化
ctx.beginPath();
ctx.arc(trailPoint.x, trailPoint.y, this.size / 3, 0, Math.PI * 2);
ctx.fillStyle = `rgba(255, 255, 255, ${alpha})`; // 轨迹点透明度
ctx.fill();
}
// 绘制五角星
drawStar(this.x, this.y, this.size, "white");
}
// 更新星星位置
update() {
this.x += this.speedX;
this.y += this.speedY;
// 随机改变速度,模拟不规则的运动
this.speedX += (Math.random() - 0.5) * 0.2;
this.speedY += (Math.random() - 0.5) * 0.2;
// 如果星星超出屏幕,重置其位置
if (this.x > canvas.width) this.x = 0;
if (this.x < 0) this.x = canvas.width;
if (this.y > canvas.height) this.y = 0;
if (this.y < 0) this.y = canvas.height;
}
}
五、创建并更新星星
我们创建了一个星星数组,数组中的每个星星对象都有独立的运动轨迹和动态效果。星星的位置和速度是随机生成的,但为了简化展示,我们先只生成一个较大的星星。
ini
const stars = [];
for (let i = 0; i < 1; i++) {
const size = Math.random() * 5 + 1;
const speedX = Math.random() * 2 - 1;
const speedY = Math.random() * 2 - 1;
const star = new Star(
canvas.width / 4,
canvas.height / 4,
10,
Math.random() * 2 - 1,
Math.random() * 2 - 1,
);
stars.push(star);
}
六、动画循环
为了让动画不断循环,我们使用requestAnimationFrame
来创建一个平滑的动画效果。在每一帧,我们都清除画布,更新并绘制所有星星。
scss
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height); // 清空画布
for (let i = 0; i < stars.length; i++) {
stars[i].update();
stars[i].draw();
}
requestAnimationFrame(animate);
}
animate();
七、完整代码
ini
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Star with Trail</title>
<style>
body,
html {
margin: 0;
height: 100%;
overflow: hidden;
}
canvas {
display: block;
background: black;
}
</style>
</head>
<body>
<canvas id="starCanvas"></canvas>
<script>
const canvas = document.getElementById("starCanvas");
const ctx = canvas.getContext("2d");
// 设置画布大小
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// 五角星绘制函数
function drawStar(x, y, radius, color) {
const spikes = 5;
const step = Math.PI / spikes;
const rotation = (Math.PI / 2) * 3;
const outerRadius = radius;
const innerRadius = radius / 2;
ctx.beginPath();
ctx.moveTo(x, y - outerRadius);
for (let i = 0; i < spikes; i++) {
ctx.lineTo(
x + Math.cos(rotation + step * i) * outerRadius,
y + Math.sin(rotation + step * i) * outerRadius,
);
ctx.lineTo(
x + Math.cos(rotation + step * i + step / 2) * innerRadius,
y + Math.sin(rotation + step * i + step / 2) * innerRadius,
);
}
ctx.closePath();
ctx.fillStyle = color;
ctx.fill();
}
// 星星对象
class Star {
constructor(x, y, size, speedX, speedY) {
this.x = x;
this.y = y;
this.size = size;
this.speedX = speedX;
this.speedY = speedY;
this.trail = []; // 存储轨迹
this.trailLifetime = 1000; // 轨迹存活时间 3 秒
}
// 绘制星星和轨迹
draw() {
// 添加新的轨迹点
this.trail.push({ x: this.x, y: this.y, time: Date.now() });
// 清除已过期的轨迹点
this.trail = this.trail.filter((point) => Date.now() - point.time < this.trailLifetime);
// 绘制轨迹点
for (let i = 0; i < this.trail.length; i++) {
const trailPoint = this.trail[i];
const alpha = 1 - (Date.now() - trailPoint.time) / this.trailLifetime; // 轨迹的透明度随时间变化
ctx.beginPath();
ctx.arc(trailPoint.x, trailPoint.y, this.size / 3, 0, Math.PI * 2);
ctx.fillStyle = `rgba(255, 255, 255, ${alpha})`; // 轨迹点透明度
ctx.fill();
}
// 绘制五角星
drawStar(this.x, this.y, this.size, "white");
}
// 更新星星位置
update() {
this.x += this.speedX;
this.y += this.speedY;
// 随机改变速度,模拟不规则的运动
this.speedX += (Math.random() - 0.5) * 0.2;
this.speedY += (Math.random() - 0.5) * 0.2;
// 如果星星超出屏幕,重置其位置
if (this.x > canvas.width) this.x = 0;
if (this.x < 0) this.x = canvas.width;
if (this.y > canvas.height) this.y = 0;
if (this.y < 0) this.y = canvas.height;
}
}
// 创建星星
const stars = [];
for (let i = 0; i < 1; i++) {
const size = Math.random() * 5 + 1;
const speedX = Math.random() * 2 - 1;
const speedY = Math.random() * 2 - 1;
// const star = new Star(Math.random() * canvas.width, Math.random() * canvas.height, size, speedX, speedY);
// 创建一个大的星星
const star = new Star(
canvas.width / 4,
canvas.height / 4,
10,
Math.random() * 2 - 1,
Math.random() * 2 - 1,
);
stars.push(star);
}
// 动画循环
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height); // 清空画布
for (let i = 0; i < stars.length; i++) {
stars[i].update();
stars[i].draw();
}
requestAnimationFrame(animate);
}
animate();
</script>
</body>
</html>
八、总结
通过这段代码,我们成功实现了一个带有动态轨迹的五角星动画效果。你可以看到,每个星星都有自己的运动轨迹,并且随着时间的推移,轨迹会逐渐消失,给人一种真实的星星划过夜空的感觉。通过canvas
的arc
和beginPath
等方法,我们能够精确控制每个星星的外形和动画效果。此外,我们还通过随机的速度和位置来模拟星星的不规则运动,增加了动画的趣味性。
完结 撒花~