10. Simple Game
Entity
• Respond to update call
• Manage position, height, width
• Attach pointer events here
11. class GameEntity
# @params: {rect} The entity's drawing primitive
constructor: (options = {}) ->
{x, y, rotation} = options
@position = new Position(x, y, rotation)
@id = options.id ? UUID.generate() # You wa this
moveTo: (pt) ->
@position.setXY(pt)
rotateTo: (rot) ->
@position.setRotation(rot)
# Coeff is a multiplier from the timer which we can use to adjust
# motion to match how far we are off our target frame rate
update: (tick, coeff) ->
# do something interesting here.
contains: (otherX, otherY) ->
@rect.contains(x, y) if @rect? and @linkedRect
module.exports = GameEntity
12. Simple Draw
Primitive
• Respond to draw call
• Manage position, height, width
• Determine containment here (image hit
detection, for instance)
13. ##
# Rect: Drawing primitive
class Rect
constructor: (options = {}) ->
@visible = options?.visible ? true
@width = options?.width ? 1
@height = options?.height ? 1
{x, y, rotation} = options
@position = new Position(x, y, rotation)
draw: (ctx) ->
throw new RenderError("Implement Me")
# Basic, rectangular containment.
contains: (otherX, otherY) ->
{x, y} = @position.get()
(otherX >= x && otherX <= x + @width) and
(otherY >= y && otherY <= y + @height)
module.exports = Rect
15. Strategy
• Attach onFoo to your canvas element
where Foo is your DOM pointer event
• Build a normalized event from the DOM
event
• Normalize your page X/Y to canvas X/Y.
• Check for containment in game entities
• Call handler if the entity contains the point
and the handler exists
17. 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
18. Single pixel Array
offsets
0 1 2 3
R G B A
8 bits 8 bits 8 bits 8 bits
4 bytes
19. 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!
20. 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;
}
};
21. 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;
}
24. 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.
25. 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, we're 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;
}