Sesion Laboratorio 7 Practica 2 3 - jesusgpa/2024-2025-CSAAI GitHub Wiki
- Tiempo: 2h
- Fecha: Jueves 20 de Marzo de 2024
-
Objetivos de la sesión:
- Trabajar en la práctica 2
Aprovecha para avanzar con la práctica 2 (BOOM) todo lo que puedas.
Esta función puede ser muy útil para conseguir los números de la clave secreta.
//-- Generar números aleatorios con un valor máximo
function getRandomInt(max) {
return Math.floor(Math.random() * max);
}
Si queremos mantener los números secretos ocultos vamos a necesitar una estructura de datos.
Un array es una buena opción.
//-- Array que almacena números secretos
const secretkey = [];
//-- Generar números aleatorios con un valor máximo
function getRandomInt(max) {
return Math.floor(Math.random() * max);
}
//-- Generamos números secretos y los almacenamos en un array
for (let i = 0; i < 10; i++) {
let rnum = getRandomInt(9);
secretkey.push(rnum.toString());
}
//-- Mostramos el contenido del array de números secretos en la consola
for (let j = 0; j < secretkey.length; j++) {
console.log( j + ' Secret Key ' + secretkey[j]);
}
TIP: Intenta crear funciones que puedas llamar desde tus funciones de callback asociadas a las acciones de los botones.
Este es un ejemplo genérico.
check_entorno() {
//-- Comprobaciones antes de empezar
//-- ...
return ok;
}
gui.start.onclick = () => {
if(check_entorno()) {
//-- Si todo está ok ejecutamos la funcionalidad de la función de callback asociada al evento click.
}
}
En este ejemplo encontrarás diferentes maneras de dibujar líneas y utilizar colores.
En este caso utilizando curvas cuadráticas de Bézier que pueden ser muy útiles para describir movimientos en forma de curva (curva de Bézier).
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ondas de Colores</title>
<script src="onda-de-colores.js" defer></script>
</head>
<body>
<canvas id="canvasGlowing" width="800" height="450"></canvas>
</body>
</html>
var canvas = document.getElementById('canvasGlowing');
var context = canvas.getContext('2d');
var lastX = context.canvas.width * Math.random();
var lastY = context.canvas.height * Math.random();
var hue = 0;
function line() {
context.save();
context.translate(context.canvas.width/2, context.canvas.height/2);
context.scale(0.9, 0.9);
context.translate(-context.canvas.width/2, -context.canvas.height/2);
context.beginPath();
context.lineWidth = 5 + Math.random() * 10;
context.moveTo(lastX, lastY);
lastX = context.canvas.width * Math.random();
lastY = context.canvas.height * Math.random();
// https://developer.mozilla.org/en-US/docs/Glossary/Bezier_curve
context.bezierCurveTo(context.canvas.width * Math.random(),
context.canvas.height * Math.random(),
context.canvas.width * Math.random(),
context.canvas.height * Math.random(),
lastX, lastY);
hue = hue + 10 * Math.random();
// https://es.wikipedia.org/wiki/Modelo_de_color_HSL
// https://www.w3schools.com/colors/colors_hsl.asp
// Cambia el color y deja la saturación y la luminosidad fija.
context.strokeStyle = 'hsl(' + hue + ', 50%, 50%)';
context.shadowColor = 'white';
context.shadowBlur = 10;
context.stroke();
context.restore();
}
setInterval(line, 150);
function blank() {
context.fillStyle = 'rgba(0,0,0,0.1)';
context.fillRect(0, 0, context.canvas.width, context.canvas.height);
}
setInterval(blank, 140);
Este es el resultado:
Vamos a empezar recordando lo que hemos aprendido sobre el canvas dibujando una pelota azul.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Blue Ball 1</title>
<link rel="stylesheet" href="canvas-blue-ball-01.css">
<script src="canva-blue-ball-01.js" defer></script>
</head>
<body>
<canvas id="canvas" width="600" height="300"></canvas>
</body>
</html>
Utiliza este css para darle un borde al canvas
#canvas {
border: 1px solid;
}
Nada del otro mundo.
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const ball = {
x: 100,
y: 100,
radius: 25,
color: "blue",
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
},
};
ball.draw();
Una vez más, window.requestAnimationFrame() nos ayuda a generar la animación.
La pelota se mueve añadiendo un vector de velocidad a la posición.
Para cada frame, también limpiamos el canvas para eliminar los círculos antiguos de los cuadros anteriores.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Blue Ball 2</title>
<link rel="stylesheet" href="canvas-blue-ball-01.css">
<script src="canvas-blue-ball-02.js" defer></script>
</head>
<body>
<canvas id="canvas" width="600" height="300"></canvas>
</body>
</html>
Vamos a darle velocidad en el eje x e y.
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let raf;
const ball = {
x: 100,
y: 100,
vx: 5,
vy: 2,
radius: 25,
color: "blue",
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
},
};
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ball.draw();
ball.x += ball.vx;
ball.y += ball.vy;
raf = window.requestAnimationFrame(draw);
}
canvas.addEventListener("mouseover", (e) => {
raf = window.requestAnimationFrame(draw);
});
canvas.addEventListener("mouseout", (e) => {
window.cancelAnimationFrame(raf);
});
ball.draw();
La bola entra en movimiento cuando ponemos el puntero del ratón sobre el canvas.
Vamos a añadir los límites necesarios para encerrar la bola en el canvas.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Blue Ball 3</title>
<link rel="stylesheet" href="canvas-blue-ball-01.css">
<script src="canvas-blue-ball-03.js" defer></script>
</head>
<body>
<canvas id="canvas" width="600" height="300"></canvas>
</body>
</html>
La pelota iniciará el movimiento al mover el puntero del ratón sobre el canvas, y se para cuando lo sacamos.
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let raf;
const ball = {
x: 100,
y: 100,
vx: 5,
vy: 2,
radius: 25,
color: "blue",
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
},
};
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ball.draw();
ball.x += ball.vx;
ball.y += ball.vy;
// Así limitamos el movimiento de la pelota
if (
ball.y + ball.vy > canvas.height - ball.radius ||
ball.y + ball.vy < ball.radius
) {
ball.vy = -ball.vy;
}
if (
ball.x + ball.vx > canvas.width - ball.radius ||
ball.x + ball.vx < ball.radius
) {
ball.vx = -ball.vx;
}
raf = window.requestAnimationFrame(draw);
}
canvas.addEventListener("mouseover", (e) => {
raf = window.requestAnimationFrame(draw);
});
canvas.addEventListener("mouseout", (e) => {
window.cancelAnimationFrame(raf);
});
ball.draw();
Cuando añadimos aceleración, conseguimos un movimiento más realista.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Blue Ball 4</title>
<link rel="stylesheet" href="canvas-blue-ball-01.css">
<script src="canvas-blue-ball-04.js" defer></script>
</head>
<body>
<canvas id="canvas" width="600" height="300"></canvas>
</body>
</html>
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let raf;
const ball = {
x: 100,
y: 100,
vx: 5,
vy: 2,
radius: 25,
color: "blue",
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
},
};
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ball.draw();
ball.x += ball.vx;
ball.y += ball.vy;
// Así añadimos el efecto de la aceleración al movimiento
ball.vy *= 0.99;
ball.vy += 0.25;
if (
ball.y + ball.vy > canvas.height - ball.radius ||
ball.y + ball.vy < ball.radius
) {
ball.vy = -ball.vy;
}
if (
ball.x + ball.vx > canvas.width - ball.radius ||
ball.x + ball.vx < ball.radius
) {
ball.vx = -ball.vx;
}
raf = window.requestAnimationFrame(draw);
}
canvas.addEventListener("mouseover", (e) => {
raf = window.requestAnimationFrame(draw);
});
canvas.addEventListener("mouseout", (e) => {
window.cancelAnimationFrame(raf);
});
ball.draw();
Vamos a ver como sería el efecto de dejar una estela, este efecto refuerza la sensación de movimiento.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Blue Ball 5</title>
<link rel="stylesheet" href="canvas-blue-ball-01.css">
<script src="canvas-blue-ball-05.js" defer></script>
</head>
<body>
<canvas id="canvas" width="600" height="300"></canvas>
</body>
</html>
Hasta ahora hemos utilizado el método clearRect al borrar los frames anteriores.
Si reemplazamos este método con fillRect semitransparente, podemos crear fácilmente un efecto de estela.
ctx.fillStyle = "rgb(255 255 255 / 30%)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
Este es el ejemplo completo.
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let raf;
const ball = {
x: 100,
y: 100,
vx: 5,
vy: 2,
radius: 25,
color: "blue",
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
},
};
function draw() {
ctx.fillStyle = "rgb(255 255 255 / 30%)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ball.draw();
ball.x += ball.vx;
ball.y += ball.vy;
ball.vy *= 0.99;
ball.vy += 0.25;
if (
ball.y + ball.vy > canvas.height - ball.radius ||
ball.y + ball.vy < ball.radius
) {
ball.vy = -ball.vy;
}
if (
ball.x + ball.vx > canvas.width - ball.radius ||
ball.x + ball.vx < ball.radius
) {
ball.vx = -ball.vx;
}
raf = window.requestAnimationFrame(draw);
}
canvas.addEventListener("mouseover", (e) => {
raf = window.requestAnimationFrame(draw);
});
canvas.addEventListener("mouseout", (e) => {
window.cancelAnimationFrame(raf);
});
ball.draw();
Para tener control sobre la pelota, podemos hacer que siga el puntero del ratón usando el evento mousemove, por ejemplo.
El evento de clic libera la pelota y la deja rebotar nuevamente.
Vamos a ver como sería.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Blue Ball 6</title>
<link rel="stylesheet" href="canvas-blue-ball-01.css">
<script src="canvas-blue-ball-06.js" defer></script>
</head>
<body>
<canvas id="canvas" width="600" height="300"></canvas>
</body>
</html>
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let raf;
let running = false;
const ball = {
x: 100,
y: 100,
vx: 5,
vy: 1,
radius: 25,
color: "blue",
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
},
};
function clear() {
ctx.fillStyle = "rgb(255 255 255 / 30%)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
function draw() {
clear();
ball.draw();
ball.x += ball.vx;
ball.y += ball.vy;
if (
ball.y + ball.vy > canvas.height - ball.radius ||
ball.y + ball.vy < ball.radius
) {
ball.vy = -ball.vy;
}
if (
ball.x + ball.vx > canvas.width - ball.radius ||
ball.x + ball.vx < ball.radius
) {
ball.vx = -ball.vx;
}
raf = window.requestAnimationFrame(draw);
}
canvas.addEventListener("mousemove", (e) => {
if (!running) {
clear();
ball.x = e.clientX;
ball.y = e.clientY;
ball.draw();
}
});
canvas.addEventListener("click", (e) => {
if (!running) {
raf = window.requestAnimationFrame(draw);
running = true;
}
});
canvas.addEventListener("mouseout", (e) => {
window.cancelAnimationFrame(raf);
running = false;
});
ball.draw();
Ahora tenemos control total sobre la pelota azul.
Entender estos ejemplos es clave para definir la física de movimiento de diferentes elementos en el canvas.
Jesús Parrado Alameda (jesusgpa)
- Creado a partir del contenido generado por el profesor Jose María Cañas
- Creado a partir del contenido generado por el profesor Juan Gonzalez-Gomez