├── README.md
├── ball.js
├── brick.js
├── index.html
├── libraries
├── p5.dom.js
├── p5.js
└── p5.sound.js
├── paddle.js
└── sketch.js
/README.md:
--------------------------------------------------------------------------------
1 | # BrickBreaker
2 | Code Repository for Yining Shi's Guest Tutorial
3 |
4 | ### Video Tutorials
5 | Watch the tutorial here! [https://youtu.be/5kEPixL8JoU](https://youtu.be/5kEPixL8JoU)
6 |
7 | ### Play the game!
8 | * https://codingtrain.github.io/BrickBreaker
9 |
10 | ### Viewer Remixes of the Game
11 | * [Colorful Brick Breaker](https://yining1023.github.io/brickBreaker), [Code](https://github.com/yining1023/brickBreaker)
12 | * Add your name and link here!
13 |
14 | ### Getting Started
15 | ```shell
16 | $ git clone https://github.com/CodingTrain/BrickBreaker.git
17 | $ cd BrickBreaker
18 | $ python -m SimpleHTTPServer # $ python3 -m http.server (if you are using python 3)
19 | ```
20 | Go to localhost:8000, you should be able to see the game interface.
21 |
22 | This is inspired by Danial Shiffman's [Asteroids Coding Challenge](https://www.youtube.com/watch?v=hacZU523FyM)
23 |
--------------------------------------------------------------------------------
/ball.js:
--------------------------------------------------------------------------------
1 | function Ball() {
2 | this.pos = createVector(width / 2, height / 2);
3 |
4 | this.r = 30;
5 | this.vel = createVector(1, 1).mult(4);
6 | this.direction = createVector(1, 1);
7 |
8 | this.update = function() {
9 | this.pos.x += this.vel.x * this.direction.x;
10 | this.pos.y += this.vel.y * this.direction.y;
11 | }
12 |
13 | this.display = function() {
14 | ellipse(this.pos.x, this.pos.y, this.r * 2, this.r * 2);
15 | }
16 |
17 | this.checkEdges = function() {
18 | if (this.pos.x > width - this.r && this.direction.x > 0) {
19 | this.direction.x *= -1;
20 | }
21 | if (this.pos.x < this.r && this.direction.x < 0) {
22 | this.direction.x *= -1;
23 | }
24 | if (this.pos.y < this.r && ball.direction.y < 0) this.direction.y *= -1;
25 | }
26 |
27 | this.meets = function(paddle) {
28 | if (this.pos.y < paddle.pos.y &&
29 | this.pos.y > paddle.pos.y - this.r &&
30 | ball.pos.x > paddle.pos.x - ball.r &&
31 | ball.pos.x < paddle.pos.x + paddle.w + ball.r) {
32 | return true;
33 | } else {
34 | return false;
35 | }
36 | }
37 |
38 | this.hits = function(brick) {
39 | var d = dist(this.pos.x, this.pos.y, brick.pos.x, brick.pos.y);
40 | if (d < brick.r + this.r) {
41 | return true;
42 | } else {
43 | return false;
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/brick.js:
--------------------------------------------------------------------------------
1 | function Brick(pos, r) {
2 | this.pos = createVector(random(100, width - 100), random(100, height - 400));
3 | this.r = random(20, 80);
4 | this.total = 6;
5 |
6 | this.display = function() {
7 | push();
8 | translate(this.pos.x, this.pos.y);
9 | beginShape();
10 | for (var i = 0; i < this.total; i++) {
11 | var angle = map(i, 0, this.total, 0, TWO_PI);
12 | var r = this.r;
13 | var x = r * cos(angle);
14 | var y = r * sin(angle);
15 | vertex(x, y);
16 | }
17 | endShape(CLOSE);
18 | pop();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Untitled
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/libraries/p5.dom.js:
--------------------------------------------------------------------------------
1 | /*! p5.dom.js v0.2.12 August 17, 2016 */
2 | /**
3 | * The web is much more than just canvas and p5.dom makes it easy to interact
4 | * with other HTML5 objects, including text, hyperlink, image, input, video,
5 | * audio, and webcam.
6 | * There is a set of creation methods, DOM manipulation methods, and
7 | * an extended p5.Element that supports a range of HTML elements. See the
8 | *
9 | * beyond the canvas tutorial for a full overview of how this addon works.
10 | *
11 | *
Methods and properties shown in black are part of the p5.js core, items in
12 | * blue are part of the p5.dom library. You will need to include an extra file
13 | * in order to access the blue functions. See the
14 | * using a library
15 | * section for information on how to include this library. p5.dom comes with
16 | * p5 complete or you can download the single file
17 | *
18 | * here.
19 | * See tutorial: beyond the canvas
20 | * for more info on how to use this libary.
21 | *
22 | * @module p5.dom
23 | * @submodule p5.dom
24 | * @for p5.dom
25 | * @main
26 | */
27 |
28 | (function (root, factory) {
29 | if (typeof define === 'function' && define.amd)
30 | define('p5.dom', ['p5'], function (p5) { (factory(p5));});
31 | else if (typeof exports === 'object')
32 | factory(require('../p5'));
33 | else
34 | factory(root['p5']);
35 | }(this, function (p5) {
36 | // =============================================================================
37 | // p5 additions
38 | // =============================================================================
39 |
40 | /**
41 | * Searches the page for an element with the given ID, class, or tag name (using the '#' or '.'
42 | * prefixes to specify an ID or class respectively, and none for a tag) and returns it as
43 | * a p5.Element. If a class or tag name is given with more than 1 element,
44 | * only the first element will be returned.
45 | * The DOM node itself can be accessed with .elt.
46 | * Returns null if none found. You can also specify a container to search within.
47 | *
48 | * @method select
49 | * @param {String} name id, class, or tag name of element to search for
50 | * @param {String} [container] id, p5.Element, or HTML element to search within
51 | * @return {Object/p5.Element|Null} p5.Element containing node found
52 | * @example
53 | *
54 | * function setup() {
55 | * createCanvas(100,100);
56 | * //translates canvas 50px down
57 | * select('canvas').position(100, 100);
58 | * }
59 | *
60 | *
61 | * // these are all valid calls to select()
62 | * var a = select('#moo');
63 | * var b = select('#blah', '#myContainer');
64 | * var c = select('#foo', b);
65 | * var d = document.getElementById('beep');
66 | * var e = select('p', d);
67 | *
68 | *
69 | */
70 | p5.prototype.select = function (e, p) {
71 | var res = null;
72 | var container = getContainer(p);
73 | if (e[0] === '.'){
74 | e = e.slice(1);
75 | res = container.getElementsByClassName(e);
76 | if (res.length) {
77 | res = res[0];
78 | } else {
79 | res = null;
80 | }
81 | }else if (e[0] === '#'){
82 | e = e.slice(1);
83 | res = container.getElementById(e);
84 | }else {
85 | res = container.getElementsByTagName(e);
86 | if (res.length) {
87 | res = res[0];
88 | } else {
89 | res = null;
90 | }
91 | }
92 | if (res) {
93 | return wrapElement(res);
94 | } else {
95 | return null;
96 | }
97 | };
98 |
99 | /**
100 | * Searches the page for elements with the given class or tag name (using the '.' prefix
101 | * to specify a class and no prefix for a tag) and returns them as p5.Elements
102 | * in an array.
103 | * The DOM node itself can be accessed with .elt.
104 | * Returns an empty array if none found.
105 | * You can also specify a container to search within.
106 | *
107 | * @method selectAll
108 | * @param {String} name class or tag name of elements to search for
109 | * @param {String} [container] id, p5.Element, or HTML element to search within
110 | * @return {Array} Array of p5.Elements containing nodes found
111 | * @example
112 | *
113 | * function setup() {
114 | * createButton('btn');
115 | * createButton('2nd btn');
116 | * createButton('3rd btn');
117 | * var buttons = selectAll('button');
118 | *
119 | * for (var i = 0; i < buttons.length; i++){
120 | * buttons[i].size(100,100);
121 | * }
122 | * }
123 | *
124 | *
125 | * // these are all valid calls to selectAll()
126 | * var a = selectAll('.moo');
127 | * var b = selectAll('div');
128 | * var c = selectAll('button', '#myContainer');
129 | * var d = select('#container');
130 | * var e = selectAll('p', d);
131 | * var f = document.getElementById('beep');
132 | * var g = select('.blah', f);
133 | *
134 | *
135 | */
136 | p5.prototype.selectAll = function (e, p) {
137 | var arr = [];
138 | var res;
139 | var container = getContainer(p);
140 | if (e[0] === '.'){
141 | e = e.slice(1);
142 | res = container.getElementsByClassName(e);
143 | } else {
144 | res = container.getElementsByTagName(e);
145 | }
146 | if (res) {
147 | for (var j = 0; j < res.length; j++) {
148 | var obj = wrapElement(res[j]);
149 | arr.push(obj);
150 | }
151 | }
152 | return arr;
153 | };
154 |
155 | /**
156 | * Helper function for select and selectAll
157 | */
158 | function getContainer(p) {
159 | var container = document;
160 | if (typeof p === 'string' && p[0] === '#'){
161 | p = p.slice(1);
162 | container = document.getElementById(p) || document;
163 | } else if (p instanceof p5.Element){
164 | container = p.elt;
165 | } else if (p instanceof HTMLElement){
166 | container = p;
167 | }
168 | return container;
169 | }
170 |
171 | /**
172 | * Helper function for getElement and getElements.
173 | */
174 | function wrapElement(elt) {
175 | if(elt.tagName === "INPUT" && elt.type === "checkbox") {
176 | var converted = new p5.Element(elt);
177 | converted.checked = function(){
178 | if (arguments.length === 0){
179 | return this.elt.checked;
180 | } else if(arguments[0]) {
181 | this.elt.checked = true;
182 | } else {
183 | this.elt.checked = false;
184 | }
185 | return this;
186 | };
187 | return converted;
188 | } else if (elt.tagName === "VIDEO" || elt.tagName === "AUDIO") {
189 | return new p5.MediaElement(elt);
190 | } else {
191 | return new p5.Element(elt);
192 | }
193 | }
194 |
195 | /**
196 | * Removes all elements created by p5, except any canvas / graphics
197 | * elements created by createCanvas or createGraphics.
198 | * Event handlers are removed, and element is removed from the DOM.
199 | * @method removeElements
200 | * @example
201 | *
202 | * function setup() {
203 | * createCanvas(100, 100);
204 | * createDiv('this is some text');
205 | * createP('this is a paragraph');
206 | * }
207 | * function mousePressed() {
208 | * removeElements(); // this will remove the div and p, not canvas
209 | * }
210 | *
211 | *
212 | */
213 | p5.prototype.removeElements = function (e) {
214 | for (var i=0; i
242 | * var myDiv;
243 | * function setup() {
244 | * myDiv = createDiv('this is some text');
245 | * }
246 | *
247 | */
248 |
249 | /**
250 | * Creates a <p></p> element in the DOM with given inner HTML. Used
251 | * for paragraph length text.
252 | * Appends to the container node if one is specified, otherwise
253 | * appends to body.
254 | *
255 | * @method createP
256 | * @param {String} html inner HTML for element created
257 | * @return {Object/p5.Element} pointer to p5.Element holding created node
258 | * @example
259 | *
260 | * var myP;
261 | * function setup() {
262 | * myP = createP('this is some text');
263 | * }
264 | *
265 | */
266 |
267 | /**
268 | * Creates a <span></span> element in the DOM with given inner HTML.
269 | * Appends to the container node if one is specified, otherwise
270 | * appends to body.
271 | *
272 | * @method createSpan
273 | * @param {String} html inner HTML for element created
274 | * @return {Object/p5.Element} pointer to p5.Element holding created node
275 | * @example
276 | *
277 | * var mySpan;
278 | * function setup() {
279 | * mySpan = createSpan('this is some text');
280 | * }
281 | *
282 | */
283 | var tags = ['div', 'p', 'span'];
284 | tags.forEach(function(tag) {
285 | var method = 'create' + tag.charAt(0).toUpperCase() + tag.slice(1);
286 | p5.prototype[method] = function(html) {
287 | var elt = document.createElement(tag);
288 | elt.innerHTML = typeof html === undefined ? "" : html;
289 | return addElement(elt, this);
290 | }
291 | });
292 |
293 | /**
294 | * Creates an <img /> element in the DOM with given src and
295 | * alternate text.
296 | * Appends to the container node if one is specified, otherwise
297 | * appends to body.
298 | *
299 | * @method createImg
300 | * @param {String} src src path or url for image
301 | * @param {String} [alt] alternate text to be used if image does not load
302 | * @param {Function} [successCallback] callback to be called once image data is loaded
303 | * @return {Object/p5.Element} pointer to p5.Element holding created node
304 | * @example
305 | *
306 | * var img;
307 | * function setup() {
308 | * img = createImg('http://p5js.org/img/asterisk-01.png');
309 | * }
310 | *
311 | */
312 | p5.prototype.createImg = function() {
313 | var elt = document.createElement('img');
314 | var args = arguments;
315 | var self;
316 | var setAttrs = function(){
317 | self.width = elt.offsetWidth;
318 | self.height = elt.offsetHeight;
319 | if (args.length > 1 && typeof args[1] === 'function'){
320 | self.fn = args[1];
321 | self.fn();
322 | }else if (args.length > 1 && typeof args[2] === 'function'){
323 | self.fn = args[2];
324 | self.fn();
325 | }
326 | };
327 | elt.src = args[0];
328 | if (args.length > 1 && typeof args[1] === 'string'){
329 | elt.alt = args[1];
330 | }
331 | elt.onload = function(){
332 | setAttrs();
333 | }
334 | self = addElement(elt, this);
335 | return self;
336 | };
337 |
338 | /**
339 | * Creates an <a></a> element in the DOM for including a hyperlink.
340 | * Appends to the container node if one is specified, otherwise
341 | * appends to body.
342 | *
343 | * @method createA
344 | * @param {String} href url of page to link to
345 | * @param {String} html inner html of link element to display
346 | * @param {String} [target] target where new link should open,
347 | * could be _blank, _self, _parent, _top.
348 | * @return {Object/p5.Element} pointer to p5.Element holding created node
349 | * @example
350 | *
351 | * var myLink;
352 | * function setup() {
353 | * myLink = createA('http://p5js.org/', 'this is a link');
354 | * }
355 | *
356 | */
357 | p5.prototype.createA = function(href, html, target) {
358 | var elt = document.createElement('a');
359 | elt.href = href;
360 | elt.innerHTML = html;
361 | if (target) elt.target = target;
362 | return addElement(elt, this);
363 | };
364 |
365 | /** INPUT **/
366 |
367 |
368 | /**
369 | * Creates a slider <input></input> element in the DOM.
370 | * Use .size() to set the display length of the slider.
371 | * Appends to the container node if one is specified, otherwise
372 | * appends to body.
373 | *
374 | * @method createSlider
375 | * @param {Number} min minimum value of the slider
376 | * @param {Number} max maximum value of the slider
377 | * @param {Number} [value] default value of the slider
378 | * @param {Number} [step] step size for each tick of the slider
379 | * @return {Object/p5.Element} pointer to p5.Element holding created node
380 | * @example
381 | *
382 | * var slider;
383 | * function setup() {
384 | * slider = createSlider(0, 255, 100);
385 | * slider.position(10, 10);
386 | * slider.style('width', '80px');
387 | * }
388 | *
389 | * function draw() {
390 | * var val = slider.value();
391 | * background(val);
392 | * }
393 | *
394 | *
395 | *
396 | * var slider;
397 | * function setup() {
398 | * colorMode(HSB);
399 | * slider = createSlider(0, 360, 60, 40);
400 | * slider.position(10, 10);
401 | * slider.style('width', '80px');
402 | * }
403 | *
404 | * function draw() {
405 | * var val = slider.value();
406 | * background(val, 100, 100, 1);
407 | * }
408 | *
409 | */
410 | p5.prototype.createSlider = function(min, max, value, step) {
411 | var elt = document.createElement('input');
412 | elt.type = 'range';
413 | elt.min = min;
414 | elt.max = max;
415 | if (step) elt.step = step;
416 | if (typeof(value) === "number") elt.value = value;
417 | return addElement(elt, this);
418 | };
419 |
420 | /**
421 | * Creates a <button></button> element in the DOM.
422 | * Use .size() to set the display size of the button.
423 | * Use .mousePressed() to specify behavior on press.
424 | * Appends to the container node if one is specified, otherwise
425 | * appends to body.
426 | *
427 | * @method createButton
428 | * @param {String} label label displayed on the button
429 | * @param {String} [value] value of the button
430 | * @return {Object/p5.Element} pointer to p5.Element holding created node
431 | * @example
432 | *
433 | * var button;
434 | * function setup() {
435 | * createCanvas(100, 100);
436 | * background(0);
437 | * button = createButton('click me');
438 | * button.position(19, 19);
439 | * button.mousePressed(changeBG);
440 | * }
441 | *
442 | * function changeBG() {
443 | * var val = random(255);
444 | * background(val);
445 | * }
446 | *
447 | */
448 | p5.prototype.createButton = function(label, value) {
449 | var elt = document.createElement('button');
450 | elt.innerHTML = label;
451 | elt.value = value;
452 | if (value) elt.value = value;
453 | return addElement(elt, this);
454 | };
455 |
456 | /**
457 | * Creates a checkbox <input></input> element in the DOM.
458 | * Calling .checked() on a checkbox returns if it is checked or not
459 | *
460 | * @method createCheckbox
461 | * @param {String} [label] label displayed after checkbox
462 | * @param {boolean} [value] value of the checkbox; checked is true, unchecked is false.Unchecked if no value given
463 | * @return {Object/p5.Element} pointer to p5.Element holding created node
464 | * @example
465 | *
466 | * var checkbox;
467 | *
468 | * function setup() {
469 | * checkbox = createCheckbox('label', false);
470 | * checkbox.changed(myCheckedEvent);
471 | * }
472 | *
473 | * function myCheckedEvent() {
474 | * if (this.checked()) {
475 | * console.log("Checking!");
476 | * } else {
477 | * console.log("Unchecking!");
478 | * }
479 | * }
480 | *
481 | */
482 | p5.prototype.createCheckbox = function() {
483 | var elt = document.createElement('div');
484 | var checkbox = document.createElement('input');
485 | checkbox.type = 'checkbox';
486 | elt.appendChild(checkbox);
487 | //checkbox must be wrapped in p5.Element before label so that label appears after
488 | var self = addElement(elt, this);
489 | self.checked = function(){
490 | var cb = self.elt.getElementsByTagName('input')[0];
491 | if (cb) {
492 | if (arguments.length === 0){
493 | return cb.checked;
494 | }else if(arguments[0]){
495 | cb.checked = true;
496 | }else{
497 | cb.checked = false;
498 | }
499 | }
500 | return self;
501 | };
502 | this.value = function(val){
503 | self.value = val;
504 | return this;
505 | };
506 | if (arguments[0]){
507 | var ran = Math.random().toString(36).slice(2);
508 | var label = document.createElement('label');
509 | checkbox.setAttribute('id', ran);
510 | label.htmlFor = ran;
511 | self.value(arguments[0]);
512 | label.appendChild(document.createTextNode(arguments[0]));
513 | elt.appendChild(label);
514 | }
515 | if (arguments[1]){
516 | checkbox.checked = true;
517 | }
518 | return self;
519 | };
520 |
521 | /**
522 | * Creates a dropdown menu <select></select> element in the DOM.
523 | * @method createSelect
524 | * @param {boolean} [multiple] [true if dropdown should support multiple selections]
525 | * @return {Object/p5.Element} pointer to p5.Element holding created node
526 | * @example
527 | *
528 | * var sel;
529 | *
530 | * function setup() {
531 | * textAlign(CENTER);
532 | * background(200);
533 | * sel = createSelect();
534 | * sel.position(10, 10);
535 | * sel.option('pear');
536 | * sel.option('kiwi');
537 | * sel.option('grape');
538 | * sel.changed(mySelectEvent);
539 | * }
540 | *
541 | * function mySelectEvent() {
542 | * var item = sel.value();
543 | * background(200);
544 | * text("it's a "+item+"!", 50, 50);
545 | * }
546 | *
547 | */
548 | p5.prototype.createSelect = function(mult) {
549 | var elt = document.createElement('select');
550 | if (mult){
551 | elt.setAttribute('multiple', 'true');
552 | }
553 | var self = addElement(elt, this);
554 | self.option = function(name, value){
555 | var opt = document.createElement('option');
556 | opt.innerHTML = name;
557 | if (arguments.length > 1)
558 | opt.value = value;
559 | else
560 | opt.value = name;
561 | elt.appendChild(opt);
562 | };
563 | self.selected = function(value){
564 | var arr = [];
565 | if (arguments.length > 0){
566 | for (var i = 0; i < this.elt.length; i++){
567 | if (value.toString() === this.elt[i].value){
568 | this.elt.selectedIndex = i;
569 | }
570 | }
571 | return this;
572 | }else{
573 | if (mult){
574 | for (var i = 0; i < this.elt.selectedOptions.length; i++){
575 | arr.push(this.elt.selectedOptions[i].value);
576 | }
577 | return arr;
578 | }else{
579 | return this.elt.value;
580 | }
581 | }
582 | };
583 | return self;
584 | };
585 |
586 | /**
587 | * Creates a radio button <input></input> element in the DOM.
588 | * The .option() method can be used to set options for the radio after it is
589 | * created. The .value() method will return the currently selected option.
590 | *
591 | * @method createRadio
592 | * @param {String} [divId] the id and name of the created div and input field respectively
593 | * @return {Object/p5.Element} pointer to p5.Element holding created node
594 | * @example
595 | *
596 | * var radio;
597 | *
598 | * function setup() {
599 | * radio = createRadio();
600 | * radio.option("black");
601 | * radio.option("white");
602 | * radio.option("gray");
603 | * radio.style('width', '60px');
604 | * textAlign(CENTER);
605 | * fill(255, 0, 0);
606 | * }
607 | *
608 | * function draw() {
609 | * var val = radio.value();
610 | * background(val);
611 | * text(val, width/2, height/2);
612 | * }
613 | *
614 | *
615 | * var radio;
616 | *
617 | * function setup() {
618 | * radio = createRadio();
619 | * radio.option('apple', 1);
620 | * radio.option('bread', 2);
621 | * radio.option('juice', 3);
622 | * radio.style('width', '60px');
623 | * textAlign(CENTER);
624 | * }
625 | *
626 | * function draw() {
627 | * background(200);
628 | * var val = radio.value();
629 | * if (val) {
630 | * text('item cost is $'+val, width/2, height/2);
631 | * }
632 | * }
633 | *
634 | */
635 | p5.prototype.createRadio = function() {
636 | var radios = document.querySelectorAll("input[type=radio]");
637 | var count = 0;
638 | if(radios.length > 1){
639 | var length = radios.length;
640 | var prev=radios[0].name;
641 | var current = radios[1].name;
642 | count = 1;
643 | for(var i = 1; i < length; i++) {
644 | current = radios[i].name;
645 | if(prev != current){
646 | count++;
647 | }
648 | prev = current;
649 | }
650 | }
651 | else if (radios.length == 1){
652 | count = 1;
653 | }
654 | var elt = document.createElement('div');
655 | var self = addElement(elt, this);
656 | var times = -1;
657 | self.option = function(name, value){
658 | var opt = document.createElement('input');
659 | opt.type = 'radio';
660 | opt.innerHTML = name;
661 | if (arguments.length > 1)
662 | opt.value = value;
663 | else
664 | opt.value = name;
665 | opt.setAttribute('name',"defaultradio"+count);
666 | elt.appendChild(opt);
667 | if (name){
668 | times++;
669 | var ran = Math.random().toString(36).slice(2);
670 | var label = document.createElement('label');
671 | opt.setAttribute('id', "defaultradio"+count+"-"+times);
672 | label.htmlFor = "defaultradio"+count+"-"+times;
673 | label.appendChild(document.createTextNode(name));
674 | elt.appendChild(label);
675 | }
676 | return opt;
677 | };
678 | self.selected = function(){
679 | var length = this.elt.childNodes.length;
680 | if(arguments.length == 1) {
681 | for (var i = 0; i < length; i+=2){
682 | if(this.elt.childNodes[i].value == arguments[0])
683 | this.elt.childNodes[i].checked = true;
684 | }
685 | return this;
686 | } else {
687 | for (var i = 0; i < length; i+=2){
688 | if(this.elt.childNodes[i].checked == true)
689 | return this.elt.childNodes[i].value;
690 | }
691 | }
692 | };
693 | self.value = function(){
694 | var length = this.elt.childNodes.length;
695 | if(arguments.length == 1) {
696 | for (var i = 0; i < length; i+=2){
697 | if(this.elt.childNodes[i].value == arguments[0])
698 | this.elt.childNodes[i].checked = true;
699 | }
700 | return this;
701 | } else {
702 | for (var i = 0; i < length; i+=2){
703 | if(this.elt.childNodes[i].checked == true)
704 | return this.elt.childNodes[i].value;
705 | }
706 | return "";
707 | }
708 | };
709 | return self
710 | };
711 |
712 | /**
713 | * Creates an <input></input> element in the DOM for text input.
714 | * Use .size() to set the display length of the box.
715 | * Appends to the container node if one is specified, otherwise
716 | * appends to body.
717 | *
718 | * @method createInput
719 | * @param {Number} [value] default value of the input box
720 | * @return {Object/p5.Element} pointer to p5.Element holding created node
721 | * @example
722 | *
723 | * function setup(){
724 | * var inp = createInput('');
725 | * inp.input(myInputEvent);
726 | * }
727 | *
728 | * function myInputEvent(){
729 | * console.log('you are typing: ', this.value());
730 | * }
731 | *
732 | *
733 | */
734 | p5.prototype.createInput = function(value) {
735 | var elt = document.createElement('input');
736 | elt.type = 'text';
737 | if (value) elt.value = value;
738 | return addElement(elt, this);
739 | };
740 |
741 | /**
742 | * Creates an <input></input> element in the DOM of type 'file'.
743 | * This allows users to select local files for use in a sketch.
744 | *
745 | * @method createFileInput
746 | * @param {Function} [callback] callback function for when a file loaded
747 | * @param {String} [multiple] optional to allow multiple files selected
748 | * @return {Object/p5.Element} pointer to p5.Element holding created DOM element
749 | */
750 | p5.prototype.createFileInput = function(callback, multiple) {
751 |
752 | // Is the file stuff supported?
753 | if (window.File && window.FileReader && window.FileList && window.Blob) {
754 | // Yup, we're ok and make an input file selector
755 | var elt = document.createElement('input');
756 | elt.type = 'file';
757 |
758 | // If we get a second argument that evaluates to true
759 | // then we are looking for multiple files
760 | if (multiple) {
761 | // Anything gets the job done
762 | elt.multiple = 'multiple';
763 | }
764 |
765 | // Function to handle when a file is selected
766 | // We're simplifying life and assuming that we always
767 | // want to load every selected file
768 | function handleFileSelect(evt) {
769 | // These are the files
770 | var files = evt.target.files;
771 | // Load each one and trigger a callback
772 | for (var i = 0; i < files.length; i++) {
773 | var f = files[i];
774 | var reader = new FileReader();
775 | function makeLoader(theFile) {
776 | // Making a p5.File object
777 | var p5file = new p5.File(theFile);
778 | return function(e) {
779 | p5file.data = e.target.result;
780 | callback(p5file);
781 | };
782 | };
783 | reader.onload = makeLoader(f);
784 |
785 | // Text or data?
786 | // This should likely be improved
787 | if (f.type.indexOf('text') > -1) {
788 | reader.readAsText(f);
789 | } else {
790 | reader.readAsDataURL(f);
791 | }
792 | }
793 | }
794 |
795 | // Now let's handle when a file was selected
796 | elt.addEventListener('change', handleFileSelect, false);
797 | return addElement(elt, this);
798 | } else {
799 | console.log('The File APIs are not fully supported in this browser. Cannot create element.');
800 | }
801 | };
802 |
803 |
804 | /** VIDEO STUFF **/
805 |
806 | function createMedia(pInst, type, src, callback) {
807 | var elt = document.createElement(type);
808 |
809 | // allow src to be empty
810 | var src = src || '';
811 | if (typeof src === 'string') {
812 | src = [src];
813 | }
814 | for (var i=0; ithis
850 | * page for further information about supported formats.
851 | *
852 | * @method createVideo
853 | * @param {String|Array} src path to a video file, or array of paths for
854 | * supporting different browsers
855 | * @param {Object} [callback] callback function to be called upon
856 | * 'canplaythrough' event fire, that is, when the
857 | * browser can play the media, and estimates that
858 | * enough data has been loaded to play the media
859 | * up to its end without having to stop for
860 | * further buffering of content
861 | * @return {Object/p5.Element} pointer to video p5.Element
862 | */
863 | p5.prototype.createVideo = function(src, callback) {
864 | return createMedia(this, 'video', src, callback);
865 | };
866 |
867 | /** AUDIO STUFF **/
868 |
869 | /**
870 | * Creates a hidden HTML5 <audio> element in the DOM for simple audio
871 | * playback. Appends to the container node if one is specified,
872 | * otherwise appends to body. The first parameter
873 | * can be either a single string path to a audio file, or an array of string
874 | * paths to different formats of the same audio. This is useful for ensuring
875 | * that your audio can play across different browsers, as each supports
876 | * different formats. See this
877 | * page for further information about supported formats.
878 | *
879 | * @method createAudio
880 | * @param {String|Array} src path to an audio file, or array of paths for
881 | * supporting different browsers
882 | * @param {Object} [callback] callback function to be called upon
883 | * 'canplaythrough' event fire, that is, when the
884 | * browser can play the media, and estimates that
885 | * enough data has been loaded to play the media
886 | * up to its end without having to stop for
887 | * further buffering of content
888 | * @return {Object/p5.Element} pointer to audio p5.Element
889 | */
890 | p5.prototype.createAudio = function(src, callback) {
891 | return createMedia(this, 'audio', src, callback);
892 | };
893 |
894 |
895 | /** CAMERA STUFF **/
896 |
897 | p5.prototype.VIDEO = 'video';
898 | p5.prototype.AUDIO = 'audio';
899 |
900 | navigator.getUserMedia = navigator.getUserMedia ||
901 | navigator.webkitGetUserMedia ||
902 | navigator.mozGetUserMedia ||
903 | navigator.msGetUserMedia;
904 |
905 | /**
906 | * Creates a new <video> element that contains the audio/video feed
907 | * from a webcam. This can be drawn onto the canvas using video().
908 | * More specific properties of the feed can be passing in a Constraints object.
909 | * See the
910 | * W3C
911 | * spec for possible properties. Note that not all of these are supported
912 | * by all browsers.
913 | * Security note: A new browser security specification requires that getUserMedia,
914 | * which is behind createCapture(), only works when you're running the code locally,
915 | * or on HTTPS. Learn more here
916 | * and here.
917 | *
918 | * @method createCapture
919 | * @param {String|Constant|Object} type type of capture, either VIDEO or
920 | * AUDIO if none specified, default both,
921 | * or a Constraints object
922 | * @param {Function} callback function to be called once
923 | * stream has loaded
924 | * @return {Object/p5.Element} capture video p5.Element
925 | * @example
926 | *
927 | * var capture;
928 | *
929 | * function setup() {
930 | * createCanvas(480, 120);
931 | * capture = createCapture(VIDEO);
932 | * }
933 | *
934 | * function draw() {
935 | * image(capture, 0, 0, width, width*capture.height/capture.width);
936 | * filter(INVERT);
937 | * }
938 | *
939 | *
940 | * function setup() {
941 | * createCanvas(480, 120);
942 | * var constraints = {
943 | * video: {
944 | * mandatory: {
945 | * minWidth: 1280,
946 | * minHeight: 720
947 | * },
948 | * optional: [
949 | * { maxFrameRate: 10 }
950 | * ]
951 | * },
952 | * audio: true
953 | * };
954 | * createCapture(constraints, function(stream) {
955 | * console.log(stream);
956 | * });
957 | * }
958 | *
959 | */
960 | p5.prototype.createCapture = function() {
961 | var useVideo = true;
962 | var useAudio = true;
963 | var constraints;
964 | var cb;
965 | for (var i=0; i
1016 | * var h2 = createElement('h2','im an h2 p5.element!');
1017 | *
1018 | */
1019 | p5.prototype.createElement = function(tag, content) {
1020 | var elt = document.createElement(tag);
1021 | if (typeof content !== 'undefined') {
1022 | elt.innerHTML = content;
1023 | }
1024 | return addElement(elt, this);
1025 | };
1026 |
1027 |
1028 | // =============================================================================
1029 | // p5.Element additions
1030 | // =============================================================================
1031 | /**
1032 | *
1033 | * Adds specified class to the element.
1034 | *
1035 | * @for p5.Element
1036 | * @method addClass
1037 | * @param {String} class name of class to add
1038 | * @return {Object/p5.Element}
1039 | * @example
1040 | *
1041 | * var div = createDiv('div');
1042 | * div.addClass('myClass');
1043 | *
1044 | */
1045 | p5.Element.prototype.addClass = function(c) {
1046 | if (this.elt.className) {
1047 | // PEND don't add class more than once
1048 | //var regex = new RegExp('[^a-zA-Z\d:]?'+c+'[^a-zA-Z\d:]?');
1049 | //if (this.elt.className.search(/[^a-zA-Z\d:]?hi[^a-zA-Z\d:]?/) === -1) {
1050 | this.elt.className = this.elt.className+' '+c;
1051 | //}
1052 | } else {
1053 | this.elt.className = c;
1054 | }
1055 | return this;
1056 | }
1057 |
1058 | /**
1059 | *
1060 | * Removes specified class from the element.
1061 | *
1062 | * @method removeClass
1063 | * @param {String} class name of class to remove
1064 | * @return {Object/p5.Element}
1065 | */
1066 | p5.Element.prototype.removeClass = function(c) {
1067 | var regex = new RegExp('(?:^|\\s)'+c+'(?!\\S)');
1068 | this.elt.className = this.elt.className.replace(regex, '');
1069 | this.elt.className = this.elt.className.replace(/^\s+|\s+$/g, ""); //prettify (optional)
1070 | return this;
1071 | }
1072 |
1073 | /**
1074 | *
1075 | * Attaches the element as a child to the parent specified.
1076 | * Accepts either a string ID, DOM node, or p5.Element.
1077 | * If no argument is specified, an array of children DOM nodes is returned.
1078 | *
1079 | * @method child
1080 | * @param {String|Object|p5.Element} [child] the ID, DOM node, or p5.Element
1081 | * to add to the current element
1082 | * @return {p5.Element}
1083 | * @example
1084 | *
1085 | * var div0 = createDiv('this is the parent');
1086 | * var div1 = createDiv('this is the child');
1087 | * div0.child(div1); // use p5.Element
1088 | *
1089 | *
1090 | * var div0 = createDiv('this is the parent');
1091 | * var div1 = createDiv('this is the child');
1092 | * div1.id('apples');
1093 | * div0.child('apples'); // use id
1094 | *
1095 | *
1096 | * var div0 = createDiv('this is the parent');
1097 | * var elt = document.getElementById('myChildDiv');
1098 | * div0.child(elt); // use element from page
1099 | *
1100 | */
1101 | p5.Element.prototype.child = function(c) {
1102 | if (c === null){
1103 | return this.elt.childNodes
1104 | }
1105 | if (typeof c === 'string') {
1106 | if (c[0] === '#') {
1107 | c = c.substring(1);
1108 | }
1109 | c = document.getElementById(c);
1110 | } else if (c instanceof p5.Element) {
1111 | c = c.elt;
1112 | }
1113 | this.elt.appendChild(c);
1114 | return this;
1115 | };
1116 |
1117 | /**
1118 | * Centers a p5 Element either vertically, horizontally,
1119 | * or both, relative to its parent or according to
1120 | * the body if the Element has no parent. If no argument is passed
1121 | * the Element is aligned both vertically and horizontally.
1122 | *
1123 | * @param {String} align passing 'vertical', 'horizontal' aligns element accordingly
1124 | * @return {Object/p5.Element} pointer to p5.Element
1125 | * @example
1126 | *
1127 | * function setup() {
1128 | * var div = createDiv('').size(10,10);
1129 | * div.style('background-color','orange');
1130 | * div.center();
1131 | *
1132 | * }
1133 | *
1134 | */
1135 | p5.Element.prototype.center = function(align) {
1136 | var style = this.elt.style.display;
1137 | var hidden = this.elt.style.display === 'none';
1138 | var parentHidden = this.parent().style.display === 'none';
1139 | var pos = { x : this.elt.offsetLeft, y : this.elt.offsetTop };
1140 |
1141 | if (hidden) this.show();
1142 |
1143 | this.elt.style.display = 'block';
1144 | this.position(0,0);
1145 |
1146 | if (parentHidden) this.parent().style.display = 'block';
1147 |
1148 | var wOffset = Math.abs(this.parent().offsetWidth - this.elt.offsetWidth);
1149 | var hOffset = Math.abs(this.parent().offsetHeight - this.elt.offsetHeight);
1150 | var y = pos.y;
1151 | var x = pos.x;
1152 |
1153 | if (align === 'both' || align === undefined){
1154 | this.position(wOffset/2, hOffset/2);
1155 | }else if (align === 'horizontal'){
1156 | this.position(wOffset/2, y);
1157 | }else if (align === 'vertical'){
1158 | this.position(x, hOffset/2);
1159 | }
1160 |
1161 | this.style('display', style);
1162 |
1163 | if (hidden) this.hide();
1164 |
1165 | if (parentHidden) this.parent().style.display = 'none';
1166 |
1167 | return this;
1168 | };
1169 |
1170 | /**
1171 | *
1172 | * If an argument is given, sets the inner HTML of the element,
1173 | * replacing any existing html. If no arguments are given, returns
1174 | * the inner HTML of the element.
1175 | *
1176 | * @for p5.Element
1177 | * @method html
1178 | * @param {String} [html] the HTML to be placed inside the element
1179 | * @return {Object/p5.Element|String}
1180 | * @example
1181 | *
1182 | * var div = createDiv('').size(100,100);
1183 | * div.style('background-color','orange');
1184 | * div.html('hi');
1185 | *
1186 | */
1187 | p5.Element.prototype.html = function(html) {
1188 | if (typeof html !== 'undefined') {
1189 | this.elt.innerHTML = html;
1190 | return this;
1191 | } else {
1192 | return this.elt.innerHTML;
1193 | }
1194 | };
1195 |
1196 | /**
1197 | *
1198 | * Sets the position of the element relative to (0, 0) of the
1199 | * window. Essentially, sets position:absolute and left and top
1200 | * properties of style. If no arguments given returns the x and y position
1201 | * of the element in an object.
1202 | *
1203 | * @method position
1204 | * @param {Number} [x] x-position relative to upper left of window
1205 | * @param {Number} [y] y-position relative to upper left of window
1206 | * @return {Object/p5.Element}
1207 | * @example
1208 | *
1209 | * function setup() {
1210 | * var cnv = createCanvas(100, 100);
1211 | * // positions canvas 50px to the right and 100px
1212 | * // below upper left corner of the window
1213 | * cnv.position(50, 100);
1214 | * }
1215 | *
1216 | */
1217 | p5.Element.prototype.position = function() {
1218 | if (arguments.length === 0){
1219 | return { 'x' : this.elt.offsetLeft , 'y' : this.elt.offsetTop };
1220 | }else{
1221 | this.elt.style.position = 'absolute';
1222 | this.elt.style.left = arguments[0]+'px';
1223 | this.elt.style.top = arguments[1]+'px';
1224 | this.x = arguments[0];
1225 | this.y = arguments[1];
1226 | return this;
1227 | }
1228 | };
1229 |
1230 | /* Helper method called by p5.Element.style() */
1231 | p5.Element.prototype._translate = function(){
1232 | this.elt.style.position = 'absolute';
1233 | // save out initial non-translate transform styling
1234 | var transform = '';
1235 | if (this.elt.style.transform) {
1236 | transform = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
1237 | transform = transform.replace(/translate[X-Z]?\(.*\)/g, '');
1238 | }
1239 | if (arguments.length === 2) {
1240 | this.elt.style.transform = 'translate('+arguments[0]+'px, '+arguments[1]+'px)';
1241 | } else if (arguments.length > 2) {
1242 | this.elt.style.transform = 'translate3d('+arguments[0]+'px,'+arguments[1]+'px,'+arguments[2]+'px)';
1243 | if (arguments.length === 3) {
1244 | this.elt.parentElement.style.perspective = '1000px';
1245 | } else {
1246 | this.elt.parentElement.style.perspective = arguments[3]+'px';
1247 | }
1248 | }
1249 | // add any extra transform styling back on end
1250 | this.elt.style.transform += transform;
1251 | return this;
1252 | };
1253 |
1254 | /* Helper method called by p5.Element.style() */
1255 | p5.Element.prototype._rotate = function(){
1256 | // save out initial non-rotate transform styling
1257 | var transform = '';
1258 | if (this.elt.style.transform) {
1259 | var transform = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
1260 | transform = transform.replace(/rotate[X-Z]?\(.*\)/g, '');
1261 | }
1262 |
1263 | if (arguments.length === 1){
1264 | this.elt.style.transform = 'rotate('+arguments[0]+'deg)';
1265 | }else if (arguments.length === 2){
1266 | this.elt.style.transform = 'rotate('+arguments[0]+'deg, '+arguments[1]+'deg)';
1267 | }else if (arguments.length === 3){
1268 | this.elt.style.transform = 'rotateX('+arguments[0]+'deg)';
1269 | this.elt.style.transform += 'rotateY('+arguments[1]+'deg)';
1270 | this.elt.style.transform += 'rotateZ('+arguments[2]+'deg)';
1271 | }
1272 | // add remaining transform back on
1273 | this.elt.style.transform += transform;
1274 | return this;
1275 | };
1276 |
1277 | /**
1278 | * Sets the given style (css) property (1st arg) of the element with the
1279 | * given value (2nd arg). If a single argument is given, .style()
1280 | * returns the value of the given property; however, if the single argument
1281 | * is given in css syntax ('text-align:center'), .style() sets the css
1282 | * appropriatly. .style() also handles 2d and 3d css transforms. If
1283 | * the 1st arg is 'rotate', 'translate', or 'position', the following arguments
1284 | * accept Numbers as values. ('translate', 10, 100, 50);
1285 | *
1286 | * @method style
1287 | * @param {String} property property to be set
1288 | * @param {String|Number|p5.Color} [value] value to assign to property
1289 | * @param {String|Number} [value] value to assign to property (rotate/translate)
1290 | * @param {String|Number} [value] value to assign to property (rotate/translate)
1291 | * @param {String|Number} [value] value to assign to property (translate)
1292 | * @return {String|Object/p5.Element} value of property, if no value is specified
1293 | * or p5.Element
1294 | * @example
1295 | *
1296 | * var myDiv = createDiv("I like pandas.");
1297 | * myDiv.style("font-size", "18px");
1298 | * myDiv.style("color", "#ff0000");
1299 | *
1300 | *
1301 | * var col = color(25,23,200,50);
1302 | * var button = createButton("button");
1303 | * button.style("background-color", col);
1304 | * button.position(10, 10);
1305 | *
1306 | *
1307 | * var myDiv = createDiv("I like lizards.");
1308 | * myDiv.style("position", 20, 20);
1309 | * myDiv.style("rotate", 45);
1310 | *
1311 | *
1312 | * var myDiv;
1313 | * function setup() {
1314 | * background(200);
1315 | * myDiv = createDiv("I like gray.");
1316 | * myDiv.position(20, 20);
1317 | * }
1318 | *
1319 | * function draw() {
1320 | * myDiv.style("font-size", mouseX+"px");
1321 | * }
1322 | *
1323 | */
1324 | p5.Element.prototype.style = function(prop, val) {
1325 | var self = this;
1326 |
1327 | if (val instanceof p5.Color) {
1328 | val = 'rgba(' + val.levels[0] + ',' + val.levels[1] + ',' + val.levels[2] + ',' + val.levels[3]/255 + ')'
1329 | }
1330 |
1331 | if (typeof val === 'undefined') {
1332 | if (prop.indexOf(':') === -1) {
1333 | var styles = window.getComputedStyle(self.elt);
1334 | var style = styles.getPropertyValue(prop);
1335 | return style;
1336 | } else {
1337 | var attrs = prop.split(';');
1338 | for (var i = 0; i < attrs.length; i++) {
1339 | var parts = attrs[i].split(':');
1340 | if (parts[0] && parts[1]) {
1341 | this.elt.style[parts[0].trim()] = parts[1].trim();
1342 | }
1343 | }
1344 | }
1345 | } else {
1346 | if (prop === 'rotate' || prop === 'translate' || prop === 'position'){
1347 | var trans = Array.prototype.shift.apply(arguments);
1348 | var f = this[trans] || this['_'+trans];
1349 | f.apply(this, arguments);
1350 | } else {
1351 | this.elt.style[prop] = val;
1352 | if (prop === 'width' || prop === 'height' || prop === 'left' || prop === 'top') {
1353 | var numVal = val.replace(/\D+/g, '');
1354 | this[prop] = parseInt(numVal, 10); // pend: is this necessary?
1355 | }
1356 | }
1357 | }
1358 | return this;
1359 | };
1360 |
1361 |
1362 | /**
1363 | *
1364 | * Adds a new attribute or changes the value of an existing attribute
1365 | * on the specified element. If no value is specified, returns the
1366 | * value of the given attribute, or null if attribute is not set.
1367 | *
1368 | * @method attribute
1369 | * @param {String} attr attribute to set
1370 | * @param {String} [value] value to assign to attribute
1371 | * @return {String|Object/p5.Element} value of attribute, if no value is
1372 | * specified or p5.Element
1373 | * @example
1374 | *
1375 | * var myDiv = createDiv("I like pandas.");
1376 | * myDiv.attribute("align", "center");
1377 | *
1378 | */
1379 | p5.Element.prototype.attribute = function(attr, value) {
1380 | if (typeof value === 'undefined') {
1381 | return this.elt.getAttribute(attr);
1382 | } else {
1383 | this.elt.setAttribute(attr, value);
1384 | return this;
1385 | }
1386 | };
1387 |
1388 |
1389 | /**
1390 | *
1391 | * Removes an attribute on the specified element.
1392 | *
1393 | * @method removeAttribute
1394 | * @param {String} attr attribute to remove
1395 | * @return {Object/p5.Element}
1396 | *
1397 | * @example
1398 | *
1399 | * var button;
1400 | * var checkbox;
1401 | *
1402 | * function setup() {
1403 | * checkbox = createCheckbox('enable', true);
1404 | * checkbox.changed(enableButton);
1405 | * button = createButton('button');
1406 | * button.position(10, 10);
1407 | * }
1408 | *
1409 | * function enableButton() {
1410 | * if( this.checked() ) {
1411 | * // Re-enable the button
1412 | * button.removeAttribute('disabled');
1413 | * } else {
1414 | * // Disable the button
1415 | * button.attribute('disabled','');
1416 | * }
1417 | * }
1418 | *
1419 | */
1420 | p5.Element.prototype.removeAttribute = function(attr) {
1421 | this.elt.removeAttribute(attr);
1422 | return this;
1423 | };
1424 |
1425 |
1426 | /**
1427 | * Either returns the value of the element if no arguments
1428 | * given, or sets the value of the element.
1429 | *
1430 | * @method value
1431 | * @param {String|Number} [value]
1432 | * @return {String|Object/p5.Element} value of element if no value is specified or p5.Element
1433 | * @example
1434 | *
1435 | * // gets the value
1436 | * var inp;
1437 | * function setup() {
1438 | * inp = createInput('');
1439 | * }
1440 | *
1441 | * function mousePressed() {
1442 | * print(inp.value());
1443 | * }
1444 | *
1445 | *
1446 | * // sets the value
1447 | * var inp;
1448 | * function setup() {
1449 | * inp = createInput('myValue');
1450 | * }
1451 | *
1452 | * function mousePressed() {
1453 | * inp.value("myValue");
1454 | * }
1455 | *
1456 | */
1457 | p5.Element.prototype.value = function() {
1458 | if (arguments.length > 0) {
1459 | this.elt.value = arguments[0];
1460 | return this;
1461 | } else {
1462 | if (this.elt.type === 'range') {
1463 | return parseFloat(this.elt.value);
1464 | }
1465 | else return this.elt.value;
1466 | }
1467 | };
1468 |
1469 | /**
1470 | *
1471 | * Shows the current element. Essentially, setting display:block for the style.
1472 | *
1473 | * @method show
1474 | * @return {Object/p5.Element}
1475 | * @example
1476 | *
1477 | * var div = createDiv('div');
1478 | * div.style("display", "none");
1479 | * div.show(); // turns display to block
1480 | *
1481 | */
1482 | p5.Element.prototype.show = function() {
1483 | this.elt.style.display = 'block';
1484 | return this;
1485 | };
1486 |
1487 | /**
1488 | * Hides the current element. Essentially, setting display:none for the style.
1489 | *
1490 | * @method hide
1491 | * @return {Object/p5.Element}
1492 | * @example
1493 | *
1494 | * var div = createDiv('this is a div');
1495 | * div.hide();
1496 | *
1497 | */
1498 | p5.Element.prototype.hide = function() {
1499 | this.elt.style.display = 'none';
1500 | return this;
1501 | };
1502 |
1503 | /**
1504 | *
1505 | * Sets the width and height of the element. AUTO can be used to
1506 | * only adjust one dimension. If no arguments given returns the width and height
1507 | * of the element in an object.
1508 | *
1509 | * @method size
1510 | * @param {Number} [w] width of the element
1511 | * @param {Number} [h] height of the element
1512 | * @return {Object/p5.Element}
1513 | * @example
1514 | *
1515 | * var div = createDiv('this is a div');
1516 | * div.size(100, 100);
1517 | *
1518 | */
1519 | p5.Element.prototype.size = function(w, h) {
1520 | if (arguments.length === 0){
1521 | return { 'width' : this.elt.offsetWidth , 'height' : this.elt.offsetHeight };
1522 | }else{
1523 | var aW = w;
1524 | var aH = h;
1525 | var AUTO = p5.prototype.AUTO;
1526 | if (aW !== AUTO || aH !== AUTO) {
1527 | if (aW === AUTO) {
1528 | aW = h * this.width / this.height;
1529 | } else if (aH === AUTO) {
1530 | aH = w * this.height / this.width;
1531 | }
1532 | // set diff for cnv vs normal div
1533 | if (this.elt instanceof HTMLCanvasElement) {
1534 | var j = {};
1535 | var k = this.elt.getContext('2d');
1536 | for (var prop in k) {
1537 | j[prop] = k[prop];
1538 | }
1539 | this.elt.setAttribute('width', aW * this._pInst._pixelDensity);
1540 | this.elt.setAttribute('height', aH * this._pInst._pixelDensity);
1541 | this.elt.setAttribute('style', 'width:' + aW + 'px; height:' + aH + 'px');
1542 | this._pInst.scale(this._pInst._pixelDensity, this._pInst._pixelDensity);
1543 | for (var prop in j) {
1544 | this.elt.getContext('2d')[prop] = j[prop];
1545 | }
1546 | } else {
1547 | this.elt.style.width = aW+'px';
1548 | this.elt.style.height = aH+'px';
1549 | this.elt.width = aW;
1550 | this.elt.height = aH;
1551 | this.width = aW;
1552 | this.height = aH;
1553 | }
1554 |
1555 | this.width = this.elt.offsetWidth;
1556 | this.height = this.elt.offsetHeight;
1557 |
1558 | if (this._pInst) { // main canvas associated with p5 instance
1559 | if (this._pInst._curElement.elt === this.elt) {
1560 | this._pInst._setProperty('width', this.elt.offsetWidth);
1561 | this._pInst._setProperty('height', this.elt.offsetHeight);
1562 | }
1563 | }
1564 | }
1565 | return this;
1566 | }
1567 | };
1568 |
1569 | /**
1570 | * Removes the element and deregisters all listeners.
1571 | * @method remove
1572 | * @example
1573 | *
1574 | * var myDiv = createDiv('this is some text');
1575 | * myDiv.remove();
1576 | *
1577 | */
1578 | p5.Element.prototype.remove = function() {
1579 | // deregister events
1580 | for (var ev in this._events) {
1581 | this.elt.removeEventListener(ev, this._events[ev]);
1582 | }
1583 | if (this.elt.parentNode) {
1584 | this.elt.parentNode.removeChild(this.elt);
1585 | }
1586 | delete(this);
1587 | };
1588 |
1589 |
1590 |
1591 | // =============================================================================
1592 | // p5.MediaElement additions
1593 | // =============================================================================
1594 |
1595 |
1596 | /**
1597 | * Extends p5.Element to handle audio and video. In addition to the methods
1598 | * of p5.Element, it also contains methods for controlling media. It is not
1599 | * called directly, but p5.MediaElements are created by calling createVideo,
1600 | * createAudio, and createCapture.
1601 | *
1602 | * @class p5.MediaElement
1603 | * @constructor
1604 | * @param {String} elt DOM node that is wrapped
1605 | * @param {Object} [pInst] pointer to p5 instance
1606 | */
1607 | p5.MediaElement = function(elt, pInst) {
1608 | p5.Element.call(this, elt, pInst);
1609 |
1610 | var self = this;
1611 | this.elt.crossOrigin = 'anonymous';
1612 |
1613 | this._prevTime = 0;
1614 | this._cueIDCounter = 0;
1615 | this._cues = [];
1616 | this._pixelDensity = 1;
1617 |
1618 | /**
1619 | * Path to the media element source.
1620 | *
1621 | * @property src
1622 | * @return {String} src
1623 | */
1624 | Object.defineProperty(self, 'src', {
1625 | get: function() {
1626 | var firstChildSrc = self.elt.children[0].src;
1627 | var srcVal = self.elt.src === window.location.href ? '' : self.elt.src;
1628 | var ret = firstChildSrc === window.location.href ? srcVal : firstChildSrc;
1629 | return ret;
1630 | },
1631 | set: function(newValue) {
1632 | for (var i = 0; i < self.elt.children.length; i++) {
1633 | self.elt.removeChild(self.elt.children[i]);
1634 | }
1635 | var source = document.createElement('source');
1636 | source.src = newValue;
1637 | elt.appendChild(source);
1638 | self.elt.src = newValue;
1639 | },
1640 | });
1641 |
1642 | // private _onended callback, set by the method: onended(callback)
1643 | self._onended = function() {};
1644 | self.elt.onended = function() {
1645 | self._onended(self);
1646 | }
1647 | };
1648 | p5.MediaElement.prototype = Object.create(p5.Element.prototype);
1649 |
1650 |
1651 |
1652 |
1653 | /**
1654 | * Play an HTML5 media element.
1655 | *
1656 | * @method play
1657 | * @return {Object/p5.Element}
1658 | */
1659 | p5.MediaElement.prototype.play = function() {
1660 | if (this.elt.currentTime === this.elt.duration) {
1661 | this.elt.currentTime = 0;
1662 | }
1663 |
1664 | if (this.elt.readyState > 1) {
1665 | this.elt.play();
1666 | } else {
1667 | // in Chrome, playback cannot resume after being stopped and must reload
1668 | this.elt.load();
1669 | this.elt.play();
1670 | }
1671 | return this;
1672 | };
1673 |
1674 | /**
1675 | * Stops an HTML5 media element (sets current time to zero).
1676 | *
1677 | * @method stop
1678 | * @return {Object/p5.Element}
1679 | */
1680 | p5.MediaElement.prototype.stop = function() {
1681 | this.elt.pause();
1682 | this.elt.currentTime = 0;
1683 | return this;
1684 | };
1685 |
1686 | /**
1687 | * Pauses an HTML5 media element.
1688 | *
1689 | * @method pause
1690 | * @return {Object/p5.Element}
1691 | */
1692 | p5.MediaElement.prototype.pause = function() {
1693 | this.elt.pause();
1694 | return this;
1695 | };
1696 |
1697 | /**
1698 | * Set 'loop' to true for an HTML5 media element, and starts playing.
1699 | *
1700 | * @method loop
1701 | * @return {Object/p5.Element}
1702 | */
1703 | p5.MediaElement.prototype.loop = function() {
1704 | this.elt.setAttribute('loop', true);
1705 | this.play();
1706 | return this;
1707 | };
1708 | /**
1709 | * Set 'loop' to false for an HTML5 media element. Element will stop
1710 | * when it reaches the end.
1711 | *
1712 | * @method noLoop
1713 | * @return {Object/p5.Element}
1714 | */
1715 | p5.MediaElement.prototype.noLoop = function() {
1716 | this.elt.setAttribute('loop', false);
1717 | return this;
1718 | };
1719 |
1720 |
1721 | /**
1722 | * Set HTML5 media element to autoplay or not.
1723 | *
1724 | * @method autoplay
1725 | * @param {Boolean} autoplay whether the element should autoplay
1726 | * @return {Object/p5.Element}
1727 | */
1728 | p5.MediaElement.prototype.autoplay = function(val) {
1729 | this.elt.setAttribute('autoplay', val);
1730 | return this;
1731 | };
1732 |
1733 | /**
1734 | * Sets volume for this HTML5 media element. If no argument is given,
1735 | * returns the current volume.
1736 | *
1737 | * @param {Number} [val] volume between 0.0 and 1.0
1738 | * @return {Number|p5.MediaElement} current volume or p5.MediaElement
1739 | * @method volume
1740 | */
1741 | p5.MediaElement.prototype.volume = function(val) {
1742 | if (typeof val === 'undefined') {
1743 | return this.elt.volume;
1744 | } else {
1745 | this.elt.volume = val;
1746 | }
1747 | };
1748 |
1749 | /**
1750 | * If no arguments are given, returns the current playback speed of the
1751 | * element. The speed parameter sets the speed where 2.0 will play the
1752 | * element twice as fast, 0.5 will play at half the speed, and -1 will play
1753 | * the element in normal speed in reverse.(Note that not all browsers support
1754 | * backward playback and even if they do, playback might not be smooth.)
1755 | *
1756 | * @method speed
1757 | * @param {Number} [speed] speed multiplier for element playback
1758 | * @return {Number|Object/p5.MediaElement} current playback speed or p5.MediaElement
1759 | */
1760 | p5.MediaElement.prototype.speed = function(val) {
1761 | if (typeof val === 'undefined') {
1762 | return this.elt.playbackRate;
1763 | } else {
1764 | this.elt.playbackRate = val;
1765 | }
1766 | };
1767 |
1768 | /**
1769 | * If no arguments are given, returns the current time of the element.
1770 | * If an argument is given the current time of the element is set to it.
1771 | *
1772 | * @method time
1773 | * @param {Number} [time] time to jump to (in seconds)
1774 | * @return {Number|Object/p5.MediaElement} current time (in seconds)
1775 | * or p5.MediaElement
1776 | */
1777 | p5.MediaElement.prototype.time = function(val) {
1778 | if (typeof val === 'undefined') {
1779 | return this.elt.currentTime;
1780 | } else {
1781 | this.elt.currentTime = val;
1782 | }
1783 | };
1784 |
1785 | /**
1786 | * Returns the duration of the HTML5 media element.
1787 | *
1788 | * @method duration
1789 | * @return {Number} duration
1790 | */
1791 | p5.MediaElement.prototype.duration = function() {
1792 | return this.elt.duration;
1793 | };
1794 | p5.MediaElement.prototype.pixels = [];
1795 | p5.MediaElement.prototype.loadPixels = function() {
1796 | if (!this.canvas) {
1797 | this.canvas = document.createElement('canvas');
1798 | this.drawingContext = this.canvas.getContext('2d');
1799 | }
1800 | if (this.loadedmetadata) { // wait for metadata for w/h
1801 | if (this.canvas.width !== this.elt.width) {
1802 | this.canvas.width = this.elt.width;
1803 | this.canvas.height = this.elt.height;
1804 | this.width = this.canvas.width;
1805 | this.height = this.canvas.height;
1806 | }
1807 | this.drawingContext.drawImage(this.elt, 0, 0, this.canvas.width, this.canvas.height);
1808 | p5.Renderer2D.prototype.loadPixels.call(this);
1809 | }
1810 | return this;
1811 | }
1812 | p5.MediaElement.prototype.updatePixels = function(x, y, w, h){
1813 | if (this.loadedmetadata) { // wait for metadata
1814 | p5.Renderer2D.prototype.updatePixels.call(this, x, y, w, h);
1815 | }
1816 | return this;
1817 | }
1818 | p5.MediaElement.prototype.get = function(x, y, w, h){
1819 | if (this.loadedmetadata) { // wait for metadata
1820 | return p5.Renderer2D.prototype.get.call(this, x, y, w, h);
1821 | } else if (!x) {
1822 | return new p5.Image(1, 1);
1823 | } else {
1824 | return [0, 0, 0, 255];
1825 | }
1826 | };
1827 | p5.MediaElement.prototype.set = function(x, y, imgOrCol){
1828 | if (this.loadedmetadata) { // wait for metadata
1829 | p5.Renderer2D.prototype.set.call(this, x, y, imgOrCol);
1830 | }
1831 | };
1832 | p5.MediaElement.prototype.copy = function(){
1833 | p5.Renderer2D.prototype.copy.apply(this, arguments);
1834 | };
1835 | /**
1836 | * Schedule an event to be called when the audio or video
1837 | * element reaches the end. If the element is looping,
1838 | * this will not be called. The element is passed in
1839 | * as the argument to the onended callback.
1840 | *
1841 | * @method onended
1842 | * @param {Function} callback function to call when the
1843 | * soundfile has ended. The
1844 | * media element will be passed
1845 | * in as the argument to the
1846 | * callback.
1847 | * @return {Object/p5.MediaElement}
1848 | * @example
1849 | *
1850 | * function setup() {
1851 | * audioEl = createAudio('assets/beat.mp3');
1852 | * audioEl.showControls(true);
1853 | * audioEl.onended(sayDone);
1854 | * }
1855 | *
1856 | * function sayDone(elt) {
1857 | * alert('done playing ' + elt.src );
1858 | * }
1859 | *
1860 | */
1861 | p5.MediaElement.prototype.onended = function(callback) {
1862 | this._onended = callback;
1863 | return this;
1864 | };
1865 |
1866 |
1867 | /*** CONNECT TO WEB AUDIO API / p5.sound.js ***/
1868 |
1869 | /**
1870 | * Send the audio output of this element to a specified audioNode or
1871 | * p5.sound object. If no element is provided, connects to p5's master
1872 | * output. That connection is established when this method is first called.
1873 | * All connections are removed by the .disconnect() method.
1874 | *
1875 | * This method is meant to be used with the p5.sound.js addon library.
1876 | *
1877 | * @method connect
1878 | * @param {AudioNode|p5.sound object} audioNode AudioNode from the Web Audio API,
1879 | * or an object from the p5.sound library
1880 | */
1881 | p5.MediaElement.prototype.connect = function(obj) {
1882 | var audioContext, masterOutput;
1883 |
1884 | // if p5.sound exists, same audio context
1885 | if (typeof p5.prototype.getAudioContext === 'function') {
1886 | audioContext = p5.prototype.getAudioContext();
1887 | masterOutput = p5.soundOut.input;
1888 | } else {
1889 | try {
1890 | audioContext = obj.context;
1891 | masterOutput = audioContext.destination
1892 | } catch(e) {
1893 | throw 'connect() is meant to be used with Web Audio API or p5.sound.js'
1894 | }
1895 | }
1896 |
1897 | // create a Web Audio MediaElementAudioSourceNode if none already exists
1898 | if (!this.audioSourceNode) {
1899 | this.audioSourceNode = audioContext.createMediaElementSource(this.elt);
1900 |
1901 | // connect to master output when this method is first called
1902 | this.audioSourceNode.connect(masterOutput);
1903 | }
1904 |
1905 | // connect to object if provided
1906 | if (obj) {
1907 | if (obj.input) {
1908 | this.audioSourceNode.connect(obj.input);
1909 | } else {
1910 | this.audioSourceNode.connect(obj);
1911 | }
1912 | }
1913 |
1914 | // otherwise connect to master output of p5.sound / AudioContext
1915 | else {
1916 | this.audioSourceNode.connect(masterOutput);
1917 | }
1918 |
1919 | };
1920 |
1921 | /**
1922 | * Disconnect all Web Audio routing, including to master output.
1923 | * This is useful if you want to re-route the output through
1924 | * audio effects, for example.
1925 | *
1926 | * @method disconnect
1927 | */
1928 | p5.MediaElement.prototype.disconnect = function() {
1929 | if (this.audioSourceNode) {
1930 | this.audioSourceNode.disconnect();
1931 | } else {
1932 | throw 'nothing to disconnect';
1933 | }
1934 | };
1935 |
1936 |
1937 | /*** SHOW / HIDE CONTROLS ***/
1938 |
1939 | /**
1940 | * Show the default MediaElement controls, as determined by the web browser.
1941 | *
1942 | * @method showControls
1943 | */
1944 | p5.MediaElement.prototype.showControls = function() {
1945 | // must set style for the element to show on the page
1946 | this.elt.style['text-align'] = 'inherit';
1947 | this.elt.controls = true;
1948 | };
1949 |
1950 | /**
1951 | * Hide the default mediaElement controls.
1952 | *
1953 | * @method hideControls
1954 | */
1955 | p5.MediaElement.prototype.hideControls = function() {
1956 | this.elt.controls = false;
1957 | };
1958 |
1959 | /*** SCHEDULE EVENTS ***/
1960 |
1961 | /**
1962 | * Schedule events to trigger every time a MediaElement
1963 | * (audio/video) reaches a playback cue point.
1964 | *
1965 | * Accepts a callback function, a time (in seconds) at which to trigger
1966 | * the callback, and an optional parameter for the callback.
1967 | *
1968 | * Time will be passed as the first parameter to the callback function,
1969 | * and param will be the second parameter.
1970 | *
1971 | *
1972 | * @method addCue
1973 | * @param {Number} time Time in seconds, relative to this media
1974 | * element's playback. For example, to trigger
1975 | * an event every time playback reaches two
1976 | * seconds, pass in the number 2. This will be
1977 | * passed as the first parameter to
1978 | * the callback function.
1979 | * @param {Function} callback Name of a function that will be
1980 | * called at the given time. The callback will
1981 | * receive time and (optionally) param as its
1982 | * two parameters.
1983 | * @param {Object} [value] An object to be passed as the
1984 | * second parameter to the
1985 | * callback function.
1986 | * @return {Number} id ID of this cue,
1987 | * useful for removeCue(id)
1988 | * @example
1989 | *
1990 | * function setup() {
1991 | * background(255,255,255);
1992 | *
1993 | * audioEl = createAudio('assets/beat.mp3');
1994 | * audioEl.showControls();
1995 | *
1996 | * // schedule three calls to changeBackground
1997 | * audioEl.addCue(0.5, changeBackground, color(255,0,0) );
1998 | * audioEl.addCue(1.0, changeBackground, color(0,255,0) );
1999 | * audioEl.addCue(2.5, changeBackground, color(0,0,255) );
2000 | * audioEl.addCue(3.0, changeBackground, color(0,255,255) );
2001 | * audioEl.addCue(4.2, changeBackground, color(255,255,0) );
2002 | * audioEl.addCue(5.0, changeBackground, color(255,255,0) );
2003 | * }
2004 | *
2005 | * function changeBackground(val) {
2006 | * background(val);
2007 | * }
2008 | *
2009 | */
2010 | p5.MediaElement.prototype.addCue = function(time, callback, val) {
2011 | var id = this._cueIDCounter++;
2012 |
2013 | var cue = new Cue(callback, time, id, val);
2014 | this._cues.push(cue);
2015 |
2016 | if (!this.elt.ontimeupdate) {
2017 | this.elt.ontimeupdate = this._onTimeUpdate.bind(this);
2018 | }
2019 |
2020 | return id;
2021 | };
2022 |
2023 | /**
2024 | * Remove a callback based on its ID. The ID is returned by the
2025 | * addCue method.
2026 | *
2027 | * @method removeCue
2028 | * @param {Number} id ID of the cue, as returned by addCue
2029 | */
2030 | p5.MediaElement.prototype.removeCue = function(id) {
2031 | for (var i = 0; i < this._cues.length; i++) {
2032 | var cue = this._cues[i];
2033 | if (cue.id === id) {
2034 | this.cues.splice(i, 1);
2035 | }
2036 | }
2037 |
2038 | if (this._cues.length === 0) {
2039 | this.elt.ontimeupdate = null
2040 | }
2041 | };
2042 |
2043 | /**
2044 | * Remove all of the callbacks that had originally been scheduled
2045 | * via the addCue method.
2046 | *
2047 | * @method clearCues
2048 | */
2049 | p5.MediaElement.prototype.clearCues = function() {
2050 | this._cues = [];
2051 | this.elt.ontimeupdate = null;
2052 | };
2053 |
2054 | // private method that checks for cues to be fired if events
2055 | // have been scheduled using addCue(callback, time).
2056 | p5.MediaElement.prototype._onTimeUpdate = function() {
2057 | var playbackTime = this.time();
2058 |
2059 | for (var i = 0 ; i < this._cues.length; i++) {
2060 | var callbackTime = this._cues[i].time;
2061 | var val = this._cues[i].val;
2062 |
2063 |
2064 | if (this._prevTime < callbackTime && callbackTime <= playbackTime) {
2065 |
2066 | // pass the scheduled callbackTime as parameter to the callback
2067 | this._cues[i].callback(val);
2068 | }
2069 |
2070 | }
2071 |
2072 | this._prevTime = playbackTime;
2073 | };
2074 |
2075 |
2076 | // Cue inspired by JavaScript setTimeout, and the
2077 | // Tone.js Transport Timeline Event, MIT License Yotam Mann 2015 tonejs.org
2078 | var Cue = function(callback, time, id, val) {
2079 | this.callback = callback;
2080 | this.time = time;
2081 | this.id = id;
2082 | this.val = val;
2083 | };
2084 |
2085 | // =============================================================================
2086 | // p5.File
2087 | // =============================================================================
2088 |
2089 |
2090 | /**
2091 | * Base class for a file
2092 | * Using this for createFileInput
2093 | *
2094 | * @class p5.File
2095 | * @constructor
2096 | * @param {File} file File that is wrapped
2097 | * @param {Object} [pInst] pointer to p5 instance
2098 | */
2099 | p5.File = function(file, pInst) {
2100 | /**
2101 | * Underlying File object. All normal File methods can be called on this.
2102 | *
2103 | * @property file
2104 | */
2105 | this.file = file;
2106 |
2107 | this._pInst = pInst;
2108 |
2109 | // Splitting out the file type into two components
2110 | // This makes determining if image or text etc simpler
2111 | var typeList = file.type.split('/');
2112 | /**
2113 | * File type (image, text, etc.)
2114 | *
2115 | * @property type
2116 | */
2117 | this.type = typeList[0];
2118 | /**
2119 | * File subtype (usually the file extension jpg, png, xml, etc.)
2120 | *
2121 | * @property subtype
2122 | */
2123 | this.subtype = typeList[1];
2124 | /**
2125 | * File name
2126 | *
2127 | * @property name
2128 | */
2129 | this.name = file.name;
2130 | /**
2131 | * File size
2132 | *
2133 | * @property size
2134 | */
2135 | this.size = file.size;
2136 |
2137 | /**
2138 | * URL string containing image data.
2139 | *
2140 | * @property data
2141 | */
2142 | this.data = undefined;
2143 | };
2144 |
2145 | }));
2146 |
--------------------------------------------------------------------------------
/paddle.js:
--------------------------------------------------------------------------------
1 | function Paddle() {
2 | this.w = 160;
3 | this.h = 20;
4 | this.pos = createVector(width / 2 - this.w / 2, height - 40);
5 | this.isMovingLeft = false;
6 | this.isMovingRight = false;
7 |
8 | this.display = function() {
9 | rect(this.pos.x, this.pos.y, this.w, this.h);
10 | }
11 |
12 | this.update = function() {
13 | if (this.isMovingLeft) {
14 | this.move(-20);
15 | } else if (this.isMovingRight) {
16 | this.move(20);
17 | }
18 | }
19 |
20 | this.move = function(step) {
21 | this.pos.x += step;
22 | }
23 |
24 | this.checkEdges = function() {
25 | if (this.pos.x <= 0) this.pos.x = 0;
26 | else if (this.pos.x + this.w >= width) this.pos.x = width - this.w;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/sketch.js:
--------------------------------------------------------------------------------
1 | var paddle;
2 | var ball;
3 | var bricks = [];
4 |
5 | var playingGame = false;
6 | var youWin = false;
7 | var winText;
8 |
9 | function setup() {
10 | createCanvas(windowWidth, windowHeight);
11 |
12 | paddle = new Paddle();
13 | ball = new Ball();
14 |
15 | for (var i = 0; i < 20; i++) {
16 | bricks.push(new Brick());
17 | }
18 | createText();
19 | }
20 |
21 | function draw() {
22 | background(255);
23 |
24 | // bricks
25 | for (var i = 0; i < bricks.length; i++) {
26 | bricks[i].display();
27 | if (ball.hits(bricks[i])) {
28 | if (bricks[i].r >= 40) {
29 | bricks[i].r = bricks[i].r / 2;
30 | } else {
31 | bricks.splice(i, 1);
32 | }
33 | ball.direction.y *= -1;
34 | }
35 | }
36 |
37 | // paddle
38 | paddle.display();
39 | if (playingGame) paddle.checkEdges();
40 | if (playingGame) paddle.update();
41 |
42 | // ball
43 | if (ball.meets(paddle)) {
44 | if (ball.direction.y > 0) ball.direction.y *= -1;
45 | }
46 | ball.display();
47 | if (playingGame) ball.checkEdges();
48 | if (playingGame) ball.update();
49 |
50 | // game logics
51 | if (ball.pos.y > height) {
52 | ball.pos = createVector(width / 2, height / 2);
53 | playingGame = false;
54 | }
55 |
56 | if (bricks.length === 0) {
57 | youWin = true;
58 | playingGame = false;
59 | }
60 |
61 | if (youWin) {
62 | winText.style('display', 'block');
63 | } else {
64 | winText.style('display', 'none');
65 | }
66 | }
67 |
68 | function keyReleased() {
69 | paddle.isMovingRight = false;
70 | paddle.isMovingLeft = false;
71 | }
72 |
73 | function keyPressed() {
74 | if (key === 'a' || key === 'A') {
75 | paddle.isMovingLeft = true;
76 | } else if (key === 'd' || key === 'D') {
77 | paddle.isMovingRight = true;
78 | } else if (key === 's' || key === 'S') {
79 | if (bricks.length === 0) {
80 | for (var i = 0; i < 20; i++) {
81 | bricks.push(new Brick());
82 | }
83 | }
84 | playingGame = true;
85 | youWin = false;
86 | }
87 | }
88 |
89 | function createText() {
90 | winText = createP('YOU WIN!');
91 | winText.position(width / 2, 80);
92 | }
93 |
--------------------------------------------------------------------------------