An Aerial Combat Game in JavaScript

The JavaScript code below implements a simple 3D aerial combat (“dogfight”) game. To see it in action, copy it into an .html file and open that file in a web browser that runs JavaScript.

Use the W, A, S, D keys to change direction, and the and the up and down arrow keys to accelerate and decelerate. The object is to catch the green ship and avoid the red ship.

DogfightGame


<html>
<body>
<script type="text/javascript">

// main

function main()
{
	var meshForMovers = new Mesh
	(
		// vertices
		[
			new Coords(-5, 5, 0),
			new Coords(5, 5, 0),
			new Coords(2, 0, 0),
			new Coords(-2, 0, 0),
			new Coords(0, 0, 20),
		],
		// faces
		[
			new MeshFace([ 0, 1, 4 ])	,
			new MeshFace([ 1, 2, 4 ]),
			new MeshFace([ 2, 3, 4 ]),
			new MeshFace([ 3, 0, 4 ]),
			new MeshFace([ 0, 1, 2, 3 ]),
		]
	);

	var venueSizeInPixels = new Coords(1, 1, 1).multiplyScalar(1000000);

	var moverForPlayer = new Mover
	(
		"Player",
		1, // integrity
		1.2, // speedMax
		0.1, // accelPerTick
		0.05, // turnPerTick
		new Location
		(
			new Coords(-100, 0, 0),
			Orientation.fromForwardAndDown
			(
				new Coords(1, 0, 0),
				new Coords(0, 0, 1)
			)
		),
		new Activity_UserInputAccept(),
		"Gray", // color
		meshForMovers
	);

	Globals.Instance.initialize
	(
		20, // framesPerSecond
		new Display(new Coords(300, 300, 1)),
		new Venue
		(
			"Venue0",
			venueSizeInPixels,
			// movers
			[
				moverForPlayer,

				new Mover
				(
					"Prey",
					1, // integrity
					1, // speedMax
					0.1, // accelPerTick
					0.05, // turnPerTick
					new Location
					(
						new Coords(100, 0, 0),
						Orientation.fromForwardAndDown
						(
							new Coords(1, 0, 0),
							new Coords(0, 0, 1)
						)
					),
					new Activity_MoveRandomly(),
					"Green", // color
					meshForMovers
				),

				new Mover
				(
					"Predator",
					1, // integrity
					1, // speedMax
					0.1, // accelPerTick
					0.05, // turnPerTick
					new Location
					(
						new Coords(0, 0, 0),
						Orientation.fromForwardAndDown
						(
							new Coords(1, 0, 0),
							new Coords(0, 0, 1)
						)
					),
					new Activity_MoveTowardTargetPos
					(
						moverForPlayer.loc.pos
					),
					"Red", // color
					meshForMovers
				),
			]
		)
	);
}

// classes

function Action()
{
	// abstract class
}
{
	// instances 

	Action.Instances = new Action_Instances();

	function Action_Instances()
	{
		this.Accelerate = new Action_Accelerate(1);
		this.Decelerate = new Action_Accelerate(-1);
		this.PitchDown = new Action_TurnAxisTowardOtherInDirection(0, 2, 1);
		this.PitchUp = new Action_TurnAxisTowardOtherInDirection(0, 2, -1);
		this.RollLeft = new Action_TurnAxisTowardOtherInDirection(2, 1, 1);
		this.RollRight = new Action_TurnAxisTowardOtherInDirection(2, 1, -1);
		this.YawLeft = new Action_TurnAxisTowardOtherInDirection(0, 1, -1);
		this.YawRight = new Action_TurnAxisTowardOtherInDirection(0, 1, 1);

	}
}

function Action_Accelerate(sign)
{
	this.sign = sign;
}
{
	Action_Accelerate.prototype.performForActor = function(actor)
	{
		var actorLoc = actor.loc;

		actorLoc.accel.overwriteWith
		(
			actorLoc.orientation.forward
		).multiplyScalar
		(
			this.sign * actor.accelPerTick
		);
	}
}

