En esta lección se presentan técnicas para elaborar juegos.
1 | <!DOCTYPE html> |
2 | <html lang="es"> |
3 | |
4 | <head> |
5 | <meta charset="UTF-8"> |
6 | <meta name="viewport" |
7 | content="width=device-width"> |
8 | <title>Sprite</title> |
9 | <style> |
10 | .sprite { |
11 | position: fixed; |
12 | font-size: 3rem; |
13 | } |
14 | </style> |
15 | </head> |
16 | |
17 | <body> |
18 | <h1>Sprite</h1> |
19 | <p> |
20 | Este ejemplo te muestra como |
21 | colocar una figura en |
22 | cualquier lugar de la |
23 | ventana. |
24 | </p> |
25 | <output class="sprite" |
26 | style="left: 100px; |
27 | bottom: 150px"> |
28 | 😄 |
29 | </output> |
30 | </body> |
31 | |
32 | </html> |
1 | <!DOCTYPE html> |
2 | <html lang="es"> |
3 | |
4 | <head> |
5 | <meta charset="UTF-8"> |
6 | <meta name="viewport" |
7 | content="width=device-width"> |
8 | <title> |
9 | Animación horizontal |
10 | </title> |
11 | <style> |
12 | .sprite { |
13 | position: fixed; |
14 | font-size: 3rem; |
15 | } |
16 | </style> |
17 | </head> |
18 | |
19 | <body> |
20 | <h1>Animación horizontal</h1> |
21 | <output id="carita" |
22 | class="sprite"> |
23 | 😄 |
24 | </output> |
25 | <script> |
26 | const REFRESCO = 5 |
27 | const VELOCIDAD = 0.5 |
28 | let x = 0 |
29 | setInterval(avanza, REFRESCO) |
30 | |
31 | function avanza() { |
32 | const y = innerHeight / 2 |
33 | const xMáxima = innerWidth |
34 | carita.style = |
35 | `left: ${x}px; bottom: ${y}px` |
36 | x = (x + VELOCIDAD) % xMáxima |
37 | } |
38 | </script> |
39 | </body> |
40 | |
41 | </html> |
1 | <!DOCTYPE html> |
2 | <html lang="es"> |
3 | |
4 | <head> |
5 | <meta charset="UTF-8"> |
6 | <meta name="viewport" |
7 | content="width=device-width"> |
8 | <title>Animación recta</title> |
9 | <style> |
10 | .sprite { |
11 | position: fixed; |
12 | font-size: 3rem; |
13 | } |
14 | </style> |
15 | </head> |
16 | |
17 | <body> |
18 | <h1>Animación recta</h1> |
19 | <output id="carita" |
20 | class="sprite"> |
21 | 😄 |
22 | </output> |
23 | <script> |
24 | const X_INICIAL = 0 |
25 | const REFRESCO = 5 |
26 | const VELOCIDAD = 0.5 |
27 | let x = X_INICIAL |
28 | setInterval(avanza, REFRESCO) |
29 | |
30 | function avanza() { |
31 | const xFinal = innerWidth |
32 | const yInicial = innerHeight / 2 |
33 | const yFinal = innerHeight |
34 | const y = ((yFinal - yInicial) / |
35 | (xFinal - X_INICIAL)) * |
36 | (x - X_INICIAL) + |
37 | yInicial |
38 | carita.style = |
39 | `left: ${x}px; bottom: ${y}px` |
40 | x = (x + VELOCIDAD) % xFinal |
41 | } |
42 | </script> |
43 | </body> |
44 | |
45 | </html> |
1 | <!DOCTYPE html> |
2 | <html lang="es"> |
3 | |
4 | <head> |
5 | <meta charset="UTF-8"> |
6 | <meta name="viewport" |
7 | content="width=device-width"> |
8 | <title>Ondula</title> |
9 | <style> |
10 | .sprite { |
11 | position: fixed; |
12 | font-size: 3rem; |
13 | } |
14 | </style> |
15 | </head> |
16 | |
17 | <body> |
18 | <h1>Ondula</h1> |
19 | <output id="carita" |
20 | class="sprite"> |
21 | 😄 |
22 | </output> |
23 | <script> |
24 | const REFRESCO = 5 |
25 | const VELOCIDAD = 0.5 |
26 | const FRECUENCIA = 0.03 |
27 | let x = 0 |
28 | setInterval(avanza, REFRESCO) |
29 | |
30 | function avanza() { |
31 | const xMáxima = innerWidth |
32 | const amplitud = innerHeight / 3 |
33 | const yBase = innerHeight / 2 |
34 | y = yBase + |
35 | amplitud * |
36 | Math.sin(FRECUENCIA * x) |
37 | carita.style = |
38 | `left: ${x}px; bottom: ${y}px` |
39 | x = (x + VELOCIDAD) % xMáxima |
40 | } |
41 | </script> |
42 | </body> |
43 | |
44 | </html> |
1 | <!DOCTYPE html> |
2 | <html lang="es"> |
3 | |
4 | <head> |
5 | <meta charset="UTF-8"> |
6 | <meta name="viewport" |
7 | content="width=device-width"> |
8 | <title>Gira</title> |
9 | <style> |
10 | .sprite { |
11 | position: fixed; |
12 | font-size: 3rem; |
13 | } |
14 | </style> |
15 | </head> |
16 | |
17 | <body> |
18 | <h1>Gira</h1> |
19 | <output id="mariposa" |
20 | class="sprite"> |
21 | 🦋 |
22 | </output> |
23 | <script> |
24 | const REFRESCO = 120 |
25 | const VELOCIDAD = 0.3 |
26 | let angulo = 0 |
27 | setInterval(gira, REFRESCO) |
28 | |
29 | function gira() { |
30 | const xBase = innerWidth / 2 |
31 | const amplitudX = innerWidth / 3 |
32 | const yBase = innerHeight / 2 |
33 | const amplitudY = |
34 | innerHeight / 3 |
35 | const x = xBase + |
36 | amplitudX * Math.cos(angulo) |
37 | const y = yBase + |
38 | amplitudY * Math.sin(angulo) |
39 | mariposa.style = |
40 | `left: ${x}px; bottom: ${y}px` |
41 | angulo += VELOCIDAD |
42 | } |
43 | </script> |
44 | </body> |
45 | |
46 | </html> |
1 | <!DOCTYPE html> |
2 | <html lang="es"> |
3 | |
4 | <head> |
5 | <meta charset="UTF-8"> |
6 | <meta name="viewport" |
7 | content="width=device-width"> |
8 | <title>Mueve con Botones</title> |
9 | <style> |
10 | .sprite { |
11 | position: fixed; |
12 | font-size: 3rem; |
13 | } |
14 | </style> |
15 | </head> |
16 | |
17 | <body> |
18 | <h1>Mueve con Botones</h1> |
19 | <p> |
20 | <button onclick="retrocede()"> |
21 | ◀ |
22 | </button> |
23 | <button onclick="avanza()"> |
24 | ▶ |
25 | </button> |
26 | </p> |
27 | <output id="carita" |
28 | class="sprite"> |
29 | 😄 |
30 | </output> |
31 | <script> |
32 | let yBase |
33 | let xMenor |
34 | let xMayor |
35 | const VELOCIDAD = 30 |
36 | actualiza() |
37 | let x = xMenor |
38 | dibuja() |
39 | |
40 | function retrocede() { |
41 | actualiza() |
42 | if (x > xMenor) { |
43 | x -= VELOCIDAD |
44 | } |
45 | dibuja() |
46 | } |
47 | |
48 | function avanza() { |
49 | actualiza() |
50 | if (x < xMayor) { |
51 | x += VELOCIDAD |
52 | } |
53 | dibuja() |
54 | } |
55 | |
56 | function actualiza() { |
57 | yBase = innerHeight / 2 |
58 | xMenor = innerWidth / 5 |
59 | xMayor = 4 * innerWidth / 5 |
60 | } |
61 | |
62 | function dibuja() { |
63 | carita.style = `left: ${x}px; |
64 | bottom: ${yBase}px` |
65 | } |
66 | </script> |
67 | </body> |
68 | |
69 | </html> |
1 | <!DOCTYPE html> |
2 | <html lang="es"> |
3 | |
4 | <head> |
5 | <meta charset="UTF-8"> |
6 | <meta name="viewport" |
7 | content="width=device-width"> |
8 | <title>Choca</title> |
9 | <style> |
10 | .sprite { |
11 | position: fixed; |
12 | font-size: 3rem; |
13 | } |
14 | </style> |
15 | </head> |
16 | |
17 | <body> |
18 | <h1>Choca</h1> |
19 | <output id="abrazo" |
20 | class="sprite" |
21 | style="background-color: |
22 | greenyellow;"> |
23 | 🤗 |
24 | </output> |
25 | <output id="triste" |
26 | class="sprite" |
27 | style="background-color: |
28 | grey;"> |
29 | 😪 |
30 | </output> |
31 | <script> |
32 | let x = 0 |
33 | const REFRESCO = 5 |
34 | setInterval(avanza, REFRESCO) |
35 | |
36 | function avanza() { |
37 | const velocidad = |
38 | innerWidth / 2000 |
39 | const x2 = innerWidth |
40 | const y = innerHeight / 2 |
41 | triste.style.left = |
42 | `${innerWidth / 2}px` |
43 | triste.style.bottom = `${y}px` |
44 | abrazo.style.left = `${x}px` |
45 | abrazo.style.bottom = `${y}px` |
46 | if (!seTocan(abrazo, triste)) { |
47 | x = (x + velocidad) % x2 |
48 | } |
49 | } |
50 | |
51 | /** |
52 | * Devuelve true si 2 |
53 | * elementos se tocan. |
54 | * @param {HTMLElement} e1 |
55 | * @param {HTMLElement} e2 |
56 | * @returns {boolean} true |
57 | * si los elementos se |
58 | * tocan. |
59 | */ |
60 | function seTocan(e1, e2) { |
61 | const rE1 = |
62 | e1.getBoundingClientRect() |
63 | const rE2 = |
64 | e2.getBoundingClientRect() |
65 | return (rE1.right >= rE2.left |
66 | && rE1.left <= rE2.right |
67 | && rE1.top <= rE2.bottom |
68 | && rE1.bottom >= rE2.top) |
69 | } |
70 | </script> |
71 | </body> |
72 | |
73 | </html> |
1 | <!DOCTYPE html> |
2 | <html lang="es"> |
3 | |
4 | <head> |
5 | <meta charset="UTF-8"> |
6 | <meta name="viewport" |
7 | content="width=device-width"> |
8 | <title>Sonrie</title> |
9 | <style> |
10 | .sprite { |
11 | position: fixed; |
12 | font-size: 3rem; |
13 | } |
14 | </style> |
15 | </head> |
16 | |
17 | <body> |
18 | <h1>Sonrie</h1> |
19 | <output id="abrazo" |
20 | class="sprite" |
21 | style="background-color: |
22 | greenyellow;"> |
23 | 🤗 |
24 | </output> |
25 | <output id="triste" |
26 | class="sprite" |
27 | style="background-color: |
28 | grey;"> |
29 | 😪 |
30 | </output> |
31 | <script> |
32 | let x = 0 |
33 | const REFRESCO = 5 |
34 | let intervalo = |
35 | setInterval(avanza, REFRESCO) |
36 | |
37 | function avanza() { |
38 | const velocidad = |
39 | innerWidth / 2000 |
40 | const x2 = innerWidth |
41 | const y = innerHeight / 2 |
42 | triste.style.left = |
43 | `${innerWidth / 2}px` |
44 | triste.style.bottom = `${y}px` |
45 | abrazo.style.left = `${x}px` |
46 | abrazo.style.bottom = `${y}px` |
47 | if (seTocan(abrazo, triste)) { |
48 | triste.value = "😊"; |
49 | triste.style. |
50 | backgroundColor = "pink"; |
51 | clearInterval(intervalo); |
52 | } else { |
53 | x = (x + velocidad) % x2 |
54 | } |
55 | } |
56 | |
57 | /** |
58 | * Devuelve true si 2 |
59 | * elementos se tocan. |
60 | * @param {HTMLElement} e1 |
61 | * @param {HTMLElement} e2 |
62 | * @returns {boolean} true |
63 | * si los elementos se |
64 | * tocan. |
65 | */ |
66 | function seTocan(e1, e2) { |
67 | const rE1 = |
68 | e1.getBoundingClientRect() |
69 | const rE2 = |
70 | e2.getBoundingClientRect() |
71 | return (rE1.right >= rE2.left |
72 | && rE1.left <= rE2.right |
73 | && rE1.top <= rE2.bottom |
74 | && rE1.bottom >= rE2.top) |
75 | } |
76 | </script> |
77 | </body> |
78 | |
79 | </html> |
1 | <!DOCTYPE html> |
2 | <html lang="es"> |
3 | |
4 | <head> |
5 | <meta charset="UTF-8"> |
6 | <meta name="viewport" |
7 | content="width=device-width"> |
8 | <title>Mueve Aleatorio</title> |
9 | <style> |
10 | .sprite { |
11 | position: fixed; |
12 | font-size: 3rem; |
13 | } |
14 | </style> |
15 | </head> |
16 | |
17 | <body> |
18 | <h1>Mueve Aleatorio</h1> |
19 | <output id="carita" |
20 | class="sprite"> |
21 | 😄 |
22 | </output> |
23 | <script> |
24 | const REFRESCO = 5 |
25 | const RUIDO = 4 |
26 | let velocidad = 0.5 |
27 | let x = 0 |
28 | setInterval(avanza, REFRESCO) |
29 | |
30 | function avanza() { |
31 | const y = innerHeight / 2 |
32 | const xMáxima = innerWidth |
33 | carita.style.left = `${x}px` |
34 | carita.style.bottom = `${y}px` |
35 | x += velocidad + |
36 | aleatorio(-RUIDO, RUIDO) |
37 | if (x < 0) { |
38 | x = 0 |
39 | velocidad = -velocidad |
40 | } else if (x > xMáxima) { |
41 | x = xMáxima |
42 | velocidad = -velocidad |
43 | } |
44 | } |
45 | |
46 | /** |
47 | * Devuelve un número |
48 | * aleatorio entre el valor |
49 | * menor y el valor mayor. |
50 | * @param {number} menor el |
51 | * menor valor que se puede |
52 | * generar |
53 | * @param {number} mayor el |
54 | * mayor valor que se puede |
55 | * generar |
56 | * @returns {number} un |
57 | * número aleatorio entre |
58 | * menor y mayor. |
59 | */ |
60 | function |
61 | aleatorio(menor, mayor) { |
62 | /* Math.floor(x): elimina |
63 | * los decimales. |
64 | * Math.random(): genera |
65 | * un número aleatorio |
66 | * >= 0 y < 1. */ |
67 | return menor + |
68 | Math.floor( |
69 | Math.random() * |
70 | (mayor - menor + 1)) |
71 | } |
72 | </script> |
73 | </body> |
74 | |
75 | </html> |
1 | <!DOCTYPE html> |
2 | <html lang="es"> |
3 | |
4 | <head> |
5 | <meta charset="UTF-8"> |
6 | <meta name="viewport" |
7 | content="width=device-width"> |
8 | <title>Custom Elements</title> |
9 | <style> |
10 | figura-web { |
11 | position: fixed; |
12 | font-size: 60px; |
13 | } |
14 | </style> |
15 | <script> |
16 | class FiguraWeb |
17 | extends HTMLElement { |
18 | connectedCallback() { |
19 | this.x = 0 |
20 | const attrY = |
21 | this.getAttribute("y") |
22 | const attrVel = |
23 | this.getAttribute("velocidad") |
24 | this.y = parseInt(attrY, 10) |
25 | this.velocidad = |
26 | parseInt(attrVel, 10) |
27 | } |
28 | muevete() { |
29 | this.style.right = |
30 | `${this.x}px` |
31 | this.style.top = `${this.y}px` |
32 | this.x = |
33 | (this.x + this.velocidad) % |
34 | innerWidth |
35 | } |
36 | } |
37 | customElements.define( |
38 | "figura-web", FiguraWeb) |
39 | </script> |
40 | </head> |
41 | |
42 | <body> |
43 | <h1>Custom Elements</h1> |
44 | <figura-web id="fantasma" |
45 | y="0" velocidad="20"> |
46 | 👻 |
47 | </figura-web> |
48 | <figura-web id="sonrisa" |
49 | y="100" velocidad="10"> |
50 | 😁 |
51 | </figura-web> |
52 | <script> |
53 | setInterval(anima, 120) |
54 | |
55 | function anima() { |
56 | fantasma.muevete() |
57 | sonrisa.muevete() |
58 | } |
59 | </script> |
60 | </body> |
61 | |
62 | </html> |
1 | <!DOCTYPE html> |
2 | <html lang="es"> |
3 | |
4 | <head> |
5 | <meta charset="UTF-8"> |
6 | <meta name="viewport" |
7 | content="width=device-width"> |
8 | <title>Asociaciones</title> |
9 | <script> |
10 | /** |
11 | * Devuelve un número |
12 | * aleatorio entre el valor |
13 | * menor y el valor mayor. |
14 | * @param {number} menor el |
15 | * menor valor que se puede |
16 | * generar |
17 | * @param {number} mayor el |
18 | * mayor valor que se puede |
19 | * generar |
20 | * @returns {number} un |
21 | * número aleatorio entre |
22 | * menor y mayor. |
23 | */ |
24 | function |
25 | aleatorio(menor, mayor) { |
26 | /* Math.floor(x): elimina |
27 | * los decimales. |
28 | * Math.random(): genera |
29 | * un número aleatorio |
30 | * >= 0 y < 1. */ |
31 | return menor + |
32 | Math.floor( |
33 | Math.random() * |
34 | (mayor - menor + 1)) |
35 | } |
36 | |
37 | class PerroWeb |
38 | extends HTMLElement { |
39 | connectedCallback() { |
40 | this.x = 0 |
41 | this.y = 0 |
42 | this.innerHTML = "🐕" |
43 | this.style.position = "fixed" |
44 | this.style.fontSize = "2rem" |
45 | this.style.right = |
46 | `${this.x}px` |
47 | this.style.bottom = |
48 | `${this.y}px` |
49 | } |
50 | |
51 | muevete() { |
52 | this.x = (this.x + 30) % |
53 | innerWidth |
54 | this.style.right = |
55 | `${this.x}px` |
56 | } |
57 | } |
58 | customElements.define( |
59 | "perro-web", PerroWeb) |
60 | |
61 | class AguilaWeb |
62 | extends HTMLElement { |
63 | connectedCallback() { |
64 | this.x = aleatorio(0, |
65 | Math.floor(innerWidth)) |
66 | this.y = aleatorio(0, |
67 | Math.floor(innerHeight)) |
68 | this.innerHTML = "🦅" |
69 | this.style.position = "fixed" |
70 | this.style.fontSize = "2.5rem" |
71 | this.style.left = `${this.x}px` |
72 | this.style.top = `${this.y}px` |
73 | } |
74 | |
75 | muevete() { |
76 | this.y = (this.y + 10) % |
77 | innerHeight |
78 | this.style.top = `${this.y}px` |
79 | } |
80 | } |
81 | customElements.define( |
82 | "aguila-web", AguilaWeb) |
83 | |
84 | class ControladorWeb |
85 | extends HTMLElement { |
86 | connectedCallback() { |
87 | this.muevete = |
88 | this.muevete.bind(this) |
89 | this.innerHTML = /* html */ |
90 | `<button onclick="this. |
91 | parentElement.muevete()"> |
92 | Mueve |
93 | </button>` |
94 | this.perro = new PerroWeb() |
95 | this.aguilas = [ |
96 | new AguilaWeb(), |
97 | new AguilaWeb()] |
98 | this.append(this.perro) |
99 | for (const a of this.aguilas) { |
100 | this.append(a) |
101 | } |
102 | } |
103 | |
104 | muevete() { |
105 | this.perro.muevete() |
106 | for (let a of this.aguilas) { |
107 | a.muevete() |
108 | } |
109 | } |
110 | } |
111 | customElements.define( |
112 | "controlador-web", |
113 | ControladorWeb) |
114 | </script> |
115 | </head> |
116 | |
117 | <body> |
118 | <h1>Asociaciones</h1> |
119 | <controlador-web> |
120 | </controlador-web> |
121 | </body> |
122 | |
123 | </html> |
1 | <!DOCTYPE html> |
2 | <html lang="es"> |
3 | |
4 | <head> |
5 | <meta charset="UTF-8"> |
6 | <meta name="viewport" |
7 | content="width=device-width"> |
8 | <title>Polimorfismo</title> |
9 | <script> |
10 | function |
11 | aleatorio(menor, mayor) { |
12 | return menor + |
13 | Math.floor( |
14 | Math.random() * |
15 | (mayor - menor + 1)) |
16 | } |
17 | |
18 | /** @interface */ |
19 | class SeMueve { |
20 | muevete() { |
21 | throw new Error("intf") |
22 | } |
23 | } |
24 | |
25 | /** @implements {SeMueve} */ |
26 | class PerroWeb |
27 | extends HTMLElement { |
28 | connectedCallback() { |
29 | this.x = 0 |
30 | this.y = 0 |
31 | this.innerHTML = "🐕" |
32 | this.style.position = "fixed" |
33 | this.style.fontSize = "2rem" |
34 | this.style.right = |
35 | `${this.x}px` |
36 | this.style.bottom = |
37 | `${this.y}px` |
38 | } |
39 | |
40 | muevete() { |
41 | this.x = (this.x + 30) % |
42 | window.innerWidth |
43 | this.style.right = |
44 | `${this.x}px` |
45 | } |
46 | } |
47 | customElements.define( |
48 | "perro-web", PerroWeb) |
49 | |
50 | /** @implements {SeMueve} */ |
51 | class AguilaWeb |
52 | extends HTMLElement { |
53 | connectedCallback() { |
54 | this.x = aleatorio(0, |
55 | Math.floor(innerWidth)) |
56 | this.y = aleatorio(0, |
57 | Math.floor(innerHeight)) |
58 | this.innerHTML = "🦅" |
59 | this.style.position = "fixed" |
60 | this.style.fontSize = "2.5rem" |
61 | this.style.left = `${this.x}px` |
62 | this.style.top = `${this.y}px` |
63 | } |
64 | |
65 | muevete() { |
66 | this.y = (this.y + 10) % |
67 | window.innerHeight |
68 | this.style.top = `${this.y}px` |
69 | } |
70 | } |
71 | customElements.define( |
72 | "aguila-web", AguilaWeb) |
73 | </script> |
74 | </head> |
75 | |
76 | <body> |
77 | <h1>Polimorfismo</h1> |
78 | <p> |
79 | <button onclick="mueve()"> |
80 | Mueve |
81 | </button> |
82 | </p> |
83 | <script> |
84 | const figuras = [ |
85 | new AguilaWeb(), |
86 | new PerroWeb(), |
87 | new AguilaWeb()] |
88 | for (let f of figuras) { |
89 | document.body.append(f) |
90 | } |
91 | function mueve() { |
92 | for (var f of figuras) { |
93 | f.muevete() |
94 | } |
95 | } |
96 | </script> |
97 | </body> |
98 | |
99 | </html> |
1 | <!DOCTYPE html> |
2 | <html> |
3 | |
4 | <head> |
5 | <meta charset="utf-8"> |
6 | <meta name="viewport" |
7 | content="width=device-width"> |
8 | <title>Jueguito 1</title> |
9 | <style> |
10 | body { |
11 | /* Rompe el flujo normal para |
12 | * poder hacer swipe hacia |
13 | * abajo. */ |
14 | position: fixed; |
15 | top: 0px; |
16 | left: 0px; |
17 | /* ocupa todo el espacio. */ |
18 | width: 100%; |
19 | height: 100%; |
20 | /* Elimina márgenes. */ |
21 | margin: 0; |
22 | /* Evita el scroll */ |
23 | overflow: hidden; |
24 | } |
25 | |
26 | .sprite { |
27 | position: fixed; |
28 | } |
29 | </style> |
30 | <script> |
31 | //@ts-check |
32 | class JugadorPaloma |
33 | extends HTMLElement { |
34 | connectedCallback() { |
35 | this.classList.add("sprite") |
36 | this.innerHTML += "🕊" |
37 | this.style.fontSize = "60px" |
38 | /* Coloca el elemento a la |
39 | * mitad de la pantalla. */ |
40 | const raiz = |
41 | document.documentElement |
42 | /* Obtiene las coordenadas del |
43 | * element. */ |
44 | const r = |
45 | this.getBoundingClientRect() |
46 | const left = |
47 | (raiz.clientWidth - r.width) / |
48 | 2 |
49 | const top = |
50 | (raiz.clientHeight - |
51 | r.height) / |
52 | 2 |
53 | this.style.left = `${left}px` |
54 | this.style.top = `${top}px` |
55 | } |
56 | |
57 | sube() { |
58 | const top = |
59 | this.getBoundingClientRect(). |
60 | top - |
61 | 20 |
62 | this.style.top = `${top}px` |
63 | } |
64 | |
65 | baja() { |
66 | const top = |
67 | this.getBoundingClientRect(). |
68 | top + |
69 | 20 |
70 | this.style.top = `${top}px` |
71 | } |
72 | |
73 | izquierda() { |
74 | const left = |
75 | this.getBoundingClientRect(). |
76 | left - |
77 | 20 |
78 | this.style.left = `${left}px` |
79 | } |
80 | |
81 | derecha() { |
82 | const left = |
83 | this.getBoundingClientRect(). |
84 | left + |
85 | 20 |
86 | this.style.left = `${left}px` |
87 | } |
88 | } |
89 | customElements.define( |
90 | "jugador-paloma", JugadorPaloma) |
91 | |
92 | class FiguraAguila |
93 | extends HTMLElement { |
94 | connectedCallback() { |
95 | this.classList.add("sprite") |
96 | this.innerHTML = "🦅" |
97 | this.style.fontSize = "40px" |
98 | const r = |
99 | this.getBoundingClientRect() |
100 | this.style.left = `${r.left}px` |
101 | this.style.top = `${r.top}px` |
102 | this.style.bottom = "auto" |
103 | this.style.right = "auto" |
104 | } |
105 | |
106 | /** |
107 | * Mueve la figura para que se |
108 | * acerque al jugador, usando la |
109 | * ecuación de la recta. |
110 | * @param {HTMLElement} jugador |
111 | * el jugador que es |
112 | * perseguido. |
113 | */ |
114 | muevete(jugador) { |
115 | const r = |
116 | this.getBoundingClientRect() |
117 | const rJ = jugador. |
118 | getBoundingClientRect() |
119 | const y2 = rJ.top |
120 | const y1 = r.top |
121 | const x2 = rJ.left |
122 | const x1 = r.left |
123 | const pendiente = x2 === x1 ? |
124 | 0 : |
125 | (y2 - y1) / (x2 - x1) |
126 | const dirección = |
127 | x2 > x1 ? 1 : -1 |
128 | const x = x1 + dirección * 5 |
129 | const y = |
130 | pendiente * (x - x1) + y1 |
131 | this.style.left = `${x}px` |
132 | this.style.top = `${y}px` |
133 | } |
134 | } |
135 | customElements.define( |
136 | "figura-aguila", FiguraAguila) |
137 | </script> |
138 | </head> |
139 | |
140 | <body> |
141 | <div> |
142 | <jugador-paloma></jugador-paloma> |
143 | <figura-aguila |
144 | style="right: 0; top: 0;"> |
145 | </figura-aguila> |
146 | <figura-aguila |
147 | style="right: 0; bottom: 0;"> |
148 | </figura-aguila> |
149 | </div> |
150 | <script> |
151 | //@ts-check |
152 | class Juego { |
153 | constructor() { |
154 | /** @type {JugadorPaloma} */ |
155 | this.jugador = document. |
156 | querySelector( |
157 | "jugador-paloma") |
158 | /** @type {FiguraAguila[]} */ |
159 | this.figuras = Array.from( |
160 | document.querySelectorAll( |
161 | "figura-aguila")) |
162 | this.iniciaX = null |
163 | this.iniciaY = null |
164 | this.interval = null |
165 | this.activo = true |
166 | } |
167 | |
168 | inicia() { |
169 | document.addEventListener( |
170 | "keydown", |
171 | evt => this.teclas(evt)) |
172 | this.interval = setInterval( |
173 | () => this.mueveFiguras(), 60) |
174 | } |
175 | |
176 | mueveFiguras() { |
177 | for (const f of this.figuras) { |
178 | f.muevete(this.jugador) |
179 | } |
180 | } |
181 | |
182 | /** @param {KeyboardEvent} ev*/ |
183 | teclas(ev) { |
184 | if (this.activo) { |
185 | switch (ev.key) { |
186 | case "ArrowLeft": |
187 | this.jugador.izquierda() |
188 | break |
189 | case "ArrowRight": |
190 | this.jugador.derecha() |
191 | break |
192 | case "ArrowUp": |
193 | this.jugador.sube() |
194 | break |
195 | case "ArrowDown": |
196 | this.jugador.baja() |
197 | break |
198 | } |
199 | } |
200 | } |
201 | } |
202 | |
203 | const juego = new Juego() |
204 | juego.inicia() |
205 | </script> |
206 | </body> |
207 | |
208 | </html> |
1 | <!DOCTYPE html> |
2 | <html> |
3 | |
4 | <head> |
5 | <meta charset="utf-8"> |
6 | <meta name="viewport" |
7 | content="width=device-width"> |
8 | <title>Jueguito 2</title> |
9 | <style> |
10 | body { |
11 | position: fixed; |
12 | top: 0px; |
13 | left: 0px; |
14 | width: 100%; |
15 | height: 100%; |
16 | margin: 0; |
17 | overflow: hidden; |
18 | } |
19 | |
20 | .sprite { |
21 | position: fixed; |
22 | } |
23 | </style> |
24 | <script> |
25 | //@ts-check |
26 | /** @abstract */ |
27 | class Jugador |
28 | extends HTMLElement { |
29 | izquierda() { |
30 | throw new Error("abstract") |
31 | } |
32 | derecha() { |
33 | throw new Error("abstract") |
34 | } |
35 | sube() { |
36 | throw new Error("abstract") |
37 | } |
38 | baja() { |
39 | throw new Error("abstract") |
40 | } |
41 | } |
42 | |
43 | /** @abstract */ |
44 | class Figura |
45 | extends HTMLElement { |
46 | /** |
47 | * @param {HTMLElement} jugador |
48 | * el jugador que persigue. |
49 | */ |
50 | muevete(jugador) { |
51 | throw new Error("abstract"); |
52 | } |
53 | } |
54 | |
55 | class Juego2 { |
56 | constructor() { |
57 | /** @type {Jugador} */ |
58 | this.jugador = document. |
59 | querySelector(".jugador") |
60 | /** @type {Figura[]} */ |
61 | this.figuras = Array.from( |
62 | document.querySelectorAll( |
63 | ".figura")) |
64 | this.iniciaX = null |
65 | this.iniciaY = null |
66 | this.interval = null |
67 | this.activo = true |
68 | } |
69 | |
70 | inicia() { |
71 | document.addEventListener( |
72 | "keydown", |
73 | evt => this.teclas(evt)) |
74 | document.addEventListener( |
75 | "touchstart", |
76 | evt => this.iniciaTouch(evt)) |
77 | document.addEventListener( |
78 | "touchmove", |
79 | evt => |
80 | this.desplazaTouch(evt)) |
81 | this.interval = setInterval( |
82 | () => this.mueveFiguras(), 60) |
83 | } |
84 | |
85 | mueveFiguras() { |
86 | for (const f of this.figuras) { |
87 | f.muevete(this.jugador) |
88 | } |
89 | this.detectaColisiones() |
90 | } |
91 | |
92 | detectaColisiones() { |
93 | for (const f of this.figuras) { |
94 | if (colisiona( |
95 | this.jugador, f)) { |
96 | this.termina() |
97 | break |
98 | } |
99 | } |
100 | } |
101 | |
102 | termina() { |
103 | this.activo = false |
104 | clearInterval(this.interval) |
105 | alert("Jueguito 2 terminado.") |
106 | } |
107 | |
108 | /** @param {KeyboardEvent} evt*/ |
109 | teclas(evt) { |
110 | if (this.activo) { |
111 | switch (evt.key) { |
112 | case "ArrowLeft": |
113 | this.jugador.izquierda() |
114 | break |
115 | case "ArrowRight": |
116 | this.jugador.derecha() |
117 | break |
118 | case "ArrowUp": |
119 | this.jugador.sube() |
120 | break |
121 | case "ArrowDown": |
122 | this.jugador.baja() |
123 | break |
124 | } |
125 | this.detectaColisiones() |
126 | } |
127 | } |
128 | |
129 | /** @param {TouchEvent} evt */ |
130 | iniciaTouch(evt) { |
131 | if (this.activo) { |
132 | const toqueInicial = |
133 | evt.touches[0] |
134 | this.iniciaX = |
135 | toqueInicial.clientX |
136 | this.iniciaY = |
137 | toqueInicial.clientY |
138 | } |
139 | } |
140 | |
141 | /** @param {TouchEvent} evt */ |
142 | desplazaTouch(evt) { |
143 | if (this.activo |
144 | && this.iniciaX |
145 | && this.iniciaY) { |
146 | const desplazamiento = |
147 | evt.touches[0] |
148 | var desplazamientoX = |
149 | desplazamiento.clientX |
150 | var desplazamientoY = |
151 | desplazamiento.clientY |
152 | var difX = desplazamientoX - |
153 | this.iniciaX |
154 | var difY = desplazamientoY - |
155 | this.iniciaY |
156 | /* Checa que el movimiento no |
157 | * sea muy corto. */ |
158 | if (Math.abs(difX) |
159 | + Math.abs(difY) |
160 | > 150) { |
161 | if (Math.abs(difX) |
162 | > Math.abs(difY)) { |
163 | if (difX > 70) { |
164 | this.jugador.derecha() |
165 | } else { |
166 | this.jugador.izquierda() |
167 | } |
168 | } else if (difY > 70) { |
169 | this.jugador.baja() |
170 | } else { |
171 | this.jugador.sube() |
172 | } |
173 | this.detectaColisiones() |
174 | // Reinicia valores. |
175 | this.iniciaX = null; |
176 | this.iniciaY = null; |
177 | } |
178 | } |
179 | } |
180 | } |
181 | |
182 | /** |
183 | * @param {HTMLElement} e1 |
184 | * @param {HTMLElement} e2 |
185 | * @returns {boolean} true si los |
186 | * element colisionan. |
187 | */ |
188 | function colisiona(e1, e2) { |
189 | const rE1 = |
190 | e1.getBoundingClientRect() |
191 | const rE2 = |
192 | e2.getBoundingClientRect() |
193 | return (rE1.right >= rE2.left |
194 | && rE1.left <= rE2.right |
195 | && rE1.top <= rE2.bottom |
196 | && rE1.bottom >= rE2.top) |
197 | } |
198 | |
199 | customElements.define( |
200 | "jugador-paloma", |
201 | class extends Jugador { |
202 | connectedCallback() { |
203 | this.classList.add("sprite") |
204 | this.classList.add("jugador") |
205 | this.innerHTML += "🕊" |
206 | this.style.fontSize = "60px" |
207 | const raiz = |
208 | document.documentElement |
209 | const r = |
210 | this.getBoundingClientRect() |
211 | const left = |
212 | (raiz.clientWidth |
213 | - r.width) / |
214 | 2 |
215 | const top = |
216 | (raiz.clientHeight - |
217 | r.height) / |
218 | 2 |
219 | this.style.left = `${left}px` |
220 | this.style.top = `${top}px` |
221 | } |
222 | |
223 | /** @override */ |
224 | sube() { |
225 | const top = |
226 | this.getBoundingClientRect(). |
227 | top - |
228 | 20 |
229 | this.style.top = `${top}px` |
230 | } |
231 | |
232 | /** @override */ |
233 | baja() { |
234 | const top = |
235 | this.getBoundingClientRect(). |
236 | top + |
237 | 20 |
238 | this.style.top = `${top}px` |
239 | } |
240 | |
241 | izquierda() { |
242 | const left = |
243 | this.getBoundingClientRect(). |
244 | left - |
245 | 20 |
246 | this.style.left = `${left}px` |
247 | } |
248 | |
249 | derecha() { |
250 | const left = |
251 | this.getBoundingClientRect(). |
252 | left + |
253 | 20 |
254 | this.style.left = `${left}px` |
255 | } |
256 | }) |
257 | |
258 | customElements.define( |
259 | "figura-aguila", |
260 | class extends Figura { |
261 | connectedCallback() { |
262 | this.classList.add("sprite") |
263 | this.classList.add("figura") |
264 | this.innerHTML = "🦅" |
265 | this.style.fontSize = "40px" |
266 | const r = |
267 | this.getBoundingClientRect() |
268 | this.style.left = |
269 | `${r.left}px` |
270 | this.style.top = `${r.top}px` |
271 | this.style.bottom = "auto" |
272 | this.style.right = "auto" |
273 | } |
274 | |
275 | /** |
276 | * @param {HTMLElement} jugador |
277 | * el jugador que es |
278 | * perseguido. |
279 | * @override |
280 | */ |
281 | muevete(jugador) { |
282 | const r = |
283 | this.getBoundingClientRect() |
284 | const rJ = jugador. |
285 | getBoundingClientRect() |
286 | const y2 = rJ.top |
287 | const y1 = r.top |
288 | const x2 = rJ.left |
289 | const x1 = r.left |
290 | const pendiente = x2 === x1 ? |
291 | 0 : |
292 | (y2 - y1) / (x2 - x1) |
293 | const dirección = |
294 | x2 > x1 ? 1 : -1 |
295 | const x = x1 + dirección * 5 |
296 | const y = |
297 | pendiente * (x - x1) + y1 |
298 | /* Evita que las figuras se |
299 | * peguen, añadiendo un |
300 | * movimiento aleatorio. */ |
301 | this.style.left = |
302 | `${desvía(x)}px` |
303 | this.style.top = |
304 | `${desvía(y)}px` |
305 | } |
306 | }) |
307 | |
308 | /** |
309 | * Obtiene una desviación |
310 | * aleatoria de 10 alrededor del |
311 | * valor i. |
312 | * @param {number} i valor base |
313 | */ |
314 | function desvía(i) { |
315 | return i + 10 - |
316 | 20 * Math.random() |
317 | } |
318 | </script> |
319 | </head> |
320 | |
321 | <body> |
322 | <jugador-paloma></jugador-paloma> |
323 | <figura-aguila |
324 | style="right: 0; top: 0;"> |
325 | </figura-aguila> |
326 | <figura-aguila |
327 | style="right: 0; bottom: 0;"> |
328 | </figura-aguila> |
329 | <script> |
330 | //@ts-check |
331 | const juego2 = new Juego2() |
332 | juego2.inicia() |
333 | </script> |
334 | </body> |
335 | |
336 | </html> |
1 | <!DOCTYPE html> |
2 | <html> |
3 | |
4 | <head> |
5 | <meta charset="utf-8"> |
6 | <meta name="viewport" |
7 | content="width=device-width"> |
8 | <title>Jueguito 3</title> |
9 | <style> |
10 | body { |
11 | position: fixed; |
12 | top: 0px; |
13 | left: 0px; |
14 | width: 100%; |
15 | height: 100%; |
16 | margin: 0; |
17 | overflow: hidden; |
18 | } |
19 | |
20 | .sprite { |
21 | position: fixed; |
22 | } |
23 | </style> |
24 | <script> |
25 | //@ts-check |
26 | /** @abstract */ |
27 | class Jugador |
28 | extends HTMLElement { |
29 | /** @param {number} velocidad */ |
30 | izquierda(velocidad) { |
31 | throw new Error("abstract") |
32 | } |
33 | /** @param {number} velocidad */ |
34 | derecha(velocidad) { |
35 | throw new Error("abstract") |
36 | } |
37 | /** @param {number} velocidad */ |
38 | sube(velocidad) { |
39 | throw new Error("abstract") |
40 | } |
41 | /** @param {number} velocidad */ |
42 | baja(velocidad) { |
43 | throw new Error("abstract") |
44 | } |
45 | } |
46 | |
47 | /** @abstract */ |
48 | class Figura |
49 | extends HTMLElement { |
50 | /** |
51 | * @param {HTMLElement} jugador |
52 | * el jugador que es |
53 | * perseguido. |
54 | */ |
55 | muevete(jugador) { |
56 | throw new Error("abstract") |
57 | } |
58 | } |
59 | |
60 | /** @interface */ |
61 | class Fabrica { |
62 | /** |
63 | * Devuelve el único jugador, |
64 | * por lo que se considera |
65 | * Singleton. |
66 | * @returns {Jugador} |
67 | */ |
68 | jugador() { |
69 | throw new Error("interface") |
70 | } |
71 | /** |
72 | * Devuelve un arreglo con las |
73 | * figuras del juego. |
74 | * @returns {Figura[]} |
75 | */ |
76 | figuras() { |
77 | throw new Error("interface") |
78 | } |
79 | } |
80 | |
81 | class Juego3 { |
82 | /** @param {Fabrica} fabrica */ |
83 | constructor(fabrica) { |
84 | this.jugador = |
85 | fabrica.jugador() |
86 | this.figuras = |
87 | fabrica.figuras() |
88 | this.iniciaX = null |
89 | this.iniciaY = null |
90 | this.interval = null |
91 | this.activo = true |
92 | } |
93 | |
94 | inicia() { |
95 | document.addEventListener( |
96 | "keydown", |
97 | evt => this.teclas(evt)) |
98 | document.addEventListener( |
99 | "touchstart", |
100 | evt => this.iniciaTouch(evt)) |
101 | document.addEventListener( |
102 | "touchmove", |
103 | evt => |
104 | this.desplazaTouch(evt)) |
105 | this.interval = setInterval( |
106 | () => this.mueveFiguras(), 60) |
107 | } |
108 | |
109 | mueveFiguras() { |
110 | for (const f of this.figuras) { |
111 | f.muevete(this.jugador) |
112 | } |
113 | this.detectaColisiones() |
114 | } |
115 | |
116 | detectaColisiones() { |
117 | for (const f of this.figuras) { |
118 | if (colisiona( |
119 | this.jugador, f)) { |
120 | this.termina() |
121 | break |
122 | } |
123 | } |
124 | } |
125 | |
126 | termina() { |
127 | this.activo = false |
128 | clearInterval(this.interval) |
129 | this.jugador.innerHTML = "💥" |
130 | } |
131 | |
132 | /** @param {KeyboardEvent} evt*/ |
133 | teclas(evt) { |
134 | if (this.activo) { |
135 | switch (evt.key) { |
136 | case "ArrowLeft": |
137 | this.jugador.izquierda(20) |
138 | break |
139 | case "ArrowRight": |
140 | this.jugador.derecha(20) |
141 | break |
142 | case "ArrowUp": |
143 | this.jugador.sube(20) |
144 | break |
145 | case "ArrowDown": |
146 | this.jugador.baja(20) |
147 | break |
148 | } |
149 | this.detectaColisiones() |
150 | } |
151 | } |
152 | |
153 | /** @param {TouchEvent} evt */ |
154 | iniciaTouch(evt) { |
155 | if (this.activo) { |
156 | const toqueInicial = |
157 | evt.touches[0] |
158 | this.iniciaX = |
159 | toqueInicial.clientX |
160 | this.iniciaY = |
161 | toqueInicial.clientY |
162 | } |
163 | } |
164 | |
165 | /** @param {TouchEvent} evt */ |
166 | desplazaTouch(evt) { |
167 | if (this.activo |
168 | && this.iniciaX |
169 | && this.iniciaY) { |
170 | const desplazamiento = |
171 | evt.touches[0] |
172 | var desplazamientoX = |
173 | desplazamiento.clientX |
174 | var desplazamientoY = |
175 | desplazamiento.clientY |
176 | var difX = desplazamientoX - |
177 | this.iniciaX |
178 | var difY = desplazamientoY - |
179 | this.iniciaY |
180 | if (Math.abs(difX) |
181 | + Math.abs(difY) |
182 | > 150) { |
183 | if (Math.abs(difX) |
184 | > Math.abs(difY)) { |
185 | if (difX > 70) { |
186 | this.jugador.derecha(40) |
187 | } else { |
188 | this.jugador.izquierda(40) |
189 | } |
190 | } else if (difY > 70) { |
191 | this.jugador.baja(40) |
192 | } else { |
193 | this.jugador.sube(40) |
194 | } |
195 | this.detectaColisiones() |
196 | this.iniciaX = null |
197 | this.iniciaY = null |
198 | } |
199 | } |
200 | } |
201 | } |
202 | |
203 | /** |
204 | * @param {HTMLElement} e1 |
205 | * @param {HTMLElement} e2 |
206 | * @returns {boolean} true si los |
207 | * element colisionan. |
208 | */ |
209 | function colisiona(e1, e2) { |
210 | const rE1 = |
211 | e1.getBoundingClientRect() |
212 | const rE2 = |
213 | e2.getBoundingClientRect() |
214 | return (rE1.right >= rE2.left |
215 | && rE1.left <= rE2.right |
216 | && rE1.top <= rE2.bottom |
217 | && rE1.bottom >= rE2.top) |
218 | } |
219 | |
220 | customElements.define( |
221 | "jugador-paloma", |
222 | class extends Jugador { |
223 | connectedCallback() { |
224 | this.classList.add("sprite") |
225 | this.innerHTML += "🕊" |
226 | this.style.fontSize = "60px" |
227 | const raiz = |
228 | document.documentElement |
229 | const r = |
230 | this.getBoundingClientRect() |
231 | const left = |
232 | (raiz.clientWidth |
233 | - r.width) / |
234 | 2 |
235 | const top = |
236 | (raiz.clientHeight - |
237 | r.height) / |
238 | 2 |
239 | this.style.left = `${left}px` |
240 | this.style.top = `${top}px` |
241 | } |
242 | |
243 | /** |
244 | * @param {number} velocidad |
245 | * @override |
246 | */ |
247 | sube(velocidad) { |
248 | const top = |
249 | this.getBoundingClientRect(). |
250 | top - |
251 | velocidad |
252 | this.style.top = `${top}px` |
253 | } |
254 | |
255 | /** |
256 | * @param {number} velocidad |
257 | * @override |
258 | */ |
259 | baja(velocidad) { |
260 | const top = |
261 | this.getBoundingClientRect(). |
262 | top + |
263 | velocidad |
264 | this.style.top = `${top}px` |
265 | } |
266 | |
267 | /** |
268 | * @param {number} velocidad |
269 | * @override |
270 | */ |
271 | izquierda(velocidad) { |
272 | const left = |
273 | this.getBoundingClientRect(). |
274 | left - |
275 | velocidad |
276 | this.style.left = `${left}px` |
277 | } |
278 | |
279 | /** |
280 | * @param {number} velocidad |
281 | * @override |
282 | */ |
283 | derecha(velocidad) { |
284 | const left = |
285 | this.getBoundingClientRect(). |
286 | left + |
287 | velocidad |
288 | this.style.left = `${left}px` |
289 | } |
290 | }) |
291 | |
292 | customElements.define( |
293 | "figura-aguila", |
294 | class extends Figura { |
295 | connectedCallback() { |
296 | this.classList.add("sprite") |
297 | this.innerHTML = "🦅" |
298 | this.style.fontSize = "40px" |
299 | const r = |
300 | this.getBoundingClientRect() |
301 | this.style.left = |
302 | `${r.left}px` |
303 | this.style.top = `${r.top}px` |
304 | this.style.bottom = "auto" |
305 | this.style.right = "auto" |
306 | } |
307 | |
308 | /** |
309 | * @param {HTMLElement} jugador |
310 | * el jugador que persigue. |
311 | * @override |
312 | */ |
313 | muevete(jugador) { |
314 | const r = |
315 | this.getBoundingClientRect() |
316 | const rJ = jugador. |
317 | getBoundingClientRect() |
318 | const y2 = rJ.top |
319 | const y1 = r.top |
320 | const x2 = rJ.left |
321 | const x1 = r.left |
322 | const pendiente = x2 === x1 ? |
323 | 0 : |
324 | (y2 - y1) / (x2 - x1) |
325 | const dirección = |
326 | x2 > x1 ? 1 : -1 |
327 | const x = x1 + dirección * 5 |
328 | const y = |
329 | pendiente * (x - x1) + y1 |
330 | this.style.left = |
331 | `${desvía(x)}px` |
332 | this.style.top = |
333 | `${desvía(y)}px` |
334 | } |
335 | }) |
336 | |
337 | function desvía(i) { |
338 | return i + 10 - |
339 | 20 * Math.random() |
340 | } |
341 | </script> |
342 | </head> |
343 | |
344 | <body> |
345 | <jugador-paloma></jugador-paloma> |
346 | <figura-aguila |
347 | style="right: 0; top: 0;"> |
348 | </figura-aguila> |
349 | <figura-aguila |
350 | style="right: 0; bottom: 0;"> |
351 | </figura-aguila> |
352 | <script> |
353 | //@ts-check |
354 | /** @implements {Fabrica} */ |
355 | class MiFabrica { |
356 | constructor() { |
357 | /** @type {Jugador} */ |
358 | this.jugadorSingleton = |
359 | document.querySelector( |
360 | "jugador-paloma"); |
361 | } |
362 | /** |
363 | * Devuelve el único jugador, |
364 | * por lo que se considera |
365 | * Singleton. |
366 | * @returns {Jugador} |
367 | */ |
368 | jugador() { |
369 | return this.jugadorSingleton |
370 | } |
371 | /** |
372 | * Devuelve un arreglo con las |
373 | * figuras del juego. |
374 | * @returns {Figura[]} |
375 | */ |
376 | figuras() { |
377 | return Array.from( |
378 | document.querySelectorAll( |
379 | "figura-aguila")) |
380 | } |
381 | } |
382 | const juego = |
383 | new Juego3(new MiFabrica()) |
384 | juego.inicia() |
385 | </script> |
386 | </body> |
387 | |
388 | </html> |
En esta lección se revisaron los elementos principales para elaborar formularios y se presentaron algunos ejemplos.