3. What is Raphaël
A small JavaScript library
Manage vector graphics in web browsers
Easy to use and cross platform
Firefox 3.0+, Safari 3.0+, Chrome 5.0+, Opera 9.5+
and Internet Explorer 6.0+
“It is not supposed to replace Flash, but it probably
does in many cases”
5. What will I show
A 1970's board game moved into a browser
How I solved the various drawing issues
Lots of Raphaël code
6. What I won't show
I used jQuery, AJAX, PHP and MySQL to manage
the infrastructure
Design decisions on the interface
I can't release the full code as it might breach
copyright laws
I can answer questions on these afterwards
8. Scalable Vector Graphics
an image format implemented in XML
allows precise images to be described
can be scaled, rotated etc without loss of quality
HTML 5 supports SVG images
Modern browsers support it differently
Dmitry Baranovskiy had bad experiences with these
differences so created Raphaël to abstract away the
special cases
11. Graphics have Layers - 2
Important to manage your layers
Raphaël does not have layers per-se
insertBefore insertAfter
Use sets to keep it together
If you use toFront or toBack, you are doing it wrong
(I have a couple in the current code from debugging)
12. Making a Game Board
Layer 1
Hexagons to regular movement
Different terrain that impacts movement and combat
Different for each game
13. Drawing a hexagon
var paper = new Raphael("holder", 200, 200);
var path = paper.path(' M 0 86.6 L 50 173.2 150 173.2 200 86.6 150 0 50 0 Z')
.attr({'stroke: '#000'});
15. Drawing lots of Hexagons
while (line < this.HEIGHT) {
var x = 0,
y = line,
s = 'M0 ' + line + 'L';
while (x < this.WIDTH) {
x += this.HEX_SIDE * this.COS60;
y += this.HEX_SIDE * this.SIN60 * (even ? -1 : 1);
s += ' ' + x + ' ' + y;
if (x >= this.WIDTH) break;
x += this.HEX_SIDE;
if (!even || y == 0) {
s += ' ' + x + ' ' + y;
} else {
s += 'M' + x + ' ' + y + 'L';
}
if (x >= this.WIDTH) break;
x += this.HEX_SIDE * this.COS60;
y += this.HEX_SIDE * this.SIN60 * (even ? 1 : -1);
s += ' ' + x + ' ' + y;
if (x >= this.WIDTH) break;
x += this.HEX_SIDE;
if (even) {
s += ' ' + x + ' ' + y;
} else {
s += 'M' + x + ' ' + y + 'L';
}
}
if (!even) line += this.HEX_SIDE * this.SIN60 * 2;
even = !even;
this.paper.path(s).attr(attr);
}
16. Drawing Rivers
Rivers are paths with a start and finish
You do not want to touch neighbouring cells
You want to have a bit of randomness
Raphaël has many different curve options
C = Curve to
S = Smooth curve to
Q = Quadratic Bezier curve to
T = Smooth quadratic Bezier curve to, etc.
Experiment!
18. Drawing Rivers - 2
$.each(source, function (idx, path) { // an array of rivers
var first = new $.Cell(path[0]);
var mid = first.getHexMidpoint("original"),
lastMid;
var line = "M" + mid.x + ' ' + mid.y + 'S';
var i = 1;
game[target].push(first);
while (i < path.length) {
lastMid = mid;
var next = new $.Cell(path[i]);
mid = next.getHexMidpoint("original");
game[target].push(next);
line += ' ' + Raphael.format('{0} {1} {2} {3}',
(mid.x + lastMid.x) / 2, (mid.y + lastMid.y) / 2,
mid.x, mid.y);
i++;
}
game.paper.path(line).attr(attr);
});
19. Drawing Forests
Forests are closed paths that are filled in
You need to find the boundaries and walk around
them
No colour in the hexes next to the forest
Not perfectly regular
22. Drawing Forests - 4
// Find a forest cell next to a non forest cell
var forestCell, clearCell, s, direction;
forest.each(function(idx, cell) {
var neighbours = cell.getAdjacentCells();
direction = -1;
$.each(neighbours, function(idx, adjacentCell) {
if (!adjacentCell) return;
var gotOne = forest.indexOf(adjacentCell);
if (gotOne >= 0) return; // Looking for a clear cell
direction = idx;
forestCell = cell;
clearCell = adjacentCell;
return false;
});
if (direction == -1) return; // cell is surrounded by forest cells, so not
needed for drawing
return false; // got one!
});
var mf = forestCell.getHexMidpoint("original"),
mc = clearCell.getHexMidpoint("original");
s = "M" + Math.round((3 * mc.x + 5 * mf.x)/8,2) + ' ' + Math.round((3 * mc.y + 5
* mf.y)/8,2) + 'S';
var countClear = 0;
var firstForest = forestCell, firstClear = clearCell;
23. Drawing Forests - 5
while (countClear < 6) {
direction = (direction + 1) % 6; // step one clockwise
var nextCell = forestCell.getAdjacentCells()[direction];
var gotOne = forest.indexOf(nextCell);
var mn = nextCell.getHexMidpoint("original");
if (gotOne >= 0) {
var midX = Math.round((10 * (mf.x + mn.x)/2 + 3 * mc.x)/13,2),
midY = Math.round((10 * (mf.y + mn.y)/2 + 3 * mc.y)/13,2);
s += ' ' + midX + ' ' + midY;
countClear = 0;
forestCell = nextCell;
mf = mn;
direction = forestCell.directionTo(clearCell);
} else if (game.forests.contains(nextCell)) {
break; // Gone around and completed the loop. Beware a clearing in the forest though
} else {
countClear += 1;
clearCell = nextCell;
mc = mn;
}
var scale = (countClear % 2) ? {c: 3, f: 5} : {c: 3, f:6};
s += " " + Math.round((scale.c * mc.x + scale.f * mf.x)/(scale.c + scale.f),2) + ' ' +
Math.round((scale.c * mc.y + scale.f * mf.y)/(scale.c + scale.f),2);
if (forestCell.equals(firstForest) && clearCell.equals(firstClear)) break; // We have
cirled the copse
if (direction == -1) break; // algorithm failure
}
game.paper.path(s + 'z').attr({
stroke: "#060",
fill: "#090",
"stroke-width": 1,
"stroke-linejoin": "round"
});
24. Drawing Villages
Four cubes
At different orientations
At different locations
Seed the random number generator to the hex index
So a redraw does not alter the buildings!
25. Drawing Slopes
Want a fan effect
Longer if end slope, shorter if next to another slope
Not too regular
A lot of experimentation
31. Making the Pieces
Pieces are cardboard chits with graphics and text
Can stack (and split and join)
Can face different directions
Can have status markers on top
During the game they can
Move
Fire missiles
Attack
Be Eliminated
33. Drawing the Icons - 2
Graphics Level 2
Stage one – try to write SVG
Stage two – terror
Stage three – check Dmitry's icons
Stage four – terror
Stage five – find an SVG drawing tool
Light bulb moment – LibreOffice can export SVG
Stage six – have a go
39. With the original game...
Stack the card board pieces
Move them, counting terrain and different speeds
Declare attacks
Roll the die and apply the results
Use the special behaviour of some pieces
All the while, your opponent is watching you like a
hawk to ensure you don't cheat
The user interface must manage this now
Hence we need controls
40. Making controls
Graphics Level 3
Deployment Control
Movement Control
Split Stack Control
Waiting Control
Combat Control
Game Menu
41. Deployment Control
Placing your units at the start of the game
Drag and drop off an “artist palette”
Set facing
Detect stacking violations
43. Deployment Control - 3
Raphaël has a method that manages drag and drop
Can be applied to a set of elements
Any element in the set is a handle
Every element in the set moves
I do lots of small movements as not only do the units
drag, so does the whole palette
Also, note the data() method below
47. Movement Control
Each stack can move into its facing hexes
Each hex costs a number of points to enter
Only if it has the movement points
Can always move one hex
Changing facing costs one point
If you make a mistake, you can reset and try again
49. Movement Control - 3
Arrows are rotated same as deployment control
They are hidden if not permitted
Everything has to spring back if the reset is pressed
So watch relative movement
51. Split Stack Control
Units in a stack can split into two stacks
Originally drag and drop,
but as the behaviour was binary,
I changed it to a simple click
58. Combat Control
No grey boxed needed
When you highlight an assailant, I put a translucent
target over potential victims
When you click a target, I draw a translucent arrow
from the assailant to the victim
(Odds are shown on the right)
66. Where to next
Touch screens and tablets
More bug fixing and improvements
What can be released?
Post onto Source Forge or Git Hub
Build a community
67. Resources
Code and documentation – http://raphaeljs.com
Designer - http://dmitry.baranovskiy.com/
Google group https://groups.google.com/forum/#!forum/raphaeljs
jQuery – http://jquery.com
Moi – maurice@redwaratah.com