function Action_TurnAxisTowardOtherInDirection(indexOfAxisToBeTurned, indexOfAxisToTurnToward, sign)
{
	this.indexOfAxisToBeTurned = indexOfAxisToBeTurned;
	this.indexOfAxisToTurnToward = indexOfAxisToTurnToward;
	this.sign = sign;

	this.temp = new Coords();
}
{
	Action_TurnAxisTowardOtherInDirection.prototype.performForActor = function(actor)
	{
		var actorLoc = actor.loc;
		var actorOrientation = actorLoc.orientation;
		var axes = actorOrientation.axes;
		
		var axisToBeTurned = axes[this.indexOfAxisToBeTurned];
		var axisToTurnToward = axes[this.indexOfAxisToTurnToward];

		axisToBeTurned.add
		(
			this.temp.overwriteWith
			(
				axisToTurnToward
			).multiplyScalar
			(
				this.sign * actor.turnPerTick
			)
		).normalize();

		actorOrientation.orthogonalizeAxes().normalizeAxes();
	}
}

function Activity_DoNothing()
{
	// do nothing
}
{
	Activity_DoNothing.prototype.performForActor = function(actor)
	{
		// do nothing
	}
}

function Activity_MoveRandomly()
{
	this.ticksToHoldCourse = 0;

	this.targetPos = new Coords();
	this.directionToTarget = new Coords();
	this.ticksToHoldCourseMax = 200;
}
{
	Activity_MoveRandomly.prototype.performForActor = function(actor)
	{
		var actorLoc = actor.loc;
		var actorOrientation = actorLoc.orientation;

		this.ticksToHoldCourse--;

		if (this.ticksToHoldCourse <= 0)
		{
			var venue = Globals.Instance.venue;
		
			this.targetPos.randomize().multiply
			(
				venue.sizeInPixels
			).subtract
			(
				venue.sizeInPixelsHalf
			);

			this.ticksToHoldCourse = Math.floor
			(
				Math.random() 
				* this.ticksToHoldCourseMax
			);
		}

		// hack - Instant turning.
		actorOrientation.forward.overwriteWith
		(
			this.targetPos
		).subtract
		(
			actorLoc.pos
		).normalize();

		actorOrientation.orthogonalizeAxes();

		Action.Instances.Accelerate.performForActor(actor);
	}
}

function Activity_MoveTowardTargetPos(targetPos)
{
	this.targetPos = targetPos;
}
{
	Activity_MoveTowardTargetPos.prototype.performForActor = function(actor)
	{
		var actorLoc = actor.loc;
		var actorOrientation = actorLoc.orientation;
		
		// hack - Instant turning.
		actorOrientation.forward.overwriteWith
		(
			this.targetPos
		).subtract
		(
			actorLoc.pos
		).normalize();

		actorOrientation.orthogonalizeAxes();

		Action.Instances.Accelerate.performForActor(actor);
	}
}

function Activity_UserInputAccept()
{
	// do nothing
}
{
	Activity_UserInputAccept.prototype.performForActor = function(actor)
	{
		var keyCodesPressed = Globals.Instance.inputHelper.keyCodesPressed;

		var actions = Action.Instances;

		for (var i = 0; i < keyCodesPressed.length; i++)
		{
			var keyCodePressed = keyCodesPressed[i];
			var actionToPerform = null;

			if (keyCodePressed == "_38") // up arrow
			{
				actionToPerform = actions.Accelerate;
			}
			if (keyCodePressed == "_40") // down arrow
			{
				actionToPerform = actions.Decelerate;
			}
			else if (keyCodePressed == "_65") // a
			{
				actionToPerform = actions.YawLeft;
			}
			else if (keyCodePressed == "_68") // d
			{
				actionToPerform = actions.YawRight;
			}
			else if (keyCodePressed == "_69") // e
			{
				actionToPerform = actions.RollRight;
			}
			else if (keyCodePressed == "_81") // q
			{
				actionToPerform = actions.RollLeft;
			}
			else if (keyCodePressed == "_83") // s
			{
				actionToPerform = actions.PitchUp;
			}
			else if (keyCodePressed == "_87") // w
			{
				actionToPerform = actions.PitchDown;
			}

			if (actionToPerform != null)
			{
				actionToPerform.performForActor(actor);
			}
		}
	}
}

