<!DOCTYPE html>
<html lang="pt-br">
<head>
<title>Simulação de Lançamento Parabólico</title>
<meta charset="UTF-8">
<style>
body { font-family: sans-serif; text-align: center; background-color: #f4f4f4; }
canvas { border: 1px solid black; background-color: #e0f7fa; }
#controles {
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
margin-bottom: 20px;
}
#controles div { margin: 5px 15px; }
#btnLimpar { margin-left: 15px; }
</style>
</head>
<body>
<h1>Simulação de Lançamento Parabólico</h1>
<div id="controles">
<div>
<label>Ângulo (º): <span id="valorAngulo">45</span></label>
<input type="range" id="angulo" min="1" max="90" value="45">
</div>
<div>
<label>Velocidade (m/s): <span id="valorVelocidade">50</span></label>
<input type="range" id="velocidade" min="10" max="100" value="50">
</div>
<div>
<label>Gravidade (m/s²): <span id="valorGravidade">9.8</span></label>
<input type="range" id="gravidade" min="1" max="20" value="9.8" step="0.1">
</div>
<button id="btnLancar">Lançar</button>
<button id="btnLimpar">Limpar Tela</button>
</div>
<canvas id="canvasSimulacao" width="600" height="300"></canvas>
<script>
// 1. OBTENDO ELEMENTOS DA PÁGINA
const canvas = document.getElementById('canvasSimulacao');
const ctx = canvas.getContext('2d');
const anguloInput = document.getElementById('angulo');
const velocidadeInput = document.getElementById('velocidade');
const gravidadeInput = document.getElementById('gravidade');
const valorAngulo = document.getElementById('valorAngulo');
const valorVelocidade = document.getElementById('valorVelocidade');
const valorGravidade = document.getElementById('valorGravidade');
// 2. FUNÇÃO PRINCIPAL DE SIMULAÇÃO
function lancar() {
const v0 = parseFloat(velocidadeInput.value);
const angulo = parseFloat(anguloInput.value) * (Math.PI / 180); // Converte para radianos
const g = parseFloat(gravidadeInput.value);
let x = 0, y = canvas.height;
let vx = v0 * Math.cos(angulo);
let vy = -v0 * Math.sin(angulo); // Negativo pois Y cresce para baixo
const dt = 0.1;
ctx.fillStyle = `hsl(${Math.random() * 360}, 90%, 50%)`;
function animar() {
vy += g * dt; // Efeito da gravidade
x += vx * dt; // Movimento horizontal
y += vy * dt; // Movimento vertical
ctx.beginPath();
ctx.arc(x, y, 3, 0, 2 * Math.PI);
ctx.fill();
if (y < canvas.height) {
requestAnimationFrame(animar);
}
}
animar();
}
// 3. CONFIGURANDO OS EVENTOS
document.getElementById('btnLancar').addEventListener('click', lancar);
document.getElementById('btnLimpar').addEventListener('click', () => ctx.clearRect(0, 0, canvas.width, canvas.height));
anguloInput.oninput = () => valorAngulo.textContent = anguloInput.value;
velocidadeInput.oninput = () => valorVelocidade.textContent = velocidadeInput.value;
gravidadeInput.oninput = () => valorGravidade.textContent = gravidadeInput.value;
</script>
</body>
</html>
<!DOCTYPE html> <!-- Define que este é um documento HTML5, o padrão mais moderno da web. -->
<html lang="pt-br"> <!-- A tag principal da página, 'lang' indica que o conteúdo é em português. -->
<head>
<!-- O <head> contém metadados e configurações da página, coisas que o navegador usa mas que não são visíveis diretamente. -->
<title>Simulação de Lançamento Parabólico</title> <!-- O título que aparece na aba do navegador. -->
<meta charset="UTF-8"> <!-- Garante que o navegador entenda caracteres especiais como 'ç' e acentos. -->
<!-- A tag <style> é onde escrevemos nosso código CSS para estilizar a página. -->
<style>
/* Estilo para o corpo da página */
body {
font-family: sans-serif; /* Usa uma fonte limpa e sem serifa. */
text-align: center; /* Centraliza todo o texto e elementos. */
background-color: #f4f4f4; /* Cor de fundo cinza bem claro. */
}
/* Estilo para a nossa tela de desenho (o canvas) */
canvas {
border: 1px solid black; /* Desenha uma borda preta de 1 pixel ao redor. */
background-color: #e0f7fa; /* Cor de fundo azul claro, para parecer o céu. */
}
/* Estilo para o 'div' que agrupa nossos controles */
#controles {
display: flex; /* MODO FLEXBOX: Trata os itens internos como flexíveis, permitindo alinhá-los facilmente. */
justify-content: center; /* Centraliza os itens na linha (horizontalmente). */
align-items: center; /* Alinha os itens no meio da linha (verticalmente). */
flex-wrap: wrap; /* Se não couber na linha, permite que os itens quebrem para a linha de baixo. */
margin-bottom: 20px; /* Adiciona um espaço de 20px abaixo do bloco de controles, antes do canvas. */
}
/* Estilo para cada 'div' DENTRO do bloco de controles (os que contêm os sliders) */
#controles div {
margin: 5px 15px; /* Adiciona um espaço vertical (5px) e horizontal (15px) para não ficarem grudados. */
}
/* Estilo específico para o botão de Limpar, para separá-lo do botão Lançar */
#btnLimpar {
margin-left: 15px; /* Adiciona um espaço de 15px à ESQUERDA do botão Limpar. */
}
</style>
</head>
<body>
<!-- O <body> contém todo o conteúdo visível da página. -->
<h1>Simulação de Lançamento Parabólico</h1>
<!-- Este 'div' agrupa todos os nossos controles (sliders e botões). O id="controles" o conecta ao CSS. -->
<div id="controles">
<!-- Controle para o Ângulo -->
<div>
<label>Ângulo (º): <span id="valorAngulo">45</span></label> <!-- O 'span' serve para mostrar o valor atual. -->
<input type="range" id="angulo" min="1" max="90" value="45"> <!-- O slider em si. -->
</div>
<!-- Controle para a Velocidade -->
<div>
<label>Velocidade (m/s): <span id="valorVelocidade">50</span></label>
<input type="range" id="velocidade" min="10" max="100" value="50">
</div>
<!-- Controle para a Gravidade -->
<div>
<label>Gravidade (m/s²): <span id="valorGravidade">9.8</span></label>
<input type="range" id="gravidade" min="1" max="20" value="9.8" step="0.1"> <!-- 'step' define o incremento do valor. -->
</div>
<!-- Botões de ação -->
<button id="btnLancar">Lançar</button>
<button id="btnLimpar">Limpar Tela</button>
</div>
<!-- Nossa tela de pintura! O JavaScript vai desenhar aqui. 'id' para ser encontrado, 'width' e 'height' para o tamanho. -->
<canvas id="canvasSimulacao" width="600" height="300"></canvas>
<!-- A tag <script> é onde nosso código JavaScript vive. Ele controla a lógica e a interatividade. -->
<script>
/*
* PARTE 1: PREPARAÇÃO - Pegando os "atores" da nossa peça (os elementos HTML)
* Antes de fazer qualquer coisa, precisamos ter uma referência a cada elemento da página
* com o qual vamos interagir. Guardamos essas referências em variáveis (usando 'const').
*/
const canvas = document.getElementById('canvasSimulacao'); // Pega a nossa tela de desenho.
const ctx = canvas.getContext('2d'); // Pega o "kit de pintura 2D" do canvas. É com o 'ctx' que desenhamos tudo.
// Pega os controles deslizantes (inputs)
const anguloInput = document.getElementById('angulo');
const velocidadeInput = document.getElementById('velocidade');
const gravidadeInput = document.getElementById('gravidade');
// Pega os locais onde vamos exibir os valores numéricos dos sliders
const valorAngulo = document.getElementById('valorAngulo');
const valorVelocidade = document.getElementById('valorVelocidade');
const valorGravidade = document.getElementById('valorGravidade');
/*
* PARTE 2: A LÓGICA PRINCIPAL - A função que faz a mágica acontecer.
* Esta função 'lancar' será chamada toda vez que o botão "Lançar" for clicado.
*/
function lancar() {
// --- Leitura dos Parâmetros Iniciais ---
const v0 = parseFloat(velocidadeInput.value); // Pega o valor do slider de velocidade e o transforma em número.
const angulo = parseFloat(anguloInput.value) * (Math.PI / 180); // Pega o ângulo em GRAUS e converte para RADIANOS, pois as funções de seno e cosseno do JS usam radianos.
const g = parseFloat(gravidadeInput.value); // Pega o valor do slider de gravidade.
// --- Definição do Estado Inicial do Projétil ---
let x = 0; // Posição inicial no eixo X (canto esquerdo).
let y = canvas.height; // Posição inicial no eixo Y (parte de baixo da tela).
// --- Decomposição da Velocidade (Física!) ---
let vx = v0 * Math.cos(angulo); // Componente horizontal da velocidade (constante na simulação).
let vy = -v0 * Math.sin(angulo); // Componente vertical da velocidade. É NEGATIVA porque no canvas o eixo Y cresce PARA BAIXO. Para "subir", a velocidade precisa ser negativa.
// --- Configuração da Animação ---
const dt = 0.1; // "Delta t": um pequeno passo de tempo. A simulação avança em pequenos saltos de 0.1s para parecer um movimento contínuo.
ctx.fillStyle = `hsl(${Math.random() * 360}, 90%, 50%)`; // Escolhe uma cor aleatória e vibrante para a nova trajetória.
// --- O Motor da Animação: a função que se repete ---
function animar() {
// APLICA A FÍSICA A CADA PASSO DE TEMPO (dt)
vy += g * dt; // A gravidade 'g' altera a velocidade vertical 'vy'.
x += vx * dt; // A posição 'x' avança de acordo com a velocidade horizontal 'vx'. (MRU)
y += vy * dt; // A posição 'y' avança de acordo com a velocidade vertical 'vy'. (MRUV)
// DESENHA O ESTADO ATUAL NA TELA
ctx.beginPath(); // Avisa o "kit de pintura" que vamos começar a desenhar algo novo.
ctx.arc(x, y, 3, 0, 2 * Math.PI); // Define o desenho: um círculo (arco completo) na posição (x,y) com raio de 3 pixels.
ctx.fill(); // Pinta o círculo com a cor que definimos antes.
// VERIFICA SE A ANIMAÇÃO DEVE CONTINUAR
if (y < canvas.height) { // Se o projétil ainda não tocou o chão...
requestAnimationFrame(animar); // ...peça ao navegador para chamar a função 'animar' de novo assim que ele puder. Isso cria o loop de animação suave.
}
}
animar(); // Dá a partida inicial no motor da animação!
}
/*
* PARTE 3: CONECTANDO TUDO - Dando função aos botões e sliders.
* Aqui, dizemos ao navegador o que fazer quando o usuário interage com a página.
*/
// Quando o elemento com id 'btnLancar' for clicado ('click'), execute a função 'lancar'.
document.getElementById('btnLancar').addEventListener('click', lancar);
// Quando o botão 'btnLimpar' for clicado, execute o comando para limpar o retângulo do canvas (apagar tudo).
document.getElementById('btnLimpar').addEventListener('click', () => ctx.clearRect(0, 0, canvas.width, canvas.height));
// Para cada slider, quando o valor dele mudar ('oninput'), atualize o texto do 'span' correspondente.
anguloInput.oninput = () => valorAngulo.textContent = anguloInput.value;
velocidadeInput.oninput = () => valorVelocidade.textContent = velocidadeInput.value;
gravidadeInput.oninput = () => valorGravidade.textContent = gravidadeInput.value;
</script>
</body>
</html>