├── Unit_1
├── Lesson_4
│ ├── items.html
│ └── let.js
├── Lesson_5
│ └── const.js
├── Lesson_6
│ ├── binary_ip.js
│ ├── includes.js
│ └── pad.js
├── Lesson_7
│ └── templates.js
└── Lesson_8_Capstone
│ └── dsl.js
├── Unit_2
├── Lesson_10
│ └── spaceship.js
├── Lesson_11
│ └── destructuring.js
├── Lesson_12
│ └── state_manager.js
├── Lesson_13
│ ├── spaceship.js
│ └── symbol_primitive.js
├── Lesson_14_Capstone
│ └── index.js
└── Lesson_9
│ └── avg.js
├── Unit_3
├── Lesson_15
│ └── rest.js
├── Lesson_16
│ └── car.js
├── Lesson_17
│ └── arrow_function.js
├── Lesson_18
│ ├── generators.js
│ └── infinite_lists.js
└── Lesson_19_Capstone
│ └── prisoners_delimma.js
├── Unit_4
└── Lesson_22_Capstone
│ ├── final
│ ├── .babelrc
│ ├── .gitignore
│ ├── dest
│ │ └── build.js
│ ├── index.html
│ ├── package.json
│ └── src
│ │ ├── index.js
│ │ ├── keyboard.js
│ │ ├── letter_slots.js
│ │ ├── status.js
│ │ ├── status_display.js
│ │ └── words.js
│ └── start
│ ├── .babelrc
│ ├── .gitignore
│ ├── dest
│ └── build.js
│ ├── index.html
│ ├── package.json
│ └── src
│ └── index.js
├── Unit_5
├── Lesson_23
│ ├── comparing_of_in.js
│ ├── html_safe.js
│ ├── list_friends.js
│ ├── primes.js
│ ├── reverse.js
│ ├── spread.js
│ ├── words.js
│ └── yield_all.js
├── Lesson_24
│ └── set_utils.js
├── Lesson_25
│ ├── obj_to_map.js
│ └── singleton.js
└── Lesson_26_Capstone
│ ├── final
│ ├── .babelrc
│ ├── .gitignore
│ ├── dest
│ │ └── build.js
│ ├── index.html
│ ├── package.json
│ └── src
│ │ ├── cards.js
│ │ ├── elements.js
│ │ ├── index.js
│ │ ├── templates.js
│ │ └── utils.js
│ └── start
│ ├── .babelrc
│ ├── .gitignore
│ ├── dest
│ └── build.js
│ ├── index.html
│ ├── package.json
│ └── src
│ ├── elements.js
│ └── templates.js
├── Unit_6
├── Lesson_27
│ └── fish.js
├── Lesson_28
│ └── car.js
└── Lesson_29_Capstone
│ ├── final
│ ├── .babelrc
│ ├── .gitignore
│ ├── dest
│ │ └── build.js
│ ├── index.html
│ ├── package.json
│ └── src
│ │ ├── comet.js
│ │ ├── explosion.js
│ │ ├── framework
│ │ ├── canvas.js
│ │ ├── controllable_sprite.js
│ │ ├── drifting_sprite.js
│ │ ├── game.js
│ │ ├── hit_test.js
│ │ ├── interactions.js
│ │ ├── sprite.js
│ │ └── utils.js
│ │ ├── index.js
│ │ ├── rocket.js
│ │ ├── shapes.js
│ │ └── ship.js
│ └── start
│ ├── .babelrc
│ ├── .gitignore
│ ├── dest
│ └── build.js
│ ├── index.html
│ ├── package.json
│ └── src
│ ├── framework
│ ├── canvas.js
│ ├── controllable_sprite.js
│ ├── drifting_sprite.js
│ ├── game.js
│ ├── hit_test.js
│ ├── interactions.js
│ ├── sprite.js
│ └── utils.js
│ └── shapes.js
├── Unit_7
├── Lesson_30
│ └── user_view.js
├── Lesson_31
│ ├── alligator.js
│ ├── catching_errors.js
│ ├── fetch_image.js
│ ├── fetch_orgs.js
│ ├── then_chaining.js
│ └── wait.js
├── Lesson_32
│ ├── all_resolved.js
│ ├── fail.js
│ ├── fetch_image.js
│ └── runner.js
├── Lesson_33
│ ├── current_time.js
│ ├── filter.js
│ └── from_set.js
└── Lesson_34_Capstone
│ ├── final
│ ├── .babelrc
│ ├── dest
│ │ └── build.js
│ ├── index.html
│ ├── package.json
│ └── src
│ │ └── index.js
│ └── start
│ ├── .babelrc
│ ├── dest
│ └── build.js
│ ├── index.html
│ ├── package.json
│ └── src
│ └── index.js
└── readme.md
/Unit_1/Lesson_4/items.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ${ letter }`;
16 | } else {
17 | return ``;
18 | }
19 | }
20 |
21 | function keyboard(guesses) {
22 | return `
23 |
24 |
${ firstRow.map(char => key(char, guesses)).join('') }
25 |
${ secondRow.map(char => key(char, guesses)).join('') }
26 |
27 | `;
28 | }
29 |
30 | },{}],2:[function(require,module,exports){
31 | 'use strict';
32 |
33 | Object.defineProperty(exports, "__esModule", {
34 | value: true
35 | });
36 | exports.default = letterSlots;
37 | function letterSlot(letter, guesses) {
38 | if (guesses.includes(letter)) {
39 | return `${ letter }`;
40 | } else {
41 | return ' ';
42 | }
43 | }
44 |
45 | function letterSlots(word, guesses) {
46 | const slots = word.split('').map(letter => letterSlot(letter, guesses));
47 |
48 | return `${ slots.join('') }
`;
49 | }
50 |
51 | },{}],3:[function(require,module,exports){
52 | 'use strict';
53 |
54 | Object.defineProperty(exports, "__esModule", {
55 | value: true
56 | });
57 | exports.guessesRemaining = guessesRemaining;
58 | exports.isGameWon = isGameWon;
59 | exports.isGameOver = isGameOver;
60 | exports.isStillPlaying = isStillPlaying;
61 | const MAX_INCORRECT_GUESSES = 5;
62 |
63 | function guessesRemaining(word, guesses) {
64 | const incorrectGuesses = guesses.filter(char => !word.includes(char));
65 | return MAX_INCORRECT_GUESSES - incorrectGuesses.length;
66 | }
67 |
68 | function isGameWon(word, guesses) {
69 | return !word.split('').find(letter => !guesses.includes(letter));
70 | }
71 |
72 | function isGameOver(word, guesses) {
73 | return !guessesRemaining(word, guesses) && !isGameWon(word, guesses);
74 | }
75 |
76 | function isStillPlaying(word, guesses) {
77 | return guessesRemaining(word, guesses) && !isGameOver(word, guesses) && !isGameWon(word, guesses);
78 | }
79 |
80 | },{}],4:[function(require,module,exports){
81 | 'use strict';
82 |
83 | Object.defineProperty(exports, "__esModule", {
84 | value: true
85 | });
86 | exports.default = statusDisplay;
87 |
88 | var _status = require('./status');
89 |
90 | var status = _interopRequireWildcard(_status);
91 |
92 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
93 |
94 | function getMessage(word, guesses) {
95 | if (status.isGameWon(word, guesses)) {
96 | return 'YOU WIN!';
97 | } else if (status.isGameOver(word, guesses)) {
98 | return 'GAME OVER';
99 | } else {
100 | return `Guesses Remaining: ${ status.guessesRemaining(word, guesses) }`;
101 | }
102 | }
103 |
104 | function statusDisplay(word, guesses) {
105 | return `${ getMessage(word, guesses) }
`;
106 | }
107 |
108 | },{"./status":3}],5:[function(require,module,exports){
109 | 'use strict';
110 |
111 | Object.defineProperty(exports, "__esModule", {
112 | value: true
113 | });
114 | exports.default = getRandomWord;
115 | function getWords(cb) {
116 | cb(['bacon', 'teacher', 'automobile']);
117 | }
118 |
119 | function getRandomWord(cb) {
120 | getWords(words => {
121 | const randomWord = words[Math.floor(Math.random() * words.length)];
122 | cb(randomWord.toUpperCase());
123 | });
124 | }
125 |
126 | },{}],6:[function(require,module,exports){
127 | 'use strict';
128 |
129 | var _words = require('./words');
130 |
131 | var _words2 = _interopRequireDefault(_words);
132 |
133 | var _status = require('./status');
134 |
135 | var _letter_slots = require('./letter_slots');
136 |
137 | var _letter_slots2 = _interopRequireDefault(_letter_slots);
138 |
139 | var _keyboard = require('./keyboard');
140 |
141 | var _keyboard2 = _interopRequireDefault(_keyboard);
142 |
143 | var _status_display = require('./status_display');
144 |
145 | var _status_display2 = _interopRequireDefault(_status_display);
146 |
147 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
148 |
149 | function drawGame(word, guesses) {
150 | document.querySelector('#status-display').innerHTML = (0, _status_display2.default)(word, guesses);
151 | document.querySelector('#letter-slots').innerHTML = (0, _letter_slots2.default)(word, guesses);
152 | document.querySelector('#keyboard').innerHTML = (0, _keyboard2.default)(guesses);
153 | }
154 |
155 | (0, _words2.default)(word => {
156 | const guesses = [];
157 |
158 | document.addEventListener('click', event => {
159 | if ((0, _status.isStillPlaying)(word, guesses) && event.target.tagName === 'BUTTON') {
160 | guesses.push(event.target.dataset.char);
161 | drawGame(word, guesses);
162 | }
163 | });
164 |
165 | drawGame(word, guesses);
166 | });
167 |
168 | },{"./keyboard":1,"./letter_slots":2,"./status":3,"./status_display":4,"./words":5}]},{},[6]);
169 |
--------------------------------------------------------------------------------
/Unit_4/Lesson_22_Capstone/final/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Hangman
6 |
52 |
53 |
54 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/Unit_4/Lesson_22_Capstone/final/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "modules-hangman",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "build": "browserify -t [ babelify ] ./src -o ./dest/build.js"
9 | },
10 | "keywords": [],
11 | "author": "",
12 | "license": "ISC",
13 | "devDependencies": {
14 | "babel-plugin-transform-es2015-modules-commonjs": "^6.18.0",
15 | "babelify": "^7.3.0"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Unit_4/Lesson_22_Capstone/final/src/index.js:
--------------------------------------------------------------------------------
1 | import getRandomWord from './words'
2 | import { isStillPlaying } from './status'
3 | import letterSlots from './letter_slots'
4 | import keyboard from './keyboard'
5 | import statusDisplay from './status_display'
6 |
7 | function drawGame(word, guesses) {
8 | document.querySelector('#status-display').innerHTML = statusDisplay(word, guesses)
9 | document.querySelector('#letter-slots').innerHTML = letterSlots(word, guesses)
10 | document.querySelector('#keyboard').innerHTML = keyboard(guesses)
11 | }
12 |
13 | getRandomWord(word => {
14 | const guesses = []
15 |
16 | document.addEventListener('click', event => {
17 | if (isStillPlaying(word, guesses) && event.target.tagName === 'BUTTON') {
18 | guesses.push(event.target.dataset.char)
19 | drawGame(word, guesses)
20 | }
21 | })
22 |
23 | drawGame(word, guesses)
24 | })
25 |
--------------------------------------------------------------------------------
/Unit_4/Lesson_22_Capstone/final/src/keyboard.js:
--------------------------------------------------------------------------------
1 | const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('')
2 |
3 | const firstRow = alphabet.slice(0, 13)
4 | const secondRow = alphabet.slice(13)
5 |
6 | function key(letter, guesses) {
7 | if (guesses.includes(letter)) {
8 | return `${letter}`
9 | } else {
10 | return ``
11 | }
12 | }
13 |
14 | export default function keyboard(guesses) {
15 | return `
16 |
17 |
${ firstRow.map(char => key(char, guesses)).join('') }
18 |
${ secondRow.map(char => key(char, guesses)).join('') }
19 |
20 | `
21 | }
22 |
--------------------------------------------------------------------------------
/Unit_4/Lesson_22_Capstone/final/src/letter_slots.js:
--------------------------------------------------------------------------------
1 | function letterSlot(letter, guesses) {
2 | if (guesses.includes(letter)) {
3 | return `${letter}`
4 | } else {
5 | return ' '
6 | }
7 | }
8 |
9 | export default function letterSlots(word, guesses) {
10 | const slots = word.split('').map(letter => letterSlot(letter, guesses))
11 |
12 | return `${ slots.join('') }
`
13 | }
14 |
--------------------------------------------------------------------------------
/Unit_4/Lesson_22_Capstone/final/src/status.js:
--------------------------------------------------------------------------------
1 | const MAX_INCORRECT_GUESSES = 5
2 |
3 | export function guessesRemaining(word, guesses) {
4 | const incorrectGuesses = guesses.filter(char => !word.includes(char))
5 | return MAX_INCORRECT_GUESSES - incorrectGuesses.length
6 | }
7 |
8 | export function isGameWon(word, guesses) {
9 | return !word.split('').find(letter => !guesses.includes(letter))
10 | }
11 |
12 | export function isGameOver(word, guesses) {
13 | return !guessesRemaining(word, guesses) && !isGameWon(word, guesses)
14 | }
15 |
16 | export function isStillPlaying(word, guesses) {
17 | return guessesRemaining(word, guesses) &&
18 | !isGameOver(word, guesses) &&
19 | !isGameWon(word, guesses)
20 | }
21 |
--------------------------------------------------------------------------------
/Unit_4/Lesson_22_Capstone/final/src/status_display.js:
--------------------------------------------------------------------------------
1 | import * as status from './status'
2 |
3 | function getMessage(word, guesses) {
4 | if (status.isGameWon(word, guesses)) {
5 | return 'YOU WIN!'
6 | } else if (status.isGameOver(word, guesses)) {
7 | return 'GAME OVER'
8 | } else {
9 | return `Guesses Remaining: ${status.guessesRemaining(word, guesses)}`
10 | }
11 | }
12 |
13 | export default function statusDisplay(word, guesses) {
14 | return `${getMessage(word, guesses)}
`
15 | }
16 |
--------------------------------------------------------------------------------
/Unit_4/Lesson_22_Capstone/final/src/words.js:
--------------------------------------------------------------------------------
1 | function getWords(cb) {
2 | cb(['bacon', 'teacher', 'automobile'])
3 | }
4 |
5 | export default function getRandomWord(cb) {
6 | getWords(words => {
7 | const randomWord = words[Math.floor(Math.random() * words.length)]
8 | cb(randomWord.toUpperCase())
9 | })
10 | }
11 |
--------------------------------------------------------------------------------
/Unit_4/Lesson_22_Capstone/start/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["transform-es2015-modules-commonjs"],
3 | "sourceMaps": "inline"
4 | }
5 |
--------------------------------------------------------------------------------
/Unit_4/Lesson_22_Capstone/start/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/Unit_4/Lesson_22_Capstone/start/dest/build.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jisaacks/get-programming-jsnext/d80df37207a6bc4df74b9e81413cd9ee45df0bb7/Unit_4/Lesson_22_Capstone/start/dest/build.js
--------------------------------------------------------------------------------
/Unit_4/Lesson_22_Capstone/start/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Hangman
6 |
52 |
53 |
54 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/Unit_4/Lesson_22_Capstone/start/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "modules-hangman",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "build": "browserify -t [ babelify ] ./src -o ./dest/build.js"
9 | },
10 | "keywords": [],
11 | "author": "",
12 | "license": "ISC",
13 | "devDependencies": {
14 | "babel-plugin-transform-es2015-modules-commonjs": "^6.18.0",
15 | "babelify": "^7.3.0"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Unit_4/Lesson_22_Capstone/start/src/index.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jisaacks/get-programming-jsnext/d80df37207a6bc4df74b9e81413cd9ee45df0bb7/Unit_4/Lesson_22_Capstone/start/src/index.js
--------------------------------------------------------------------------------
/Unit_5/Lesson_23/comparing_of_in.js:
--------------------------------------------------------------------------------
1 | const obj = { series: "Get Programming", publisher: "Manning" };
2 | const arr = [ "Get Programming", "Manning" ];
3 |
4 | for (const name in obj) {
5 | console.log(name);
6 | }
7 |
8 | for (const name of arr) {
9 | console.log(name);
10 | }
11 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_23/html_safe.js:
--------------------------------------------------------------------------------
1 | function interlace(strs, vals, processer=String) {
2 | vals = [ ...vals ];
3 | return strs.reduce((all, str) => {
4 | return all + processer(vals.shift()) + str;
5 | });
6 | }
7 |
8 | const htmlSafe = (strs, ...vals) => interlace(strs, vals, htmlEscape);
9 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_23/list_friends.js:
--------------------------------------------------------------------------------
1 | function* listFriends(friends) {
2 | const [first, second, ...others] = friends
3 | if (first) yield first
4 | if (second) yield second
5 | if (others.length === 1) yield others[0]
6 | if (others.length > 1) yield `${others.length} others`
7 | }
8 |
9 | const friends = ['JD', 'Christina', 'Talan', 'Jonathan']
10 |
11 | const friendsList = [ ...listFriends(friends) ]
12 |
13 | const liked = `${sentenceJoin(friendsList)} liked this.`
14 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_23/primes.js:
--------------------------------------------------------------------------------
1 | // function primesIterator () {
2 | // const primes = [2, 3, 5]
3 | // return {
4 | // next() {
5 | // const value = primes.shift()
6 | // const done = !value
7 | // return {
8 | // value,
9 | // done
10 | // }
11 | // }
12 | // }
13 | // }
14 |
15 | function* primesIterator () {
16 | yield 2
17 | yield 3
18 | yield 5
19 | }
20 |
21 | const primesIterable = {
22 | [Symbol.iterator]: primesIterator
23 | }
24 |
25 | const myPrimes = [ ...primesIterable ]
26 |
27 | [ ...primesIterator() ]
28 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_23/reverse.js:
--------------------------------------------------------------------------------
1 | myArray[Symbol.iterator] = function* () {
2 | const copy = [ ...this ]; <1>
3 | copy.reverse();
4 | for (const item of copy) yield item;
5 | }
6 | const backwards = [ ...myArray ]
7 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_23/spread.js:
--------------------------------------------------------------------------------
1 | const surname = "Isaacks";
2 | const letters = [ ...surname ];
3 | console.log(letters);
4 |
5 | const easyAs = [ ...'123', 'ABC' ];
6 | console.log(easyAs);
7 |
8 |
9 | const vowels = ['A', 'E', 'I', 'O', 'U'];
10 | const consonants = 'BCDFGHJKLMNPQRSTVWXYZ';
11 |
12 | const alphabet = [ ...vowels, ...consonants ].sort();
13 |
14 | console.log(alphabet.length);
15 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_23/words.js:
--------------------------------------------------------------------------------
1 | const myString = Object("Iterables are quite something");
2 | myString[Symbol.iterator] = function* () {
3 | for (const word of this.split(' ')) yield word;
4 | }
5 | const words = [ ...myString ]
6 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_23/yield_all.js:
--------------------------------------------------------------------------------
1 | function* yieldAll(...values) {
2 | for (const val of values) {
3 | yield val
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_24/set_utils.js:
--------------------------------------------------------------------------------
1 | function pop(set) {
2 | const last = [ ...set ].pop();
3 | set.delete(last);
4 | return last;
5 | }
6 |
7 | function shift(set) {
8 | const first = [ ...set ].shift();
9 | set.delete(first);
10 | return first;
11 | }
12 |
13 | function sendFirstToBack(set) {
14 | const arr = [ ...set ];
15 | arr.push( arr.shift() );
16 | return new Set(arr);
17 | }
18 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_25/obj_to_map.js:
--------------------------------------------------------------------------------
1 | const myObj = { foo: 'bar' }
2 | const myMap = new Map(Object.keys(myObj).map(key => [ key, myObj[key] ]))
3 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_25/singleton.js:
--------------------------------------------------------------------------------
1 | const instances = new Map();
2 | export default function Singleton(constructor) {
3 | if (!instances.has(constructor)) {
4 | instances.set(constructor, new constructor());
5 | }
6 | return instances.get(constructor);
7 | }
8 |
9 | console.log(Singleton(Array))
10 | console.log(Singleton(Array).length)
11 | console.log(Singleton(Array).push("new value"))
12 | console.log(Singleton(Array).push("another value"))
13 | console.log(Singleton(Array).length)
14 | const now = Singleton(Date)
15 | setTimeout(() => {
16 | const later = Singleton(Date)
17 | console.log(now === later)
18 | }, 10000)
19 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_26_Capstone/final/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["transform-es2015-modules-commonjs"],
3 | "presets": ["stage-3"],
4 | "sourceMaps": "inline"
5 | }
6 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_26_Capstone/final/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_26_Capstone/final/dest/build.js:
--------------------------------------------------------------------------------
1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0) {
32 | idx--;
33 | const swap = Math.floor(Math.random() * cards.length);
34 | const card = cards[swap];
35 | cards[swap] = cards[idx];
36 | cards[idx] = card;
37 | }
38 | deck.clear();
39 | cards.forEach(card => deck.add(card));
40 | }
41 |
42 | function pop(deck) {
43 | const card = [...deck].pop();
44 | isCardFlipped.set(card, true);
45 | deck.delete(card);
46 | return card;
47 | }
48 |
49 | function createDeck() {
50 | const deck = new Set();
51 | for (const suit of suits) {
52 | for (const face of faces) {
53 | deck.add({ face, suit });
54 | }
55 | }
56 | shuffle(deck);
57 | return deck;
58 | }
59 |
60 | function dealInitialHand(hand, deck) {
61 | hand.add(pop(deck));
62 | hand.add(pop(deck));
63 | }
64 |
65 | function countHand(hand) {
66 | let count = 0;
67 | const aces = new Set();
68 | for (const card of hand) {
69 | const { face } = card;
70 | if (face === 'A') {
71 | count += 1;
72 | aces.add(card);
73 | } else {
74 | count += faceValues.get(face);
75 | }
76 | }
77 | for (const card of aces) {
78 | if (count <= 11) {
79 | count += 10;
80 | }
81 | }
82 | return count;
83 | }
84 |
85 | },{}],2:[function(require,module,exports){
86 | 'use strict';
87 |
88 | Object.defineProperty(exports, "__esModule", {
89 | value: true
90 | });
91 | exports.buttonsEl = exports.playerEl = exports.dealerEl = undefined;
92 | exports.render = render;
93 | exports.addCard = addCard;
94 | exports.updateLabel = updateLabel;
95 | exports.status = status;
96 |
97 | var _templates = require('./templates');
98 |
99 | var _cards = require('./cards');
100 |
101 | const app = document.querySelector('#blackjack');
102 | const statusEl = app.querySelector('.status');
103 |
104 | const dealerEl = exports.dealerEl = app.querySelector('.dealer');
105 | const playerEl = exports.playerEl = app.querySelector('.player');
106 | const buttonsEl = exports.buttonsEl = app.querySelector('.buttons');
107 |
108 | function domNode(str) {
109 | var template = document.createElement('template');
110 | template.innerHTML = str;
111 | return template.content.firstChild;
112 | }
113 |
114 | function render(element, hand) {
115 | element.querySelector('.hand').innerHTML = [...hand].map(_templates.cardTemplate).join('');
116 | element.querySelector('.score').innerHTML = (0, _cards.countHand)(hand);
117 | updateLabel(element, hand);
118 | }
119 |
120 | function addCard(element, hand, card) {
121 | hand.add(card);
122 | const cardNode = domNode((0, _templates.cardTemplate)(card));
123 | element.querySelector('.hand').classList.add("adding");
124 | element.querySelector('.hand').appendChild(cardNode);
125 | element.querySelector('.score').innerHTML = (0, _cards.countHand)(hand);
126 | setTimeout(() => element.querySelector('.hand').classList.remove("adding"), 10);
127 | }
128 |
129 | function updateLabel(element, hand) {
130 | const scoreEl = element.querySelector('.score');
131 | const score = (0, _cards.countHand)(hand);
132 | if (score > 21) {
133 | scoreEl.classList.add('bust');
134 | } else if (score === 21) {
135 | scoreEl.classList.add('blackjack');
136 | }
137 | }
138 |
139 | function status(msg) {
140 | statusEl.classList.remove('hidden');
141 | statusEl.innerHTML = msg;
142 | }
143 |
144 | },{"./cards":1,"./templates":3}],3:[function(require,module,exports){
145 | 'use strict';
146 |
147 | Object.defineProperty(exports, "__esModule", {
148 | value: true
149 | });
150 | exports.cardTemplate = undefined;
151 |
152 | var _cards = require('./cards');
153 |
154 | function suitIcon(card) {
155 | const Spades = '\u2660';
156 | const Clubs = '\u2663';
157 | const Diamonds = '\u2666';
158 | const Hearts = '\u2665';
159 | return { Spades, Clubs, Diamonds, Hearts }[card.suit];
160 | }
161 |
162 | function getCssClass(card) {
163 | return `
164 | card
165 | ${ card.suit.toLowerCase() }
166 | ${ _cards.isCardFlipped.get(card) && 'flipped' }
167 | `;
168 | }
169 |
170 | const cardTemplate = exports.cardTemplate = card => `
172 |
\uD83D\uDC09
173 |
174 | ${ card.face }
175 |
176 |
`;
177 |
178 | },{"./cards":1}],4:[function(require,module,exports){
179 | "use strict";
180 |
181 | Object.defineProperty(exports, "__esModule", {
182 | value: true
183 | });
184 | exports.wait = wait;
185 | function wait(iterator, milliseconds, callback) {
186 | const int = setInterval(() => {
187 | const { done } = iterator.next();
188 | if (done) {
189 | clearInterval(int);
190 | callback();
191 | }
192 | }, milliseconds);
193 | }
194 |
195 | },{}],5:[function(require,module,exports){
196 | 'use strict';
197 |
198 | var _templates = require('./templates');
199 |
200 | var _utils = require('./utils');
201 |
202 | var _elements = require('./elements');
203 |
204 | var _cards = require('./cards');
205 |
206 | const deck = (0, _cards.createDeck)();
207 |
208 | const dealerHand = new Set();
209 | (0, _cards.dealInitialHand)(dealerHand, deck);
210 | (0, _cards.flipCardDown)([...dealerHand][0]);
211 |
212 | const playerHand = new Set();
213 | (0, _cards.dealInitialHand)(playerHand, deck);
214 |
215 | (0, _elements.render)(_elements.dealerEl, dealerHand);
216 | (0, _elements.render)(_elements.playerEl, playerHand);
217 |
218 | function* dealerPlay() {
219 | _elements.dealerEl.querySelector('.card').classList.add("flipped");
220 | // keep hitting until you at least tie
221 | while ((0, _cards.countHand)(dealerHand) < (0, _cards.countHand)(playerHand)) {
222 | (0, _elements.addCard)(_elements.dealerEl, dealerHand, (0, _cards.pop)(deck));
223 | yield;
224 | }
225 | // if tied but less than 17, hit again for the win
226 | if ((0, _cards.countHand)(dealerHand) === (0, _cards.countHand)(playerHand)) {
227 | if ((0, _cards.countHand)(dealerHand) < 17) {
228 | (0, _elements.addCard)(_elements.dealerEl, dealerHand, (0, _cards.pop)(deck));
229 | yield;
230 | }
231 | }
232 | }
233 |
234 | function dealerTurn(callback) {
235 | (0, _utils.wait)(dealerPlay(), 1000, callback);
236 | }
237 |
238 | function hit() {
239 | (0, _elements.addCard)(_elements.playerEl, playerHand, (0, _cards.pop)(deck));
240 | (0, _elements.updateLabel)(_elements.playerEl, playerHand);
241 | const score = (0, _cards.countHand)(playerHand);
242 | if (score > 21) {
243 | _elements.buttonsEl.classList.add('hidden');
244 | (0, _elements.status)('Bust!');
245 | } else if (score === 21) {
246 | stay();
247 | }
248 | }
249 |
250 | function stay() {
251 | _elements.buttonsEl.classList.add('hidden');
252 | _elements.dealerEl.querySelector('.score').classList.remove('hidden');
253 | dealerTurn(() => {
254 | (0, _elements.updateLabel)(_elements.dealerEl, dealerHand);
255 | const dealerScore = (0, _cards.countHand)(dealerHand);
256 | const playerScore = (0, _cards.countHand)(playerHand);
257 | if (dealerScore > 21 || dealerScore < playerScore) {
258 | (0, _elements.status)('You win!');
259 | } else if (dealerScore === playerScore) {
260 | (0, _elements.status)('Push.');
261 | } else {
262 | (0, _elements.status)('Dealer wins!');
263 | }
264 | });
265 | }
266 |
267 | document.querySelector('.hit-me').addEventListener('click', hit);
268 | document.querySelector('.stay').addEventListener('click', stay);
269 |
270 | },{"./cards":1,"./elements":2,"./templates":3,"./utils":4}]},{},[5]);
271 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_26_Capstone/final/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
157 |
158 |
159 |
160 |
nbsp;
161 |
165 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_26_Capstone/final/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "blackjack",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "build": "browserify -t [ babelify ] ./src -o ./dest/build.js"
9 | },
10 | "author": "",
11 | "license": "ISC",
12 | "devDependencies": {
13 | "babel-plugin-transform-es2015-modules-commonjs": "^6.18.0",
14 | "babel-preset-stage-3": "^6.17.0",
15 | "babelify": "^7.3.0"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_26_Capstone/final/src/cards.js:
--------------------------------------------------------------------------------
1 | const suits = new Set(['Spades', 'Clubs', 'Diamonds', 'Hearts']);
2 | const faces = new Set([
3 | '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A'
4 | ]);
5 | const faceValues = new Map([
6 | ['2', 2], ['3', 3], ['4', 4], ['5', 5], ['6', 6], ['7', 7], ['8', 8],
7 | ['9', 9], ['10', 10], ['J', 10], ['Q', 10], ['K', 10]
8 | ]);
9 |
10 | export const isCardFlipped = new Map();
11 |
12 | export function flipCardUp(card) {
13 | isCardFlipped.set(card, true);
14 | }
15 |
16 | export function flipCardDown(card) {
17 | isCardFlipped.set(card, false);
18 | }
19 |
20 | export function shuffle(deck) {
21 | const cards = [ ...deck ];
22 | let idx = cards.length;
23 | while (idx > 0) {
24 | idx--
25 | const swap = Math.floor(Math.random() * cards.length);
26 | const card = cards[swap];
27 | cards[swap] = cards[idx];
28 | cards[idx] = card;
29 | }
30 | deck.clear();
31 | cards.forEach(card => deck.add(card));
32 | }
33 |
34 | export function pop(deck) {
35 | const card = [ ...deck ].pop()
36 | isCardFlipped.set(card, true)
37 | deck.delete(card)
38 | return card
39 | }
40 |
41 | export function createDeck() {
42 | const deck = new Set();
43 | for (const suit of suits) {
44 | for (const face of faces) {
45 | deck.add({ face, suit });
46 | }
47 | }
48 | shuffle(deck);
49 | return deck;
50 | }
51 |
52 | export function dealInitialHand(hand, deck) {
53 | hand.add(pop(deck));
54 | hand.add(pop(deck));
55 | }
56 |
57 | export function countHand(hand) {
58 | let count = 0;
59 | const aces = new Set();
60 | for (const card of hand) {
61 | const { face } = card;
62 | if (face === 'A') {
63 | count += 1;
64 | aces.add(card);
65 | } else {
66 | count += faceValues.get(face);
67 | }
68 | }
69 | for (const card of aces) {
70 | if (count <= 11) {
71 | count += 10;
72 | }
73 | }
74 | return count;
75 | }
76 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_26_Capstone/final/src/elements.js:
--------------------------------------------------------------------------------
1 | import { cardTemplate } from './templates';
2 | import { countHand } from './cards';
3 |
4 | const app = document.querySelector('#blackjack');
5 | const statusEl = app.querySelector('.status');
6 |
7 | export const dealerEl = app.querySelector('.dealer');
8 | export const playerEl = app.querySelector('.player');
9 | export const buttonsEl = app.querySelector('.buttons');
10 |
11 | function domNode(str) {
12 | var template = document.createElement('template');
13 | template.innerHTML = str;
14 | return template.content.firstChild;
15 | }
16 |
17 | export function render(element, hand) {
18 | element.querySelector('.hand').innerHTML = [...hand].map(cardTemplate).join('');
19 | element.querySelector('.score').innerHTML = countHand(hand);
20 | updateLabel(element, hand);
21 | }
22 |
23 | export function addCard(element, hand, card) {
24 | hand.add(card);
25 | const cardNode = domNode(cardTemplate(card));
26 | element.querySelector('.hand').classList.add("adding");
27 | element.querySelector('.hand').appendChild(cardNode);
28 | element.querySelector('.score').innerHTML = countHand(hand);
29 | setTimeout(() => element.querySelector('.hand').classList.remove("adding"), 10);
30 | }
31 |
32 | export function updateLabel(element, hand) {
33 | const scoreEl = element.querySelector('.score');
34 | const score = countHand(hand);
35 | if (score > 21) {
36 | scoreEl.classList.add('bust');
37 | } else if (score === 21) {
38 | scoreEl.classList.add('blackjack');
39 | }
40 | }
41 |
42 | export function status(msg) {
43 | statusEl.classList.remove('hidden');
44 | statusEl.innerHTML = msg;
45 | }
46 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_26_Capstone/final/src/index.js:
--------------------------------------------------------------------------------
1 | import { cardTemplate } from './templates';
2 | import { wait } from './utils';
3 |
4 | import {
5 | dealerEl, playerEl, buttonsEl, updateLabel, status, render, addCard
6 | } from './elements';
7 |
8 | import {
9 | createDeck, pop, countHand, dealInitialHand, flipCardDown, flipCardUp
10 | } from './cards';
11 |
12 | const deck = createDeck();
13 |
14 | const dealerHand = new Set();
15 | dealInitialHand(dealerHand, deck);
16 | flipCardDown([ ...dealerHand ][0]);
17 |
18 | const playerHand = new Set();
19 | dealInitialHand(playerHand, deck);
20 |
21 | render(dealerEl, dealerHand);
22 | render(playerEl, playerHand);
23 |
24 | function* dealerPlay() {
25 | dealerEl.querySelector('.card').classList.add("flipped");
26 | // keep hitting until you at least tie
27 | while( countHand(dealerHand) < countHand(playerHand) ) {
28 | addCard(dealerEl, dealerHand, pop(deck));
29 | yield;
30 | }
31 | // if tied but less than 17, hit again for the win
32 | if ( countHand(dealerHand) === countHand(playerHand) ) {
33 | if (countHand(dealerHand) < 17) {
34 | addCard(dealerEl, dealerHand, pop(deck));
35 | yield;
36 | }
37 | }
38 | }
39 |
40 | function dealerTurn(callback) {
41 | wait(dealerPlay(), 1000, callback);
42 | }
43 |
44 | function hit() {
45 | addCard(playerEl, playerHand, pop(deck));
46 | updateLabel(playerEl, playerHand);
47 | const score = countHand(playerHand);
48 | if (score > 21) {
49 | buttonsEl.classList.add('hidden');
50 | status('Bust!');
51 | } else if (score === 21) {
52 | stay();
53 | }
54 | }
55 |
56 | function stay() {
57 | buttonsEl.classList.add('hidden');
58 | dealerEl.querySelector('.score').classList.remove('hidden');
59 | dealerTurn(() => {
60 | updateLabel(dealerEl, dealerHand);
61 | const dealerScore = countHand(dealerHand);
62 | const playerScore = countHand(playerHand);
63 | if (dealerScore > 21 || dealerScore < playerScore) {
64 | status('You win!');
65 | } else if (dealerScore === playerScore) {
66 | status('Push.');
67 | } else {
68 | status('Dealer wins!');
69 | }
70 | });
71 | }
72 |
73 | document.querySelector('.hit-me').addEventListener('click', hit);
74 | document.querySelector('.stay').addEventListener('click', stay);
75 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_26_Capstone/final/src/templates.js:
--------------------------------------------------------------------------------
1 | import { isCardFlipped } from './cards';
2 |
3 | function suitIcon(card) {
4 | const Spades = '\u2660';
5 | const Clubs = '\u2663';
6 | const Diamonds = '\u2666';
7 | const Hearts = '\u2665';
8 | return { Spades, Clubs, Diamonds, Hearts }[card.suit];
9 | }
10 |
11 | function getCssClass(card) {
12 | return `
13 | card
14 | ${card.suit.toLowerCase()}
15 | ${isCardFlipped.get(card) && 'flipped'}
16 | `
17 | }
18 |
19 | export const cardTemplate = card => (
20 | `
22 |
\uD83D\uDC09
23 |
24 | ${card.face}
25 |
26 |
`
27 | );
28 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_26_Capstone/final/src/utils.js:
--------------------------------------------------------------------------------
1 | export function wait(iterator, milliseconds, callback) {
2 | const int = setInterval(() => {
3 | const { done } = iterator.next();
4 | if (done) {
5 | clearInterval(int);
6 | callback();
7 | }
8 | }, milliseconds);
9 | }
10 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_26_Capstone/start/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["transform-es2015-modules-commonjs"],
3 | "presets": ["stage-3"],
4 | "sourceMaps": "inline"
5 | }
6 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_26_Capstone/start/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_26_Capstone/start/dest/build.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jisaacks/get-programming-jsnext/d80df37207a6bc4df74b9e81413cd9ee45df0bb7/Unit_5/Lesson_26_Capstone/start/dest/build.js
--------------------------------------------------------------------------------
/Unit_5/Lesson_26_Capstone/start/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
155 |
156 |
157 |
158 |
nbsp;
159 |
163 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_26_Capstone/start/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "blackjack",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "build": "browserify -t [ babelify ] ./src -o ./dest/build.js"
9 | },
10 | "author": "",
11 | "license": "ISC",
12 | "devDependencies": {
13 | "babel-plugin-transform-es2015-modules-commonjs": "^6.18.0",
14 | "babel-preset-stage-3": "^6.17.0",
15 | "babelify": "^7.3.0"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_26_Capstone/start/src/elements.js:
--------------------------------------------------------------------------------
1 | import { cardTemplate } from './templates';
2 | import { countHand } from './cards';
3 |
4 | const app = document.querySelector('#blackjack');
5 | const statusEl = app.querySelector('.status');
6 |
7 | export const dealerEl = app.querySelector('.dealer');
8 | export const playerEl = app.querySelector('.player');
9 | export const buttonsEl = app.querySelector('.buttons');
10 |
11 | function domNode(str) {
12 | var template = document.createElement('template');
13 | template.innerHTML = str;
14 | return template.content.firstChild;
15 | }
16 |
17 | export function render(element, hand) {
18 | element.querySelector('.hand').innerHTML = [...hand].map(cardTemplate).join('');
19 | element.querySelector('.score').innerHTML = countHand(hand);
20 | updateLabel(element, hand);
21 | }
22 |
23 | export function addCard(element, hand, card) {
24 | hand.add(card);
25 | const cardNode = domNode(cardTemplate(card));
26 | element.querySelector('.hand').classList.add("adding");
27 | element.querySelector('.hand').appendChild(cardNode);
28 | element.querySelector('.score').innerHTML = countHand(hand);
29 | setTimeout(() => element.querySelector('.hand').classList.remove("adding"), 10);
30 | }
31 |
32 | export function updateLabel(element, hand) {
33 | const scoreEl = element.querySelector('.score');
34 | const score = countHand(hand);
35 | if (score > 21) {
36 | scoreEl.classList.add('bust');
37 | } else if (score === 21) {
38 | scoreEl.classList.add('blackjack');
39 | }
40 | }
41 |
42 | export function status(msg) {
43 | statusEl.classList.remove('hidden');
44 | statusEl.innerHTML = msg;
45 | }
46 |
--------------------------------------------------------------------------------
/Unit_5/Lesson_26_Capstone/start/src/templates.js:
--------------------------------------------------------------------------------
1 | import { isCardFlipped } from './cards';
2 |
3 | function suitIcon(card) {
4 | const Spades = '\u2660';
5 | const Clubs = '\u2663';
6 | const Diamonds = '\u2666';
7 | const Hearts = '\u2665';
8 | return { Spades, Clubs, Diamonds, Hearts }[card.suit];
9 | }
10 |
11 | function getCssClass(card) {
12 | return `
13 | card
14 | ${card.suit.toLowerCase()}
15 | ${isCardFlipped.get(card) && 'flipped'}
16 | `
17 | }
18 |
19 | export const cardTemplate = card => (
20 | `
22 |
\uD83D\uDC09
23 |
24 | ${card.face}
25 |
26 |
`
27 | );
28 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_27/fish.js:
--------------------------------------------------------------------------------
1 | function Fish(name) {
2 | this.name = name;
3 | this.hunger = 1;
4 | this.dead = false;
5 | this.born = new Date();
6 | }
7 | Fish.prototype = {
8 | eat(amount=1) {
9 | if (this.dead) {
10 | console.log(`${this.name} is dead and can no longer eat.`);
11 | return;
12 | }
13 | this.hunger -= amount;
14 | if (this.hunger < 0) {
15 | this.dead = true;
16 | console.log(`${this.name} has died from over eating.`)
17 | return
18 | }
19 | },
20 | sleep() {
21 | this.hunger++;
22 | if (this.hunger >= 5) {
23 | this.dead = true;
24 | console.log(`${this.name} has starved.`)
25 | }
26 | },
27 | isHungry: function() {
28 | return this.hunger > 0;
29 | }
30 | }
31 |
32 | const oscar = new Fish('oscar');
33 | console.assert(oscar instanceof Fish);
34 | console.assert(oscar.isHungry());
35 | while(oscar.isHungry()) {
36 | oscar.eat();
37 | }
38 | console.assert(!oscar.isHungry());
39 | console.assert(!oscar.dead);
40 | oscar.eat();
41 | console.assert(oscar.dead);
42 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_28/car.js:
--------------------------------------------------------------------------------
1 | class Car {
2 | constructor() {
3 | this.gas = 50;
4 | this.milage = 0;
5 | }
6 |
7 | hasGas() {
8 | return this.gas > 0;
9 | }
10 |
11 | drive() {
12 | if (this.hasGas()) {
13 | this.milage++;
14 | this.gas--;
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/final/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["transform-es2015-modules-commonjs"],
3 | "presets": ["stage-2"],
4 | "sourceMaps": "inline"
5 | }
6 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/final/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/final/dest/build.js:
--------------------------------------------------------------------------------
1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o new Comet({
56 | x, y, size, speed, removeOnExit,
57 | rotation: r + ninetyDeg * i
58 | }));
59 | this.remove();
60 | }
61 | }
62 | exports.default = Comet;
63 | Comet.stroke = '#73C990';
64 |
65 | },{"./framework/canvas":3,"./framework/drifting_sprite":5,"./framework/game":6,"./framework/utils":10,"./shapes":12}],2:[function(require,module,exports){
66 | 'use strict';
67 |
68 | Object.defineProperty(exports, "__esModule", {
69 | value: true
70 | });
71 |
72 | var _sprite = require('./framework/sprite');
73 |
74 | var _sprite2 = _interopRequireDefault(_sprite);
75 |
76 | var _shapes = require('./shapes');
77 |
78 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
79 |
80 | const START_SIZE = 10;
81 | const END_SIZE = 50;
82 | const SIDES = 8;
83 |
84 | const defaultOptions = {
85 | size: START_SIZE
86 | };
87 |
88 | class Explosion extends _sprite2.default {
89 | constructor(options) {
90 | super(Object.assign({}, defaultOptions, options));
91 | this.shape = (0, _shapes.explosionShape)(this.size, SIDES);
92 | }
93 |
94 | next() {
95 | this.size = this.size * 1.1;
96 | this.shape = (0, _shapes.explosionShape)(this.size, SIDES);
97 | this.fill = `rgba(255, 100, 0, ${ (END_SIZE - this.size) * .005 })`;
98 | this.stroke = `rgba(255, 0, 0, ${ (END_SIZE - this.size) * .1 })`;
99 | if (this.size > END_SIZE) {
100 | this.remove();
101 | }
102 | return this;
103 | }
104 | }
105 | exports.default = Explosion;
106 |
107 | },{"./framework/sprite":9,"./shapes":12}],3:[function(require,module,exports){
108 | 'use strict';
109 |
110 | Object.defineProperty(exports, "__esModule", {
111 | value: true
112 | });
113 | exports.clear = clear;
114 | exports.next = next;
115 | exports.draw = draw;
116 | const canvas = document.querySelector("#canvas");
117 | const ctx = canvas.getContext('2d');
118 |
119 | const CANVAS_WIDTH = exports.CANVAS_WIDTH = canvas.width;
120 | const CANVAS_HEIGHT = exports.CANVAS_HEIGHT = canvas.height;
121 |
122 | function clear() {
123 | ctx.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
124 | }
125 |
126 | function next() {
127 | ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
128 | ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
129 | }
130 |
131 | function draw({ x, y, rotation, shape, fill, stroke }) {
132 | ctx.save();
133 | ctx.translate(x, y);
134 | ctx.rotate(rotation);
135 | ctx.moveTo(shape[0][0], shape[0][1]);
136 | ctx.beginPath();
137 | shape.forEach(([x, y]) => ctx.lineTo(x, y));
138 | ctx.closePath();
139 | if (fill) {
140 | ctx.fillStyle = fill;
141 | ctx.fill();
142 | }
143 | if (stroke) {
144 | ctx.strokeStyle = stroke;
145 | ctx.stroke();
146 | }
147 | ctx.restore();
148 | }
149 |
150 | },{}],4:[function(require,module,exports){
151 | 'use strict';
152 |
153 | Object.defineProperty(exports, "__esModule", {
154 | value: true
155 | });
156 |
157 | var _sprite = require('./sprite');
158 |
159 | var _sprite2 = _interopRequireDefault(_sprite);
160 |
161 | var _canvas = require('./canvas');
162 |
163 | var _interactions = require('./interactions');
164 |
165 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
166 |
167 | const defaultOptions = {
168 | x: _canvas.CANVAS_WIDTH / 2,
169 | y: _canvas.CANVAS_HEIGHT / 2,
170 | rotation: 0,
171 | vr: 0,
172 | vx: 0,
173 | vy: 0
174 | };
175 |
176 | class ControllableSprite extends _sprite2.default {
177 |
178 | constructor(options) {
179 | super(Object.assign({}, defaultOptions, options));
180 | (0, _interactions.registerControllableSprite)(this);
181 | }
182 |
183 | next() {
184 | this.rotation += this.vr;
185 | this.vr *= .95;
186 |
187 | this.x += this.vx;
188 | this.y += this.vy;
189 | this.vx *= .99;
190 | this.vy *= .99;
191 |
192 | return this;
193 | }
194 |
195 | accelerate() {
196 | const dx = Math.cos(this.rotation);
197 | const dy = Math.sin(this.rotation);
198 |
199 | this.vx += dx * .2;
200 | this.vy += dy * .2;
201 | }
202 |
203 | turnCCW() {
204 | if (this.vr > 0) {
205 | this.vr = 0;
206 | }
207 | this.vr = Math.max(this.vr - .03, -.09);
208 | }
209 |
210 | turnCW() {
211 | if (this.vr < 0) {
212 | this.vr = 0;
213 | }
214 | this.vr = Math.min(this.vr + .03, .09);
215 | }
216 |
217 | }
218 | exports.default = ControllableSprite;
219 |
220 | },{"./canvas":3,"./interactions":8,"./sprite":9}],5:[function(require,module,exports){
221 | 'use strict';
222 |
223 | Object.defineProperty(exports, "__esModule", {
224 | value: true
225 | });
226 |
227 | var _sprite = require('./sprite');
228 |
229 | var _sprite2 = _interopRequireDefault(_sprite);
230 |
231 | var _game = require('./game');
232 |
233 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
234 |
235 | class DriftingSprite extends _sprite2.default {
236 |
237 | next() {
238 | const speed = (0, _game.getSpriteProperty)(this, 'speed') || 1;
239 | const rotation = (0, _game.getSpriteProperty)(this, 'rotation') || 0;
240 |
241 | this.x += Math.cos(rotation) * speed;
242 | this.y += Math.sin(rotation) * speed;
243 |
244 | return this;
245 | }
246 |
247 | }
248 | exports.default = DriftingSprite;
249 |
250 | },{"./game":6,"./sprite":9}],6:[function(require,module,exports){
251 | 'use strict';
252 |
253 | Object.defineProperty(exports, "__esModule", {
254 | value: true
255 | });
256 | exports.registerSprite = registerSprite;
257 | exports.unregisterSprite = unregisterSprite;
258 | exports.getSpriteProperty = getSpriteProperty;
259 | exports.getSpriteProperties = getSpriteProperties;
260 | exports.start = start;
261 | exports.stop = stop;
262 |
263 | var _sprite = require('./sprite');
264 |
265 | var _sprite2 = _interopRequireDefault(_sprite);
266 |
267 | var _canvas = require('./canvas');
268 |
269 | var canvas = _interopRequireWildcard(_canvas);
270 |
271 | var _interactions = require('./interactions');
272 |
273 | var interactions = _interopRequireWildcard(_interactions);
274 |
275 | var _hit_test = require('./hit_test');
276 |
277 | var _hit_test2 = _interopRequireDefault(_hit_test);
278 |
279 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
280 |
281 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
282 |
283 | const allSprites = new Set();
284 | const spritesByType = new Map();
285 | let raf;
286 | let gameOver = false;
287 |
288 | function registerSprite(sprite) {
289 | const type = sprite.constructor;
290 |
291 | allSprites.add(sprite);
292 |
293 | let proto = Object.getPrototypeOf(sprite);
294 | while (proto instanceof _sprite2.default) {
295 |
296 | const type = proto.constructor;
297 |
298 | if (!spritesByType.has(type)) {
299 | spritesByType.set(type, new Set());
300 | }
301 |
302 | spritesByType.get(type).add(sprite);
303 |
304 | proto = Object.getPrototypeOf(proto);
305 | }
306 | }
307 |
308 | function unregisterSprite(sprite) {
309 | allSprites.delete(sprite);
310 | for (const set of spritesByType.values()) {
311 | set.delete(sprite);
312 | }
313 | }
314 |
315 | function loopCanvas(sprite) {
316 | if (sprite.x < 0) sprite.x = canvas.CANVAS_WIDTH;
317 | if (sprite.y < 0) sprite.y = canvas.CANVAS_HEIGHT;
318 | if (sprite.x > canvas.CANVAS_WIDTH) sprite.x = 0;
319 | if (sprite.y > canvas.CANVAS_HEIGHT) sprite.y = 0;
320 | }
321 |
322 | function isOutsideCanvas(sprite) {
323 | if (sprite.x < 0) return true;
324 | if (sprite.y < 0) return true;
325 | if (sprite.x > canvas.CANVAS_WIDTH) return true;
326 | if (sprite.y > canvas.CANVAS_HEIGHT) return true;
327 | return false;
328 | }
329 |
330 | function getObjectProperty(obj, name) {
331 | const prop = obj[name];
332 | if (typeof prop === 'function') {
333 | return obj[name]();
334 | } else {
335 | return prop;
336 | }
337 | }
338 |
339 | function getSpriteProperty(sprite, name) {
340 | const obj = sprite[name] ? sprite : sprite.constructor;
341 | return getObjectProperty(obj, name);
342 | }
343 |
344 | function getSpriteProperties(sprite, names) {
345 | return names.map(name => getSpriteProperty(sprite, name));
346 | }
347 |
348 | function colliding(spriteA, spriteB) {
349 | if (spriteA === spriteB) return false;
350 | return (0, _hit_test2.default)({
351 | x: getSpriteProperty(spriteA, 'x'),
352 | y: getSpriteProperty(spriteA, 'y'),
353 | shape: getSpriteProperty(spriteA, 'shape')
354 | }, {
355 | x: getSpriteProperty(spriteB, 'x'),
356 | y: getSpriteProperty(spriteB, 'y'),
357 | shape: getSpriteProperty(spriteB, 'shape')
358 | });
359 | }
360 |
361 | function draw(sprite) {
362 |
363 | const collidesWith = getSpriteProperty(sprite, 'collidesWith');
364 | if (collidesWith) {
365 | searching: for (const type of collidesWith) {
366 | const set = type === _sprite2.default ? allSprites : spritesByType.get(type);
367 | for (const instance of set || new Set()) {
368 | if (colliding(sprite, instance)) {
369 | sprite.collision(instance);
370 | break searching;
371 | }
372 | }
373 | }
374 | }
375 |
376 | if (isOutsideCanvas(sprite)) {
377 | if (getSpriteProperty(sprite, 'removeOnExit')) {
378 | unregisterSprite(sprite);
379 | return;
380 | } else {
381 | loopCanvas(sprite);
382 | }
383 | }
384 |
385 | const props = 'x y rotation shape fill stroke'.split(' ');
386 | const [x, y, rotation, shape, fill, stroke] = getSpriteProperties(sprite, props);
387 |
388 | canvas.draw({ x, y, rotation, shape, fill, stroke });
389 | }
390 |
391 | function frame() {
392 | if (gameOver) return;
393 |
394 | canvas.next();
395 |
396 | interactions.next();
397 |
398 | allSprites.forEach(sprite => draw(sprite.next()));
399 |
400 | raf = window.requestAnimationFrame(frame);
401 | }
402 |
403 | function start() {
404 | canvas.clear();
405 | interactions.start();
406 |
407 | raf = window.requestAnimationFrame(frame);
408 | }
409 |
410 | function stop() {
411 | console.log('Game Over');
412 | gameOver = true;
413 | interactions.stop();
414 | window.cancelAnimationFrame(raf);
415 | }
416 |
417 | },{"./canvas":3,"./hit_test":7,"./interactions":8,"./sprite":9}],7:[function(require,module,exports){
418 | "use strict";
419 |
420 | Object.defineProperty(exports, "__esModule", {
421 | value: true
422 | });
423 | exports.default = hitTest;
424 | function squareBounds(shape) {
425 | const xPoints = shape.shape.map(([x, y]) => x);
426 | const yPoints = shape.shape.map(([x, y]) => y);
427 | return {
428 | top: shape.y + Math.min(...yPoints),
429 | bottom: shape.y + Math.max(...yPoints),
430 | left: shape.x + Math.min(...xPoints),
431 | right: shape.x + Math.max(...xPoints)
432 | };
433 | }
434 |
435 | function intersects(a, b) {
436 | if (a.left > b.right || b.left > a.right) return false;
437 |
438 | if (a.bottom < b.top || b.bottom < a.top) return false;
439 |
440 | return true;
441 | }
442 |
443 | function hitTest(a, b) {
444 | return intersects(squareBounds(a), squareBounds(b));
445 | }
446 |
447 | },{}],8:[function(require,module,exports){
448 | 'use strict';
449 |
450 | Object.defineProperty(exports, "__esModule", {
451 | value: true
452 | });
453 | exports.registerControllableSprite = registerControllableSprite;
454 | exports.next = next;
455 | exports.isPressingSpace = isPressingSpace;
456 | exports.start = start;
457 | exports.stop = stop;
458 |
459 | var _utils = require('./utils');
460 |
461 | const SPACE = 32;
462 | const UP = 38;
463 | const LEFT = 37;
464 | const RIGHT = 39;
465 |
466 | const actions = {
467 | [SPACE]: false,
468 | [UP]: false,
469 | [LEFT]: false,
470 | [RIGHT]: false
471 | };
472 |
473 | const constrolledSprites = new Set();
474 |
475 | function registerControllableSprite(sprite) {
476 | constrolledSprites.add(sprite);
477 | }
478 |
479 | function handleKeyDown(event) {
480 | actions[event.keyCode] = true;
481 | }
482 |
483 | function handleKeyUp(event) {
484 | actions[event.keyCode] = false;
485 | }
486 |
487 | const delay = method => (0, _utils.throttle)(() => {
488 | for (const sprite of constrolledSprites) {
489 | sprite[method]();
490 | }
491 | });
492 |
493 | const accelerate = delay('accelerate');
494 | const turnCCW = delay('turnCCW');
495 | const turnCW = delay('turnCW');
496 |
497 | function next() {
498 | if (actions[UP]) accelerate();
499 | if (actions[RIGHT]) turnCW();
500 | if (actions[LEFT]) turnCCW();
501 | }
502 |
503 | function isPressingSpace() {
504 | return actions[SPACE];
505 | }
506 |
507 | function start() {
508 | document.addEventListener('keydown', handleKeyDown);
509 | document.addEventListener('keyup', handleKeyUp);
510 | }
511 |
512 | function stop() {
513 | document.removeEventListener('keydown', handleKeyDown);
514 | document.removeEventListener('keyup', handleKeyUp);
515 | }
516 |
517 | },{"./utils":10}],9:[function(require,module,exports){
518 | 'use strict';
519 |
520 | Object.defineProperty(exports, "__esModule", {
521 | value: true
522 | });
523 |
524 | var _canvas = require('./canvas');
525 |
526 | var _game = require('./game');
527 |
528 | function defaultOptions() {
529 | const x = Math.random() * _canvas.CANVAS_WIDTH;
530 | const y = Math.random() * _canvas.CANVAS_HEIGHT;
531 | const rotation = Math.random() * (Math.PI * 2);
532 | }
533 |
534 | class Sprite {
535 |
536 | constructor(options) {
537 | Object.assign(this, defaultOptions(), options);
538 | (0, _game.registerSprite)(this);
539 | }
540 |
541 | remove() {
542 | (0, _game.unregisterSprite)(this);
543 | }
544 |
545 | next() {
546 | return this;
547 | }
548 | collision() {}
549 |
550 | }
551 | exports.default = Sprite;
552 |
553 | },{"./canvas":3,"./game":6}],10:[function(require,module,exports){
554 | "use strict";
555 |
556 | Object.defineProperty(exports, "__esModule", {
557 | value: true
558 | });
559 | exports.range = range;
560 | exports.throttle = throttle;
561 | function range(length) {
562 | return Array.from({ length }, (x, i) => i);
563 | }
564 |
565 | function throttle(fn) {
566 | let count = 0;
567 | return (...args) => {
568 | count++;
569 | if (count >= 5) {
570 | count = 0;
571 | fn(...args);
572 | }
573 | };
574 | }
575 |
576 | },{}],11:[function(require,module,exports){
577 | 'use strict';
578 |
579 | Object.defineProperty(exports, "__esModule", {
580 | value: true
581 | });
582 |
583 | var _drifting_sprite = require('./framework/drifting_sprite');
584 |
585 | var _drifting_sprite2 = _interopRequireDefault(_drifting_sprite);
586 |
587 | var _game = require('./framework/game');
588 |
589 | var _explosion = require('./explosion');
590 |
591 | var _explosion2 = _interopRequireDefault(_explosion);
592 |
593 | var _shapes = require('./shapes');
594 |
595 | var _comet = require('./comet');
596 |
597 | var _comet2 = _interopRequireDefault(_comet);
598 |
599 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
600 |
601 | class Rocket extends _drifting_sprite2.default {
602 |
603 | collision(target) {
604 | new _explosion2.default({
605 | x: (0, _game.getSpriteProperty)(this, 'x'),
606 | y: (0, _game.getSpriteProperty)(this, 'y')
607 | });
608 | target.multiply();
609 | this.remove();
610 | }
611 | }
612 | exports.default = Rocket;
613 | Rocket.shape = _shapes.rocket;
614 | Rocket.fill = '#1AC2FB';
615 | Rocket.removeOnExit = true;
616 | Rocket.speed = 5;
617 | Rocket.collidesWith = [_comet2.default];
618 |
619 | },{"./comet":1,"./explosion":2,"./framework/drifting_sprite":5,"./framework/game":6,"./shapes":12}],12:[function(require,module,exports){
620 | "use strict";
621 |
622 | Object.defineProperty(exports, "__esModule", {
623 | value: true
624 | });
625 | exports.cometShape = cometShape;
626 | exports.explosionShape = explosionShape;
627 | const ship = exports.ship = [[10, 0], [-10, -5], [-7, 0], [-10, 5], [10, 0]];
628 |
629 | const rocket = exports.rocket = [[10, 0], [0, -5], [0, 5], [10, 0]];
630 |
631 | const ufo = exports.ufo = [[-20, 0], [-5, -5], [-5, -10], [5, -10], [5, -5], [20, 0], [5, 10], [-5, 10], [-20, 0]];
632 |
633 | function cometShape(size, sides) {
634 | const points = [];
635 | for (let i = 0; i < 2; i += 2 / sides) {
636 | const distance = size + Math.random() * 6 - 3;
637 | points.push([Math.cos(Math.PI * i) * distance, Math.sin(Math.PI * i) * distance]);
638 | }
639 |
640 | return points;
641 | }
642 |
643 | function explosionShape(size, sides) {
644 | const points = [];
645 | let point = 0;
646 | for (let i = 0; i < 2; i += 1 / sides) {
647 | const distance = point % 2 ? size : size / 2;
648 | points.push([Math.cos(Math.PI * i) * distance, Math.sin(Math.PI * i) * distance]);
649 | point++;
650 | }
651 |
652 | return points;
653 | }
654 |
655 | },{}],13:[function(require,module,exports){
656 | 'use strict';
657 |
658 | Object.defineProperty(exports, "__esModule", {
659 | value: true
660 | });
661 |
662 | var _controllable_sprite = require('./framework/controllable_sprite');
663 |
664 | var _controllable_sprite2 = _interopRequireDefault(_controllable_sprite);
665 |
666 | var _game = require('./framework/game');
667 |
668 | var _interactions = require('./framework/interactions');
669 |
670 | var _utils = require('./framework/utils');
671 |
672 | var _shapes = require('./shapes');
673 |
674 | var _comet = require('./comet');
675 |
676 | var _comet2 = _interopRequireDefault(_comet);
677 |
678 | var _rocket = require('./rocket');
679 |
680 | var _rocket2 = _interopRequireDefault(_rocket);
681 |
682 | var _explosion = require('./explosion');
683 |
684 | var _explosion2 = _interopRequireDefault(_explosion);
685 |
686 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
687 |
688 | class Ship extends _controllable_sprite2.default {
689 | constructor(...args) {
690 | var _temp;
691 |
692 | return _temp = super(...args), this.fire = (0, _utils.throttle)(() => {
693 | const x = (0, _game.getSpriteProperty)(this, 'x');
694 | const y = (0, _game.getSpriteProperty)(this, 'y');
695 | const rotation = (0, _game.getSpriteProperty)(this, 'rotation');
696 |
697 | new _rocket2.default({ x, y, rotation });
698 | }), _temp;
699 | }
700 |
701 | collision() {
702 | new _explosion2.default({
703 | x: (0, _game.getSpriteProperty)(this, 'x'),
704 | y: (0, _game.getSpriteProperty)(this, 'y')
705 | });
706 |
707 | this.remove();
708 |
709 | setTimeout(_game.stop, 500);
710 | }
711 |
712 | next() {
713 | super.next();
714 |
715 | if ((0, _interactions.isPressingSpace)()) {
716 | this.fire();
717 | }
718 |
719 | return this;
720 | }
721 | }
722 | exports.default = Ship;
723 | Ship.shape = _shapes.ship;
724 | Ship.stroke = '#fff';
725 | Ship.collidesWith = [_comet2.default];
726 |
727 | },{"./comet":1,"./explosion":2,"./framework/controllable_sprite":4,"./framework/game":6,"./framework/interactions":8,"./framework/utils":10,"./rocket":11,"./shapes":12}],14:[function(require,module,exports){
728 | 'use strict';
729 |
730 | var _game = require('./framework/game');
731 |
732 | var _ship = require('./ship');
733 |
734 | var _ship2 = _interopRequireDefault(_ship);
735 |
736 | var _comet = require('./comet');
737 |
738 | var _comet2 = _interopRequireDefault(_comet);
739 |
740 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
741 |
742 | new _ship2.default();
743 |
744 | new _comet2.default();
745 | new _comet2.default();
746 | new _comet2.default();
747 |
748 | (0, _game.start)();
749 |
750 | },{"./comet":1,"./framework/game":6,"./ship":13}]},{},[14]);
751 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/final/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/final/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "canvas-ship",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "build": "browserify -t [ babelify ] ./src -o ./dest/build.js"
9 | },
10 | "author": "",
11 | "license": "ISC",
12 | "devDependencies": {
13 | "babel-plugin-transform-es2015-modules-commonjs": "^6.18.0",
14 | "babel-preset-stage-2": "^6.17.0",
15 | "babelify": "^7.3.0"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/final/src/comet.js:
--------------------------------------------------------------------------------
1 | import { CANVAS_WIDTH, CANVAS_HEIGHT } from './framework/canvas';
2 | import DriftingSprite from './framework/drifting_sprite';
3 | import { cometShape } from './shapes'
4 | import { getSpriteProperty } from './framework/game';
5 | import { range } from './framework/utils';
6 |
7 | function defaultOptions() {
8 | return {
9 | size: 20,
10 | sides: 20,
11 | speed: 1,
12 | x: Math.random() * CANVAS_WIDTH,
13 | y: Math.random() * CANVAS_HEIGHT,
14 | rotation: Math.random() * (Math.PI * 2)
15 | }
16 | }
17 |
18 | export default class Comet extends DriftingSprite {
19 | static stroke = '#73C990';
20 |
21 | constructor(options) {
22 | super(Object.assign({}, defaultOptions(), options));
23 | this.shape = cometShape(this.size, this.sides);
24 | }
25 |
26 | multiply() {
27 | const x = getSpriteProperty(this, 'x');
28 | const y = getSpriteProperty(this, 'y');
29 | let size = getSpriteProperty(this, 'size');
30 | let speed = getSpriteProperty(this, 'speed');
31 |
32 | if (size < 5) {
33 | this.remove();
34 | return;
35 | }
36 | size /= 2;
37 | speed *= 1.5;
38 | const removeOnExit = size < 5;
39 | const r = Math.random() * Math.PI;
40 | const ninetyDeg = Math.PI/2;
41 | range(4).forEach(i => new Comet({
42 | x, y, size, speed, removeOnExit,
43 | rotation: r + ninetyDeg * i,
44 | }))
45 | this.remove();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/final/src/explosion.js:
--------------------------------------------------------------------------------
1 | import Sprite from './framework/sprite';
2 | import { explosionShape } from './shapes';
3 |
4 | const START_SIZE = 10;
5 | const END_SIZE = 50;
6 | const SIDES = 8;
7 |
8 | const defaultOptions = {
9 | size: START_SIZE
10 | }
11 |
12 | export default class Explosion extends Sprite {
13 | constructor(options) {
14 | super(Object.assign({}, defaultOptions, options));
15 | this.shape = explosionShape(this.size, SIDES);
16 | }
17 |
18 | next() {
19 | this.size = this.size * 1.1;
20 | this.shape = explosionShape(this.size, SIDES);
21 | this.fill = `rgba(255, 100, 0, ${(END_SIZE-this.size)*.005})`
22 | this.stroke = `rgba(255, 0, 0, ${(END_SIZE-this.size)*.1})`
23 | if (this.size > END_SIZE) {
24 | this.remove();
25 | }
26 | return this;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/final/src/framework/canvas.js:
--------------------------------------------------------------------------------
1 | const canvas = document.querySelector("#canvas");
2 | const ctx = canvas.getContext('2d');
3 |
4 | export const CANVAS_WIDTH = canvas.width;
5 | export const CANVAS_HEIGHT = canvas.height;
6 |
7 | export function clear() {
8 | ctx.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
9 | }
10 |
11 | export function next() {
12 | ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
13 | ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
14 | }
15 |
16 | export function draw({x, y, rotation, shape, fill, stroke}) {
17 | ctx.save();
18 | ctx.translate(x, y);
19 | ctx.rotate(rotation);
20 | ctx.moveTo(shape[0][0], shape[0][1]);
21 | ctx.beginPath();
22 | shape.forEach(([x, y]) => ctx.lineTo(x, y));
23 | ctx.closePath();
24 | if (fill) {
25 | ctx.fillStyle = fill;
26 | ctx.fill();
27 | }
28 | if (stroke) {
29 | ctx.strokeStyle = stroke;
30 | ctx.stroke();
31 | }
32 | ctx.restore();
33 | }
34 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/final/src/framework/controllable_sprite.js:
--------------------------------------------------------------------------------
1 | import Sprite from './sprite';
2 | import { CANVAS_WIDTH, CANVAS_HEIGHT } from './canvas';
3 | import { registerControllableSprite } from './interactions';
4 |
5 | const defaultOptions = {
6 | x: CANVAS_WIDTH/2,
7 | y: CANVAS_HEIGHT/2,
8 | rotation: 0,
9 | vr: 0,
10 | vx: 0,
11 | vy: 0
12 | };
13 |
14 | export default class ControllableSprite extends Sprite {
15 |
16 | constructor(options) {
17 | super(Object.assign({}, defaultOptions, options));
18 | registerControllableSprite(this);
19 | }
20 |
21 | next() {
22 | this.rotation += this.vr;
23 | this.vr *= .95;
24 |
25 | this.x += this.vx;
26 | this.y += this.vy;
27 | this.vx *= .99;
28 | this.vy *= .99;
29 |
30 | return this;
31 | }
32 |
33 | accelerate() {
34 | const dx = Math.cos( this.rotation );
35 | const dy = Math.sin( this.rotation );
36 |
37 | this.vx += dx * .2;
38 | this.vy += dy * .2;
39 | }
40 |
41 | turnCCW() {
42 | if (this.vr > 0) {
43 | this.vr = 0;
44 | }
45 | this.vr = Math.max(this.vr - .03, -.09);
46 | }
47 |
48 | turnCW() {
49 | if (this.vr < 0) {
50 | this.vr = 0;
51 | }
52 | this.vr = Math.min(this.vr + .03, .09);
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/final/src/framework/drifting_sprite.js:
--------------------------------------------------------------------------------
1 | import Sprite from './sprite';
2 | import { getSpriteProperty } from './game';
3 |
4 | export default class DriftingSprite extends Sprite {
5 |
6 | next() {
7 | const speed = getSpriteProperty(this, 'speed') || 1;
8 | const rotation = getSpriteProperty(this, 'rotation') || 0;
9 |
10 | this.x += Math.cos(rotation) * speed;
11 | this.y += Math.sin(rotation) * speed;
12 |
13 | return this;
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/final/src/framework/game.js:
--------------------------------------------------------------------------------
1 | import Sprite from './sprite';
2 | import * as canvas from './canvas';
3 | import * as interactions from './interactions';
4 | import hitTest from './hit_test';
5 |
6 | const allSprites = new Set();
7 | const spritesByType = new Map();
8 | let raf;
9 | let gameOver = false;
10 |
11 | export function registerSprite(sprite) {
12 | const type = sprite.constructor;
13 |
14 | allSprites.add(sprite);
15 |
16 | let proto = Object.getPrototypeOf(sprite)
17 | while(proto instanceof Sprite) {
18 |
19 | const type = proto.constructor;
20 |
21 | if (!spritesByType.has(type)) {
22 | spritesByType.set(type, new Set());
23 | }
24 |
25 | spritesByType.get(type).add(sprite);
26 |
27 | proto = Object.getPrototypeOf(proto);
28 | }
29 | }
30 |
31 | export function unregisterSprite(sprite) {
32 | allSprites.delete(sprite);
33 | for (const set of spritesByType.values()) {
34 | set.delete(sprite);
35 | }
36 | }
37 |
38 | function loopCanvas(sprite) {
39 | if (sprite.x < 0) sprite.x = canvas.CANVAS_WIDTH;
40 | if (sprite.y < 0) sprite.y = canvas.CANVAS_HEIGHT;
41 | if (sprite.x > canvas.CANVAS_WIDTH) sprite.x = 0;
42 | if (sprite.y > canvas.CANVAS_HEIGHT) sprite.y = 0;
43 | }
44 |
45 | function isOutsideCanvas(sprite) {
46 | if (sprite.x < 0) return true;
47 | if (sprite.y < 0) return true;
48 | if (sprite.x > canvas.CANVAS_WIDTH) return true;
49 | if (sprite.y > canvas.CANVAS_HEIGHT) return true;
50 | return false;
51 | }
52 |
53 | function getObjectProperty(obj, name) {
54 | const prop = obj[name];
55 | if (typeof prop === 'function') {
56 | return obj[name]();
57 | } else {
58 | return prop;
59 | }
60 | }
61 |
62 | export function getSpriteProperty(sprite, name) {
63 | const obj = sprite[name] ? sprite : sprite.constructor;
64 | return getObjectProperty(obj, name);
65 | }
66 |
67 | export function getSpriteProperties(sprite, names) {
68 | return names.map(name => getSpriteProperty(sprite, name));
69 | }
70 |
71 | function colliding(spriteA, spriteB) {
72 | if (spriteA === spriteB) return false;
73 | return hitTest({
74 | x: getSpriteProperty(spriteA, 'x'),
75 | y: getSpriteProperty(spriteA, 'y'),
76 | shape: getSpriteProperty(spriteA, 'shape')
77 | }, {
78 | x: getSpriteProperty(spriteB, 'x'),
79 | y: getSpriteProperty(spriteB, 'y'),
80 | shape: getSpriteProperty(spriteB, 'shape')
81 | });
82 | }
83 |
84 | function draw(sprite) {
85 |
86 | const collidesWith = getSpriteProperty(sprite, 'collidesWith');
87 | if (collidesWith) {
88 | searching: for (const type of collidesWith) {
89 | const set = type === Sprite ? allSprites : spritesByType.get(type);
90 | for (const instance of set || new Set) {
91 | if (colliding(sprite, instance)) {
92 | sprite.collision(instance);
93 | break searching;
94 | }
95 | }
96 | }
97 | }
98 |
99 | if (isOutsideCanvas(sprite)) {
100 | if (getSpriteProperty(sprite, 'removeOnExit')) {
101 | unregisterSprite(sprite);
102 | return;
103 | } else {
104 | loopCanvas(sprite);
105 | }
106 | }
107 |
108 | const props = 'x y rotation shape fill stroke'.split(' ');
109 | const [x, y, rotation, shape, fill, stroke] = getSpriteProperties(sprite, props);
110 |
111 | canvas.draw({ x, y, rotation, shape, fill, stroke });
112 | }
113 |
114 | function frame() {
115 | if (gameOver) return;
116 |
117 | canvas.next();
118 |
119 | interactions.next();
120 |
121 | allSprites.forEach(sprite => draw( sprite.next() ));
122 |
123 | raf = window.requestAnimationFrame(frame);
124 | }
125 |
126 | export function start() {
127 | canvas.clear();
128 | interactions.start();
129 |
130 | raf = window.requestAnimationFrame(frame);
131 | }
132 |
133 | export function stop() {
134 | console.log('Game Over');
135 | gameOver = true;
136 | interactions.stop();
137 | window.cancelAnimationFrame(raf);
138 | }
139 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/final/src/framework/hit_test.js:
--------------------------------------------------------------------------------
1 | function squareBounds(shape) {
2 | const xPoints = shape.shape.map(([x, y]) => x)
3 | const yPoints = shape.shape.map(([x, y]) => y)
4 | return {
5 | top: shape.y + Math.min(...yPoints),
6 | bottom: shape.y + Math.max(...yPoints),
7 | left: shape.x + Math.min(...xPoints),
8 | right: shape.x + Math.max(...xPoints)
9 | }
10 | }
11 |
12 | function intersects(a, b) {
13 | if (a.left > b.right || b.left > a.right)
14 | return false
15 |
16 | if (a.bottom < b.top || b.bottom < a.top)
17 | return false
18 |
19 | return true
20 | }
21 |
22 | export default function hitTest(a, b) {
23 | if (Number.isNaN(a.x + a.y + b.x + b.y)) return false;
24 | return intersects(
25 | squareBounds(a),
26 | squareBounds(b)
27 | )
28 | }
29 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/final/src/framework/interactions.js:
--------------------------------------------------------------------------------
1 | import { throttle } from './utils';
2 |
3 | const SPACE = 32
4 | const UP = 38
5 | const LEFT = 37
6 | const RIGHT = 39
7 |
8 | const actions = {
9 | [SPACE]: false,
10 | [UP]: false,
11 | [LEFT]: false,
12 | [RIGHT]: false
13 | }
14 |
15 | const constrolledSprites = new Set();
16 |
17 | export function registerControllableSprite(sprite) {
18 | constrolledSprites.add(sprite);
19 | }
20 |
21 | function handleKeyDown(event) {
22 | actions[event.keyCode] = true
23 | }
24 |
25 | function handleKeyUp(event) {
26 | actions[event.keyCode] = false
27 | }
28 |
29 | const delay = method => throttle(
30 | () => {
31 | for (const sprite of constrolledSprites) {
32 | sprite[method]();
33 | }
34 | }
35 | );
36 |
37 | const accelerate = delay('accelerate');
38 | const turnCCW = delay('turnCCW');
39 | const turnCW = delay('turnCW');
40 |
41 | export function next() {
42 | if (actions[UP]) accelerate();
43 | if (actions[RIGHT]) turnCW();
44 | if (actions[LEFT]) turnCCW();
45 | }
46 |
47 | export function isPressingSpace() {
48 | return actions[SPACE];
49 | }
50 |
51 | export function start() {
52 | document.addEventListener('keydown', handleKeyDown)
53 | document.addEventListener('keyup', handleKeyUp)
54 | }
55 |
56 | export function stop() {
57 | document.removeEventListener('keydown', handleKeyDown)
58 | document.removeEventListener('keyup', handleKeyUp)
59 | }
60 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/final/src/framework/sprite.js:
--------------------------------------------------------------------------------
1 | import { CANVAS_WIDTH, CANVAS_HEIGHT } from './canvas';
2 | import { registerSprite, unregisterSprite } from './game';
3 |
4 | function defaultOptions() {
5 | const x = Math.random() * CANVAS_WIDTH;
6 | const y = Math.random() * CANVAS_HEIGHT;
7 | const rotation = Math.random() * (Math.PI * 2);
8 | }
9 |
10 | export default class Sprite {
11 |
12 | constructor(options) {
13 | Object.assign(this, defaultOptions(), options);
14 | registerSprite(this);
15 | }
16 |
17 | remove() {
18 | unregisterSprite(this);
19 | }
20 |
21 | next() {
22 | return this;
23 | }
24 | collision() {
25 |
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/final/src/framework/utils.js:
--------------------------------------------------------------------------------
1 | export function range(length) {
2 | return Array.from({ length }, (x, i) => i)
3 | }
4 |
5 | export function throttle(fn) {
6 | let count = 0
7 | return (...args) => {
8 | count++
9 | if (count >= 5) {
10 | count = 0
11 | fn(...args)
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/final/src/index.js:
--------------------------------------------------------------------------------
1 | import { start } from './framework/game';
2 |
3 | import Ship from './ship';
4 | import Comet from './comet';
5 |
6 | new Ship();
7 |
8 | new Comet();
9 | new Comet();
10 | new Comet();
11 |
12 | start();
13 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/final/src/rocket.js:
--------------------------------------------------------------------------------
1 | import DriftingSprite from './framework/drifting_sprite';
2 | import { getSpriteProperty } from './framework/game';
3 | import Explosion from './explosion';
4 | import { rocket } from './shapes';
5 | import Comet from './comet';
6 |
7 |
8 | export default class Rocket extends DriftingSprite {
9 | static shape = rocket;
10 | static fill = '#1AC2FB';
11 | static removeOnExit = true;
12 | static speed = 5;
13 | static collidesWith = [Comet];
14 |
15 | collision(target) {
16 | new Explosion({
17 | x: getSpriteProperty(this, 'x'),
18 | y: getSpriteProperty(this, 'y'),
19 | });
20 | target.multiply();
21 | this.remove();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/final/src/shapes.js:
--------------------------------------------------------------------------------
1 | export const ship = [
2 | [10, 0], [-10, -5], [-7, 0], [-10, 5], [10, 0]
3 | ]
4 |
5 | export const rocket = [
6 | [10, 0], [0, -5], [0, 5], [10, 0]
7 | ]
8 |
9 | export const ufo = [
10 | [-20, 0], [-5, -5], [-5, -10], [5, -10], [5, -5],
11 | [20, 0], [5, 10], [-5, 10], [-20, 0]
12 | ]
13 |
14 | export function cometShape(size, sides) {
15 | const points = []
16 | for (let i = 0; i < 2; i += 2/sides) {
17 | const distance = size + (Math.random() * 6) - 3
18 | points.push([
19 | Math.cos(Math.PI*i)*distance,
20 | Math.sin(Math.PI*i)*distance
21 | ])
22 | }
23 |
24 | return points
25 | }
26 |
27 | export function explosionShape(size, sides) {
28 | const points = []
29 | let point = 0
30 | for (let i = 0; i < 2; i += 1/sides) {
31 | const distance = point % 2 ? size : size / 2
32 | points.push([
33 | Math.cos(Math.PI*i)*distance,
34 | Math.sin(Math.PI*i)*distance
35 | ])
36 | point++
37 | }
38 |
39 | return points
40 | }
41 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/final/src/ship.js:
--------------------------------------------------------------------------------
1 | import ControllableSprite from './framework/controllable_sprite';
2 | import { getSpriteProperty, stop } from './framework/game';
3 | import { isPressingSpace } from './framework/interactions';
4 | import { throttle } from './framework/utils';
5 | import { ship as shape } from './shapes';
6 | import Comet from './comet';
7 | import Rocket from './rocket';
8 | import Explosion from './explosion';
9 |
10 | export default class Ship extends ControllableSprite {
11 | static shape = shape;
12 | static stroke = '#fff';
13 | static collidesWith = [Comet];
14 |
15 | fire = throttle(() => {
16 | const x = getSpriteProperty(this, 'x');
17 | const y = getSpriteProperty(this, 'y');
18 | const rotation = getSpriteProperty(this, 'rotation');
19 |
20 | new Rocket({ x, y, rotation });
21 | })
22 |
23 | collision() {
24 | new Explosion({
25 | x: getSpriteProperty(this, 'x'),
26 | y: getSpriteProperty(this, 'y'),
27 | });
28 |
29 | this.remove();
30 |
31 | setTimeout(stop, 500);
32 | }
33 |
34 | next() {
35 | super.next();
36 |
37 | if (isPressingSpace()) {
38 | this.fire();
39 | }
40 |
41 | return this;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/start/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["transform-es2015-modules-commonjs"],
3 | "presets": ["stage-2"],
4 | "sourceMaps": "inline"
5 | }
6 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/start/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/start/dest/build.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jisaacks/get-programming-jsnext/d80df37207a6bc4df74b9e81413cd9ee45df0bb7/Unit_6/Lesson_29_Capstone/start/dest/build.js
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/start/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/start/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "canvas-ship",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "build": "browserify -t [ babelify ] ./src -o ./dest/build.js"
9 | },
10 | "author": "",
11 | "license": "ISC",
12 | "devDependencies": {
13 | "babel-plugin-transform-es2015-modules-commonjs": "^6.18.0",
14 | "babel-preset-stage-2": "^6.17.0",
15 | "babelify": "^7.3.0"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/start/src/framework/canvas.js:
--------------------------------------------------------------------------------
1 | const canvas = document.querySelector("#canvas");
2 | const ctx = canvas.getContext('2d');
3 |
4 | export const CANVAS_WIDTH = canvas.width;
5 | export const CANVAS_HEIGHT = canvas.height;
6 |
7 | export function clear() {
8 | ctx.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
9 | }
10 |
11 | export function next() {
12 | ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
13 | ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
14 | }
15 |
16 | export function draw({x, y, rotation, shape, fill, stroke}) {
17 | ctx.save();
18 | ctx.translate(x, y);
19 | ctx.rotate(rotation);
20 | ctx.moveTo(shape[0][0], shape[0][1]);
21 | ctx.beginPath();
22 | shape.forEach(([x, y]) => ctx.lineTo(x, y));
23 | ctx.closePath();
24 | if (fill) {
25 | ctx.fillStyle = fill;
26 | ctx.fill();
27 | }
28 | if (stroke) {
29 | ctx.strokeStyle = stroke;
30 | ctx.stroke();
31 | }
32 | ctx.restore();
33 | }
34 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/start/src/framework/controllable_sprite.js:
--------------------------------------------------------------------------------
1 | import Sprite from './sprite';
2 | import { CANVAS_WIDTH, CANVAS_HEIGHT } from './canvas';
3 | import { registerControllableSprite } from './interactions';
4 |
5 | const defaultOptions = {
6 | x: CANVAS_WIDTH/2,
7 | y: CANVAS_HEIGHT/2,
8 | rotation: 0,
9 | vr: 0,
10 | vx: 0,
11 | vy: 0
12 | };
13 |
14 | export default class ControllableSprite extends Sprite {
15 |
16 | constructor(options) {
17 | super(Object.assign({}, defaultOptions, options));
18 | registerControllableSprite(this);
19 | }
20 |
21 | next() {
22 | this.rotation += this.vr;
23 | this.vr *= .95;
24 |
25 | this.x += this.vx;
26 | this.y += this.vy;
27 | this.vx *= .99;
28 | this.vy *= .99;
29 |
30 | return this;
31 | }
32 |
33 | accelerate() {
34 | const dx = Math.cos( this.rotation );
35 | const dy = Math.sin( this.rotation );
36 |
37 | this.vx += dx * .2;
38 | this.vy += dy * .2;
39 | }
40 |
41 | turnCCW() {
42 | if (this.vr > 0) {
43 | this.vr = 0;
44 | }
45 | this.vr = Math.max(this.vr - .03, -.09);
46 | }
47 |
48 | turnCW() {
49 | if (this.vr < 0) {
50 | this.vr = 0;
51 | }
52 | this.vr = Math.min(this.vr + .03, .09);
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/start/src/framework/drifting_sprite.js:
--------------------------------------------------------------------------------
1 | import Sprite from './sprite';
2 | import { getSpriteProperty } from './game';
3 |
4 | export default class DriftingSprite extends Sprite {
5 |
6 | next() {
7 | const speed = getSpriteProperty(this, 'speed') || 1;
8 | const rotation = getSpriteProperty(this, 'rotation') || 0;
9 |
10 | this.x += Math.cos(rotation) * speed;
11 | this.y += Math.sin(rotation) * speed;
12 |
13 | return this;
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/start/src/framework/game.js:
--------------------------------------------------------------------------------
1 | import Sprite from './sprite';
2 | import * as canvas from './canvas';
3 | import * as interactions from './interactions';
4 | import hitTest from './hit_test';
5 |
6 | const allSprites = new Set();
7 | const spritesByType = new Map();
8 | let raf;
9 | let gameOver = false;
10 |
11 | export function registerSprite(sprite) {
12 | const type = sprite.constructor;
13 |
14 | allSprites.add(sprite);
15 |
16 | let proto = Object.getPrototypeOf(sprite)
17 | while(proto instanceof Sprite) {
18 |
19 | const type = proto.constructor;
20 |
21 | if (!spritesByType.has(type)) {
22 | spritesByType.set(type, new Set());
23 | }
24 |
25 | spritesByType.get(type).add(sprite);
26 |
27 | proto = Object.getPrototypeOf(proto);
28 | }
29 | }
30 |
31 | export function unregisterSprite(sprite) {
32 | allSprites.delete(sprite);
33 | for (const set of spritesByType.values()) {
34 | set.delete(sprite);
35 | }
36 | }
37 |
38 | function loopCanvas(sprite) {
39 | if (sprite.x < 0) sprite.x = canvas.CANVAS_WIDTH;
40 | if (sprite.y < 0) sprite.y = canvas.CANVAS_HEIGHT;
41 | if (sprite.x > canvas.CANVAS_WIDTH) sprite.x = 0;
42 | if (sprite.y > canvas.CANVAS_HEIGHT) sprite.y = 0;
43 | }
44 |
45 | function isOutsideCanvas(sprite) {
46 | if (sprite.x < 0) return true;
47 | if (sprite.y < 0) return true;
48 | if (sprite.x > canvas.CANVAS_WIDTH) return true;
49 | if (sprite.y > canvas.CANVAS_HEIGHT) return true;
50 | return false;
51 | }
52 |
53 | function getObjectProperty(obj, name) {
54 | const prop = obj[name];
55 | if (typeof prop === 'function') {
56 | return obj[name]();
57 | } else {
58 | return prop;
59 | }
60 | }
61 |
62 | export function getSpriteProperty(sprite, name) {
63 | const obj = sprite[name] ? sprite : sprite.constructor;
64 | return getObjectProperty(obj, name);
65 | }
66 |
67 | export function getSpriteProperties(sprite, names) {
68 | return names.map(name => getSpriteProperty(sprite, name));
69 | }
70 |
71 | function colliding(spriteA, spriteB) {
72 | if (spriteA === spriteB) return false;
73 | return hitTest({
74 | x: getSpriteProperty(spriteA, 'x'),
75 | y: getSpriteProperty(spriteA, 'y'),
76 | shape: getSpriteProperty(spriteA, 'shape')
77 | }, {
78 | x: getSpriteProperty(spriteB, 'x'),
79 | y: getSpriteProperty(spriteB, 'y'),
80 | shape: getSpriteProperty(spriteB, 'shape')
81 | });
82 | }
83 |
84 | function draw(sprite) {
85 |
86 | const collidesWith = getSpriteProperty(sprite, 'collidesWith');
87 | if (collidesWith) {
88 | searching: for (const type of collidesWith) {
89 | const set = type === Sprite ? allSprites : spritesByType.get(type);
90 | for (const instance of set || new Set) {
91 | if (colliding(sprite, instance)) {
92 | sprite.collision(instance);
93 | break searching;
94 | }
95 | }
96 | }
97 | }
98 |
99 | if (isOutsideCanvas(sprite)) {
100 | if (getSpriteProperty(sprite, 'removeOnExit')) {
101 | unregisterSprite(sprite);
102 | return;
103 | } else {
104 | loopCanvas(sprite);
105 | }
106 | }
107 |
108 | const props = 'x y rotation shape fill stroke'.split(' ');
109 | const [x, y, rotation, shape, fill, stroke] = getSpriteProperties(sprite, props);
110 |
111 | canvas.draw({ x, y, rotation, shape, fill, stroke });
112 | }
113 |
114 | function frame() {
115 | if (gameOver) return;
116 |
117 | canvas.next();
118 |
119 | interactions.next();
120 |
121 | allSprites.forEach(sprite => draw( sprite.next() ));
122 |
123 | raf = window.requestAnimationFrame(frame);
124 | }
125 |
126 | export function start() {
127 | canvas.clear();
128 | interactions.start();
129 |
130 | raf = window.requestAnimationFrame(frame);
131 | }
132 |
133 | export function stop() {
134 | console.log('Game Over');
135 | gameOver = true;
136 | interactions.stop();
137 | window.cancelAnimationFrame(raf);
138 | }
139 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/start/src/framework/hit_test.js:
--------------------------------------------------------------------------------
1 | function squareBounds(shape) {
2 | const xPoints = shape.shape.map(([x, y]) => x)
3 | const yPoints = shape.shape.map(([x, y]) => y)
4 | return {
5 | top: shape.y + Math.min(...yPoints),
6 | bottom: shape.y + Math.max(...yPoints),
7 | left: shape.x + Math.min(...xPoints),
8 | right: shape.x + Math.max(...xPoints)
9 | }
10 | }
11 |
12 | function intersects(a, b) {
13 | if (a.left > b.right || b.left > a.right)
14 | return false
15 |
16 | if (a.bottom < b.top || b.bottom < a.top)
17 | return false
18 |
19 | return true
20 | }
21 |
22 | export default function hitTest(a, b) {
23 | if (Number.isNaN(a.x + a.y + b.x + b.y)) return false;
24 | return intersects(
25 | squareBounds(a),
26 | squareBounds(b)
27 | )
28 | }
29 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/start/src/framework/interactions.js:
--------------------------------------------------------------------------------
1 | import { throttle } from './utils';
2 |
3 | const SPACE = 32
4 | const UP = 38
5 | const LEFT = 37
6 | const RIGHT = 39
7 |
8 | const actions = {
9 | [SPACE]: false,
10 | [UP]: false,
11 | [LEFT]: false,
12 | [RIGHT]: false
13 | }
14 |
15 | const constrolledSprites = new Set();
16 |
17 | export function registerControllableSprite(sprite) {
18 | constrolledSprites.add(sprite);
19 | }
20 |
21 | function handleKeyDown(event) {
22 | actions[event.keyCode] = true
23 | }
24 |
25 | function handleKeyUp(event) {
26 | actions[event.keyCode] = false
27 | }
28 |
29 | const delay = method => throttle(
30 | () => {
31 | for (const sprite of constrolledSprites) {
32 | sprite[method]();
33 | }
34 | }
35 | );
36 |
37 | const accelerate = delay('accelerate');
38 | const turnCCW = delay('turnCCW');
39 | const turnCW = delay('turnCW');
40 |
41 | export function next() {
42 | if (actions[UP]) accelerate();
43 | if (actions[RIGHT]) turnCW();
44 | if (actions[LEFT]) turnCCW();
45 | }
46 |
47 | export function isPressingSpace() {
48 | return actions[SPACE];
49 | }
50 |
51 | export function start() {
52 | document.addEventListener('keydown', handleKeyDown)
53 | document.addEventListener('keyup', handleKeyUp)
54 | }
55 |
56 | export function stop() {
57 | document.removeEventListener('keydown', handleKeyDown)
58 | document.removeEventListener('keyup', handleKeyUp)
59 | }
60 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/start/src/framework/sprite.js:
--------------------------------------------------------------------------------
1 | import { CANVAS_WIDTH, CANVAS_HEIGHT } from './canvas';
2 | import { registerSprite, unregisterSprite } from './game';
3 |
4 | function defaultOptions() {
5 | const x = Math.random() * CANVAS_WIDTH;
6 | const y = Math.random() * CANVAS_HEIGHT;
7 | const rotation = Math.random() * (Math.PI * 2);
8 | }
9 |
10 | export default class Sprite {
11 |
12 | constructor(options) {
13 | Object.assign(this, defaultOptions(), options);
14 | registerSprite(this);
15 | }
16 |
17 | remove() {
18 | unregisterSprite(this);
19 | }
20 |
21 | next() {
22 | return this;
23 | }
24 | collision() {
25 |
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/start/src/framework/utils.js:
--------------------------------------------------------------------------------
1 | export function range(length) {
2 | return Array.from({ length }, (x, i) => i)
3 | }
4 |
5 | export function throttle(fn) {
6 | let count = 0
7 | return (...args) => {
8 | count++
9 | if (count >= 5) {
10 | count = 0
11 | fn(...args)
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Unit_6/Lesson_29_Capstone/start/src/shapes.js:
--------------------------------------------------------------------------------
1 | export const ship = [
2 | [10, 0], [-10, -5], [-7, 0], [-10, 5], [10, 0]
3 | ]
4 |
5 | export const rocket = [
6 | [10, 0], [0, -5], [0, 5], [10, 0]
7 | ]
8 |
9 | export const ufo = [
10 | [-20, 0], [-5, -5], [-5, -10], [5, -10], [5, -5],
11 | [20, 0], [5, 10], [-5, 10], [-20, 0]
12 | ]
13 |
14 | export function cometShape(size, sides) {
15 | const points = []
16 | for (let i = 0; i < 2; i += 2/sides) {
17 | const distance = size + (Math.random() * 6) - 3
18 | points.push([
19 | Math.cos(Math.PI*i)*distance,
20 | Math.sin(Math.PI*i)*distance
21 | ])
22 | }
23 |
24 | return points
25 | }
26 |
27 | export function explosionShape(size, sides) {
28 | const points = []
29 | let point = 0
30 | for (let i = 0; i < 2; i += 1/sides) {
31 | const distance = point % 2 ? size : size / 2
32 | points.push([
33 | Math.cos(Math.PI*i)*distance,
34 | Math.sin(Math.PI*i)*distance
35 | ])
36 | point++
37 | }
38 |
39 | return points
40 | }
41 |
--------------------------------------------------------------------------------
/Unit_7/Lesson_30/user_view.js:
--------------------------------------------------------------------------------
1 | // You will need axios
2 | import axios from 'axios';
3 |
4 | function getOrgs(username) {
5 | return axios.get(`https://api.github.com/users/${username}/orgs`);
6 | }
7 |
8 | class UserView {
9 | constructor(user) {
10 | this.user = user;
11 | this.orgs = getOrgs(user.username); <1>
12 | }
13 |
14 | defaultView() {
15 | // show the default view
16 | }
17 |
18 | orgView() {
19 | // show loading screen
20 | this.orgs.then(resp => { <2>
21 | const orgs = resp.orgs;
22 | // show the orgs
23 | })
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Unit_7/Lesson_31/alligator.js:
--------------------------------------------------------------------------------
1 | const later = new Promise((resolve, reject) => {
2 | // Do something asynchronously
3 | resolve('alligator');
4 | });
5 |
6 | later.then(response => {
7 | console.log(response);
8 | });
9 |
--------------------------------------------------------------------------------
/Unit_7/Lesson_31/catching_errors.js:
--------------------------------------------------------------------------------
1 | Promise.resolve()
2 | .then(() => console.log('A'))
3 | .then(() => Promise.reject('X'))
4 | .then(() => console.log('B'))
5 | .catch(err => console.log('caught:', err))
6 | .then(() => console.log('C'));
7 |
--------------------------------------------------------------------------------
/Unit_7/Lesson_31/fetch_image.js:
--------------------------------------------------------------------------------
1 | function fetchImage(src) {
2 | return new Promise((res, rej) => {
3 | const img = new Image();
4 | img.onload = res;
5 | img.onerror = rej;
6 | img.src = src;
7 | });
8 | }
9 |
10 | fetchImage('https://www.fillmurray.com/200/300').then(
11 | () => console.log('image loaded'),
12 | () => console.log('image failed')
13 | );
14 |
--------------------------------------------------------------------------------
/Unit_7/Lesson_31/fetch_orgs.js:
--------------------------------------------------------------------------------
1 | fetch("https://api.github.com/users/jisaacks/orgs")
2 | .then(resp => resp.json())
3 | .then(results => {
4 | // do something with results
5 | });
6 |
--------------------------------------------------------------------------------
/Unit_7/Lesson_31/then_chaining.js:
--------------------------------------------------------------------------------
1 | Promise.resolve(1)
2 | .then(number => number + 1) <1>
3 | .then(number => number + 1) <2>
4 | .then(number => number + 1) <3>
5 | .then(number => {
6 | console.log(number) <4>
7 | });
8 |
--------------------------------------------------------------------------------
/Unit_7/Lesson_31/wait.js:
--------------------------------------------------------------------------------
1 | function wait(milliseconds) {
2 | return new Promise((resolve) => {
3 | setTimeout(resolve, milliseconds);
4 | });
5 | }
6 |
7 | wait(5000).then(() => {
8 | // 5 seconds later...
9 | });
10 |
--------------------------------------------------------------------------------
/Unit_7/Lesson_32/all_resolved.js:
--------------------------------------------------------------------------------
1 | async function allResolved(promises) {
2 | const resolved = [];
3 | const handlers = promises.map(promise => (
4 | promise
5 | .then(resp => resolved.push(resp))
6 | .catch(() => { /* skip rejects */ })
7 | ));
8 | await Promise.all(handlers);
9 | return resolved;
10 | }
11 |
--------------------------------------------------------------------------------
/Unit_7/Lesson_32/fail.js:
--------------------------------------------------------------------------------
1 | async function fail() {
2 | const msg = await Promise.reject('I failed.');
3 | return 'I Succeeded.';
4 | };
5 |
6 | fail().then(msg => console.log(msg), msg => console.log(msg))
7 |
8 | async function tryTest() {
9 | try {
10 | return Promise.reject('err err');
11 | } catch(err) {
12 | return Promise.resolve(`caught: ${err}`);
13 | }
14 | }
15 |
16 | tryTest().then(response => {
17 | console.log('response:', response);
18 | });
19 |
--------------------------------------------------------------------------------
/Unit_7/Lesson_32/fetch_image.js:
--------------------------------------------------------------------------------
1 | async function fetchImage(url) {
2 | const resp = await fetch(url);
3 | const blob = await resp.blob();
4 | return createImageBitmap(blob);
5 | };
6 |
7 | fetchImage('my-image.png').then(image => {
8 | // do something with image
9 | });
10 |
--------------------------------------------------------------------------------
/Unit_7/Lesson_32/runner.js:
--------------------------------------------------------------------------------
1 | const runner = gen => (...args) => {
2 | const generator = gen(...args);
3 | return new Promise((resolve, reject) => {
4 | const run = prev => {
5 | const { value, done } = generator.next(prev);
6 | if (done) {
7 | resolve(value);
8 | } else if (value instanceof Promise) {
9 | value.then(run, reject);
10 | } else {
11 | run(value);
12 | }
13 | }
14 | run();
15 | });
16 | }
17 |
18 | const fetchImageAsync = runner(function* fetchImage(url) {
19 | const resp = yield fetch(url);
20 | const blob = yield resp.blob();
21 | const image = yield createImageBitmap(blob);
22 |
23 | return image;
24 | });
25 |
26 | fetchImageAsync('my-image.png').then(image => {
27 | // do something with image
28 | });
29 |
--------------------------------------------------------------------------------
/Unit_7/Lesson_33/current_time.js:
--------------------------------------------------------------------------------
1 | // You can use zen-observable as a polyfil
2 |
3 | const currentTime$ = new Observable(observer => {
4 | const interval = setInterval(() => {
5 | const currentTime = new Date();
6 | observer.next(currentTime);
7 | }, 1000);
8 |
9 | return () => clearInterval(interval);
10 | });
11 |
12 | const currentTimeSubscription = currentTime$.subscribe({
13 | next(currentTime) {
14 | // show current time
15 | }
16 | });
17 |
18 | currentTime$.map(data => `${date.getHours()}:${date.getMinutes()}`).distinct();
19 |
20 | // currentTimeSubscription.unsubscribe();
21 |
--------------------------------------------------------------------------------
/Unit_7/Lesson_33/filter.js:
--------------------------------------------------------------------------------
1 | function filter (obs$, fn) {
2 | return new Observable(observer => obs$.subscribe({
3 | next(val) {
4 | if (fn(val)) observer.next(val);
5 | }
6 | }));
7 | }
8 |
9 | filter(Observable.of(1, 2, 3, 4, 5), n => n % 2).subscribe({
10 | next(val) {
11 | console.log('filtered: ', val);
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/Unit_7/Lesson_33/from_set.js:
--------------------------------------------------------------------------------
1 | Observable.from(new Set([1, 2, 3])).subscribe({
2 | start() {
3 | console.log('--- started getting values ---');
4 | },
5 | next(value) {
6 | console.log('==> next value', value);
7 | },
8 | complete(a) {
9 | console.log('--- done getting values ---');
10 | }
11 | });
12 |
--------------------------------------------------------------------------------
/Unit_7/Lesson_34_Capstone/final/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["transform-es2015-modules-commonjs"],
3 | "presets": ["stage-2"],
4 | "sourceMaps": "inline"
5 | }
6 |
--------------------------------------------------------------------------------
/Unit_7/Lesson_34_Capstone/final/dest/build.js:
--------------------------------------------------------------------------------
1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o {
5 | var _ref = _asyncToGenerator(function* (url) {
6 | const resp = yield fetch(url);
7 | const blob = yield resp.blob();
8 | return createImageBitmap(blob);
9 | });
10 |
11 | return function fetchImage(_x) {
12 | return _ref.apply(this, arguments);
13 | };
14 | })();
15 |
16 | function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
17 |
18 | function getRandomImage() {
19 | return fetchImage('https://source.unsplash.com/random');
20 | }
21 |
22 | function draw(img, alpha = 1) {
23 | const gal = document.getElementById('gallery');
24 | const ctx = gal.getContext('2d');
25 | ctx.globalAlpha = alpha;
26 | ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, gal.width, gal.height);
27 | }
28 |
29 | function fade(image) {
30 | return new Promise(resolve => {
31 | function fadeIn(alpha) {
32 | draw(image, alpha);
33 | if (alpha >= .99) {
34 | resolve();
35 | } else {
36 | alpha += (1 - alpha) / 24;
37 | window.requestAnimationFrame(() => fadeIn(alpha));
38 | }
39 | }
40 | fadeIn(0.1);
41 | });
42 | }
43 |
44 | function wait(ms) {
45 | return new Promise(resolve => {
46 | setTimeout(resolve, ms);
47 | });
48 | }
49 |
50 | const pause = () => wait(1500);
51 |
52 | function repeat(fn) {
53 | return new Promise((resolve, reject) => {
54 | const go = () => fn().then(() => {
55 | setTimeout(go, 0);
56 | }, reject);
57 | go();
58 | });
59 | }
60 |
61 | function nextImage() {
62 | return getRandomImage().then(fade).then(pause);
63 | }
64 |
65 | function start() {
66 | return repeat(nextImage).catch(start);
67 | }
68 |
69 | start();
70 |
71 | },{}]},{},[1]);
72 |
--------------------------------------------------------------------------------
/Unit_7/Lesson_34_Capstone/final/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Unit_7/Lesson_34_Capstone/final/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gallery",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "build": "browserify -t [ babelify ] ./src -o ./dest/build.js"
9 | },
10 | "author": "",
11 | "license": "ISC",
12 | "devDependencies": {
13 | "babel-plugin-transform-es2015-modules-commonjs": "^6.18.0",
14 | "babel-preset-stage-2": "^6.17.0",
15 | "babelify": "^7.3.0"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Unit_7/Lesson_34_Capstone/final/src/index.js:
--------------------------------------------------------------------------------
1 | async function fetchImage(url) {
2 | const resp = await fetch(url);
3 | const blob = await resp.blob();
4 | return createImageBitmap(blob);
5 | }
6 |
7 | function getRandomImage() {
8 | return fetchImage('https://source.unsplash.com/random');
9 | }
10 |
11 | function draw(img, alpha=1) {
12 | const gal = document.getElementById('gallery');
13 | const ctx = gal.getContext('2d');
14 | ctx.globalAlpha = alpha;
15 | ctx.drawImage(img,
16 | 0, 0, img.width, img.height,
17 | 0, 0, gal.width, gal.height
18 | );
19 | }
20 |
21 | function fade(image) {
22 | return new Promise(resolve => {
23 | function fadeIn(alpha) {
24 | draw(image, alpha);
25 | if (alpha >= .99) {
26 | resolve();
27 | } else {
28 | alpha += (1-alpha)/24;
29 | window.requestAnimationFrame(() => fadeIn(alpha));
30 | }
31 | }
32 | fadeIn(0.1);
33 | });
34 | }
35 |
36 | function wait(ms) {
37 | return new Promise(resolve => {
38 | setTimeout(resolve, ms);
39 | })
40 | }
41 |
42 | const pause = () => wait(1500);
43 |
44 | function repeat(fn) {
45 | return new Promise((resolve, reject) => {
46 | const go = () => fn().then(() => {
47 | setTimeout(go, 0);
48 | }, reject);
49 | go();
50 | });
51 | }
52 |
53 | function nextImage() {
54 | return getRandomImage().then(fade).then(pause);
55 | }
56 |
57 | function start() {
58 | return repeat(nextImage).catch(start);
59 | }
60 |
61 | start();
62 |
--------------------------------------------------------------------------------
/Unit_7/Lesson_34_Capstone/start/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["transform-es2015-modules-commonjs"],
3 | "presets": ["stage-2"],
4 | "sourceMaps": "inline"
5 | }
6 |
--------------------------------------------------------------------------------
/Unit_7/Lesson_34_Capstone/start/dest/build.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jisaacks/get-programming-jsnext/d80df37207a6bc4df74b9e81413cd9ee45df0bb7/Unit_7/Lesson_34_Capstone/start/dest/build.js
--------------------------------------------------------------------------------
/Unit_7/Lesson_34_Capstone/start/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Unit_7/Lesson_34_Capstone/start/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gallery",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "build": "browserify -t [ babelify ] ./src -o ./dest/build.js"
9 | },
10 | "author": "",
11 | "license": "ISC",
12 | "devDependencies": {
13 | "babel-plugin-transform-es2015-modules-commonjs": "^6.18.0",
14 | "babel-preset-stage-2": "^6.17.0",
15 | "babelify": "^7.3.0"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Unit_7/Lesson_34_Capstone/start/src/index.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jisaacks/get-programming-jsnext/d80df37207a6bc4df74b9e81413cd9ee45df0bb7/Unit_7/Lesson_34_Capstone/start/src/index.js
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Get Programming With JavaScript Next
2 |
3 | This is the code for the book [Get Programming with JavaScript Next](https://www.manning.com/books/get-programming-with-javascript-next)
4 |
--------------------------------------------------------------------------------