function Camera(focalLength, loc)
{
	this.focalLength = focalLength;
	this.loc = loc;
}

function CompassPoint(name, direction)
{
	this.name = name;
	this.direction = direction;
	this.loc = new Location(new Coords());
}
{
	CompassPoint.prototype.updateForVenueTimerTick = function(venue)
	{
		this.loc.pos.overwriteWith
		(
			this.direction
		).multiplyScalar
		(
			100
		).add
		(
			venue.moverForPlayer.loc.pos
		);

	}
}

function Constants()
{
	// static class
}
{
	Constants.RadiansPerCycle = Math.PI * 2.0;
}

function Coords(x, y, z)
{
	this.x = x;
	this.y = y;
	this.z = z;
}
{
	Coords.prototype.add = function(other)
	{
		this.x += other.x;
		this.y += other.y;
		this.z += other.z;
		return this;
	}

	Coords.prototype.clear = function()
	{
		this.x = 0;
		this.y = 0;
		this.z = 0;
		return this;
	}

	Coords.prototype.clone = function()
	{
		return new Coords(this.x, this.y, this.z);
	}

	Coords.prototype.crossProduct = function(other)
	{
		return this.overwriteWithXYZ
		(
			this.y * other.z - this.z * other.y,
			this.z * other.x - this.x * other.z,
			this.x * other.y - this.y * other.x
		);
	}

	Coords.prototype.divide = function(other)
	{
		this.x /= other.x;
		this.y /= other.y;
		this.z /= other.z;
		return this;
	}

	Coords.prototype.divideScalar = function(scalar)
	{
		this.x /= scalar;
		this.y /= scalar;
		this.z /= scalar;
		return this;
	}

	Coords.prototype.dotProduct = function(other)
	{
		return this.x * other.x + this.y * other.y + this.z * other.z;
	}

	Coords.prototype.isInRangeMax = function(max)
	{
		returnValue = 
		(
			this.x >= 0 && this.x <= max.x
			&& this.y >= 0 && this.y <= max.y
			&& this.z >= 0 && this.z <= max.z
		);

		return returnValue;
	}

	Coords.prototype.isInRangeMaxXY = function(max)
	{
		returnValue = 
		(
			this.x >= 0 && this.x <= max.x
			&& this.y >= 0 && this.y <= max.y
		);

		return returnValue;
	}

	Coords.prototype.magnitude = function()
	{
		return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
	}

	Coords.prototype.multiply = function(other)
	{
		this.x *= other.x;
		this.y *= other.y;
		this.z *= other.z;
		return this;
	}

	Coords.prototype.multiplyScalar = function(scalar)
	{
		this.x *= scalar;
		this.y *= scalar;
		this.z *= scalar;
		return this;
	}

	Coords.prototype.normalize = function()
	{
		return this.divideScalar(this.magnitude());
	}

	Coords.prototype.overwriteWith = function(other)
	{
		this.x = other.x;
		this.y = other.y;
		this.z = other.z;
		return this;
	}

	Coords.prototype.overwriteWithXYZ = function(x, y, z)
	{
		this.x = x;
		this.y = y;
		this.z = z;
		return this;
	}

	Coords.prototype.randomize = function()
	{
		this.x = Math.random();
		this.y = Math.random();
		this.z = Math.random();
		return this;
	}

	Coords.prototype.subtract = function(other)
	{
		this.x -= other.x;
		this.y -= other.y;
		this.z -= other.z;
		return this;
	}

	Coords.prototype.toString = function()
	{
		return "(" + this.x + "," + this.y + "," + this.z + ")"
	}

	Coords.prototype.trimToMagnitudeMax = function(magnitudeMax)
	{
		var magnitude = this.magnitude();
		if (magnitude > magnitudeMax)
		{
			this.divideScalar
			(
				magnitude
			).multiplyScalar
			(
				magnitudeMax
			);
		}
		return this;
	}

	Coords.prototype.trimToRangeMinMax = function(min, max)
	{
		if (this.x < min.x)
		{
			this.x = min.x;
		}
		else if (this.x > max.x)
		{
			this.x = max.x;
		}

		if (this.y < min.y)
		{
			this.y = min.y;
		}
		else if (this.y > max.y)
		{
			this.y = max.y;
		}

		if (this.z < min.z)
		{
			this.z = min.z;
		}
		else if (this.z > max.z)
		{
			this.z = max.z;
		}

		return this;
	}
}

