folder names

This commit is contained in:
Jen Looper
2020-11-09 22:51:04 -05:00
parent 33e5d5f777
commit 1d81829ac1
367 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,17 @@
*Complete this quiz after the lesson by checking one answer per question.*
1. Classes rely on inheritance to ascribe to behaviors
- [ ] true
- [ ] false
2. Composition is a preferred design pattern for game objects
- [ ] true
- [ ] false
3. Pub/Sub stands for:
- [ ] Publish/Subscribe
- [ ] Print/Staple
- [ ] Publish/Sanitize

View File

@@ -0,0 +1,18 @@
*A warm-up quiz about game development using JavaScript*
Complete this quiz in class
1. JavaScript is an unpopular language for building games
- [ ] [true]
- [ ] [false]
2. Pub/Sub is a preferred pattern for managing the game's assets and flow
- [ ] [true]
- [ ] [false]
3. Object inheritance can be handled by either using classes or composition
- [ ] [true]
- [ ] [false]

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 WebDev-For-Beginners
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,220 @@
# Build a Space Game Part I: Introduction
![video](video-url)
## [Pre-lecture quiz](.github/pre-lecture-quiz.md)
### Inheritance and Composition in game development
In earlier lessons, there was not much need to worry about the design architecture of the apps you built, as the projects were very small in scope. However, when your applications grow in size and scope, architectural decisions become a larger concern. There are two major approaches to creating larger applications in JavaScript: *composition* or *inheritance*. There are pros and cons to both but let's explain them from within the context of a game.
✅ One of the most famous programming books ever written has to do with [design patterns](https://en.wikipedia.org/wiki/Design_Patterns).
In a game you have `game objects` which are objects that exist on a screen. This means they have a location on a cartesian coordinate system, characterized by having an `x` and `y` coordinate. As you develop a game you will notice that all your game objects have a standard property, common for every game you create, namely elements that are:
- **location-based** Most, if not all, game elements are location based. This means that they have a location, an `x` and `y`.
- **movable** These are objects that can move to a new location. This is typically a hero, a monster or an NPC (a non player character), but not for example, a static object like a tree.
- **self-destructing** These objects only exist for a set period of time before they set themselves up for deletion. Usually this is represented by a `dead` or `destroyed` boolean that signals to the game engine that this object should no longer be rendered.
- **cool-down** 'Cool-down' is a typical property among short-lived objects. A typical example is a piece of text or graphical effect like an explosion that should only be seen for a few milliseconds.
✅ Think about a game like Pac-Man. Can you identify the four object types listed above in this game?
### Expressing behavior
All we described above are behavior that game objects can have. So how do we encode those? We can express this behavior as methods associated to either classes or objects.
**Classes**
The idea is to use `classes` in conjunction with `inheritance` to accomplish adding a certain behavior to a class.
✅ Inheritance is an important concept to understand. Learn more on [MDN's article about inheritance](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain).
Expressed via code, a game object can typically look like this:
```javascript
//set up the class GameObject
class GameObject {
constructor(x, y, type) {
this.x = x;
this.y = y;
this.type = type;
}
}
//this class will extend the GameObject's inherent class properties
class Movable extends GameObject {
constructor(x,y, type) {
super(x,y, type)
}
//this movable object can be moved on the screen
moveTo(x, y) {
this.x = x;
this.y = y;
}
}
//this is a specific class that extends the Movable class, so it can take advantage of all the properties that it inherits
class Hero extends Movable {
constructor(x,y) {
super(x,y, 'Hero')
}
}
//this class, on the other hand, only inherits the GameObject properties
class Tree extends GameObject {
constructor(x,y) {
super(x,y, 'Tree')
}
}
//a hero can move...
const hero = new Hero();
hero.moveTo(5,5);
//but a tree cannot
const tree = new Tree();
```
✅ Take a few minutes to re-envision a Pac-Man hero (Inky, Pinky or Blinky, for example) and how it would be written in JavaScript.
**Composition**
A different way of handling object inheritance is by using *Composition*. Then, objects express their behavior like this:
```javascript
//create a constant gameObject
const gameObject = {
x: 0,
y: 0,
type: ''
};
//...and a constant movable
const movable = {
moveTo(x, y) {
this.x = x;
this.y = y;
}
}
//then the constant movableObject is composed of the gameObject and movable constants
const movableObject = {...gameObject, ...movable};
//then create a function to create a new Hero who inherits the movableObject properties
function createHero(x, y) {
return {
...movableObject,
x,
y,
type: 'Hero'
}
}
//...and a static object that inherits only the gameObject properties
function createStatic(x, y, type) {
return {
...gameObject
x,
y,
type
}
}
//create the hero and move it
const hero = createHero(10,10);
hero.moveTo(5,5);
//and create a static tree which only stands around
const tree = createStatic(0,0, 'Tree');
```
**Which pattern should I use?**
It's up to you which pattern you choose. JavaScript supports both these paradigms.
--
Another pattern common in game development addresses the problem of handling the game's user experience and performance.
## Pub/sub pattern
✅ Pub/Sub stands for 'publish-subscribe'
This pattern addresses the idea that the disparate parts of your application shouldn't know about one another. Why is that? It makes it a lot easier to see what's going on in general if various parts are separated. It also makes it easier to suddenly change behavior if you need to. How do we accomplish this? We do this by establishing some concepts:
- **message**: A message is usually a text string accompanied by an optional payload (a piece of data that clarifies what the message is about). A typical message in a game can be `KEY_PRESSED_ENTER`.
- **publisher**: This element *publishes* a message and sends it out to all subscribers.
- **subscriber**: This element *listens* to specific messages and carries out some task as the result of receiving this message, such as firing a laser.
The implementation is quite small in size but it's a very powerful pattern. Here's how it can be implemented:
```javascript
//set up an EventEmitter class that contains listeners
class EventEmitter {
constructor() {
this.listeners = {};
}
//when a message is received, let the listener to handle its payload
on(message, listener) {
if (!this.listeners[message]) {
this.listeners[message] = [];
}
this.listeners[message].push(listener);
}
//when a message is sent, send it to a listener with some payload
emit(message, payload = null) {
if (this.listeners[message]) {
this.listeners[message].forEach(l => l(message, payload))
}
}
}
```
To use the above code we can create a very small implementation:
```javascript
//set up a message structure
const Messages = {
HERO_MOVE_LEFT: 'HERO_MOVE_LEFT'
};
//invoke the eventEmitter you set up above
const eventEmitter = new EventEmitter();
//set up a hero
const hero = createHero(0,0);
//let the eventEmitter know to watch for messages pertaining to the hero moving left, and act on it
eventEmitter.on(Messages.HERO_MOVE_LEFT, () => {
hero.move(5,0);
});
//set up the window to listen for the keyup event, specifically if the left arrow is hit, emit a message to move the hero left
window.addEventListener('keyup', (evt) => {
if (evt.key === 'ArrowLeft') {
eventEmitter.emit(Messages.HERO_MOVE_LEFT)
}
});
```
Above we connect a keyboard event, `ArrowLeft` and send the `HERO_MOVE_LEFT` message. We listen to that message and move the `hero` as a result. The strength with this pattern is that the event listener and the hero don't know about each other. You can remap the `ArrowLeft` to the `A` key. Additionally it would be possible to do something completely different on `ArrowLeft` by making a few edits to the eventEmitter's `on` function:
```javascript
eventEmitter.on(Messages.HERO_MOVE_LEFT, () => {
hero.move(5,0);
});
```
As things gets more complicated when your game grows, this pattern stays the same in complexity and your code stays clean. It's really recommended to adopt this pattern.
---
## 🚀 Challenge
Think about how the pub-sub pattern can enhance a game. Which parts should emit events, and how should the game react to them? Now's your chance to get creative, thinking of a new game and how its parts might behave.
## [Post-lecture quiz](.github/post-lecture-quiz.md)
## Review & Self Study
Learn more about Pub/Sub by [reading about it](https://docs.microsoft.com/en-us/azure/architecture/patterns/publisher-subscriber).
## Assignment
[Mock up a game](assignment.md)

View File

@@ -0,0 +1,11 @@
# Mock up a game
## Instructions
Using the code samples in the lesson, write a representation of a game you enjoy. It will have to be a simple game, but the goal is to use either the class or the composition pattern and the pub/sub pattern to show how a game might launch. Get creative!
## Rubric
| Criteria | Exemplary | Adequate | Needs Improvement |
| -------- | ------------------------------------------------------- | ----------------------------------------------------- | --------------------------------------------------- |
| | Three elements are placed on the screen and manipulated | Two elements are placed on the screen and manipulated | One element is placed on the screen and manipulated |

View File

@@ -0,0 +1,216 @@
# Construye un juego espacial Parte I: Introducción
![video](video-url)
## [Pre-lecture prueba](.github/pre-lecture-quiz.md)
### Herencia y composición en el desarrollo de juegos
En lecciones anteriores, no había mucha necesidad de preocuparse por la arquitectura de diseño de las aplicaciones que creó, ya que los proyectos tenían un alcance muy pequeño. Sin embargo, cuando sus aplicaciones crecen en tamaño y alcance, las decisiones de arquitectura se vuelven una preocupación mayor. Hay dos enfoques principales para crear aplicaciones más grandes en JavaScript: *composición* o *herencia*. Ambos tienen pros y contras, pero vamos a explicarlos desde el contexto de un juego.
✅ Uno de los libros de programación más famosos jamás escrito tiene que ver con [patrones de diseño](https://en.wikipedia.org/wiki/Design_Patterns).
En un juego tienes `game objects` que son objetos que existen en una pantalla. Esto significa que tienen una ubicación en un sistema de coordenadas cartesiano, caracterizado por tener una coordenada `x` e `y`. A medida que desarrolle un juego, notará que todos los objetos de su juego tienen una propiedad estándar, común para todos los juegos que crea, es decir, elementos que son:
- **location-based** (basado en la ubicación): La mayoría, si no todos, los elementos del juego se basan en la ubicación. Esto significa que tienen una ubicación, una `x` y una` y`.
- **movable** (movible): Estos son objetos que pueden moverse a una nueva ubicación. Suele ser un héroe, un monstruo o un NPC (un personaje no jugador), pero no, por ejemplo, un objeto estático como un árbol.
- **self-destructing** (autodestructivo): Estos objetos solo existen durante un período de tiempo determinado antes de que se configuren para su eliminación. Por lo general, esto está representado por un booleano `dead` o `destroyed` que indica al motor del juego que este objeto ya no debe procesarse.
- **cool-down** (enfriamiento): 'Cool-down' es una propiedad típica entre los objetos de corta duración. Un ejemplo típico es un fragmento de texto o efecto gráfico como una explosión que solo debería verse durante unos pocos milisegundos.
✅ Piense en un juego como Pac-Man. ¿Puedes identificar los cuatro tipos de objetos enumerados anteriormente en este juego?
### Expresando comportamiento
Todo lo que describimos anteriormente son comportamientos que pueden tener los objetos del juego. Entonces, ¿cómo los codificamos? Podemos expresar este comportamiento como métodos asociados a clases u objetos.
**Clases**
La idea es usar `classes` junto con `inheritance` para lograr agregar un cierto comportamiento a una clase.
✅ La herencia es un concepto importante de comprender. Obtenga más información en el [artículo de MDN sobre herencia](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain).
Expresado a través de código, un objeto de juego normalmente puede verse así:
```javascript
//configurar la clase GameObject
class GameObject {
constructor(x, y, type) {
this.x = x;
this.y = y;
this.type = type;
}
}
//esta clase extenderá las propiedades de clase inherentes del GameObject
class Movable extends GameObject {
constructor(x,y, type) {
super(x,y, type)
}
//este objeto móvil se puede mover en la pantalla
moveTo(x, y) {
this.x = x;
this.y = y;
}
}
//esta es una clase específica que extiende la clase Movable, por lo que puede aprovechar todas las propiedades que hereda
class Hero extends Movable {
constructor(x,y) {
super(x,y, 'Hero')
}
}
//esta clase, por otro lado, solo hereda las propiedades GameObject
class Tree extends GameObject {
constructor(x,y) {
super(x,y, 'Tree')
}
}
// un héroe puede moverse...
const hero = new Hero();
hero.moveTo(5,5);
//pero un árbol no puede
const tree = new Tree();
```
✅ Tómate unos minutos para volver a imaginar un héroe de Pac-Man (Inky, Pinky o Blinky, por ejemplo) y cómo se escribiría en JavaScript.
**Composición**
Una forma diferente de manejar la herencia de objetos es usando *Composición*. Entonces, los objetos expresan su comportamiento así:
```javascript
//crear un gameObject constante
const gameObject = {
x: 0,
y: 0,
type: ''
};
//...y un movible constante
const movable = {
moveTo(x, y) {
this.x = x;
this.y = y;
}
}
//entonces la constante movableObject está compuesta por gameObject y constantes movibles
const movableObject = {...gameObject, ...movable};
//luego crea una función para crear un nuevo Hero que hereda las propiedades de movableObject
function createHero(x, y) {
return {
...movableObject,
x,
y,
type: 'Hero'
}
}
//...y un objeto estático que hereda solo las propiedades de gameObject
function createStatic(x, y, type) {
return {
...gameObject
x,
y,
type
}
}
//crea el héroe y muévelo
const hero = createHero(10,10);
hero.moveTo(5,5);
//y crea un árbol estático que solo se para alrededor
const tree = createStatic(0,0, 'Tree');
```
**¿Qué patrón debo usar?**
Depende de usted qué patrón elija. JavaScript es compatible con ambos paradigmas.
--
Otro patrón común en el desarrollo de juegos aborda el problema de manejar la experiencia y el rendimiento del usuario del juego.
## Patrón de pub/sub
✅ Pub/Sub significa publish-subscribe (publicar-suscribirse).
Este patrón aborda la idea de que las distintas partes de su aplicación no deben conocerse entre sí. ¿Porqué es eso? Hace que sea mucho más fácil ver lo que sucede en general si se separan varias partes. También facilita el cambio repentino de comportamiento si es necesario. ¿Cómo logramos esto? Hacemos esto estableciendo algunos conceptos:
- **message** (mensaje: un mensaje suele ser una cadena de texto acompañada de una carga útil opcional (un dato que aclara de qué se trata el mensaje). Un mensaje típico en un juego puede ser `KEY_PRESSED_ENTER`.
- **publisher** (editor): este elemento *publica* un mensaje y lo envía a todos los suscriptores.
- **subscriber** (suscriptor): Este elemento *escucha* mensajes específicos y realiza alguna tarea como resultado de recibir este mensaje, como disparar un láser.
La implementación es bastante pequeña pero es un patrón muy poderoso. Así es como se puede implementar:
```javascript
//configurar una clase EventEmitter que contenga oyentes
class EventEmitter {
constructor() {
this.listeners = {};
}
//cuando se recibe un mensaje, deje que el oyente maneje su carga útil
on(message, listener) {
if (!this.listeners[message]) {
this.listeners[message] = [];
}
this.listeners[message].push(listener);
}
//cuando se envía un mensaje, envíelo a un oyente con alguna carga útil
emit(message, payload = null) {
if (this.listeners[message]) {
this.listeners[message].forEach(l => l(message, payload))
}
}
}
```
Para usar el código anterior, podemos crear una implementación muy pequeña:
```javascript
//configurar una estructura de mensaje
const Messages = {
HERO_MOVE_LEFT: 'HERO_MOVE_LEFT'
};
//invocar el eventEmitter que configuró anteriormente
const eventEmitter = new EventEmitter();
//configurar un héroe
const hero = createHero(0,0);
//Informe al emisor de eventos que esté atento a los mensajes relacionados con el héroe que se mueve hacia la izquierda y actúe en consecuencia
eventEmitter.on(Messages.HERO_MOVE_LEFT, () => {
hero.move(5,0);
});
//configurar la ventana para escuchar el evento keyup, específicamente si se golpea la flecha izquierda, emite un mensaje para mover al héroe a la izquierda
window.addEventListener('keyup', (evt) => {
if (evt.key === 'ArrowLeft') {
eventEmitter.emit(Messages.HERO_MOVE_LEFT)
}
});
```
Arriba conectamos un evento de teclado, `ArrowLeft` y enviamos el mensaje `HERO_MOVE_LEFT`. Escuchamos ese mensaje y, como resultado, movemos al `hero`. El punto fuerte de este patrón es que el oyente del evento y el héroe no se conocen. Puede reasignar la ʻArrowLeft` a la tecla ʻA`. Además, sería posible hacer algo completamente diferente en `ArrowLeft` haciendo algunas ediciones en la función `on` del eventEmitter:
```javascript
eventEmitter.on(Messages.HERO_MOVE_LEFT, () => {
hero.move(5,0);
});
```
A medida que las cosas se complican cuando tu juego crece, este patrón permanece igual en complejidad y tu código se mantiene limpio. Realmente se recomienda adoptar este patrón.
🚀Desafío: Piense en cómo el patrón pub-sub puede mejorar un juego. ¿Qué partes deberían emitir eventos y cómo debería reaccionar el juego ante ellos? Ahora tienes la oportunidad de ser creativo, pensar en un nuevo juego y en cómo podrían comportarse sus partes.
## [Post-lecture prueba](.github/post-lecture-quiz.md)
## Revisión y autoestudio
Obtenga más información sobre Pub / Sub al [leer sobre él](https://docs.microsoft.com/en-us/azure/architecture/patterns/publisher-subscriber).
**Tarea**: [Mock up a game](assignment.md)

View File

@@ -0,0 +1,11 @@
# Simula un juego
## Instrucciones
Utilizando los ejemplos de código de la lección, escriba una representación de un juego que disfrute. Tendrá que ser un juego simple, pero el objetivo es usar la clase o el patrón de composición y el patrón pub / sub para mostrar cómo se puede lanzar un juego. ¡Se creativo!
## Rúbrica
| Criterios | Ejemplar | Adecuado | Necesita mejorar |
| -------- | -------------------------------------------------- ----- | -------------------------------------------------- --- | -------------------------------------------------- - |
| | Se colocan tres elementos en la pantalla y se manipulan | Se colocan dos elementos en la pantalla y se manipulan | Un elemento se coloca en la pantalla y se manipula |