matterjs实现沙漏动画效果代码
代码语言:html
所属分类:动画
代码描述:matterjs实现沙漏动画效果代码,显示沙漏通过的粮食量、所用时间和平均每秒通过量。
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
canvas {
border: 1px solid black;
}
</style>
</head>
<body translate="no">
<div style="display: flex; align-items: start; scale:0.6; margin-top:-20vh">
<canvas id="hourglassCanvas" width="400" height="500"></canvas>
<div id="dataDisplay" style="margin-left: 20px; font-family: Arial; font-size: 26px;">
<p id="grainsPassed">Number of Grains Passed: 0</p>
<p id="currentTime">Current Time: 00:00.000</p>
</div>
</div>
<script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/matter.0.19.0.js"></script>
<script >
let canvas, ctx;
let grains = [];
const numGrains = 2000;
let grainsPassedCenter = 0;
let timerStarted = false;
let timerEnded = false;
let startTime;
let endTime;
let lastGrainPassedTime = null;
const glassThickness = 6;
window.onload = function () {
initializeCanvas();
initializeGrains();
startTimer();
animate();
};
function initializeCanvas() {
canvas = document.getElementById("hourglassCanvas");
ctx = canvas.getContext("2d");
canvas.width = 800;
canvas.height = 1000;
}
function initializeGrains() {
grains = [];
grainsPassedCenter = 0;
const startY = canvas.height / 2 - neckHeight / 2 - glassThickness; // Just above the center
const endY = 120 + glassThickness;
const spreadX = hourglassWidth - 2 * glassThickness;
const cellSize = 4;
const spatialHash = new Map();
for (let i = 0; i < numGrains; i++) {
let x, y;
let placed = false;
let attempts = 0;
const maxAttempts = 1000;
while (!placed && attempts < maxAttempts) {
x = canvas.width / 2 + (Math.random() - 0.5) * spreadX;
y = startY - Math.random() * (startY - endY); // Fill upwards
attempts++;
const cellX = Math.floor(x / cellSize);
const cellY = Math.floor(y / cellSize);
const cellKey = `${cellX},${cellY}`;
const nearbyKeys = [
cellKey,
`${cellX - 1},${cellY}`,
`${cellX + 1},${cellY}`,
`${cellX},${cellY - 1}`,
`${cellX},${cellY + 1}`,
`${cellX - 1},${cellY - 1}`,
`${cellX + 1},${cellY - 1}`,
`${cellX - 1},${cellY + 1}`,
`${cellX + 1},${cellY + 1}`];
let overlaps = false;
for (const key of nearbyKeys) {
if (spatialHash.has(key)) {
for (const otherGrain of spatialHash.get(key)) {
const dx = x - otherGrain.x;
const dy = y - otherGrain.y;
if (dx * dx + dy * dy < 16) {
// 4^2, square of 2 * collisionRadius
overlaps = true;
break;
}
}
if (overlaps) break;
}
}
if (!overlaps && isInsideHourglass(x, y, 2)) {
// Check if inside hourglass
placed = true;
const grain = {
x: x,
y: y,
radius: 3,
collisionRadius: 3,
velocity: { x: 0, y: 0 },
acceleration: 0,
passedCenter: false,
isDone: false };
grains.push(grain);
if (!spatialHash.has(cellKey)) {
spatialHash.set(cellKey, []);
}
spatialHash.get(cellKey).push(grain);
}
}
// If we couldn't place the grain after max attempts, skip it
if (!placed) {
console.warn(`Couldn't place grain ${i}`);
}
}
console.log(`Placed ${grains.length} out of ${numGrains} grains`);
}
function startTimer() {
timerStarted = true;
startTime = Date.now();
}
// Hourglass parameters
const hourglassWidth = 500;
const hourglassHeight = 800;
const neckWidth = 26;
const neckHeight = 40;
const curvature = 200;
function drawHourglass() {
const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
gradient.addColorStop(0, "rgba(0, 255, 255, 0.7)"); // Cyan
gradient.addColorStop(0.3, "rgba(255, 255, 255, 0.9)"); // White
gradient.addColorStop(0.5, "rgba(0, 255, 255, 0.7)"); // Cyan
gradient.addColorStop(0.7, "rgba(255, 255, 255, 0.9)"); // White
gradient.addColorStop(1, "rgba(0, 255, 255, 0.7)"); // Cyan
// Draw the main outline
ctx.beginPath();
// Top half
ctx.moveTo(canvas.width / 2 - hourglassWidth / 2, 100); // Doubled from 50
ctx.lineTo(canvas.width / 2 + hourglassWidth / 2, 100); // Doubled from 50
ctx.quadraticCurveTo(
canvas.width / 2 + hourglassWidth / 2,
canvas.height / 2 - curvature,
canvas.width / 2 + neckWidth / 2,
canvas.height / 2 - neckHeight / 2);
// Straight center part
ctx.lineTo(
canvas.width / 2 + neckWidth / 2,
canvas.height / 2 + neckHeight / 2);
// Bottom half
ctx.quadraticCurveTo(
canvas.width / 2 + hourglassWidth / 2,
canvas.height / 2 + curvature,
canvas.width / 2 + hourglassWidth / 2,
canvas.height - 100 // Doubled from 50
);
ctx.lineTo(canvas.width / 2 - hourglassWidth / 2, canvas.height - 100);
ctx.quadraticCurveTo(
canvas.width / 2 - hourglassWidth / 2,
canvas.height / 2 + curvature,
canvas.width / 2 - neckWidth / 2,
canvas.height / 2 + neckHeight / 2);
// Straight center part
ctx.lineTo(
canvas.width / 2 - neckWidth / 2,
canvas.height / 2 - neckHeight / 2);
ctx.quadraticCurveTo(
canvas.width / 2 - hourglassWidth / 2,
canvas.height / 2 - curvature,
canvas.width / 2 - hourglassWidth / 2,
100);
ctx.closePath();
ctx.strokeStyle = gradient;
ctx.line.........完整代码请登录后点击上方下载按钮下载查看
网友评论0