function Display(sizeInPixels)
{
	this.sizeInPixels = sizeInPixels;

	this.sizeInPixelsHalf = sizeInPixels.clone().divideScalar(2);

	// temporary variables
	this.drawPos = new Coords();
	this.transformOrient = new Transform_Orient();
}
{
	Display.prototype.clear = function()
	{
		this.graphics.fillStyle = "Black";
		this.graphics.fillRect
		(
			0, 0, this.sizeInPixels.x, this.sizeInPixels.y
		);

		this.graphics.strokeStyle = "Gray";
		this.graphics.strokeRect
		(
			0, 0, this.sizeInPixels.x, this.sizeInPixels.y
		);
	}

	Display.prototype.drawCompassPointForCamera = function(compassPoint, camera)
	{
		this.graphics.strokeStyle = "Gray";
		this.graphics.fillStyle = "Gray";

		var drawPos = this.drawPos;
		this.transformWorldPosToViewPos
		(
			drawPos.overwriteWith(compassPoint.loc.pos),
			camera
		);

		if (drawPos.isInRangeMaxXY(this.sizeInPixels) == true)
		{
			this.drawTextAtLocationForCamera
			(
				compassPoint.name, 
				compassPoint.loc, 
				camera
			);
		}
	}

	Display.prototype.drawMeshAtLocationForCamera = function(mesh, loc, camera)
	{
		var drawPos = this.drawPos;
		var vertices = mesh.vertices;
		var faces = mesh.faces;

		this.transformOrient.orientation = loc.orientation;
		var meshPos = loc.pos;

		for (var f = 0; f < faces.length; f++)
		{
			var face = faces[f];

			this.graphics.beginPath();

			for (var vi = 0; vi < face.vertexIndices.length; vi++)
			{
				var vertexIndex = face.vertexIndices[vi];
				var vertex = vertices[vertexIndex];

				drawPos.overwriteWith
				(
					vertex
				);

				this.transformOrient.applyToCoords
				(
					drawPos
				);

				drawPos.add
				(
					meshPos
				);

				this.transformWorldPosToViewPos
				(
					drawPos,
					camera
				);

				if (drawPos.z < 0)
				{
					break;
				}
				else if (vi == 0)
				{	
					this.graphics.moveTo(drawPos.x, drawPos.y);
				}
				else
				{
					this.graphics.lineTo(drawPos.x, drawPos.y);
				}
			}

			this.graphics.closePath();
			this.graphics.stroke();
		}
	}

	Display.prototype.drawMoverForCamera = function(mover, camera)
	{
		this.graphics.strokeStyle = mover.color;

		var drawPos = this.drawPos;
		this.transformWorldPosToViewPos
		(
			drawPos.overwriteWith(mover.loc.pos),
			camera
		);

		var moverDistanceFromPlayer = Math.round(mover.displacementFromPlayer.magnitude());
		var moverLabel = mover.name + "\n" + moverDistanceFromPlayer;
		
		if (drawPos.z > 0 && drawPos.isInRangeMaxXY(this.sizeInPixels) == true)
		{
			this.drawTextAtPos(moverLabel, drawPos);
			this.drawMeshAtLocationForCamera(mover.mesh, mover.loc, camera);
		}
		else
		{
			drawPos.z = 0;
			drawPos.subtract
			(
				this.sizeInPixelsHalf
			).trimToMagnitudeMax
			(
				this.sizeInPixelsHalf.x
			).add
			(
				this.sizeInPixelsHalf
			);

			this.drawTextAtPos(moverLabel, drawPos);

			this.graphics.beginPath();
			this.graphics.arc
			(
				drawPos.x, drawPos.y, 
				5, // radius
				0, Constants.RadiansPerCycle
			);
			this.graphics.stroke();
		}


	}

	Display.prototype.drawTextAtLocationForCamera = function(textToDraw, loc, camera)
	{
		var drawPos = this.drawPos;

		drawPos.overwriteWith
		(
			loc.pos
		);

		this.transformWorldPosToViewPos
		(
			drawPos,
			camera
		);

		if (drawPos.z > 0)
		{
			this.drawTextAtPos(textToDraw, drawPos);
		}
	}

	Display.prototype.drawTextAtPos = function(textToDraw, drawPos)
	{
		var textToDrawAsLines = textToDraw.split("\n");
		for (var i = 0; i < textToDrawAsLines.length; i++)
		{
			var lineToDraw = textToDrawAsLines[i];
			this.graphics.fillText(lineToDraw, drawPos.x, drawPos.y);	
			this.graphics.strokeText(lineToDraw, drawPos.x, drawPos.y);
			drawPos.y += 10; // hack
		}
	}


	Display.prototype.drawVenue = function(venue)
	{
		this.clear();

		var camera = venue.camera;
		var movers = venue.movers;
		var compassPoints = venue.compassPoints;

		for (var i = 1; i < movers.length; i++)
		{
			var mover = movers[i];
			this.drawMoverForCamera(mover, camera);
		}

		for (var i = 0; i < compassPoints.length; i++)
		{
			var compassPoint = compassPoints[i];
			this.drawCompassPointForCamera(compassPoint, camera);
		}

		this.drawTextAtPos("Time:" + Globals.Instance.secondsSoFar() + "s", new Coords(10, 10));
		this.drawTextAtPos("Kills:" + venue.killsSoFar, new Coords(10, 20));
		this.drawTextAtPos("Deaths:" + venue.deathsSoFar, new Coords(10, 30));
	}

	Display.prototype.initialize = function()
	{
		var canvas = document.createElement("canvas");
		canvas.width = this.sizeInPixels.x;
		canvas.height = this.sizeInPixels.y;

		this.graphics = canvas.getContext("2d");

		document.body.appendChild(canvas);
	}

	Display.prototype.transformWorldPosToViewPos = function(drawPos, camera)
	{
		var cameraLoc = camera.loc;
		var cameraOrientation = cameraLoc.orientation;

		drawPos.subtract
		(
			cameraLoc.pos
		).overwriteWithXYZ
		(
			drawPos.dotProduct(cameraOrientation.right),
			drawPos.dotProduct(cameraOrientation.down),
			drawPos.dotProduct(cameraOrientation.forward)
		)

		var distanceAlongCameraForward = drawPos.z;

		drawPos.multiplyScalar
		(
			camera.focalLength
		).divideScalar
		(
			distanceAlongCameraForward
		).add
		(
			this.sizeInPixelsHalf
		);

		drawPos.z = distanceAlongCameraForward;
	}
}

