Others
Collisions
This is an example managing collisions:
<!DOCTYPE html>
<html>
<head>
<!-- This file belongs to a CrossBrowdy.com example, made by Joan Alba Maldonado. Creative Commons Attribution 4.0 International License. -->
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<link rel="canonical" href="https://crossbrowdy.com/examples/others/collisions/try" />
<title>Others: Collisions - Example</title>
<!-- Loads the needed CSS files: -->
<link rel="stylesheet" type="text/css" href="main.css" />
<!-- Loads FlashCanvas (Flash emulation) before CrossBrowdy. Needed also to use ExplorerCanvas (VML emulation) without problems: -->
<!-- Note: it is recommended to download CrossBrowdy instead of hotlinking the online version. This is just for the example! -->
<script src="https://crossbrowdy.com/CrossBrowdy/CrossBase/audiovisual/image/canvas/FlashCanvas/pro/bin/flashcanvas.js" type="text/javascript" language="javascript"></script><!-- FlashCanvas/ExplorerCanvas do not support lazy load. -->
<!-- Loads CrossBrowdy.js (main file): -->
<!-- Note: it is recommended to download CrossBrowdy instead of hotlinking the online version. This is just for the example! -->
<script src="https://crossbrowdy.com/CrossBrowdy/CrossBrowdy.js" type="text/javascript" language="javascript"></script><!-- "type" and "language" parameters for legacy clients. -->
<!-- Loads the other needed script files: -->
<script src="main.js" type="text/javascript" language="javascript"></script>
</head>
<body>
<canvas id="my_canvas">if you read this, canvas is not working</canvas><!-- Some emulation methods will require the canvas element created in HTML (not dynamically by JavaScript). -->
<br />
<br />
Messages:
<div id="messages"></div>
<br />
<br />
Point A:
<span>
X: <input type="text" id="point_a_x" size="7" maxlength="7" value="70" />,
Y: <input type="text" id="point_a_y" size="7" maxlength="7" value="30" />
</span>
<br />
Point B:
<span>
X: <input type="text" id="point_b_x" size="7" maxlength="7" value="35" />,
Y: <input type="text" id="point_b_y" size="7" maxlength="7" value="60" />
</span>
<br />
<br />
Rectangle A:
<span>
X: <input type="text" id="rectangle_a_x" size="7" maxlength="7" value="2" />,
Y: <input type="text" id="rectangle_a_y" size="7" maxlength="7" value="10" />,
Width: <input type="text" id="rectangle_a_width" size="7" maxlength="7" value="30" />,
Height: <input type="text" id="rectangle_a_height" size="7" maxlength="7" value="60" />
</span>
<br />
Rectangle B:
<span>
X: <input type="text" id="rectangle_b_x" size="7" maxlength="7" value="8" />,
Y: <input type="text" id="rectangle_b_y" size="7" maxlength="7" value="20" />,
Width: <input type="text" id="rectangle_b_width" size="7" maxlength="7" value="50" />,
Height: <input type="text" id="rectangle_b_height" size="7" maxlength="7" value="10" />
</span>
<br />
<br />
Circle A:
<span>
X (centre): <input type="text" id="circle_a_x" size="7" maxlength="7" value="160" />,
Y (centre): <input type="text" id="circle_a_y" size="7" maxlength="7" value="70" />,
Radius: <input type="text" id="circle_a_radius" size="7" maxlength="7" value="30" />
</span>
<br />
Circle B:
<span>
X (centre): <input type="text" id="circle_b_x" size="7" maxlength="7" value="90" />,
Y (centre): <input type="text" id="circle_b_y" size="7" maxlength="7" value="130" />,
Radius: <input type="text" id="circle_b_radius" size="7" maxlength="7" value="80" />
</span>
<br />
<br />
Ellipse A:
<span>
X (centre): <input type="text" id="ellipse_a_x" size="7" maxlength="7" value="200" />,
Y (centre): <input type="text" id="ellipse_a_y" size="7" maxlength="7" value="170" />,
Radius vertical: <input type="text" id="ellipse_a_radius_x" size="7" maxlength="7" value="30" />
Radius horizontal: <input type="text" id="ellipse_a_radius_y" size="7" maxlength="7" value="50" />
</span>
<br />
<br />
Line A:
<span>
1st point X: <input type="text" id="line_x1" size="7" maxlength="7" value="10" />,
1st point Y: <input type="text" id="line_y1" size="7" maxlength="7" value="100" />,
2nd point X: <input type="text" id="line_x2" size="7" maxlength="7" value="0" />,
2nd point Y: <input type="text" id="line_y2" size="7" maxlength="7" value="0" />
</span>
<br />
<br />
Segment A:
<span>
first point X: <input type="text" id="segment_x1" size="7" maxlength="7" value="30" />,
first point Y: <input type="text" id="segment_y1" size="7" maxlength="7" value="60" />,
last point X: <input type="text" id="segment_x2" size="7" maxlength="7" value="210" />,
last point Y: <input type="text" id="segment_y2" size="7" maxlength="7" value="210" />
</span>
<br />
<!-- The "CB_console" element will be used automatically in the case that the client does not support console: -->
<div id="CB_console" style="display:none; visibility:hidden; overflow:scroll;">
<span style="font-weight:bold;">Console:</span><br />
</div>
<div id="crossbrowdy_info"><a href="https://crossbrowdy.com/examples/others/collisions" target="_blank">CrossBrowdy.com example</a></div>
</body>
</html>
/* This file belongs to a CrossBrowdy.com example, made by Joan Alba Maldonado. Creative Commons Attribution 4.0 International License. */
body { background-color:#aaddee; word-wrap:break-word; }
#crossbrowdy_info { position:fixed; bottom:2px; right:2px; }
#crossbrowdy_info a { color:#00aadd; }
#crossbrowdy_info a:hover { color:#0033aa; }
span { color:#aa0000; }
#messages { color:#ffffff; background-color:#aa0000; font-weight:bold; width:100%; height:300px; overflow:auto; }
.message_collision { color:#ffff00; }
/* This file belongs to a CrossBrowdy.com example, made by Joan Alba Maldonado. Creative Commons Attribution 4.0 International License. */
CB_init(main); //It will call the "main" function when ready.
//This function will be called when CrossBrowdy is ready:
function main()
{
printMessage("Creating canvas...");
//Creates the canvas:
var onLoadCanvas = function()
{
printMessage("Canvas loaded!");
//Processes the elements:
processElements(this);
};
myCanvas = new CB_Canvas
(
"my_canvas", //canvasId. Unique required parameter.
"2d", //contextType. NOTE: some emulation methods only support "2d". Default: "2d".
250, //canvasWidth. Use 'CB_Screen.getWindowWidth()' for complete width. Default: CB_Canvas.WIDTH_DEFAULT.
250, //canvasHeight. Use 'CB_Screen.getWindowHeight()' for complete height. Default: CB_Canvas.HEIGHT_DEFAULT.
onLoadCanvas, //onLoad.
function(error) { printMessage("Canvas object problem! Error: " + error); } //onError.
);
}
//Shows a message:
function printMessage(message)
{
message = CB_trim(message);
if (message.indexOf("COLLISION: ") !== -1) { message = '<span class="message_collision">' + message + '</span>'; }
if (message === "") { CB_Elements.insertContentById("messages", ""); }
else
{
CB_Elements.appendContentById("messages", message + "<br />");
CB_Elements.id("messages").scrollTop = CB_Elements.id("messages").scrollHeight; //Scrolls to the bottom.
}
}
//Processes the elements:
var inputIds =
[
"point_a_x", "point_a_y",
"point_b_x", "point_b_y",
"rectangle_a_x", "rectangle_a_y", "rectangle_a_width", "rectangle_a_height",
"rectangle_b_x", "rectangle_b_y", "rectangle_b_width", "rectangle_b_height",
"circle_a_x", "circle_a_y", "circle_a_radius",
"circle_b_x", "circle_b_y", "circle_b_radius",
"ellipse_a_x", "ellipse_a_y", "ellipse_a_radius_x", "ellipse_a_radius_y",
"line_x1", "line_y1", "line_x2", "line_y2",
"segment_x1", "segment_y1", "segment_x2", "segment_y2"
];
var lastElementsData = {};
function processElements(CB_CanvasObject)
{
//Sanitize inputs and extract their values:
var elementsData = {};
var elementsDataChanged = false;
for (var x = inputIds.length - 1; x >= 0; x--)
{
CB_Elements.id(inputIds[x]).value = elementsData[inputIds[x]] = sanitizeNumber(inputIds[x], CB_CanvasObject);
if (elementsData[inputIds[x]] !== lastElementsData[inputIds[x]]) { elementsDataChanged = true; }
}
if (elementsDataChanged)
{
printMessage(""); //Clears the previous messages (if any).
printMessage("Processing the elements...");
printMessage("Elements data sanitized: " + JSON.stringify(elementsData));
//Draws the elements in the canvas:
drawElements(elementsData, CB_CanvasObject);
//Checks collisions of the elements:
checkElementsCollisions(elementsData);
lastElementsData = elementsData;
}
//Calls itself again:
setTimeout(function() { processElements(CB_CanvasObject); }, 1);
}
//Sanitize inputs to only allow numeric values:
function sanitizeNumber(idElement, CB_CanvasObject)
{
var value = parseFloat(CB_Elements.id(idElement).value);
value = isNaN(value) ? 0 : value;
if (idElement.indexOf("_x") !== -1)
{
var canvasWidth = CB_CanvasObject.getWidth();
if (value < 0) { value = 0; }
else if (value > canvasWidth) { value = canvasWidth; }
}
else if (idElement.indexOf("_y") !== -1)
{
var canvasHeight = CB_CanvasObject.getHeight();
if (value < 0) { value = 0; }
else if (value > canvasHeight) { value = canvasHeight; }
}
return value;
}
//Draws the elements in the canvas:
function drawElements(elementsData, CB_CanvasObject)
{
printMessage("Trying to draw the elements...");
//Clears the canvas:
CB_CanvasObject.clear(true, "#ffffff"); //Clears the canvas keeping the transform and using desired background colour.
//Gets the "context" object to start working with the canvas:
var canvasContext = CB_CanvasObject.getContext();
if (!canvasContext) { printMessage("ERROR: canvas context could not be obtained! Drawing cannot be performed."); return; }
var canvasWidth = CB_CanvasObject.getWidth();
var canvasHeight = CB_CanvasObject.getHeight();
canvasContext.globalAlpha = 0.3;
//Draws the points:
canvasContext.fillStyle = "#ff0000";
canvasContext.fillRect(elementsData.point_a_x, elementsData.point_a_y, 1, 1);
canvasContext.fillStyle = "#0000ff";
canvasContext.fillRect(elementsData.point_b_x, elementsData.point_b_y, 1, 1);
//Draw label for the points (they are difficult to see):
//Note: SLCanvas doesn't support font property and fillText method:
canvasContext.fillStyle = "#00aaaa";
canvasContext.strokeStyle = "#003300";
canvasContext.font = "10px arial";
canvasContext.fillText("Point A", elementsData.point_a_x < canvasWidth - 38 ? elementsData.point_a_x + 2 : elementsData.point_a_x - 38, elementsData.point_a_y > 12 ? elementsData.point_a_y + 2 : elementsData.point_a_y + 12);
canvasContext.fillText("Point B", elementsData.point_b_x < canvasWidth - 38 ? elementsData.point_b_x + 2 : elementsData.point_b_x - 38, elementsData.point_b_y > 12 ? elementsData.point_b_y + 2 : elementsData.point_b_y + 12);
//Draws the rectangles:
canvasContext.fillStyle = "#00ff00";
canvasContext.fillRect(elementsData.rectangle_a_x, elementsData.rectangle_a_y, elementsData.rectangle_a_width, elementsData.rectangle_a_height);
canvasContext.fillStyle = "#00ffff";
canvasContext.fillRect(elementsData.rectangle_b_x, elementsData.rectangle_b_y, elementsData.rectangle_b_width, elementsData.rectangle_b_height);
//Draws the circles:
canvasContext.fillStyle = "#ffff00";
canvasContext.beginPath();
canvasContext.arc(elementsData.circle_a_x, elementsData.circle_a_y, elementsData.circle_a_radius, 0, Math.PI * 2, true);
canvasContext.closePath();
canvasContext.fill();
canvasContext.fillStyle = "#ff00ff";
canvasContext.beginPath();
canvasContext.arc(elementsData.circle_b_x, elementsData.circle_b_y, elementsData.circle_b_radius, 0, Math.PI * 2, true);
canvasContext.closePath();
canvasContext.fill();
//Draws the ellipse:
canvasContext.fillStyle = "#ccbbaa";
canvasContext.beginPath();
canvasContext.arc(elementsData.circle_a_x, elementsData.circle_a_y, elementsData.circle_a_radius, 0, Math.PI * 2, true);
try
{
canvasContext.ellipse(elementsData.ellipse_a_x, elementsData.ellipse_a_y, elementsData.ellipse_a_radius_x, elementsData.ellipse_a_radius_y, 0, 2, 11, false);
}
catch(ellipseError)
{
//The 'ellipse' function is not supported by Internet Explorer 11 and lower. Uses an alternative:
//Note: the 'CB_Canvas.prototype._context_drawEllipse' still cannot be considered a valid polyfill as it still does not mimic the native 'ellipse' function.
CB_Canvas.prototype._context_drawEllipse.call(canvasContext, elementsData.ellipse_a_x, elementsData.ellipse_a_y, elementsData.ellipse_a_radius_x, elementsData.ellipse_a_radius_y, 0, 2, 11, false);
}
canvasContext.closePath();
canvasContext.fill();
//Draws the line:
//NOTE: using the slope-of-a-rect formula: y = mx + n (m = "slope", n = "value of 'y' when 'x' = 0").
var yDifference = (elementsData.line_y2 - elementsData.line_y1);
var xDifference = (elementsData.line_x2 - elementsData.line_x1);
var m = 0; //Slope. By default, it will be default as no slope (horizontal line).
var n = elementsData.line_y1; //value of 'y' when 'x' = 0.
//If there is no horizontal difference between the points, the line is vertical:
if (xDifference === 0) { m = null; n = undefined; } //Infinite slope (vertical line). The 'null' will be considered infinite.
//...otherwise, if there is vertical difference between the points, the line is neither vertical nor horizontal:
else if (yDifference !== 0)
{
m = yDifference / xDifference; //Slope.
//var n = (-m + elementsData.line_y1) / elementsData.line_x1; //Value of 'y' when 'x' = 0. Calculus: y = mx + n => elementsData.line_y1 = m * elementsData.line_x1 + n => n = (-m + elementsData.line_y1) / elementsData.line_x1.
var n = (-m + yDifference) / xDifference; //Value of 'y' when 'x' = 0. Calculus: y = mx + n => elementsData.line_y1 = m * elementsData.line_x1 + n => n = (-m + elementsData.line_y1) / elementsData.line_x1.
}
//No slope (horizontal line):
var xFirst = 0;
var yFirst = Math.max(0, Math.min(elementsData.line_y1, canvasHeight)); //y = n = elementsData.line_y1 = elementsData.line_y2, when x = 0.
var xLast = canvasWidth; //To the limit.
var yLast = Math.max(0, Math.min(elementsData.line_y2, canvasHeight));
//Infinite slope (vertical line):
if (m === null)
{
xFirst = Math.max(0, Math.min(elementsData.line_x1, canvasWidth));
yFirst = 0;
xLast = Math.max(0, Math.min(elementsData.line_x1, canvasWidth));
yLast = canvasHeight; //To the limit.
}
//Normal slope:
else if (m !== 0)
{
xFirst = 0;
yFirst = n;
if (yFirst > 0 || yFirst < canvasHeight) //If the first "y" starts in the middle of the canvas:
{
xFirst = -n / m; //y = mx + n => 0 = mx + n => x = (0 - n) / m = -n / m
yFirst = 0;
}
xLast = canvasWidth;
yLast = m * xLast + n; //y = mx + n.
if (yLast < canvasHeight) //If the last "y" does not reach the canvas bottom:
{
yLast = canvasHeight; //x = elementsData.line_x2 * 10000, y = mx + n => y = (m * elementsData.line_x2 * 10000) + n.
xLast = (yLast - n) / m; //y = mx + n => x = (y - n) / m.
}
}
canvasContext.strokeStyle = "#3512ad";
canvasContext.beginPath();
canvasContext.moveTo(xFirst, yFirst);
canvasContext.lineWidth = 1;
canvasContext.lineTo(xLast, yLast); //x = elementsData.line_x2 * 10000, y = mx + n => y = (m * elementsData.line_x2 * 10000) + n.
canvasContext.closePath();
canvasContext.stroke();
//Draws the segment:
canvasContext.strokeStyle = "#35ad12";
canvasContext.beginPath();
canvasContext.moveTo(elementsData.segment_x1, elementsData.segment_y1);
canvasContext.lineWidth = 1;
canvasContext.lineTo(elementsData.segment_x2, elementsData.segment_y2);
canvasContext.closePath();
canvasContext.stroke();
}
//Checks collisions of the elements:
function checkElementsCollisions(elementsData)
{
printMessage("Processing elements to check collisions...");
//Distance between two points:
printMessage("The distance between 'Point A' and 'Point B' is: " + CB_Collisions.getDistancePoints(elementsData.point_a_x, elementsData.point_a_y, elementsData.point_b_x, elementsData.point_b_y));
//A point and a rectangle:
if (CB_Collisions.isPointOverRectangle(elementsData.point_a_x, elementsData.point_a_y, elementsData.rectangle_a_x, elementsData.rectangle_a_y, elementsData.rectangle_a_width, elementsData.rectangle_a_height))
{
printMessage("COLLISION: The point is over a rectangle whose left upper corner coordinates start at (" + elementsData.point_a_x + ", " + elementsData.point_a_y + ") and whose width is " + elementsData.rectangle_a_width + " and height is " + elementsData.rectangle_a_height + ".");
}
if (CB_Collisions.isPointTouchingRectangle(elementsData.point_a_x, elementsData.point_a_y, elementsData.rectangle_a_x, elementsData.rectangle_a_y, elementsData.rectangle_a_width, elementsData.rectangle_a_height)) //Also if they are adjacent (next to each other).
{
printMessage("COLLISION: The point is touching (maybe over) a rectangle whose left upper corner coordinates start at (" + elementsData.point_a_x + ", " + elementsData.point_a_y + ") and whose width is " + elementsData.rectangle_a_width + " and height is " + elementsData.rectangle_a_height + ".");
}
//A point and a circle:
if (CB_Collisions.isPointOverCircle(elementsData.point_a_x, elementsData.point_a_y, elementsData.circle_a_x, elementsData.circle_a_y, elementsData.circle_a_radius))
{
printMessage("COLLISION: The point is over a circle whose center is in (" + elementsData.circle_a_x + ", " + elementsData.circle_a_y + ") pixel coordinates and its radius is " + elementsData.circle_a_radius + " pixels.");
}
if (CB_Collisions.isPointTouchingCircle(elementsData.point_a_x, elementsData.point_a_y, elementsData.circle_a_x, elementsData.circle_a_y, elementsData.circle_a_radius)) //Also if they are adjacent (next to each other).
{
printMessage("COLLISION: The point is touching (maybe over) a circle whose center is in (" + elementsData.circle_a_x + ", " + elementsData.circle_a_y + ") pixel coordinates and its radius is " + elementsData.circle_a_radius + " pixels.");
}
//A point and an ellipse:
if (CB_Collisions.isPointOverEllipse(elementsData.point_a_x, elementsData.point_a_y, elementsData.ellipse_a_x, elementsData.ellipse_a_y, elementsData.ellipse_a_radius_x, elementsData.ellipse_a_radius_y))
{
printMessage("COLLISION: The point is over a ellipse whose center is in (" + elementsData.ellipse_a_x + ", " + elementsData.ellipse_a_y + ") pixel coordinates and its horizontal and vertical radii are " + elementsData.ellipse_a_radius_x + " and " + elementsData.ellipse_a_radius_y + " pixels respectively.");
}
if (CB_Collisions.isPointTouchingEllipse(elementsData.point_a_x, elementsData.point_a_y, elementsData.ellipse_a_x, elementsData.ellipse_a_y, elementsData.ellipse_a_radius_x, elementsData.ellipse_a_radius_y)) //Also if they are adjacent (next to each other).
{
printMessage("COLLISION: The point is touching (maybe over) a ellipse whose center is in (" + elementsData.ellipse_a_x + ", " + elementsData.ellipse_a_y + ") pixel coordinates and its horizontal and vertical radii are " + elementsData.ellipse_a_radius_x + " and " + elementsData.ellipse_a_radius_y + " pixels respectively.");
}
//A point and a line (infinite):
if (CB_Collisions.isPointOverLine(elementsData.point_a_x, elementsData.point_a_y, elementsData.line_x1, elementsData.line_y1, elementsData.line_x2, elementsData.line_y2))
{
printMessage("COLLISION: The point is over an infinite line which cross both the (" + elementsData.line_x1 + ", " + elementsData.line_y1 + ") and (" + elementsData.line_x2 + ", " + elementsData.line_y2 + ") coordinates.");
}
//A point and a line segment (limited):
if (CB_Collisions.isPointOverSegment(elementsData.point_a_x, elementsData.point_a_y, elementsData.segment_x1, elementsData.segment_y1, elementsData.segment_x2, elementsData.segment_y2))
{
printMessage("COLLISION: The point is over a line segment which starts in the (" + elementsData.segment_x1 + ", " + elementsData.segment_y1 + ") and ends in the (" + elementsData.segment_x2 + ", " + elementsData.segment_y2 + ") coordinates.");
}
//Two rectangles:
if (CB_Collisions.isRectangleOverRectangle(elementsData.rectangle_a_x, elementsData.rectangle_a_y, elementsData.rectangle_a_width, elementsData.rectangle_a_height, elementsData.rectangle_b_x, elementsData.rectangle_b_y, elementsData.rectangle_b_width, elementsData.rectangle_b_height))
{
printMessage("COLLISION: The rectangle whose left upper corner coordinates start at (" + elementsData.point_a_x + ", " + elementsData.point_a_y + ") and whose width is " + elementsData.rectangle_a_width + " and height is " + elementsData.rectangle_a_height + " is over the rectangle whose left upper corner coordinates start at (" + elementsData.point_b_x + ", " + elementsData.point_b_y + ") and whose width is " + elementsData.rectangle_b_width + " and height is " + elementsData.rectangle_b_height + ".");
}
if (CB_Collisions.isRectangleTouchingRectangle(elementsData.rectangle_a_x, elementsData.rectangle_a_y, elementsData.rectangle_a_width, elementsData.rectangle_a_height, elementsData.rectangle_b_x, elementsData.rectangle_b_y, elementsData.rectangle_b_width, elementsData.rectangle_b_height)) //Also if they are adjacent (next to each other).
{
printMessage("COLLISION: The rectangle whose left upper corner coordinates start at (" + elementsData.point_a_x + ", " + elementsData.point_a_y + ") and whose width is " + elementsData.rectangle_a_width + " and height is " + elementsData.rectangle_a_height + " is touching (maybe over) the rectangle whose left upper corner coordinates start at (" + elementsData.point_b_x + ", " + elementsData.point_b_y + ") and whose width is " + elementsData.rectangle_b_width + " and height is " + elementsData.rectangle_b_height + ".");
}
//Two circles:
if (CB_Collisions.isCircleOverCircle(elementsData.circle_a_x, elementsData.circle_a_y, elementsData.circle_a_radius, elementsData.circle_b_x, elementsData.circle_b_y, elementsData.circle_b_radius))
{
printMessage("COLLISION: The circle whose center is in (" + elementsData.circle_a_x + ", " + elementsData.circle_a_y + ") pixel coordinates and its radius is " + elementsData.circle_a_radius + " pixels is over the circle whose center is in (" + elementsData.circle_b_x + ", " + elementsData.circle_b_y + ") pixel coordinates and its radius is " + elementsData.circle_b_radius + " pixels.");
}
if (CB_Collisions.isCircleTouchingCircle(elementsData.circle_a_x, elementsData.circle_a_y, elementsData.circle_a_radius, elementsData.circle_b_x, elementsData.circle_b_y, elementsData.circle_b_radius)) //Also if they are adjacent (next to each other).
{
printMessage("COLLISION: The circle whose center is in (" + elementsData.circle_a_x + ", " + elementsData.circle_a_y + ") pixel coordinates and its radius is " + elementsData.circle_a_radius + " pixels is touching (maybe over) the circle whose center is in (" + elementsData.circle_b_x + ", " + elementsData.circle_b_y + ") pixel coordinates and its radius is " + elementsData.circle_b_radius + " pixels.");
}
}
You can check the Guides & Tutorials category as well as the API documentation in the case you need more information.
All the examples together can be downloaded here.