// F6. Симулятор скоростной дороги (§20 в ch2) — μ и тормозной путь.
(function(){
'use strict';
const B = () => window.PHYS9_FLAG_BASE;
const C = () => window.PHYS9_COLORS || {};
const SURFACES = {
asphalt_dry: { mu: 0.7, name: 'асфальт сухой', col: '#1e293b' },
asphalt_wet: { mu: 0.4, name: 'асфальт мокрый', col: '#475569' },
gravel: { mu: 0.55, name: 'гравий', col: '#92400e' },
snow: { mu: 0.2, name: 'снег', col: '#cbd5e1' },
ice: { mu: 0.08, name: 'лёд', col: '#bfdbfe' }
};
function init(secId){
if (!B()) return false;
let surfBtns = '';
for (const id in SURFACES){
const s = SURFACES[id];
surfBtns += '';
}
const body = ''
+ '
'+surfBtns+'
'
+ ''
+ ''
+ '
'
+ ''
+ ''
+ ''
+ ''
+ '
'
+ ''
+ '
Покрытиесухой асфальт
'
+ '
μ0.7
'
+ '
Тормозной путь20.4 м
'
+ '
Время торможения2.43 с
'
+ '
'
+ '';
const card = B().makeCard(secId,
'F6. Симулятор скоростной дороги',
'Выбери покрытие и скорость. При торможении: $s = v^2/(2\\mu g)$. На льду путь в 8 раз длиннее!',
body);
if (!card) return false;
const cv = document.getElementById('F6-cv');
const ctx = cv.getContext('2d');
const W = cv.width, H = cv.height;
let surf = 'asphalt_dry';
let st = { x: 50, v: 0, vTarget: 60/3.6, mode: 'cruise' };
function update(){
const v_kmh = +document.getElementById('F6-v').value;
document.getElementById('F6-vv').textContent = v_kmh;
st.vTarget = v_kmh / 3.6;
const mu = SURFACES[surf].mu;
const v = st.vTarget;
const sStop = v*v / (2 * mu * 9.8);
const tStop = v / (mu * 9.8);
document.getElementById('F6-surf').textContent = SURFACES[surf].name;
document.getElementById('F6-mu').textContent = mu;
document.getElementById('F6-stop').textContent = sStop.toFixed(1) + ' м';
document.getElementById('F6-tstop').textContent = tStop.toFixed(2) + ' с';
}
function reset(){
st = { x: 50, v: st.vTarget, mode: 'cruise' };
document.getElementById('F6-fb').className = 'flag-feedback';
draw();
}
function tick(dt){
const mu = SURFACES[surf].mu;
if (st.mode === 'cruise'){
st.v = st.vTarget;
st.x += st.v * dt * 5; /* 5 px = 1 м */
if (st.x > W + 50) st.x = -20;
} else if (st.mode === 'brake'){
st.v -= mu * 9.8 * dt;
if (st.v < 0){ st.v = 0; st.mode = 'stopped'; }
st.x += st.v * dt * 5;
}
draw();
}
function draw(){
const col = C();
ctx.fillStyle = col.bg || '#fafafa';
ctx.fillRect(0, 0, W, H);
/* небо */
ctx.fillStyle = col.gas || '#dbeafe';
ctx.fillRect(0, 0, W, 80);
/* дорога */
const s = SURFACES[surf];
ctx.fillStyle = s.col;
ctx.fillRect(0, 80, W, 80);
/* разметка */
ctx.strokeStyle = '#fff';
ctx.lineWidth = 3;
ctx.setLineDash([24, 16]);
ctx.beginPath();
ctx.moveTo(0, 120); ctx.lineTo(W, 120);
ctx.stroke();
ctx.setLineDash([]);
/* шкала метров */
ctx.fillStyle = col.text || '#0f172a';
ctx.font = '11px Inter,sans-serif';
for (let m = 0; m <= 140; m += 10){
const px = 50 + m*5;
if (px > W) break;
ctx.fillRect(px-1, 160, 2, 6);
if (m % 20 === 0) ctx.fillText(m + ' м', px - 8, 178);
}
/* трава */
ctx.fillStyle = '#16a34a';
ctx.fillRect(0, 180, W, H - 180);
/* машина */
ctx.fillStyle = col.fail || '#dc2626';
ctx.fillRect(st.x - 25, 95, 50, 22);
ctx.fillRect(st.x - 18, 88, 36, 9);
ctx.fillStyle = '#0f172a';
ctx.fillRect(st.x - 16, 117, 8, 8);
ctx.fillRect(st.x + 8, 117, 8, 8);
/* подпись */
ctx.fillStyle = col.text || '#0f172a';
ctx.font = 'bold 13px Inter,sans-serif';
ctx.fillText((st.v*3.6).toFixed(0) + ' км/ч', st.x - 22, 78);
/* shadow */
ctx.fillStyle = 'rgba(0,0,0,0.3)';
ctx.fillRect(st.x - 25, 130, 50, 4);
}
card.querySelectorAll('[data-surf]').forEach(btn => {
btn.addEventListener('click', () => {
surf = btn.dataset.surf;
card.querySelectorAll('[data-surf]').forEach(b => b.classList.remove('primary'));
btn.classList.add('primary');
update();
reset();
});
});
document.getElementById('F6-v').addEventListener('input', () => { update(); if(st.mode==='cruise') st.v = st.vTarget; });
document.getElementById('F6-brake').addEventListener('click', () => {
if (st.mode === 'cruise'){
st.mode = 'brake';
const fb = document.getElementById('F6-fb');
const mu = SURFACES[surf].mu;
const v = st.v;
const sStop = v*v / (2 * mu * 9.8);
fb.className = 'flag-feedback warn show';
fb.innerHTML = 'Торможение на ' + SURFACES[surf].name + ' с ' + (v*3.6).toFixed(0) + ' км/ч — потребуется ' + sStop.toFixed(1) + ' м.';
}
});
document.getElementById('F6-reset').addEventListener('click', reset);
update();
reset();
B().startLoop('F6', cv, tick);
return true;
}
if (window.PHYS9_FLAG_BASE) window.PHYS9_FLAG_BASE.register('F6', { init: init, cleanup: function(){} });
else document.addEventListener('DOMContentLoaded', ()=>{
if (window.PHYS9_FLAG_BASE) window.PHYS9_FLAG_BASE.register('F6', { init: init, cleanup: function(){} });
});
})();