Warning: Declaration of Bootstrap_Walker_Nav_Menu::start_lvl(&$output, $depth) should be compatible with Walker_Nav_Menu::start_lvl(&$output, $depth = 0, $args = Array) in /home/farbs/www/www/wp-content/themes/strappress/strappress/includes/strap-extras.php on line 58
Blog | Farbs.org

Captain Jameson 0.6 prerelease

Woo! A new build! Here’s what’s going on:

The long promised 0.6 build is still, uh, building. However, the game is stable enough for me to share and I figured you might like to see it. I don’t want this to be anyone’s first Captain Jameson experience since it’s a bit wonky incomplete, so I’ve listed it as a prerelease build at the bottom of the page. I figure this way I can share what I’m up to without breaking anyone’s brain. So what’s new? Let’s see…

Wormholes!

The main feature of 0.6, this is where most of my time has gone as I’ve bludgeoned this into the game and bludgeoned it further into a thousand different shapes. Wormholes allow you to travel from one sector to another, thereby expanding the Jameson world into a massive array of locations. My next focus, once all of this is squared away, will be to fill all of those locations with interesting stuff. Right now there is some interesting stuff, but I’d like to add a lot more. Wormholes have, as mentioned, been redesigned many times over the past year as I tried to find a system that really shined. The main problem I faced was that in finishing a sector the player would also build a super awesome ship, so if they then wandered off to a new sector they’d already be at the top of the power curve. I spent a long time pondering this, considering delevelling systems, infinite power curves (and the fun mathematics you have to deal with to make that work), and resigned myself to just destroying the player’s ship at the end of each sector. I knew from feedback right back on the original Captain Forever that people hated this, so I wasn’t happy about it at all. Meanwhile, some other games came out. Spelunky, The Binding of Isaac, and most of all FTL pushed forward the roguelikelike genre and made me rethink the idea of a 40 hour epic. I started to think that width of experience was much more important than length. So, instead of a single 40 hour epic, why not build a 4 hour epic that you can play 10 times? Or a 1 hour epic you might want to play 40 times? With this in mind, a single playthrough of a single sector of Captain Jameson was already a pretty good length. Unfortunately once you finished that sector you were pretty much done. I wanted people to explore a huge space, but there’s only so much room in a two dimensional disc. Here’s where wormholes crept back in.

I created small sectors that only cover ~20% of the game’s power curve, and allowed the player to keep all their progress as they travel through. The sectors branch to between one and four other sectors, which in turn branch, and so on. By the time you reach the end you’ve traveled roughly as far as in the old single sector model, however the total area that the game occupies, and therefore the total space you could explore, is roughly 500x as large. That’s pretty big!

Fullscreen

Finally Adobe realised that people would want to see a game in fullscreen and use their keyboard at the same time. Since this feature is now available in the flash web player I figured I should start using it. Unfortunately the interface for this is still a little wonky, so you have to click the game to give it focus before hitting enter, then click Allow to keep playing. The first time you enter fullscreen it’ll be at your desktop resolution, which might run a bit slowly for some people. Hit enter again (after clicking Allow) to try different resolutions if this is the case for you. Once I start distributing the game as a standalone application (rather than embedded in a web page) I should be able to clean this up a lot, since there won’t be so many issues with security restrictions. This’ll do for the moment though, and I’ll probably add a less wonky interface to the system menu later.

Autosave

You don’t have to return your ship to a garage anymore in order to keep it. Instead, the game autosaves periodically and after important events. Now you can just close your browser whenever you like, and open it up again to continue where you left off. Nifty.

Manual Docking

The telnet system was cool, but I watched a lot of playtesters nudge their ships up against stations in an attempt to dock with them. Rather than fight player expectation and try to force people into using a system they didn’t want or understand, I figured it best to just embrace the nudging. Now every station you can interact with has a little docking port, which you can ram into with any part of your ship. It’s not entirely elegant but it works.

Permadeath

Oooo! Banking and warehousing and all-round space squirreling seemed like a good idea, but in practice it just wasn’t fun. By taking these things out the player is now free to flit about in the present, which is a lot more enjoyable. Now when you die, all your progress is lost and you start back at the origin sector. At some point I’ll add stats and other metagame data that you can review and revisit, so that some memory of your doomed voyage remains. I’d also like to unlock things for subsequent playthroughs, so will have a think on that when it comes time to add more content.

VMEDS Mouse Input

Again, it’s good to meet player expectation. Now I need to add a button to bring back VMEDS while in flight.