function Globals()
{
	// do nothing
}
{
	// instance

	Globals.Instance = new Globals();

	// methods

	Globals.prototype.initialize = function(timerTicksPerSecond, display, venue)
	{
		this.display = display;
		this.venue = venue;

		this.inputHelper = new InputHelper();

		this.display.initialize();

		this.timerTicksSoFar = 0;
		this.timerTicksPerSecond = timerTicksPerSecond;
		var millisecondsPerTimerTick = Math.round(1000 / this.timerTicksPerSecond);
		this.timer = setInterval
		(
			this.handleEventTimerTick.bind(this), 
			millisecondsPerTimerTick
		);

		this.inputHelper.initialize();
	}

	Globals.prototype.secondsSoFar = function()
	{
		return Math.floor(this.timerTicksSoFar / this.timerTicksPerSecond);
	}

	// events

	Globals.prototype.handleEventTimerTick = function()
	{
		this.venue.updateForTimerTick();
		this.timerTicksSoFar++;
	}
}

function InputHelper()
{
	// do nothing
}
{
	InputHelper.prototype.initialize = function()
	{
		this.keyCodesPressed = [];

		document.body.onkeydown = this.handleEventKeyDown.bind(this);
		document.body.onkeyup = this.handleEventKeyUp.bind(this);
	}

	// events

	InputHelper.prototype.handleEventKeyDown = function(event)
	{
		var keyCode = "_" + event.keyCode;
		if (this.keyCodesPressed[keyCode] == null)
		{
			this.keyCodesPressed.push(keyCode);
			this.keyCodesPressed[keyCode] = keyCode;
		}
	}

	InputHelper.prototype.handleEventKeyUp = function(event)
	{
		var keyCode = "_" + event.keyCode;
		delete this.keyCodesPressed[keyCode];
		this.keyCodesPressed.splice
		(
			this.keyCodesPressed.indexOf(keyCode), 1
		);
	}

}

