For all it's awesomeness, Canvas has drawbacks as well:
API is too low-level (line, rect, fill, circle, image, and text. That's it.)
complex shapes...? NOPE.
mouse/gesture tracking...? NOPE.
hit detection...? NOPE.
entity management...? NOPE.
sprite animation...? NOPE.
Abstractions Needed
Why reinvent the wheel?
Plenty of third-party libraries / frameworks available, but there are tradeoffs
Possibly unnecessary bloat
Risk of overengineering
Square Peg / Round Hole
DIY vs DRY
DIY = Do It Yourself
Common symptom of "Not Invented Here" mentality
Obligatory XKCD:
DIY vs DRY
DRY = Don't Repeat Yourself
Eschews "Not Invented Here"
Less code matters
Principle: Keeping it Lean
Push as little code down the wire as possible
This is especially important on mobile
Only build & include as much as you actually need
Focus on each component doing one thing, really well.
I don't always write my own frameworks, but when I do...
The "first-party" library
DRY-U-DIY-IMA™
Don't Repeat Yourself, Unless Doing It Yourself Is More Appropriate
Practicality over dogma (there's no one true "right way", there's just your right way)
Reuse where it makes sense, reimplement where it doesn't
You probably don't need Box2D for your Super Mario clone, if something simpler and custom will suffice
But rewriting jQuery / Dojo / Zepto is probably unnecessary
Don't switch to CoffeeScript just so you can use CoffeePhysics
(Unless you decide you really like CoffeeScript!)
Recycle, recycle, recycle!
Take inspiration from everywhere you can
Flash developers solved a lot of these problems already
(And desktop devs before them)
There are loads of great development blogs for Flash, C++, .NET... don't be afraid to use them!
Jamis Buck's
Ruby-based maze-generation stuff formed the basis of Infinite Dungeon's map generator
The original Prince of Persia source code is on Github. Have you looked at it yet?
Ruby...
# --------------------------------------------------------------------
# 2. Set up constants to aid with describing the passage directions
# --------------------------------------------------------------------
N, S, E, W = 1, 2, 4, 8
DX = { E => 1, W => -1, N => 0, S => 0 }
DY = { E => 0, W => 0, N => -1, S => 1 }
OPPOSITE = { E => W, W => E, N => S, S => N }
# --------------------------------------------------------------------
# 3. The recursive-backtracking algorithm itself
# --------------------------------------------------------------------
def carve_passages_from(cx, cy, grid)
directions = [N, S, E, W].sort_by{rand}
directions.each do |direction|
nx, ny = cx + DX[direction], cy + DY[direction]
if ny.between?(0, grid.length-1) && nx.between?(0, grid[ny].length-1) && grid[ny][nx] == 0
grid[cy][cx] |= direction
grid[ny][nx] |= OPPOSITE[direction]
carve_passages_from(nx, ny, grid)
end
end
end
carve_passages_from(0, 0, grid)
... to JavaScript
// --------------------------------------------------------------------
// 2. Set up constants & helper functions
// --------------------------------------------------------------------
var N = 1, S = 2, E = 4, W = 8,
DIRECTIONS = { N: 1, S: 2, E: 4, W: 8 },
DX = { E: 1, W: -1, N: 0, S: 0 },
DY = { E: 0, W: 0, N: -1, S: 1 },
OPPOSITE = { E: W, W: E, N: S, S: N }
function shuffle(array)
{ // from http://stackoverflow.com/questions/5150665/generate-random-list-of-unique-rows-columns-javascript
for(var j, x, i = array.length; i; j = parseInt(Math.random() * i), x = array[--i], array[i] = array[j], array[j] = x);
return array;
};
// --------------------------------------------------------------------
// 3. The recursive-backtracking algorithm itself
// --------------------------------------------------------------------
function carve_passages_from(cx, cy, grid) {
dir_keys = shuffle("NSEW".split(''));
for (var d=0; d= 0 && ny <= grid.length-1) && (nx >= 0 && nx <= grid[ny].length-1) && (grid[ny][nx].d == 0)) {
grid[cy][cx].d |= DIRECTIONS[dir];
grid[ny][nx].d |= OPPOSITE[dir];
carve_passages_from(nx, ny, grid)
}
}
}