Stupid Canvas Tricks

8,799 views

Published on

A grab bag of tricks for

0 Comments
7 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
8,799
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
24
Comments
0
Likes
7
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Stupid Canvas Tricks

    1. 1. Stupid Canvas Tricks
    2. 2. Who Am I? Dean Hudson, @deaneroBit Twiddler at Massively Fun
    3. 3. We make games withopen web technology. We’re hiring!
    4. 4. What this is?• Tips tricks and about the Canvas API• 2D Context• Focus on game programming• Focus on bitmaps• Me v. Me Lightning Talks
    5. 5. What this isn’t• A talk about WebGL• Terribly deep on any one topic• A JavaScript or Canvas API tutorial
    6. 6. But first: thedumbest trick Icould think of
    7. 7. Pro Tip: Use HSL instead of RGB when interpolating color.
    8. 8. 1) Basic Tools
    9. 9. A SimpleAnimation Loop
    10. 10. Outline• Call requestAnimationFrame• Handle queued UI events• Call update on your game entities• Render!
    11. 11. Outline• Call requestAnimationFrame• Handle queued UI events• Call update on your game entities• Render!
    12. 12. // game loopgameLoop = { run: function () { this.id = requestAnimationFrame(this.run); update(); draw(); }, stop: function () { cancelAnimationFrame(this.id); }};gameLoop.run();
    13. 13. RAF Shim• Lots of examples on the internet• Set RAF to whichever your browser has• Fallback to set timeout at ~16ms
    14. 14. buildRAFPolyfill = function () { window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (cb, elt) { window.setTimeout(function() { cb(+new Date()); }, 1000 / 60); };}
    15. 15. Profiling
    16. 16. chrome://tracing• Wrap things you care about in console.time() / console.timeEnd() calls• Bring up tracing in a tab• Downside: console spam
    17. 17. var profile = function (name, cb) { console.time(name); cb(); console.timeEnd(name);}// then later...profile(render, function () { // my render call. render();});
    18. 18. Testing?
    19. 19. Testing Canvas is hard.• PhantomJS (A little scary...)• Stub out the Canvas API
    20. 20. Testing Canvas is hard.• PhantomJS (A little scary...)• Stub out the Canvas API
    21. 21. 2) Caching Tricks
    22. 22. Basic Technique• Create a canvas element in your code• Get its context• Write pixels to that context• Use the canvas in a drawImage() call on another canvas context• YOU DON’T ADD THE CACHED CANVAS TO THE DOM!
    23. 23. var canvasCache = document.createElement(canvas), cacheCtx;canvasCache.setAttribute(width, 400);canvasCache.setAttribute(height, 400);cacheCtx = canvasCache.getContext(2d);cacheCtx.drawImage(someImage, 0, 0);// later...mainCtx.drawImage(canvasCache, 0, 0);
    24. 24. Double Buffering
    25. 25. Basic Idea• drawImage() (to screen) is expensive• Build a whole screen cache in a back buffer (in memory)• Draw entities to that cache with drawImage() during render• Write the entire cache to the screen with a single drawImage() call
    26. 26. Basic Idea• drawImage() (to screen) is expensive• Build a whole screen cache in a back buffer (in memory)• Draw entities to that cache with drawImage() during render• Write the entire cache to the screen with a single drawImage() call
    27. 27. var backBuffer = document.createElement(canvas), backBufferCtx;backBufferCtx = canvasCache.getContext(2d);// later...var render = function () { var i, ent; mainCtx.drawImage(backBuffer, 0, 0); for (i = 0; i > entities.length; i++) { ent = entities[i]; // this is not quite what youd do but... backBufferCtx.drawImage(ent.cache, ent.x, ent.y) }}
    28. 28. Layered Images
    29. 29. Similar thing...• Save drawImage() calls by compositing into a cache• Draw multiple images to the same cache in order• Attach the cache to a single game entity• Write the composited cache to your frame buffer in your draw call.
    30. 30. =+
    31. 31. ...and much more!
    32. 32. 3) Your Friend, ImageData
    33. 33. WTF is ImageData?• ImageData is what you get back from a getImageData() call• A single byte Array with ALL your pixel data• Pixel data is stored as R, G, B, A tuples
    34. 34. Single pixel Array offsets 0 1 2 3 R G B A 8 bits 8 bits 8 bits 8 bits 4 bytes
    35. 35. Hit Detection
    36. 36. What we want
    37. 37. Strategy• If (x, y) is in the bounding box for the image, check pixels.• getImageData() to get a pixel data array for your sprite at pixel x, y.• Check byte values for pixel.
    38. 38. var isPixelPainted = function (x, y) { ctx = this.imageCache; // this must be a canvas! thresh = this.transparencyThreshold || 100; // Grab a single pixel at x, y: if the alpha channel is greater // than the threshold, were in business. idata acts like a byte // array with each pixel occupying 4 slots (R, G, B , A). idata = ctx.getImageData(x, y, 1, 1); return idata.data[3] > thresh;}
    39. 39. DON’T FORGET: each idata.datavalue is between 0-255!
    40. 40. Image Filters
    41. 41. Since ImageData acts like a byte array....• We can iterate through the pixels and do arithmetic or bitwise manipulation on the data.• Use XOR, NOT, etc. Get weird!
    42. 42. var filter = function (x, y, w, h) { if (!this._cache) return; var ctx = this._cache.getContext(2d), idata = ctx.getImageData(x, y, w, h), i; for (i = 0; i < idata.data.length; i++) { idata.data[i] = (idata.data[i]++) % 255; }};
    43. 43. var filter = function (x, y, w, h) { if (!this._cache) return; var ctx = this._cache.getContext(2d), idata = ctx.getImageData(x, y, w, h), i; for (i = 0; i < idata.data.length; i++) { if (! i % 4 === 3) continue; idata.data[i] = (idata.data[i]++) % 255; }
    44. 44. Also possible, (but not necessarily recommended)• Masking (if the pixel is colored in one image...)• Pixel-wise composition.• Etc.!
    45. 45. Caveats• Cross-domain issues: if your data came from somewhere untrusted, the browser will not send it to the GPU.• Canvas calls exist for some of these things.• You can easily produce garbage.
    46. 46. Questions?
    47. 47. Thanks!Slides: http://j.mp/stupidcanvastricksdean@massivelyfun.com, @deanero http://massivelyfun.com/jobs

    ×