function Location(pos, orientation)
{
	this.pos = pos;
	this.orientation = orientation;

	this.vel = new Coords(0, 0, 0);
	this.accel = new Coords(0, 0, 0);
}

function Plane(normal, distanceFromOrigin)
{
	this.normal = normal;
	this.distanceFromOrigin = distanceFromOrigin;
}

function Mesh(vertices, faces)
{
	this.vertices = vertices;
	this.faces = faces;

	this.recalculate();
}
{
	Mesh.prototype.recalculate = function()
	{
		for (var f = 0; f < this.faces.length; f++)
		{
			var face = this.faces[f];
			face.recalculateForMesh(this);
		}
	}
}

function MeshFace(vertexIndices)
{
	this.vertexIndices = vertexIndices;

	this.plane = new Plane(new Coords(), 0);
}
{
	MeshFace.prototype.recalculateForMesh = function(mesh)
	{
		var vertex0 = mesh.vertices[this.vertexIndices[0]];
		var vertex1 = mesh.vertices[this.vertexIndices[1]];
		var vertex2 = mesh.vertices[this.vertexIndices[2]];

		var edge0 = vertex1.clone().subtract(vertex0);
		var edge1 = vertex2.clone().subtract(vertex1);

		this.plane.normal.overwriteWith(edge0).crossProduct(edge1);
		this.plane.distanceFromOrigin = this.plane.normal.dotProduct(vertex0);
	}
}

function Mover
(
	name, integrity, speedMax, accelPerTick, turnPerTick, loc, activity, color, mesh
)
{
	this.name = name;
	this.integrity = integrity;
	this.speedMax = speedMax;
	this.accelPerTick = accelPerTick;
	this.turnPerTick = turnPerTick;
	this.loc = loc;
	this.activity = activity;
	this.color = color;
	this.mesh = mesh;

	this.displacementFromPlayer = new Coords();
}
{
	Mover.prototype.updateForVenueTimerTick = function(venue)
	{
		this.activity.performForActor(this);

		var loc = this.loc;
		loc.vel.add(loc.accel);
		loc.accel.clear();
		loc.vel.trimToMagnitudeMax(this.speedMax);
		loc.pos.add(loc.vel);
		loc.pos.trimToRangeMinMax
		(
			venue.sizeInPixelsHalfNegative, 
			venue.sizeInPixelsHalf
		);

		var moverForPlayer = venue.moverForPlayer;

		if (this != moverForPlayer)
		{
			this.displacementFromPlayer.overwriteWith
			(
				loc.pos
			).subtract
			(
				moverForPlayer.loc.pos
			);

			var distanceFromPlayer = this.displacementFromPlayer.magnitude();
			var distanceMinForKill = 10;
			if (distanceFromPlayer <= distanceMinForKill)
			{
				if (this.name == "Prey")
				{
					venue.killsSoFar++;
				}
				else if (this.name == "Predator")
				{
					venue.deathsSoFar++;
				}

				loc.pos.randomize().multiply
				(
					venue.sizeInPixels
				).subtract
				(
					venue.sizeInPixelsHalf
				).divideScalar
				(
					1000
				).add
				(
					moverForPlayer.loc.pos
				);
			}
		}
	}
}

