File size: 5,074 Bytes
3d1e105 7dfd210 03a4526 7dfd210 82d9cf6 7dfd210 03a4526 7dfd210 3d1e105 03a4526 7dfd210 3d1e105 82d9cf6 7dfd210 3d1e105 82d9cf6 7dfd210 3d1e105 7dfd210 3d1e105 2720565 7dfd210 2720565 3d1e105 03a4526 3d1e105 7dfd210 3d1e105 82d9cf6 3d1e105 7dfd210 3d1e105 7dfd210 3d1e105 03a4526 3d1e105 03a4526 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
// モジュールの設定
const { Engine, Render, Runner, Bodies, World, Events } = Matter;
// エンジンとワールドの作成
const engine = Engine.create();
const world = engine.world;
// レンダラの作成
const render = Render.create({
element: document.body,
engine: engine,
canvas: document.getElementById('world'),
options: {
width: 800,
height: 600,
wireframes: false,
background: '#ffffff'
}
});
Render.run(render);
const runner = Runner.create();
Runner.run(runner, engine);
// シミュレーションに必要な変数
let ball = null;
let vxData = [];
let vyData = [];
let xData = [];
let tData = [];
let vxyData = [];
let breadcrumbs = [];
let startTime = null;
// キャンバスの境界を取得する関数
function getCanvasBounds() {
return render.canvas.getBoundingClientRect();
}
// クリックイベントで小球を生成
document.addEventListener('click', (event) => {
const canvasBounds = getCanvasBounds();
// キャンバス内のクリックのみ反応
if (event.clientX < canvasBounds.left || event.clientX > canvasBounds.right ||
event.clientY < canvasBounds.top || event.clientY > canvasBounds.bottom) {
return;
}
// 既存のボールがあれば新しいボールを生成しない
if (ball) {
return;
}
const x = event.clientX - canvasBounds.left;
const y = event.clientY - canvasBounds.top;
const velocityX = parseFloat(document.getElementById('vx').value); // ユーザー入力の初速度X
const velocityY = parseFloat(document.getElementById('vy').value); // ユーザー入力の初速度Y
ball = Bodies.circle(x, y, 20, { restitution: 0.8 });
Matter.Body.setVelocity(ball, { x: velocityX, y: velocityY });
World.add(world, ball);
// データの初期化
startTime = new Date().getTime();
});
// シミュレーションのアップデート
Events.on(engine, 'beforeUpdate', () => {
if (ball) {
const elapsedTime = (new Date().getTime() - startTime) / 1000;
vxData.push(ball.velocity.x);
vyData.push(ball.velocity.y);
xData.push(ball.position.x);
tData.push(elapsedTime);
vxyData.push({ x: ball.velocity.x, y: ball.velocity.y });
// BreadCrumbsの追加
breadcrumbs.push(Bodies.circle(ball.position.x, ball.position.y, 2, { isStatic: true }));
World.add(world, breadcrumbs[breadcrumbs.length - 1]);
// 画面外に出た場合、ボールを削除
if (ball.position.x < 0 || ball.position.x > render.options.width ||
ball.position.y < 0 || ball.position.y > render.options.height) {
World.remove(world, ball);
ball = null;
plotGraphs();
resetVariables();
}
}
});
// 変数をリセットする関数
function resetVariables() {
vxData = [];
vyData = [];
xData = [];
tData = [];
vxyData = [];
breadcrumbs.forEach(breadcrumb => World.remove(world, breadcrumb));
breadcrumbs = [];
}
// グラフ描画の関数
function plotGraphs() {
plotChart('vxChart', 'Velocity-X vs Time', tData, vxData);
plotChart('vyChart', 'Velocity-Y vs Time', tData, vyData);
plotChart('xtChart', 'Position-X vs Time', tData, xData);
plotScatterChart('vxyChart', 'Velocity-Y vs Velocity-X', vxyData);
}
function plotChart(canvasId, label, xData, yData) {
const ctx = document.getElementById(canvasId).getContext('2d');
new Chart(ctx, {
type: 'line',
data: {
labels: xData,
datasets: [{
label: label,
data: yData,
borderColor: 'rgba(75, 192, 192, 1)',
borderWidth: 1,
fill: false
}]
},
options: {
scales: {
x: {
beginAtZero: true
},
y: {
beginAtZero: true
}
}
}
});
}
function plotScatterChart(canvasId, label, data) {
const ctx = document.getElementById(canvasId).getContext('2d');
new Chart(ctx, {
type: 'scatter',
data: {
datasets: [{
label: label,
data: data,
borderColor: 'rgba(75, 192, 192, 1)',
backgroundColor: 'rgba(75, 192, 192, 0.5)',
borderWidth: 1
}]
},
options: {
scales: {
x: {
type: 'linear',
position: 'bottom',
beginAtZero: true,
title: {
display: true,
text: 'Velocity-X'
}
},
y: {
beginAtZero: true,
title: {
display: true,
text: 'Velocity-Y'
}
}
}
}
});
}
|