Onboard NAV System

Since you can’t telnet to NAV stations anymore you’re going to get awfully lost! I did, anyway. That’s why I added an onboard NAV program which stitches together maps downloaded from NAV stations. You can bring this up any time in flight. What’s more, it can be used to export all your map data at once. It’s pretty cool. And a bit wonky. Again, I need to do some more work here.

New Voice Synth

If you’ve played Captain Foraxian EX then you’ve already heard this in action. If not, you probably should! Captain Foraxian EX is a bonus downloadable shmup available to all Captain Forever supporters. Unfortunately it’s Windows only. Sorry about that. Anyhow, it uses the new synth tech I wrote for Jameson. This tech is based on the old Speak & Spell toy, and effectively tries to recreate the acoustic mechanisms of the human voice. It’s not great at it, but it sounds lovely. It also allows me to muck about with its parameters in realtime, so now every pilot in Captain Jameson has their own voice, and each time they speak it comes out a little differently. At the moment I’m still using the old robospeech data, so it’s not as expressive or human as in Foraxian EX, but later in production I’ll record a heap of speech and add it to the game. Oh, another benefit of this synth is that the speech files are tiny. Like, around 5% the size of an equivalent MP3. So I can fit a lot in there.

Anyhow, why are you reading this? You have a game to play!

<3 Farbs


SketchFXR

                        

Whoops! You need flash 10.1 or better for this.