function Orientation(forward, right, down)
{
	this.forward = forward;
	this.right = right;
	this.down = down;

	this.axes = 
	[
		this.forward,
		this.right,
		this.down
	];
}
{
	// static methods

	Orientation.fromForwardAndDown = function(forward, down)
	{
		return new Orientation
		(
			forward, 
			new Coords(0, 0, 0), 
			down
		).orthogonalizeAxes();
	}

	// instance methods

	Orientation.prototype.normalizeAxes = function()
	{
		this.forward.normalize();
		this.right.normalize();
		this.down.normalize();
		return this;
	}

	Orientation.prototype.orthogonalizeAxes = function()
	{
		this.right.overwriteWith
		(
			this.down
		).crossProduct
		(
			this.forward
		);

		this.down.overwriteWith
		(
			this.forward
		).crossProduct
		(
			this.right
		);

		this.normalizeAxes();

		return this;
	}

	Orientation.prototype.overwriteWith = function(other)
	{
		this.forward.overwriteWith(other.forward);
		this.right.overwriteWith(other.right);
		this.down.overwriteWith(other.down);
	}

	Orientation.prototype.toString = function()
	{
		var returnValue = 
			this.forward.toString() 
			+ "x" + this.right.toString()
			+ "x" + this.down.toString();

		return returnValue;
	}
}

function Transform_Orient(orientation)
{
	this.orientation = orientation;

	this.orientationTemp = new Orientation(new Coords(), new Coords(), new Coords());
	this.result = new Coords();
}
{
	Transform_Orient.prototype.applyToCoords = function(coordsToTransform)
	{
		this.orientationTemp.overwriteWith(this.orientation);
		this.result.clear().add
		(
			this.orientationTemp.forward.multiplyScalar(coordsToTransform.z)
		).add
		(
			this.orientationTemp.right.multiplyScalar(coordsToTransform.x)
		).add
		(
			this.orientationTemp.down.multiplyScalar(coordsToTransform.y)
		);
		coordsToTransform.overwriteWith(this.result);
	}
}

function Venue(name, sizeInPixels, movers)
{
	this.name = name;
	this.sizeInPixels = sizeInPixels;
	this.movers = movers;

	this.sizeInPixelsHalf = this.sizeInPixels.clone().divideScalar(2);
	this.sizeInPixelsHalfNegative = this.sizeInPixelsHalf.clone().multiplyScalar(-1);

	this.moverForPlayer = this.movers[0];

	this.camera = new Camera
	(
		300, // focalLength
		this.moverForPlayer.loc
	);

	var directionNamesAndOffsets = 
	[
		[ "West", new Coords(-1, 0, 0) ],
		[ "East", new Coords(1, 0, 0) ],
		[ "North", new Coords(0, -1, 0) ],
		[ "South", new Coords(0, 1, 0) ],
		[ "Up", new Coords(0, 0, -1) ],
		[ "Down", new Coords(0, 0, 1) ],
	];

	this.compassPoints = [];

	for (var i = 0; i < directionNamesAndOffsets.length; i++)
	{
		var directionNameAndOffset = directionNamesAndOffsets[i];
		var directionName = directionNameAndOffset[0];
		var directionOffset = directionNameAndOffset[1];
		var compassPoint = new CompassPoint(directionName, directionOffset); 
		this.compassPoints.push(compassPoint);
	}

	this.killsSoFar = 0;
	this.deathsSoFar = 0;
}
{
	Venue.prototype.updateForTimerTick = function()
	{
		for (var i = 0; i < this.movers.length; i++)
		{
			var mover = this.movers[i];
			mover.updateForVenueTimerTick(this);
		}		

		for (var i = 0; i < this.compassPoints.length; i++)
		{
			var compassPoint = this.compassPoints[i];
			compassPoint.updateForVenueTimerTick(this);
		}

		Globals.Instance.display.drawVenue(this);
	}
}

// run

main();

</script>
</body>
</html>

Advertisement
This entry was posted in Uncategorized and tagged , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s