(7/8/2013 - This Unit is still a work-in-progress - There's missing notes on transformations and explanations on the code
	
	
	
	Overview
	
	
		This is a fun Unit, as you'll really start seeing the fruits of your hard work! Expect it to take about 3 hours, depending on your comfort with Linear Algebra. To demonstrate what you should have at the end of this Unit, check out the Demo for Unit 9.
		
Two big things we're going to talk about this Unit are Sprites and Sprite Sheets. This will be a big setup going into building an Animation system in the next Unit.
		
Sprites are essentially GameObjects, but have the ability to be drawn. We are going to have some math-y stuff in order to deal with transformations (position, rotation, and scale), as well as getting more comfortable with the Canvas API, otherwise are very straightforward and nearly the same to the Test Code and demo from the previous Unit.
		
A Sprite Sheet is an important feature that should solidify our comfortability with build layers of encapsulation. It is a single texture that can represent lots of smaller images, and we want to support it for many good reasons, but primarily it's a lot easier and faster if we get one larger image from the server rather than lots of little images. The game loads faster and your teammates and players are both happy.
		
The three sections of this Unit are:
			
			- Sprite Game Object class
			
- Sprite Sheet class
			
- Engine extension to manage Sprite Sheets
			
 
	
	Sprite GameObject class
	
	
		Sprite properties
		
For simplicity, all sprites are going to use a SpriteSheet whether there are sub-images in the image or not.
		
API Source Code:  
//=========================================================================
// Sprite Class
// - Sprite Class is a GameObject, so it can have its own components
// (like an animation or physics) and bind to events.
// Plus it derives from DrawNode, so we'll implement the draw() function.
//=========================================================================
Engine.Sprite = Engine.GameObject.extend({
	// Class name, for debugging
	typename: "Sprite",
	//=========================================================================
	// Sprite Properties
	//
	defaults: {
		x: 0,					// position along the x-axis
		y: 0,					// position along the y-axis
		angle: 0,				// rotation in Radians
		alpha: 1,				// controls transparencty (between 0 and 1)
		isVisible: true,		// toggles visibility
		scaleX: 1,				// the scale along the x-axis (left/right)
		scaleY: 1,				// the scale along the y-axis (up/down)
		sheetName: undefined,	// the sprite name out of a loaded sprite sheet
		frame: 0,				// current frame in the Sprite Sheet
	},
	//=========================================================================
	// Constructor function that takes in configuration propertiers
	//
	init: function(props) {
		//@TODO - Implementation
	},
	//=========================================================================
	// Draws the sprite on the canvas with it's current properties
	// Can handle whether this sprite is using a single asset or SpriteSheet.
	// Triggers a draw event in case components need to do any additional drawing.
	//
	draw: function(ctx) {
		//@TODO - Implementation
	}
});
 
		init()
		
			Implementation Source Code:  
init: function(props) {
	// base class constructor
	this._super(props);
	if( this.sheetName === undefined ) {
		alert( "Cannot create a sprite that has no sheetName assigned to it" );
		return;
	}
	// request the sprite sheet from the engine. If none was loaded, then it
	// will create a new sprite sheet that falls back to using the entire image
	this.spriteSheet = Engine.GetSingleton().getSpriteSheet(this.sheetName);
	if( this.spriteSheet === undefined ) {
		alert( this.spriteSheet, "Sprite could not find image by assetName: " + this.assetName );
		return;
	}
	// if the user didn't supply width/height properties grab them from the asset
	this.tilew = this.spriteSheet.tilew;
	this.tileh = this.spriteSheet.tileh;
	if(!this.width) {
		this.width = this.tilew;
	}
	if(!this.height) {
		this.height = this.tileh;
	}
},
 
		 
		draw()
		
			If you played around with your homework from the previous unit, you might have noticed that when you render an image it draws it so that the top-left corner of the image is at the position you provided to the canvas. Sometimes that can cause other behavior that you don't want - say you were to adjust the scale of the sprite, it would scale outward from the top-left corner but that corner will still be in the same position. Now if the sprite were centered around the position you meant to draw it at, then it would grow outward in all directions (and this is typically what most developers want).
			
Implementation Source Code:  
draw: function(ctx) {
	if( this.isVisible && this.spriteSheet) {
		var width = this.width * this.scaleX;
		var height = this.height * this.scaleY;
		// save the current co-ordinate system before we screw with it
		ctx.save();
		ctx.globalAlpha = this.alpha;
		// move to the middle of where we want to draw our image
		ctx.translate( this.x, this.y );
		// rotate around that point
		ctx.rotate( this.angle );
		// draw it up and to the left by half the width and height of the image
		var sx = this.spriteSheet.frameX(this.frame);	// where to start clipping
		var sy = this.spriteSheet.frameY(this.frame);	// where to start clipping
		ctx.drawImage( this.spriteSheet.image, sx, sy,
			this.tilew, this.tileh,
			-(this.width/2), -(this.height/2),
			this.width, this.height );
		// and restore the co-ords to how they were when we began
		ctx.restore();
	}
	// Let components know that a draw event occured, in case they need to do anything
	this.triggerEvent('draw',ctx);
}
 
		 
	 
	
	SpriteSheet class
	
	
		There's not a lot to this class, as it's mostly a holder of data.
		
A SpriteSheet is not an Image. It is a wrapper of data, that knows about a set of sub-images within a larger image. A single image might have more than one Sprite Sheet associated with it!
		
This approach is also called a Texture Atlas, and there is a good amount of reading material available.
		
The real magic is in the data file (JSON) it gets associated with.
		
Implementation Source Code:  
	//=========================================================================
	// Sprite Sheet Class
	// A single set of like-sized frames of the same sprite.
	// References an image asset with extra data about the frames, so that we
	// can quickly draw a specific frame at an x/y location on the canvas.
	//
	// Requires a resource name (how sprites reference a SpriteSheet)
	// and an image asset name.
	// Other constructor options:
	//  tilew  - tile width
	//  tileh  - tile height
	//  width  - width of the sprite block
	//  height - height of the sprite block
	//  sx     - start x
	//  sy     - start y
	//  cols   - number of columns per row
	//=========================================================================
	Engine.SpriteSheet = Class.extend({
		// Class name, for debugging
		name: "SpriteSheet",
		//=========================================================================
		// Constructor function
		init: function(assetName, options) {
			this.engine = Engine.GetSingleton();
			var imageAsset = this.engine.getAsset(assetName);
			var defaultProperties = {
				image: imageAsset,
				assetName: assetName,
				width: imageAsset.width,
				height: imageAsset.height,
				tilew: imageAsset.width,
				tileh: imageAsset.height,
				sx: 0,
				sy: 0
			};
			_.extend(this, defaultProperties, options);
			this.cols = this.cols || Math.floor(this.width / this.tilew);
		},
		//=========================================================================
		// Calculates the frame x position within the image asset
		frameX: function(frame) {
			return (frame % this.cols) * this.tilew + this.sx;
		},
		//=========================================================================
		// Calculates the frame y position within the image asset
		frameY: function(frame) {
			return Math.floor(frame / this.cols) * this.tileh + this.sy;
		}
	});
 
	 
	
	SpriteSheet management
	
	
		Create new Sprite Sheets. Creating multiple sprite sheets from a single image and data file.
		
Accessing sprite sheets by name.
		
Implementation Source Code:  
	//=========================================================================
	// Sprite Engine Module
	// Centralized mechanism for compiling and tracking sheets to make
	// them easy to reference and lookup.
	//=========================================================================
	Engine.defaults.spriteSheets = { };
	//=========================================================================
	// Creates a new sprite sheet
	Engine.prototype.createSpriteSheet = function(name, imageAssetName, options) {
		var asset = new Engine.SpriteSheet(imageAssetName, options);
		this.spriteSheets[name] = asset;
		return asset;
	};
	//=========================================================================
	// Combines an image asset with a JSON sprite data asset to generate
	// one or more SpriteSheets auomatically from the data generated
	// by the spriter generator in Chapter 8.
	Engine.prototype.compileSheets = function(imageAssetName, spriteDataAsset) {
		var engine = this;
		var data = engine.getAsset(spriteDataAsset);
		engineAssert( data, "Cannot compile sprite sheets for missing image asset name: " + imageAssetName );
		_(data).each(function(spriteData,name) {
			engine.createSpriteSheet(name,imageAssetName,spriteData);
		});
	};
	//=========================================================================
	// Getter for a sprite sheet
	// Lazy load mechanism, for images where the entire image is the sprite
	Engine.prototype.getSpriteSheet = function(name) {
		var asset = this.spriteSheets[name];
		if( !asset ) {
			return this.createSpriteSheet(name, name);
		}
		return this.spriteSheets[name];
	};
 
	 
	
	Test Code
	
	
		Source Code:  
// Let's create a canvas object
var mainBGLayer = Engine.GetSingleton().createCanvas( "mainBGLayer", {
	container: $('#gameContainer'),
	backgroundColor: "#000",
	width: 640,
	height: 480,
} );
var assetList = { "playerSprite": "gamedata/Character Boy.png" };
var onFinishedCallback = function() {
	
	var props = {
		sheetName: "playerSprite"
	};
	var player = new Engine.Sprite( props );
	mainBGLayer.attachChild( player );
};
Engine.GetSingleton().load( assetList, onFinishedCallback );
 
	 
	
	Homework
	
	
		Part 1. Create and add sprites.js to your project, filling it out with the code from this Unit.
		
Part 2. In your test code, create a new sprite instance.
		
Part 3. Load a
			
			- Create a canvas that gets added to the DOM (you may need to update your html - create a <div> and give it an 'id' to use)
			
- Create a new GameObject that will behave as a sprite
			
- Move the position of the object every frame. Try using Input events to trigger changes in the sprite's position.
			
 
	
	Extra Credit
	
	
		The SpriteSheet class makes an assumption: all frames have the same tile width and tile height. If we are going to say that a SpriteSheet has 
		
Part 2. In your test code, create a new sprite instance.
		
Part 3. Load a
			
			- Create a canvas that gets added to the DOM (you may need to update your html - create a <div> and give it an 'id' to use)
			
- Create a new GameObject that will behave as a sprite
			
- Move the position of the object every frame. Try using Input events to trigger changes in the sprite's position.