Building Farmer Joe and Creating a New Theme For My Shopping List
New Theme For The Shopping List
Let's start off on a positive note. I love the new theme here at Wisedocks. So much so, that I scoped it over to a new theme on my shopping list app. The app isn't available to the public, it was just built for my girlfriend and I to use for household items that we can share and use while out shopping. This new theme is the 7th theme I have built for the app. The variety keeps the app fresh if we want a new look.
This theme may look familiar since you are likely reading this on Wisedocks.com. I directly ported over the color theme and fonts to use on this new theme. Cassy and I tend to split the bill for groceries and household items so when we go shopping we usually grab two carts and open this app and start swiping away at it. A left swipe deletes the items from the list and it auto updates so we can both have it open and see what is left to grab.
I have been thinking about introducing points into the app so we can keep score. As prices sky rocket at least we can have a little fun shopping that way. I won't go on a rant, but I spent $17 for two pounds of ground beef yesterday. That's insane. But moving on...
Farmer Joe May Get The Axe
This game was started over one year ago and the idea was to build a game entirely on canvas in JavaScript. When I say entirely in JavaScript, I mean it, lol. For instance some of the items in game are built like this:
// ---- OBJECTS ----
function drawTree(x, y, hp) {
var cy = y + TS - 12 - (3 - hp) * 5;
ctx.fillStyle = PAL.trunk; ctx.fillRect(x + TS / 2 - 4, cy - 6, 8, 16);
if (hp >= 1) { ctx.fillStyle = PAL.treeB; ctx.beginPath(); ctx.arc(x + TS / 2, cy - 10, 17, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = PAL.treeA; ctx.beginPath(); ctx.arc(x + TS / 2, cy - 10, 14, 0, Math.PI * 2); ctx.fill(); }
if (hp >= 2) { ctx.fillStyle = PAL.treeB; ctx.beginPath(); ctx.arc(x + TS / 2 - 8, cy - 20, 13, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = PAL.treeC; ctx.beginPath(); ctx.arc(x + TS / 2 - 8, cy - 20, 10, 0, Math.PI * 2); ctx.fill(); }
if (hp >= 3) { ctx.fillStyle = PAL.treeB; ctx.beginPath(); ctx.arc(x + TS / 2 + 7, cy - 24, 12, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = PAL.treeC; ctx.beginPath(); ctx.arc(x + TS / 2 + 7, cy - 24, 9, 0, Math.PI * 2); ctx.fill(); }
if (hp < 3) { ctx.fillStyle = PAL.yellow; for (var i = 0; i < hp; i++) ctx.fillRect(x + 4 + i * 7, y + 3, 5, 5); }
}
function drawBush(x, y, hp) {
var cx = x + TS / 2, cy = y + TS - 12;
ctx.fillStyle = PAL.bushB; ctx.beginPath(); ctx.arc(cx, cy, hp === 2 ? 18 : 12, 0, Math.PI * 2); ctx.fill();
ctx.fillStyle = PAL.bushA; ctx.beginPath(); ctx.arc(cx - 7, cy - 6, hp === 2 ? 13 : 8, 0, Math.PI * 2); ctx.fill();
if (hp === 2) { ctx.beginPath(); ctx.arc(cx + 7, cy - 4, 10, 0, Math.PI * 2); ctx.fill(); }
ctx.fillStyle = '#CC2020'; ctx.fillRect(cx - 4, cy - 6, 4, 4);
if (hp === 2) ctx.fillRect(cx + 6, cy - 8, 4, 4);
}
function drawWood(x, y) {
var cx = x + TS / 2, cy = y + TS - 10;
ctx.fillStyle = PAL.wood;
ctx.fillRect(cx - 14, cy - 5, 28, 8); ctx.fillRect(cx - 12, cy - 13, 24, 8); ctx.fillRect(cx - 10, cy - 20, 20, 8);
ctx.fillStyle = PAL.woodDk;
ctx.fillRect(cx - 14, cy - 2, 28, 2); ctx.fillRect(cx - 12, cy - 10, 24, 2);
ctx.fillStyle = '#C07845';
ctx.beginPath(); ctx.arc(cx + 14, cy - 1, 5, 0, Math.PI * 2); ctx.fill();
ctx.beginPath(); ctx.arc(cx + 12, cy - 9, 4, 0, Math.PI * 2); ctx.fill();
ctx.fillStyle = 'rgba(255,230,100,0.55)'; ctx.beginPath(); ctx.arc(cx, cy - 12, 5, 0, Math.PI * 2); ctx.fill();
}
function drawCrop(tile, x, y) {
var def = CROPS[tile.crop]; if (!def) return;
var now = Date.now(), cx = x + TS / 2, cy = y + TS / 2;
var pct = tile.type === TREADY ? 1 : Math.min(1, (now - tile.pt) / def.gm);
var bounce = tile.type === TREADY ? Math.sin(now / 250) * 3 : 0;
if (pct < 0.33) {
ctx.fillStyle = def.stem; ctx.fillRect(cx - 1, cy + 4, 3, 8); ctx.fillRect(cx - 5, cy + 2, 10, 3);
} else if (pct < 0.66) {
ctx.fillStyle = def.stem; ctx.fillRect(cx - 2, cy - 3 + bounce, 4, 14); ctx.fillRect(cx - 8, cy - 5 + bounce, 16, 5);
ctx.fillStyle = def.col; drawCropShape(tile.crop, cx, cy + 5 + bounce, 0.55);
} else {
ctx.fillStyle = def.stem; ctx.fillRect(cx - 2, cy - 9 + bounce, 4, 18); ctx.fillRect(cx - 10, cy - 9 + bounce, 20, 6);
ctx.fillStyle = def.col; drawCropShape(tile.crop, cx, cy + bounce, 1);
if (tile.type === TREADY) {
ctx.fillStyle = 'rgba(255,255,80,' + (0.3 + Math.sin(now / 300) * 0.35) + ')';
ctx.beginPath(); ctx.arc(x + 7, y + 9, 5, 0, Math.PI * 2); ctx.arc(x + TS - 9, y + 9, 4, 0, Math.PI * 2); ctx.fill();
}
}
}
function drawCropShape(id, cx, cy, s) {
if (id === 'carrot') { ctx.beginPath(); ctx.moveTo(cx, cy + 11 * s); ctx.lineTo(cx - 7 * s, cy - 7 * s); ctx.lineTo(cx + 7 * s, cy - 7 * s); ctx.fill(); }
else if (id === 'wheat') { for (var i = -2; i <= 2; i++) ctx.fillRect(cx + i * 3 * s - 3 * s, cy - 10 * s + Math.abs(i) * 2 * s, 5 * s, 9 * s); }
else { ctx.beginPath(); ctx.arc(cx, cy + 2 * s, 10 * s, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = 'rgba(255,255,255,0.2)'; ctx.beginPath(); ctx.arc(cx - 3 * s, cy, 3 * s, 0, Math.PI * 2); ctx.fill(); }
}
// ---- BUILDINGS ----
function drawWindow(wx2, wy2, w, h) {
w = w || 32; h = h || 28;
ctx.fillStyle = '#ffe0a0'; ctx.fillRect(wx2, wy2, w, h);
ctx.fillStyle = '#87CEEB'; ctx.fillRect(wx2 + 3, wy2 + 3, w - 6, h - 6);
ctx.strokeStyle = PAL.trunk; ctx.lineWidth = 2; ctx.strokeRect(wx2, wy2, w, h);
ctx.beginPath(); ctx.moveTo(wx2 + w / 2, wy2); ctx.lineTo(wx2 + w / 2, wy2 + h); ctx.moveTo(wx2, wy2 + h / 2); ctx.lineTo(wx2 + w, wy2 + h / 2); ctx.stroke();
ctx.fillStyle = 'rgba(255,255,255,0.35)'; ctx.fillRect(wx2 + 4, wy2 + 4, 8, 8);
}
function drawHouse() {
var bx = wx(5), by = wy(4), bw = 6 * TS, bh = 5 * TS;
if (bx + bw < 0 || bx > VW) return;
ctx.fillStyle = 'rgba(0,0,0,0.12)'; ctx.fillRect(bx + 8, by + 8, bw, bh);
ctx.fillStyle = PAL.wallA; ctx.fillRect(bx, by + TS, bw, bh - TS);
// Siding lines
ctx.strokeStyle = PAL.wallB; ctx.lineWidth = 1.5;
for (var i = 1; i < 4; i++) { ctx.beginPath(); ctx.moveTo(bx, by + TS + i * (bh - TS) / 4); ctx.lineTo(bx + bw, by + TS + i * (bh - TS) / 4); ctx.stroke(); }
// Roof
ctx.fillStyle = PAL.roof; ctx.beginPath(); ctx.moveTo(bx - 8, by + TS); ctx.lineTo(bx + bw / 2, by - 22); ctx.lineTo(bx + bw + 8, by + TS); ctx.closePath(); ctx.fill();
ctx.strokeStyle = PAL.roofDk; ctx.lineWidth = 2.5;
for (var i = 0; i < 3; i++) { ctx.beginPath(); ctx.moveTo(bx + i * 22 + 4, by + TS - 20 + i * 16); ctx.lineTo(bx + bw / 2, by - 20); ctx.stroke(); ctx.beginPath(); ctx.moveTo(bx + bw - i * 22 - 4, by + TS - 20 + i * 16); ctx.lineTo(bx + bw / 2, by - 20); ctx.stroke(); }
// Chimney
ctx.fillStyle = PAL.wallB; ctx.fillRect(bx + bw - 68, by - 28, 22, 48);
ctx.fillStyle = PAL.roof; ctx.fillRect(bx + bw - 72, by - 32, 30, 8);
// Smoke
var t = Date.now() / 800;
for (var i = 0; i < 3; i++) { ctx.fillStyle = 'rgba(200,200,210,' + (0.14 + Math.sin(t + i) * 0.07) + ')'; ctx.beginPath(); ctx.arc(bx + bw - 57 + Math.sin(t * 0.7 + i) * 4, by - 44 - i * 13, 8 + i * 3, 0, Math.PI * 2); ctx.fill(); }
// Windows
drawWindow(bx + 16, by + TS + 18); drawWindow(bx + bw - 56, by + TS + 18);
// Door
var dx = bx + bw / 2 - 14, dy = by + bh - 54;
ctx.fillStyle = '#4A1C06'; ctx.fillRect(dx, dy, 28, 54);
ctx.beginPath(); ctx.arc(dx + 14, dy, 14, Math.PI, 0); ctx.fill();
ctx.strokeStyle = '#2A0C00'; ctx.lineWidth = 2; ctx.strokeRect(dx, dy, 28, 54);
ctx.fillStyle = '#2A0C00'; ctx.fillRect(dx + 4, dy + 8, 8, 18); ctx.fillRect(dx + 16, dy + 8, 8, 18);
ctx.fillStyle = PAL.yellow; ctx.beginPath(); ctx.arc(dx + 22, dy + 28, 3, 0, Math.PI * 2); ctx.fill();
// Sign
ctx.fillStyle = PAL.detail; ctx.fillRect(bx + bw / 2 - 44, by + TS - 14, 88, 22);
ctx.strokeStyle = PAL.trunk; ctx.lineWidth = 1.5; ctx.strokeRect(bx + bw / 2 - 44, by + TS - 14, 88, 22);
ctx.fillStyle = '#3A1808'; ctx.font = 'bold 11px monospace'; ctx.textAlign = 'center'; ctx.fillText("JOE'S PLACE", bx + bw / 2, by + TS + 3);
}
function drawBarn() {
var bx = wx(13), by = wy(4), bw = 6 * TS, bh = 5 * TS;
if (bx + bw < 0 || bx > VW) return;
ctx.fillStyle = 'rgba(0,0,0,0.10)'; ctx.fillRect(bx + 8, by + 8, bw, bh);
ctx.fillStyle = '#8B1A1A'; ctx.fillRect(bx, by + TS, bw, bh - TS);
ctx.strokeStyle = '#5a1010'; ctx.lineWidth = 1.5;
for (var i = 1; i < 4; i++) { ctx.beginPath(); ctx.moveTo(bx, by + TS + i * (bh - TS) / 4); ctx.lineTo(bx + bw, by + TS + i * (bh - TS) / 4); ctx.stroke(); }
ctx.fillStyle = '#7a1010'; ctx.beginPath(); ctx.moveTo(bx - 7, by + TS); ctx.lineTo(bx + bw / 2, by - 26); ctx.lineTo(bx + bw + 7, by + TS); ctx.closePath(); ctx.fill();
ctx.strokeStyle = '#5a0808'; ctx.lineWidth = 2.5;
for (var i = 0; i < 3; i++) { ctx.beginPath(); ctx.moveTo(bx + i * 22, by + TS - 18 + i * 16); ctx.lineTo(bx + bw / 2, by - 24); ctx.stroke(); ctx.beginPath(); ctx.moveTo(bx + bw - i * 22, by + TS - 18 + i * 16); ctx.lineTo(bx + bw / 2, by - 24); ctx.stroke(); }
ctx.fillStyle = '#ffe0a0'; ctx.beginPath(); ctx.arc(bx + bw / 2, by + TS / 2 - 16, 16, 0, Math.PI, true); ctx.fill();
ctx.strokeStyle = '#5a2808'; ctx.lineWidth = 2; ctx.stroke();
var ddx = bx + bw / 2 - 30, ddy = by + bh - 68;
ctx.fillStyle = '#5a1a08'; ctx.fillRect(ddx, ddy, 28, 68); ctx.fillRect(ddx + 32, ddy, 28, 68);
ctx.strokeStyle = '#8a3010'; ctx.lineWidth = 2; ctx.strokeRect(ddx, ddy, 28, 68); ctx.strokeRect(ddx + 32, ddy, 28, 68);
ctx.beginPath(); ctx.moveTo(ddx, ddy); ctx.lineTo(ddx + 28, ddy + 68); ctx.moveTo(ddx + 28, ddy); ctx.lineTo(ddx, ddy + 68); ctx.stroke();
ctx.beginPath(); ctx.moveTo(ddx + 32, ddy); ctx.lineTo(ddx + 60, ddy + 68); ctx.moveTo(ddx + 60, ddy); ctx.lineTo(ddx + 32, ddy + 68); ctx.stroke();
ctx.fillStyle = PAL.yellow;
ctx.beginPath(); ctx.arc(ddx + 24, ddy + 36, 3, 0, Math.PI * 2); ctx.fill();
ctx.beginPath(); ctx.arc(ddx + 36, ddy + 36, 3, 0, Math.PI * 2); ctx.fill();
ctx.fillStyle = '#f0e0a0'; ctx.fillRect(bx + bw / 2 - 28, by + TS + 4, 56, 18);
ctx.strokeStyle = '#8a3010'; ctx.lineWidth = 1.5; ctx.strokeRect(bx + bw / 2 - 28, by + TS + 4, 56, 18);
ctx.fillStyle = '#5a1008'; ctx.font = 'bold 11px monospace'; ctx.textAlign = 'center'; ctx.fillText('BARN', bx + bw / 2, by + TS + 18);
}
function drawMarket() {
var bx = wx(23), by = wy(4), bw = 7 * TS, bh = 6 * TS;
if (bx + bw < 0 || bx > VW) return;
ctx.fillStyle = 'rgba(0,0,0,0.12)'; ctx.fillRect(bx + 8, by + 8, bw, bh);
ctx.fillStyle = '#c4865c'; ctx.fillRect(bx, by, bw, bh);
ctx.fillStyle = '#a87048'; ctx.fillRect(bx, by + bh / 2, bw, bh / 2);
ctx.fillStyle = '#881010'; ctx.beginPath(); ctx.moveTo(bx - 14, by + 8); ctx.lineTo(bx + bw / 2, by - 44); ctx.lineTo(bx + bw + 14, by + 8); ctx.closePath(); ctx.fill();
ctx.fillStyle = '#600808'; ctx.fillRect(bx - 16, by + 2, bw + 32, 10);
drawWindow(bx + 18, by + 22); drawWindow(bx + bw - 52, by + 22);
var dx = bx + bw / 2 - 16, dy = by + bh - 62;
ctx.fillStyle = '#5a2808'; ctx.fillRect(dx, dy, 32, 62);
ctx.beginPath(); ctx.arc(dx + 16, dy, 16, Math.PI, 0); ctx.fill();
ctx.strokeStyle = '#7a4a20'; ctx.lineWidth = 2; ctx.strokeRect(dx, dy, 32, 62);
ctx.fillStyle = PAL.yellow; ctx.beginPath(); ctx.arc(dx + 24, dy + 33, 3, 0, Math.PI * 2); ctx.fill();
ctx.fillStyle = PAL.yellow; ctx.fillRect(bx + bw / 2 - 50, by - 24, 100, 28);
ctx.strokeStyle = '#8a5010'; ctx.lineWidth = 2; ctx.strokeRect(bx + bw / 2 - 50, by - 24, 100, 28);
ctx.fillStyle = '#5a2808'; ctx.font = 'bold 14px monospace'; ctx.textAlign = 'center'; ctx.fillText('MARKET', bx + bw / 2, by - 4);
}
function drawWell() {
var bx = wx(20), by = wy(8); if (bx + TS * 2 < 0 || bx > VW) return;
var cx = bx + TS, cy = by + TS * 0.6;
ctx.fillStyle = '#888070'; ctx.beginPath(); ctx.ellipse(cx, cy + 14, 22, 8, 0, 0, Math.PI * 2); ctx.fill();
ctx.fillStyle = '#aaa090'; ctx.fillRect(cx - 22, cy - 16, 44, 30);
ctx.fillStyle = '#888070'; ctx.beginPath(); ctx.ellipse(cx, cy - 16, 22, 8, 0, 0, Math.PI * 2); ctx.fill();
ctx.fillStyle = 'rgba(30,110,200,0.55)'; ctx.beginPath(); ctx.ellipse(cx, cy - 15, 21, 7, 0, 0, Math.PI * 2); ctx.fill();
ctx.fillStyle = PAL.trunk; ctx.fillRect(cx - 20, cy - 34, 8, 34); ctx.fillRect(cx + 12, cy - 34, 8, 34);
ctx.fillStyle = PAL.roof; ctx.beginPath(); ctx.moveTo(cx - 26, cy - 34); ctx.lineTo(cx, cy - 52); ctx.lineTo(cx + 26, cy - 34); ctx.closePath(); ctx.fill();
ctx.fillStyle = PAL.roofDk; ctx.fillRect(cx - 22, cy - 36, 44, 6);
ctx.strokeStyle = '#8a8080'; ctx.lineWidth = 2; ctx.beginPath(); ctx.moveTo(cx, cy - 30); ctx.lineTo(cx, cy - 12); ctx.stroke();
ctx.fillStyle = '#8a6040'; ctx.fillRect(cx - 5, cy - 8, 10, 10);
}
// ---- FENCE ----
function isOwned(c, r) { var t = ta(c, r); return t && (t.type === TOWN || t.type === TD || t.type === TNPL || t.type === TREADY); }
function drawFence() {
for (var r = 0; r < ROWS; r++) for (var c = 0; c < COLS; c++) {
if (!isOwned(c, r)) continue;
var x = wx(c), y = wy(r);
if (x + TS < -20 || x > VW + 20 || y + TS < -20 || y > VH + 20) continue;
if (!isOwned(c, r - 1)) drawFenceH(x, y);
if (!isOwned(c, r + 1)) drawFenceH(x, y + TS);
if (!isOwned(c - 1, r)) drawFenceV(x, y);
if (!isOwned(c + 1, r)) drawFenceV(x + TS, y);
}
}
function drawFenceH(x, y) {
// Bottom rail
ctx.fillStyle = PAL.fenceSh; ctx.fillRect(x, y + 5, TS, 4);
ctx.fillStyle = PAL.fence; ctx.fillRect(x, y + 4, TS, 4);
// Top rail
ctx.fillStyle = PAL.fenceSh; ctx.fillRect(x, y + 11, TS, 4);
ctx.fillStyle = PAL.fence; ctx.fillRect(x, y + 10, TS, 4);
// Pickets
for (var i = 0; i < 4; i++) {
var px2 = x + 2 + i * 12;
ctx.fillStyle = PAL.fenceSh; ctx.fillRect(px2 + 1, y - 4, 6, 18);
ctx.fillStyle = PAL.fence; ctx.fillRect(px2, y - 5, 6, 18);
// Pointed top
ctx.beginPath(); ctx.moveTo(px2 + 3, y - 10); ctx.lineTo(px2, y - 5); ctx.lineTo(px2 + 6, y - 5); ctx.closePath(); ctx.fill();
}
}
function drawFenceV(x, y) {
ctx.fillStyle = PAL.fenceSh; ctx.fillRect(x + 5, y, 4, TS);
ctx.fillStyle = PAL.fence; ctx.fillRect(x + 4, y, 4, TS);
ctx.fillStyle = PAL.fenceSh; ctx.fillRect(x + 11, y, 4, TS);
ctx.fillStyle = PAL.fence; ctx.fillRect(x + 10, y, 4, TS);
for (var i = 0; i < 4; i++) {
var py2 = y + 2 + i * 12;
ctx.fillStyle = PAL.fenceSh; ctx.fillRect(x - 3, py2 + 1, 18, 6);
ctx.fillStyle = PAL.fence; ctx.fillRect(x - 4, py2, 18, 6);
ctx.beginPath(); ctx.moveTo(x - 9, py2 + 3); ctx.lineTo(x - 4, py2); ctx.lineTo(x - 4, py2 + 6); ctx.closePath(); ctx.fill();
}
}
// ---- JOE SPRITE ----
function drawJoe() {
var sx = Math.round(JOE.x - cam.x), sy = Math.round(JOE.y - cam.y);
var leg = 0, arm = 0, bob = 0;
if (JOE.state === 'walk') { leg = Math.sin(JOE.wf * 0.2) * 5; arm = Math.sin(JOE.wf * 0.2) * 4; bob = -Math.abs(Math.sin(JOE.wf * 0.2)) * 2; }
else if (JOE.state === 'work') { var wt = JOE.wf * 0.28; bob = Math.sin(wt) * 4; arm = Math.sin(wt) * 11; leg = Math.sin(wt * 0.5) * 2; }
else bob = Math.sin(JOE.wf * 0.04) * 0.8;
ctx.save(); ctx.translate(sx, sy);
if (JOE.fl) ctx.scale(-1, 1);
// Shadow
ctx.fillStyle = 'rgba(0,0,0,0.22)'; ctx.beginPath(); ctx.ellipse(0, 8, 13, 5, 0, 0, Math.PI * 2); ctx.fill();
// Legs
ctx.save(); ctx.translate(-5, 2); ctx.rotate(leg * 0.055);
ctx.fillStyle = '#1A3A88'; ctx.fillRect(-4, 0, 7, 15);
ctx.fillStyle = '#2A4A99'; ctx.fillRect(-4, 0, 3, 8);
ctx.fillStyle = '#0A1020'; ctx.fillRect(-5, 13, 9, 6); ctx.restore();
ctx.save(); ctx.translate(5, 2); ctx.rotate(-leg * 0.055);
ctx.fillStyle = '#1A3A88'; ctx.fillRect(-3, 0, 7, 15);
ctx.fillStyle = '#0A1020'; ctx.fillRect(-4, 13, 9, 6); ctx.restore();
// Body
var by2 = bob - 17;
ctx.fillStyle = '#1A3A88'; ctx.fillRect(-10, by2, 20, 19);
ctx.fillStyle = '#3A5AAA'; ctx.fillRect(-9, by2, 9, 7);
ctx.fillStyle = '#2A4A99'; ctx.fillRect(-9, by2, 7, 9);
ctx.fillStyle = PAL.yellow; ctx.fillRect(-8, by2 - 1, 3, 3); ctx.fillRect(5, by2 - 1, 3, 3);
ctx.fillStyle = '#CC4422'; ctx.fillRect(-14, by2 + 5, 5, 13); ctx.fillRect(10, by2 + 5, 5, 13);
// Arms
ctx.fillStyle = '#E8A870';
if (JOE.state === 'work') {
ctx.save(); ctx.translate(-13, by2 + 5); ctx.rotate(arm * 0.08);
ctx.fillStyle = '#CC4422'; ctx.fillRect(-3, 0, 6, 13); ctx.fillStyle = '#E8A870'; ctx.beginPath(); ctx.arc(0, 15, 4, 0, Math.PI * 2); ctx.fill(); ctx.restore();
ctx.save(); ctx.translate(13, by2 + 5); ctx.rotate(-arm * 0.08);
ctx.fillStyle = '#CC4422'; ctx.fillRect(-3, 0, 6, 13); ctx.fillStyle = '#E8A870'; ctx.beginPath(); ctx.arc(0, 15, 4, 0, Math.PI * 2); ctx.fill(); ctx.restore();
} else {
ctx.save(); ctx.translate(-13, by2 + 5); ctx.rotate(arm * 0.05);
ctx.fillStyle = '#CC4422'; ctx.fillRect(-3, 0, 6, 12); ctx.fillStyle = '#E8A870'; ctx.beginPath(); ctx.arc(0, 14, 3.5, 0, Math.PI * 2); ctx.fill(); ctx.restore();
ctx.save(); ctx.translate(13, by2 + 5); ctx.rotate(-arm * 0.05);
ctx.fillStyle = '#CC4422'; ctx.fillRect(-3, 0, 6, 12); ctx.fillStyle = '#E8A870'; ctx.beginPath(); ctx.arc(0, 14, 3.5, 0, Math.PI * 2); ctx.fill(); ctx.restore();
}
// Head
var hy = by2 - 25;
ctx.fillStyle = '#E8A870'; ctx.fillRect(-4, by2 - 5, 8, 7);
ctx.fillStyle = '#F0B880'; ctx.fillRect(-10, hy, 20, 22);
ctx.fillStyle = '#E8A870'; ctx.fillRect(-10, hy + 14, 20, 8);
ctx.fillStyle = '#201008'; ctx.fillRect(-5, hy + 5, 4, 4); ctx.fillRect(2, hy + 5, 4, 4);
ctx.fillStyle = 'rgba(255,255,255,0.7)'; ctx.fillRect(-4, hy + 5, 2, 2); ctx.fillRect(3, hy + 5, 2, 2);
ctx.fillStyle = 'rgba(240,100,70,0.3)'; ctx.beginPath(); ctx.arc(-7, hy + 13, 5, 0, Math.PI * 2); ctx.arc(7, hy + 13, 5, 0, Math.PI * 2); ctx.fill();
ctx.strokeStyle = '#A04818'; ctx.lineWidth = 1.5; ctx.beginPath(); ctx.arc(0, hy + 14, 5, 0.3, Math.PI - 0.3); ctx.stroke();
// Hat
var hh = hy - 4;
ctx.fillStyle = '#D4A828'; ctx.beginPath(); ctx.ellipse(0, hh, 18, 5, 0, 0, Math.PI * 2); ctx.fill();
ctx.fillStyle = '#C09820'; ctx.fillRect(-10, hh - 17, 20, 17);
ctx.fillStyle = '#7A2800'; ctx.fillRect(-12, hh - 5, 24, 5);
ctx.fillStyle = 'rgba(255,255,200,0.18)'; ctx.fillRect(-8, hh - 16, 5, 13);
ctx.fillStyle = '#B89010'; ctx.beginPath(); ctx.ellipse(3, hh + 1, 18, 5, 0.1, 0, Math.PI); ctx.fill();
ctx.restore();
}
Everything is built as shapes on canvas with JavaScript. The image at the top of the page is what it currently looks like. Ignore the terrible HUD, they are mostly placeholders, lol.
It started out as a fun game, but it is taking so long that I'm not sure I'll ever get it to a "fun" playable state. Technically, you can play it now, but, it is so basic that there isn't much point. I spent a solid 2 days on it this week and I just really want to give up.
I had so much fun a few weeks ago redesigning the admin areas of a few of the sites with AI, that I'm tempted to do the same with this game just to get it playable. But, anyone can do that and what would be the point then? Maybe, I just need a break for a while. The game was started over one year ago, but I only work on it in spurts. I think I will just leave it alone for awhile longer until the mood strikes me again.
The Universe
Another project I have been working on for well over a year off and on is "The Universe." It started off as 100 individual PHP pages that would load in dynamically as you scrolled around. I took my new knowledge of JavaScript and canvas elements and have started reworking the feature from scratch. It is now faster loading and has a lot of potential. I jumped the gun and put a link to it in the top of the site.
The plan is to add tons of stars that you can leave messages on and there will be lots of Easter Eggs to find and other interactive features and even random links dropped around to some of my other website features. I've been tossing around the idea of maybe putting the icons from some of my games in the universe that will pop up a small window and you can play them from there as well. It should be fun. Once it is fully fleshed out, I will likely add the feature to FartDump.com and it could potentially even replace the whole website one day.
Nearly all websites work as folders, you have links that lead to other pages. The Universe will act as the entire website on one page. That's the idea at the moment.
Droppin' Fat
A few months ago, I set myself a goal to walk at least 10,000 steps everyday. That is still happening and I've managed to finally get below 200 pounds. My healthy weight is between 185 and 195 with my build. I do a lot of manual labor so I carry a little bit of muscle bulk, but I hit 215 pounds about 3 months ago. That was my breaking point.
All of my life when I would hit 200 pounds that was my sign to go on a diet. This time it almost got away from me. I got so out of shape that I could barely run 100 yards before my body would start screaming. It wasn't my lungs that was the problem; my knees, muscles and joints would hurt so bad that I would have to stop. Shin splints are no joke!
Today, I can run about a mile before I actually start getting tired. So at least my legs are regaining their strength. I twisted my knee over the winter at work and was sporting a knee brace for quite some time and I haven't needed to use it for the last few months at all so that's another good sign.
I love working on my websites, but the sedentary lifestyle that comes along with them was doing more harm than I realized so I have been pulling back a bit and keeping myself more active. I feel much better for it. Farmer Joe will never get built if I fall over from a heart attack, so I have to keep moving.
You should to, get your butt up and go run somewhere. When you get back check out Stephen Colbert's new YouTube Channel.