sliders = []; sliderSets = []; sliderHeld = null; hue = 0.16; function makeSlider( x, y, scaleX, scaleY, lowValue, highValue, valueScale, markerPeriod, value ) { var slider = {}; slider.value = value; slider.x = x; slider.y = y; slider.scaleX = scaleX; slider.scaleY = scaleY; slider.lowValue = lowValue; slider.highValue = highValue; slider.valueScale = valueScale; slider.markerPeriod = markerPeriod; slider.draw = function( slider ) { crosshairTransform(); translate( slider.x, slider.y ); scale( slider.scaleX, slider.scaleY ); for( mark in slider.lowValue ...( slider.highValue + 1 ) ) { drawRect( hue, 0.6, 0.1, 1, 0, ( mark - slider.lowValue * 1.0 ) / ( slider.highValue - slider.lowValue ) * 2 - 1, ( mark % slider.markerPeriod == 0 ) ? 1.5 : 0.75, 0.003 ); } drawRect( hue, 0.6, 0.3, 1, 0, 0, 0.25, 1 ); drawBlob( hue, 0.9, slider == sliderHeld || slider.underMouse( slider ) ? 0.9 : 0.1, 1, 0, slider.value * 2 - 1, 1, 0.05, 4 ); } slider.update = function( slider ) { // move the value // rect test if( sliderHeld == slider ) { // yep! Better update it. slider.value = Math.round( Math.max( Math.min( ( ( mouseY - slider.y ) / slider.scaleY ) * 0.5 + 0.5, 1 ), 0 ) * ( slider.highValue - slider.lowValue ) ) / ( slider.highValue - slider.lowValue ); } } slider.underMouse = function( slider ) { return mouseX < slider.x + slider.scaleX + 5 && mouseX >= slider.x - slider.scaleX - 5 && mouseY < slider.y + slider.scaleY + 5 && mouseY >= slider.y - slider.scaleY - 5; } slider.getOutput = function( slider ) { return ( slider.lowValue + slider.value * ( slider.highValue - slider.lowValue ) ) * slider.valueScale; } return slider; } function setSet( index ) { sliders = sliderSets[index]; hue = 0.16 + index / 8.0; } function update() { // update the sliders for( s in sliders ) { s.update( s ); } } function render() { fillBackground( hue, 0.5, 0.4 ); crosshairTransform(); drawRoundedRect( hue, 0.5, 0.45, 1, sliders[4].x / 2 + sliders[5].x / 2, sliders[4].y, Math.abs( sliders[4].x - sliders[5].x ) / 2 + sliders[4].scaleX + 12, sliders[4].scaleY + 12, 10, 10 ); drawRoundedRect( hue, 0.5, 0.45, 1, sliders[8].x / 2 + sliders[8].x / 2, sliders[8].y, Math.abs( sliders[8].x - sliders[8].x ) / 2 + sliders[8].scaleX + 12, sliders[8].scaleY + 12, 10, 10 ); drawRoundedRect( hue, 0.5, 0.55, 1, sliders[0].x / 2 + sliders[3].x / 2, sliders[0].y, Math.abs( sliders[0].x - sliders[3].x ) / 2 + sliders[0].scaleX + 12, sliders[0].scaleY + 12, 10, 10 ); drawRoundedRect( hue, 0.5, 0.55, 1, sliders[6].x / 2 + sliders[7].x / 2, sliders[6].y, Math.abs( sliders[6].x - sliders[7].x ) / 2 + sliders[6].scaleX + 12, sliders[6].scaleY + 12, 10, 10 ); for( pair in 0...2 ) { var sa = sliders[pair * 2]; var sb = sliders[pair * 2 + 1]; for( blob in 1...4 ) { var a = blob / 4.0; var ai = 1 - a; drawBlob( hue, 0.6, 0.3, 0.5, sa.x * ai + sb.x * a, sa.y * ai + sb.y * a + ( ( sa.value * ai + sb.value * a ) * 2 - 1 ) * ( sa.scaleY * ai + sb.scaleY * a ), blob == 2 ? 5 : 3, blob == 2 ? 5 : 3 ); } } for( s in sliders ) { s.draw( s ); } crosshairTransform(); for( setIndex in 0...sliderSets.length ) { drawRect( 0.16 + setIndex / 8.0, 0.5, 0.4, 1, ( setIndex - 3.5 ) * 60, -140, 30, 20 ); if( sliderSets[setIndex] != sliders ) { drawRect( 0, 0, 0, 0.125, ( setIndex - 3.5 ) * 60, -122, 30, 2 ); drawRect( 0, 0, 0, 0.125, ( setIndex - 3.5 ) * 60, -124, 30, 4 ); drawRect( 0, 0, 0, 0.125, ( setIndex - 3.5 ) * 60, -126, 30, 6 ); } } } function onMouseDown() { sliderHeld = null; for( slider in sliders ) { if( slider.underMouse( slider ) ) { sliderHeld = slider; } } if( mouseY < -120 ) { setSet( Math.min( Math.max( Math.floor( ( mouseX + 240 ) / 60 ), 0 ), 7 ) ); } } function onMouseUp() { var textOut = ""; var delay = 0; for( set in sliderSets ) { playNote( set[0].getOutput( set[0] ) + set[1].getOutput( set[1] ), set[2].getOutput( set[2] ) + set[3].getOutput( set[3] ), set[4].getOutput( set[4] ), set[5].getOutput( set[5] ), set[6].getOutput( set[6] ), set[7].getOutput( set[7] ), 0, delay, set[8].getOutput( set[8] ) ); if( set[4].value != 0 || set[5].value != 0 ) { textOut += "playNote( " + ( set[0].getOutput( set[0] ) + set[1].getOutput( set[1] ) ) + ", " + ( set[2].getOutput( set[2] ) + set[3].getOutput( set[3] ) ) + ", " + set[4].getOutput( set[4] ) + ", " + set[5].getOutput( set[5] ) + ", " + set[6].getOutput( set[6] ) + ", " + set[7].getOutput( set[7] ) + ", " + "0, " + delay + ", " + set[8].getOutput( set[8] ) + " );\n"; } delay += set[8].getOutput( set[8] ); } sliderHeld = null; setClipboard( textOut ); } // create slider objects var ranges = [ [ -5, 5, 12, 5 ], [ -12, 12, 1, 12 ], [ -5, 5, 12, 5 ], [ -12, 12, 1, 12 ], [ 0, 20, 0.2, 5 ], [ 0, 20, 0.2, 5 ], [ 0, 20, 0.1, 5 ], [ 0, 20, 0.1, 5 ], [ 1, 40, 1, 4 ] ]; for( ss in 0...8 ) { var newSliders = []; for( s in 0...( ranges.length ) ) { newSliders.push( makeSlider( ( s - 4 ) * 51, 20, 15, 120, ranges[s][0], ranges[s][1], ranges[s][2], ranges[s][3], ss == 0 ? 0.5 : 0 ) ); } sliderSets.push( newSliders ); } setSet( 0 ); [/gamesketch]

Here is a thing! You can use it to make beepy noises, and you may notice that it fills your clipboard with chunks of code. That code is what I use to then play the beepy noises in GameSketch, so yeah, it's a tool for me that I've published here even though you can't really use it for anything. Um... sorry? Anyhow it's pretty fun, and if you're interested in such things it'll give you a good idea of how the GameSketch synthesizer works.

Tips:

The first four sliders set pitch. The first two give the octave and note (offset from the middle) of the start of the beep, and the second two give the octave and note of the end.

The next two sliders set the initial and final volume. Full volume is actually half way up, with full slider height giving a nice overdrive effect.

The next two are a different kind of distortion, again as the start and end of the beep.

The final slider is the beep length.

The tabs down the bottom select individual beeps that are played back in sequence. Combining these together can create more complex sounds and short melodies.

Enjoy!

<3
Farbs


Floral Memories

                        

Whoops! You need flash 10.1 or better for this.

Hey look, another game sketch!

This is the first pass at a memory style game, which I can win about 1 time in 3 if I really pay attention. I might polish it up, add stems and animation and blahdeblah, but for now I find it fun and figured I’d share. It also took about an hour, which is well in line with how I’d like to make these.

I had planned (and even begun) to make a subtly postapocalyptic breakout/space invaders mechanics mashup thing, but having just written a pong clone I’m a bit bored with ball games and wanted to try something different. Hopefully I’ll get back to that later.

Anyhow, can you open all the flowers? It’s simple and fun, and probably impossible for anyone who is at all colourblind. Sorry about that.

<3
Farbs


Beaver Badminton, Part The Second

                        

Whoops! You need flash 10.1 or better for this.

###Setup### // create common funcs function drawBeaver( x, y, facing, step, depth ) { var stepSin = Math.sin( step * Math.PI ); // beaver tail drawRoundedRect( 0.15, 0.2, 0.2, 1, x - facing * 10, y, 10, 25, 5, 5 ); // beaver body drawRoundedRect( 0.1, 0.2, 0.5, 1, x, y - 15, 10, 15, 5, 5 ); drawRect( 0.1, 0.2, 0.5, 1, x, y - 5, 10, 5 ); drawBlob( 0.1, 0.2, 0.5, 1, x, y, 10, 30 ); // beaver arms drawBlob( 0.15, 0.2, 0.7, 1, x + 5 + 4 * facing, y + stepSin * 3, 3, 7 ); drawBlob( 0.15, 0.2, 0.7, 1, x - 5 + 4 * facing, y - stepSin * 3, 3, 7 ); // beaver feet drawBlob( 0.15, 0.2, 0.2, 1, x + 5 + 2 * facing, y - 28 - Math.min( stepSin, 0 ) * 5, 4, 2 ); drawBlob( 0.15, 0.2, 0.2, 1, x - 5 + 2 * facing, y - 28 + Math.max( stepSin, 0 ) * 5, 4, 2 ); // beaver face drawRoundedRect( 1, 1, 1, 1, x + 4 * facing, y + 15, 4, 5, 2, 2 ); drawBlob( 0.15, 0.2, 0.7, 1, x + 5 * facing, y + 20, 6, 5 ); drawFixedCircle( 0, 0, 0, 1, x + 3 + 4 * facing, y + 25, 2 ); drawFixedCircle( 0, 0, 0, 1, x - 3 + 4 * facing, y + 25, 2 ); // beaver arms // water overlay drawRect( 0.6, 0.4, 0.5, 0.75, x, y - 30, 20, depth ); // debug bounds overlay if( false && Math.random() < 0.5 ) { drawRect( 1, 1, 1, 0.25, x, y, 10, 30 ); } } // start it up //setPage( "BeaverRenderTest" ); //setPage( "Game" ); setPage( "StartButton" ); ###BeaverRenderTest### var time = 0; function update() { time += delta; } function render() { fillBackground( 0.6, 0.4, 0.5 ); drawBeaver( 0, 0, Math.sin( time ), ( time % 1 ) * 2 - 1, Math.sin( time ) * 3 + 10 ); } ###StartButton### showMouse(); var state = ""; var pressing = false; var cooldown = 1; function isOver() { return mouseX * mouseX + mouseY * mouseY < 80*80; } function refresh() { if( state == "done" ) { var s = ( 1 - cooldown ) * 4 + 1; crosshairTransform(); scale( s, s ); } fillBackground( 0, 0, 0 ); drawFixedCircle( 1, 0, ( state == "none" ? 0.5 : state == "over" || state == "done" ? 1 : 0.25 ) * cooldown * cooldown, 1, 0, 0, 80 ); drawRect( 0, 0, 0, 1, -15, 0, 10, 30 ); drawRect( 0, 0, 0, 1, 5, 0, 10, 20 ); drawRect( 0, 0, 0, 1, 25, 0, 10, 10 ); } function setButtonState( newState ) { if( state != newState && state != "done" ) { state = newState; refresh(); } } function update() { if( state != "done" ) { if( isOver() ) { setButtonState( mouseDown && pressing ? "down" : "over" ); } else { setButtonState( "none" ); } } else { cooldown -= delta; refresh(); if( cooldown <= 0 ) { setPage( "Game" ); } } } function onMouseUp() { if( isOver() ) { setButtonState( "done" ); } } function onMouseDown() { if( isOver() && state != "done" ) { playNote( 0 ); pressing = true; } else { pressing = false; } } function feedSynth() { if( state == "done" ) { playNote( 12, 12, cooldown * cooldown, cooldown * cooldown, 1-cooldown, 1-cooldown, 0, 1 ); } } mouseX = 1000; // hacky, assume mouse is a long way away at first setButtonState( "none" ); ###Game### hideMouse(); var players = []; players.push( {x: -180, y: 0, score: 0, hitCooldown: 0 } ); players.push( {x: 180, y: 0, score: 0, hitCooldown: 0 } ); var ball; var time = 0; var winCooldown = 0; function newBall() { ball = { x:0, y:0, dx: Math.random() > 0.5 ? -200 : 200, dy: Math.random() * 200 - 100, hitCount: 0, sx: 0, sy: 0 }; } function update() { // timers time += delta; for( player in players ) { player.hitCooldown = Math.max( player.hitCooldown - delta, 0 ); } if( winCooldown > 0 ) { winCooldown -= delta; if( winCooldown <= 0 ) { setPage( "StartButton" ); } } // move player paddle if( hasMouse ) { players[0].y = Math.min( Math.max( mouseY, -120 ), 110 ); } // move ai paddle var aiDy = 0; var aiDelta = ball.y - players[1].y; if( aiDelta > 20 ) { aiDy = 300; } if( aiDelta < -20 ) { aiDy = -300; } players[1].y = Math.min( Math.max( players[1].y + aiDy * delta, -120 ), 110 ); // move ball if( winCooldown == 0 ) { ball.x += ball.dx * delta; ball.y += ball.dy * delta; // bounce ball if( ball.y < -120 ) { ball.y = -120; ball.dy = Math.abs( ball.dy ); playNote( 0, 0, 1, 0, 1, 0, ball.x ); } if( ball.y > 100 ) { ball.y = 100; ball.dy = -Math.abs( ball.dy ); playNote( 0, 0, 1, 0, 1, 0, ball.x ); } // endzones var scored = false; if( ball.x > 270 ) { players[0].score += 1; scored = true; if( players[0].score >= 3 ) { winCooldown = 3; } else { newBall(); } } if( ball.x < -270 ) { players[1].score += 1; scored = true; if( players[1].score >= 3 ) { winCooldown = 3; } else { newBall(); } } if( scored ) { for( i in 0...3 ) { playNote( 12, 12, 1, 0, 0.2, 0.2, -ball.x, 0 + i * 3 ); playNote( 16, 16, 1, 0, 0.2, 0.2, -ball.x, 1 + i * 3 ); playNote( 19, 19, 1, 0, 0.2, 0.2, -ball.x, 2 + i * 3 ); } } // paddle collisions for( player in players ) { if( Math.abs( ball.x - player.x ) < 20 && Math.abs( ball.y - player.y ) < 40 && ball.dx * player.x > 0) { // hit! ball.dx = ( ball.x < 0 ? 200 : -200 ) * ( 1 + ball.hitCount / 4 ); ball.dy = ( ball.y - player.y ) * 7 * ( 1 + ball.hitCount / 4 ); // ball.x = ( Math.abs( player.x ) - 20 ) * ( ball.x < 0 ? -1 : 1 ); ball.hitCount += 1; playNote( 12, 12, 0, 1, 1, 0.2, player.x, 0 ); playNote( 12, 24, 1, 1, 0.2, 0.2, player.x, 1 ); playNote( 24, 24, 1, 0, 0.2, 1, player.x, 2 ); player.hitCooldown = 1; } } // feathers if( ball.x != ball.sx || ball.y != ball.sy ) { var oldLength = Math.pow( Math.pow( ball.x - ball.sx, 2 ) + Math.pow( ball.y - ball.sy, 2 ), 0.5 ); ball.sx = ball.x + ( ball.sx - ball.x ) * 30 / oldLength; ball.sy = ball.y + ( ball.sy - ball.y ) * 30 / oldLength; } } } function render() { // calc height of water var depth = Math.sin( time ) * 3 + 10; // actual background, as water fillBackground( 0.6, 0.4, 0.5 ); // upper ground drawRect( 0.3, 0.7, 0.5, 1, 0, 140, 240, 20 ); drawRect( 0.3, 0.7, 0.6, 1, 0, 115, 240, 5 ); drawRect( 0.1, 0.2, 0.6, 1, 0, 100, 240, 10 ); // water overlay drawRect( 0.6, 0.4, 0.5, 0.75, 0, 90, 240, depth ); // beavers for( player in players ) { var hit = player.hitCooldown * player.hitCooldown; var facing = player.x < 0 ? 1 : -1; drawBeaver( player.x, player.y, facing * ( 1 - hit ) - facing * hit, ( ( player.y * 0.02) % 1.0 ) * 2 - 1, depth ); } // ball translate( ball.x, ball.y ); stretch( Math.pow( ball.dx * ball.dx + ball.dy * ball.dy, 0.5 ) * 0.0003 + 1, Math.atan2( -ball.dy, ball.dx ) ); if( ball.sx != ball.x || ball.sy != ball.y ) { var featherAngle = Math.atan2( -( ball.sy - ball.y ), ball.sx - ball.x ) + Math.PI / 2; drawArc( 1, 1, 1, 0.5, 0, 0, 20, 20, featherAngle - Math.PI / 6, featherAngle + Math.PI / 6, 3 ); } drawBlob( 1, 0.6, 0.5, 1, 0, 0, 10, 10, 8 ); crosshairTransform(); // score flowers for( player in players ) { for( score in 0...3 ) { var x = ( -score * 30 + 150 ) * ( player.x < 0 ? -1 : 1 ); var y = 150 - Math.sin( x * 0.005 * Math.PI * 2 + 1 ) * 4; // flower stem drawRoundedRect( 0.3, 0.8, 0.3, 1, x, y - 10, 2, 10, 2, 2 ); if( score < player.score ) { // flower! translate( x, y ); rotate( Math.PI / 4 ); drawRoundedRect( 0.7, 0.8, 0.9, 1, 0, 0, 4, 8, 4, 4 ); rotate( Math.PI / 2 ); drawRoundedRect( 0.7, 0.8, 0.9, 1, 0, 0, 4, 8, 4, 4 ); drawFixedCircle( 0.16, 1, 0.5, 1, 0, 0, 3 ); crosshairTransform(); } else { // bud drawFixedCircle( 0.3, 0.8, 0.2, 1, x, y, 4 ); } } } // lower ground drawRect( 0.3, 0.7, 0.4, 1, 0, -140, 240, 20 ); } newBall(); [/gamesketch]

Is this what beavers look like? I really don't know. Regardless, I think I'm going to call this game done. I'm about three hours in now, and it's been fun. So there's that. I'm less confident about making games in under an hour but I'll keep at it. Maybe I'll speed up.

Any suggestions for the next microgame?

<3
Farbs

EDIT: I added a few new primitives to the renderer, including arcs, which reminded me that I hadn't finished the shuttlecock. So I finished the shuttlecock.


Episodic, and stepping on it!

Hello!

Have you ever looked at a webcomic and thought wow, this person is really talented? Have you ever then hit the First Comic button and seen where they started out, and how long ago? Have you been amazed at how their writing, illustration, layout, world, and any number of other things I don’t know about have developed in such a short time? I have. And because I like making games I’ve wondered if there was a way to do that with game development. And so I tried.

I’ve failed to make highly episodic games many times already, but nonetheless remain positive. Whereas Polychromatic Funk Monkey: The Series never got to the prototype stage, my flash (and now Haxe) skills are now strong enough that I can actually finish things. Whereas Little Sh*t Planet took hours of work per episode, the focussed code-only workflow I used for TickyTacky let me create something playable in just a few minutes. Whereas TickyTacky was finicky to code in and tedious to publish with, GameSketch is as easy as writing a blog post. In fact, GameSketch is a wordpress plugin, so it’s exactly as easy as writing a blog post. The game code is written directly into – and you might be able to guess where I’m going with this – a blog post. Like this one.

Tonight I’ll take GameSketch (I skimped on the name, but since it’s an internal tool I think that’s okay) out for its first run. Tonight, I’ll try to make, and publish, Pong In An Hour. Lan has suggested that I present it as Beavers playing Badminton. We’ll see how I go for time.

Speaking of time, it’s now 7:26pm. My time starts… after the jump!

Read More