API Docs for: 0.1.0
Show:

File: src/zerk/class/game/engine/system/wireframe.js

/**
 * Wireframe System
 * 
 * Render the world as wireframes for debugging purposes.
 * 
 * @class wireframe
 * @namespace zerk.game.engine.system
 * @extends zerk.game.engine.system
 * @module zerk
 **/
zerk.define({
	
	name: 'zerk.game.engine.system.wireframe',
	extend: 'zerk.game.engine.system'
	
},{
	
	/**
	 * Name of the system
	 * 
	 * @property _name
	 * @type String
	 * @protected
	 **/
	_name: 'wireframe',
	
	/**
	 * Thread that runs this system
	 * 
	 * @property _thread
	 * @type String
	 * @protected
	 **/
	_thread: 'render',
	
	/**
	 * Priority of this system
	 * 
	 * @property _priority
	 * @type Integer
	 * @protected
	 **/
	_priority: 102,
	
	/**
	 * Viewport system instance
	 * 
	 * @property _viewport
	 * @type zerk.game.engine.system.viewport
	 * @protected
	 **/
	_viewport: null,
	
	/**
	 * Physics system instance
	 * 
	 * @property _physics
	 * @type zerk.game.engine.system.physics
	 * @protected
	 **/
	_physics: null,
	
	/**
	 * Class constructor
	 * 
	 * @method init
	 * @param {zerk.game.engine} engine Game engine
	 * @param {Object} config System configuration
	 **/
	init: function(engine,config) {
		
		zerk.parent('zerk.game.engine.system.wireframe').init.apply(
			this,
			arguments
		);
		
		this._viewport=this._getSystem('viewport');
		
		this._physics=this._getSystem('physics');
		
	},
	
	/**
	 * Returns the configuration defaults of the system
	 * 
	 * @method _getConfigDefaults
	 * @return {Object} Default configuration
	 * @protected
	 **/
	_getConfigDefaults: function() {
		
		return {
			showBodyAngleIndicator: true,
			showEntityOriginIndicator: false,
			showFixtureBoundingBox: true,
			style: {
				bodyActive: {
					strokeColor: 'rgba(127,127,76,1)',
					fillColor: 'rgba(127,127,76,0.4)'
				},
				bodyStatic: {
					strokeColor: 'rgba(127,229,127,1)',
					fillColor: 'rgba(127,229,127,0.4)'
				},
				bodyKinematic: {
					strokeColor: 'rgba(127,127,229,1)',
					fillColor: 'rgba(127,127,229,0.4)'
				},
				bodyAwake: {
					strokeColor: 'rgba(153,153,153,1)',
					fillColor: 'rgba(153,153,153,0.4)'
				},
				bodyDefault: {
					strokeColor: 'rgba(229,178,178,1)',
					fillColor: 'rgba(229,178,178,0.4)'
				},
				fixtureSensor: {
					strokeColor: 'rgba(255,0,0,0.5)',
					fillColor: 'rgba(255,0,0,0.1)'
				}
			}
		};
		
	},
	
	/**
	 * Returns true when the system is interested in given component
	 * 
	 * @method useComponent
	 * @param {String} name Component name
	 * @return {Boolean} True when the system is intereseted in given component
	 **/
	useComponent: function(name) {
		
		return (name=='physics');
		
	},
	
	/**
	 * Starts the system
	 * 
	 * @method start
	 **/
	start: function() {
		
		zerk.parent('zerk.game.engine.system.wireframe').start.apply(
			this,
			arguments
		);
		
	},
	
	/**
	 * Stops the system
	 * 
	 * @method stop
	 **/
	stop: function() {
		
		zerk.parent('zerk.game.engine.system.wireframe').stop.apply(
			this,
			arguments
		);
		
	},
	
	/**
	 * Updates the system
	 * 
	 * @method update
	 **/
	update: function() {
		
		zerk.parent('zerk.game.engine.system.wireframe').update.apply(
			this,
			arguments
		);
		
		// Render all entities in the view area
		var entityStates=this._viewport.getEntitiesInViewport();
		
		for (var i=0;i<entityStates.length;i++) {
			
			this._renderEntity(entityStates[i]);
		}
		
	},
	
	/**
	 * Renders an entity onto the game canvas
	 * 
	 * @method _renderEntity 
	 * @param {config.entity} entity Entity state
	 * @protected
	 **/
	_renderEntity: function(entity) {
		
		// Render all bodies of the entity
		
		var bodies=entity.components.physics._bodyList;
		
		for (var i=0;i<bodies.length;i++) {
			
			this._renderBody(entity,bodies[i]);
			
		}
		
		if (this._config.showEntityOriginIndicator) {
			
			this._renderEntityOriginIndicator(entity);
			
		}
		
	},
	
	/**
	 * Renders a body onto the game canvas
	 * 
	 * @method _renderBody
	 * @param {config.entity} entity Entity state
	 * @param {config.component.physics.body} body Body state
	 * @protected
	 **/
	_renderBody: function(entity,body) {
		
		// Render all the fixtures of the body
		for (var i=0;i<body._fixtureList.length;i++) {
			
			this._renderFixture(entity,body,body._fixtureList[i]);
			
		}
		
		if (this._config.showBodyAngleIndicator
		&& body.moveable) {
			
			this._renderBodyAngleIndicator(entity,body);
			
		}
		
	},
	
	/**
	 * Renders a fixture onto the body buffer canvas
	 * 
	 * @method _renderFixture
	 * @param {config.entity} entity Entity state
	 * @param {config.component.physics.body} body Body state
	 * @param {config.component.physics.fixture} fixture Fixture state
	 * @protected
	 **/
	_renderFixture: function(entity,body,fixture) {
		
		if (this._config.showFixtureBoundingBox) {
			
			this._renderFixtureBoundingShape(entity,body,fixture);
			
		}
		
	},
	
	/**
	 * Renders a shape indicating the bounding area of a fixture
	 * 
	 * Delegate method for the fixture bounding shape methods
	 * 
	 * @method _renderFixtureBoundingShape
	 * @param {config.entity} entity Entity state
	 * @param {config.component.physics.body} body Body state
	 * @param {config.component.physics.fixture} fixture Fixture state
	 * @protected
	 **/
	_renderFixtureBoundingShape: function(entity,body,fixture) {
		
		switch (fixture.shape) {
			case 'box':
				this._renderFixtureBoundingBox(entity,body,fixture);
				break;
			case 'circle':
				this._renderFixtureBoundingCircle(entity,body,fixture);
				break;
			case 'polygon':
				this._renderFixtureBoundingPolygon(entity,body,fixture);
				break;
		}
		
	},
	
	/**
	 * Returns the style of a fixture bounding shape
	 * 
	 * @method _getFixtureBoundingStyle
	 * @param {config.entity} entity Entity state
	 * @param {config.component.physics.body} body Body state
	 * @param {config.component.physics.fixture} fixture Fixture state
	 * @return {Object} An object containing strokeColor, fillColor and 
	 * 	lineWidth
	 * @protected
	 **/
	_getFixtureBoundingStyle: function(entity,body,fixture) {
		
		var result={};
		
		var style='';
		
		if (fixture.isSensor) {
			
			style=this._config.style.fixtureSensor;
			
		} else if (!this._physics.isBodyActive(body)) {
			
			style=this._config.style.bodyActive;
			
		} else if (this._physics.isBodyStatic(body)) {
			
			style=this._config.style.bodyStatic;
			
		} else if (this._physics.isBodyKinematic(body)) {
			
			style=this._config.style.bodyKinematic;
			
		} else if (!this._physics.isBodyAwake(body)) {
			
			style=this._config.style.bodyAwake;
			
		} else {
			
			style=this._config.style.bodyDefault;
			
		}
		
		result.strokeColor=style.strokeColor;
		result.fillColor=style.fillColor;
		result.lineWidth=1;
		
		return result;
		
	},
	
	/**
	 * Renders the bounding area for a box shaped fixture
	 * 
	 * @method _renderFixtureBoundingShape
	 * @param {config.entity} entity Entity state
	 * @param {config.component.physics.body} body Body state
	 * @param {config.component.physics.fixture} fixture Fixture state
	 * @protected
	 **/
	_renderFixtureBoundingBox: function(entity,body,fixture) {
		
		var style=this._getFixtureBoundingStyle(entity,body,fixture);
		
		var position=entity.components.position;
		var bodyState=entity.components.physics.bodies[body.key];
		var fixtureState=bodyState.fixtures[fixture.key];
		
		if (!bodyState) return;
		if (!fixtureState) return;
		
		var fixtureWidth=((typeof fixture.width=='string') 
			? (body.width/100)*parseInt(fixture.width)
			: fixture.width);
		
		var fixtureHeight=((typeof fixture.height=='string') 
			? (body.height/100)*parseInt(fixture.height)
			: fixture.height);
		
		// Tranform rectangle into polygon
		var rectangleVertices=[
			[fixtureState.x-(fixtureWidth/2),fixtureState.y-(fixtureHeight/2)],
			[fixtureState.x+(fixtureWidth/2),fixtureState.y-(fixtureHeight/2)],
			[fixtureState.x+(fixtureWidth/2),fixtureState.y+(fixtureHeight/2)],
			[fixtureState.x-(fixtureWidth/2),fixtureState.y+(fixtureHeight/2)]
		];
		
		var vertices=[];
		
		for (var i=0;i<rectangleVertices.length;i++) {
			
			var rotatedVertice=zerk.helper.rotatePosition(
				rectangleVertices[i][0],
				rectangleVertices[i][1],
				bodyState.angle
			);
			
			var x=this._viewport._getCanvasX(
				position.x
				+bodyState.x
				+rotatedVertice.x
			);
			var y=this._viewport._getCanvasY(
				position.y
				+bodyState.y
				+rotatedVertice.y
			);
			
			vertices.push([
				x,
				y
			]);
			
		}
		
		this._viewport.drawPolygon(
			'display',
			vertices,
			style.fillColor,
			style.strokeColor,
			style.lineWidth
		);
		
		/*
		this._viewport.drawLines(
			'display',
			[
				[vertices[0][0],vertices[0][1],vertices[2][0],vertices[2][1]],
				[vertices[1][0],vertices[1][1],vertices[3][0],vertices[3][1]]
			],
			style.color,
			style.lineWidth
		);
		*/
		
	},
	
	/**
	 * Renders the bounding area for a circle shaped fixture
	 * 
	 * @method _renderFixtureBoundingCircle
	 * @param {config.entity} entity Entity state
	 * @param {config.component.physics.body} body Body state
	 * @param {config.component.physics.fixture} fixture Fixture state
	 * @protected
	 **/
	_renderFixtureBoundingCircle: function(entity,body,fixture) {
		
		var style=this._getFixtureBoundingStyle(entity,body,fixture);
		
		var position=entity.components.position;
		var bodyState=entity.components.physics.bodies[body.key];
		var fixtureState=bodyState.fixtures[fixture.key];
		
		if (!bodyState) return;
		if (!fixtureState) return;
		
		var x=this._viewport._getCanvasX(
			position.x
			+bodyState.x
			+fixtureState.x
		);
		var y=this._viewport._getCanvasY(
			position.y
			+bodyState.y
			+fixtureState.y
		);
		
		this._viewport.drawArc(
			'display',
			x,
			y,
			this._viewport.toScaleX(zerk.helper.fromMeter(fixture.radius)),
			0,
			Math.PI*2,
			true,
			style.fillColor,
			style.strokeColor,
			style.lineWidth
		);
		
		var rotatedAngleIndicator=zerk.helper.rotatePosition(
			fixtureState.x,
			fixtureState.y-fixtureState.radius,
			bodyState.angle
		);
		
		var angleIndicatorX=this._viewport._getCanvasX(
			position.x
			+bodyState.x
			+rotatedAngleIndicator.x
		);
		var angleIndicatorY=this._viewport._getCanvasY(
			position.y
			+bodyState.y
			+rotatedAngleIndicator.y
		);
		
		this._viewport.drawLines(
			'display',
			[[angleIndicatorX,angleIndicatorY,x,y]],
			style.strokeColor,
			style.lineWidth
		);
		
	},
	
	/**
	 * Renders the bounding area for a polygon shaped fixture
	 * 
	 * @method _renderFixtureBoundingPolygon
	 * @param {config.entity} entity Entity state
	 * @param {config.component.physics.body} body Body state
	 * @param {config.component.physics.fixture} fixture Fixture state
	 * @protected
	 **/
	_renderFixtureBoundingPolygon: function(entity,body,fixture) {
		
		var style=this._getFixtureBoundingStyle(entity,body,fixture);
		
		var position=entity.components.position;
		var bodyState=entity.components.physics.bodies[body.key];
		var fixtureState=bodyState.fixtures[fixture.key];
		
		if (!bodyState) return;
		if (!fixtureState) return;
		
		var vertices=[];
		
		for (var i=0;i<fixture.vertices.length;i++) {
			
			var rotatedVertice=zerk.helper.rotatePosition(
				fixture.vertices[i][0],
				fixture.vertices[i][1],
				bodyState.angle
			);
			
			var x=this._viewport._getCanvasX(
				position.x
				+bodyState.x
				+rotatedVertice.x
			);
			var y=this._viewport._getCanvasY(
				position.y
				+bodyState.y
				+rotatedVertice.y
			);
			
			vertices.push([
				x,
				y
			]);
			
		}
		
		this._viewport.drawPolygon(
			'display',
			vertices,
			style.fillColor,
			style.strokeColor,
			style.lineWidth
		);
		
	},
	
	/**
	 * Renders an angle indicator for each body of the entity
	 * 
	 * @method _renderBodyAngleIndicator
	 * @param {config.entity} entity Entity state
	 * @param {config.component.physics.body} body Body state
	 * @protected
	 **/
	_renderBodyAngleIndicator: function(entity,body,fixture) {
		
		var position=entity.components.position;
		var bodyState=entity.components.physics.bodies[body.key];
		
		var x=position.x+bodyState.x;
		var y=position.y+bodyState.y;
		
		var size=0.35;
		
		var positions=[
			{
				x: -size,
				y: 0
			},
			{
				x: 0,
				y: 0
			},
			{
				x: 0,
				y: -size
			},
			{
				x: 0,
				y: 0
			}
		];
		
		for (i=0;i<positions.length;i++) {
			
			positions[i]=zerk.helper.rotatePosition(
				positions[i].x,
				positions[i].y,
				bodyState.angle
			);
			
		}
		
		this._viewport.drawLines(
			'display',
			[
				[
					this._viewport._getCanvasX(x+positions[0].x),
					this._viewport._getCanvasY(y+positions[0].y),
					this._viewport._getCanvasX(x+positions[1].x),
					this._viewport._getCanvasY(y+positions[1].y)
				]
			],
			'rgb(255,0,0)'
		);
		
		this._viewport.drawLines(
			'display',
			[
				[
					this._viewport._getCanvasX(x+positions[2].x),
					this._viewport._getCanvasY(y+positions[2].y),
					this._viewport._getCanvasX(x+positions[3].x),
					this._viewport._getCanvasY(y+positions[3].y)
				]
			],
			'rgb(0,255,0)'
		);
		
		/*
		 * TODO Create drawEntityName config value
		 */
		// Draw entity name
		/*
		 * this._bufferBodyContext.fillStyle="rgb(0,255,0)";
		 * this._bufferBodyContext.fillText(entity.name,x+15,y+8);
		 */
		
	},
	
	/**
	 * Renders the entity origin indicator
	 * 
	 * @method _renderEntityOriginIndicator
	 * @param {config.entity} entity Entity state
	 * @protected
	 **/
	_renderEntityOriginIndicator: function(entity) {
		
		var position=entity.components.position;
		
		this._viewport.drawLines(
			'display',
			[
				[
					this._viewport._getCanvasX(position.x-0.2),
					this._viewport._getCanvasY(position.y),
					this._viewport._getCanvasX(position.x+0.2),
					this._viewport._getCanvasY(position.y)
				],
				[
					this._viewport._getCanvasX(position.x),
					this._viewport._getCanvasY(position.y-0.2),
					this._viewport._getCanvasX(position.x),
					this._viewport._getCanvasY(position.y+0.2)
				]
			],
			'rgb(255,0,0)'
		);
		
	}
	
});