Released My First Real Product!

2 August, 2009 (11:48) | Craftsmanship, Entrepreneurship, Software development, ThoughtMuse | 5 comments

For the past couple of months I've worked on a nontrivial project: build, launch and sell a commercial product on my own.

I set fairly strict constraints for the project:

  • Use less than five months to release the first version.
  • Work on it no more than fifteen hours a week (nights and weekends).
  • Don't neglect my family, which I love.
  • Keep my dayjob, which I really enjoy.

Well, I did it. The result is ThoughtMuse, an online mindmapping tool which runs in your browser. I released v.1.0 a week ago.

It's early days.  ThoughtMuse has some rough edges which I need to improve, and there's plenty of additional features I'd like to add to it.

So do I have any paying customers yet? Well, the magical first sale ticked in a few days after launch; the sweetest $35.40 I've ever earned. Building and selling something on your own is extremely rewarding. Making a profit? Sure, that would be nice as well. :)

You learn a lot by building a commercial product all on your own. I'm going to write more on this later on.

My First Product Has Gone Live!
For the past months I've tinkered with a non-trivial personal project: build, launch and sell a commercial product on my own. I've set fairly strict constraints for the project:
Take less than six months.
Use less than fifteen hours a week.
Don't neglect my family, which I love.
Keep my dayjob, which I also love.
Well, I did it. The product is ThoughtMuse, an online mindmapping tool. I released v.1.0 a week ago.
THOUGHTMUSE LOGO (CLICKABLE), MOVIE?
It's very early days.  I took Eric Ries advice (LINK) and went for a lean approach. "Release the minimally viable product as early as possible, then iterate based on user feedback". The product has rough edges, and there's a ton of features I'd like to add.
The magical first sale ticked in a few days after launch. The sweetest $ 35.40 I've ever earned, and one of the most rewarding moments I've had as a software developer. Building and selling something all on your own is extremely rewarding in itself. Making a profit? Yes, that would be nice as well. :)
You learn *a lot* by building a commercial product all on your own. I'm going to write more on this later on.
Try ThoughtMuse out yourself (interactive demo, no registration required). Tell me what you think of it! Are you encountering bugs? What parts of the user interface annoys you? What do you feel is missing? I appreciate all the feedback I can get; it really helps me decide what to improve first

Pomodoro Technique Revisited

30 June, 2009 (16:16) | Productivity, Software development | 6 comments

Three months ago I stumbled across a time management system called 'The Pomodoro Technique'. I really liked it due to the immediate productivity gains it gave me. I thought I'd follow that blog post up with my current impression of the technique, now that I've used it for a while. Todays blog entry will make more sense if you read my the original post first.

pomodoroTechniqueLogo

Recap

The idea of the Pomodoro Technique is that you work in timeboxed intervals of 25 minutes. Each interval is called a "Pomodoro" (tomato). Once you've completed a pomodoro you make a note of it, and take a five minute break. After four pomodoros you take a longer break.

The Good

I'm ultra focused when I work on tasks using this system. I initially found the ticking egg timer somewhat distracting and stressful, but that passed after a week or two. Once I start the clock I'm usually able to enter a state of flow really quickly.

I've repeatedly seen clear benefits from the self-enforced breaks; they sometimes make me step back, rethink and adjust what I'm working on. This has prevented me from going too far down some potentially time-consuming dead ends.

Recording completed pomodoros forces me to document and take stock of how much time I spend on different tasks. This provides historical data which really helps when I estimate similar future tasks.

"I'm going to complete a few eggs, dear" has become a catchphrase at home (eggs = egg timers / pomodoros). It's a clear way of communicating to my fiancè that I'm setting aside a concrete amount of time for work. This lets her know exactly when I'll emerge from my cave again. :)

The Bad

It's hard to stop working once the egg timer rings. This is especially noticeable if I'm almost done with a task; it's very tempting to put a few more minutes in before I take that break. Of course, those "few minutes" sometimes end up taking an hour or two...

The technique forces me into a certain mindset. I become really focused and efficient, which is great for concrete, well planned tasks. It's not always suitable for more reflective and explorative work, though. I find I do better at things like research, brainstorming, design and general planning when I'm not under the gun of my egg timer.

I have not used the technique seriously at my dayjob yet. I'm not using a mechanical timer there, since a ringing egg timer would be quite distracting for my coworkers (several of us share an office). One solution: use headphones combined with a software-based timer instead. Unfortunately, I find tools like mytomatoes.com much less effective than a mechanical clock; the "break" audio signal is far less noticable, and it's often lost on me because I take off my headphones or listen to music while working.

Conclusion

The Pomodoro technique has boosted my productivity, and I highly encourage more software developers to try it out. I will keep using it for my side projects. It has been less useful at my dayjob, but I'm going to try to adapt it to work well there as well.

How To Build Something Real (In Your Spare Time)

29 May, 2009 (16:40) | Entrepreneurship, Productivity, Software development, ThoughtMuse | 35 comments

stackedRocks

Starting a new pet project is easy. But finishing it? That's a different story.

Many programmers love to tinker with side projects. I'll argue that most of the decent ones do, anyway. Learning new tools makes us want to build things. Innovative technologies, cool product ideas. Unfortunately, the result is usually just a sad collection of forgotten files on some hard drive.

I'm certainly no exception to this - my portfolio isn't exactly jam packed with polished results. I've worked up enthusiasm for a variety of hobby projects over the years, with somewhat spotty follow-through.

Recently, however, I decided to step it up a notch. "This time I'm going to stick with it until I end up with a real product." So I did. I bootstrapped ThoughtMuse, an online mindmapping tool,  in under five months using only my spare time during nights and weekends.

To keep development of my product rolling I try to consistently apply basic productivity techniques. They're not particularly new and amazing methods - many of them are just Project Management 101. Unfortunately, they often seem to go straight out the window when programmers sit down to work on their own time. Perhaps using basic project management practices makes pet projects feel less sexy, somehow?

Anyway, these are some of my favourite techniques to keep producing in my spare time.

Set goals

Stating exactly what you want to achieve motivates you and focuses your efforts. And no, saying that you "kinda want to build this thingamajig" won't cut it. Be specific. Quantify. What am I creating? For whom? By when? What, and how much of it, do I need to achieve? Write down concrete, measurable objectives.

Divide into milestones

If your project will take more than a few weeks it's crucial that you divide the work into separate deliverables. Always having a single enormous blob of work left is demotivating. Instead, structure your project as a collection of smaller increments. And reward yourself every time you complete one of them!

Make yourself accountable

Tell someone what you are doing, and keep people informed of your progress. Talk to friends, post progress updates on your blog, whatever. The idea is to set up a small amount of external pressure to keep you going when the chips are down. I told Bob that I'd finish this cool widget by March - so I'd better get cracking!

Something every day

You need steady momentum to keep the project rolling. It's much harder to sit down and work if you only do so every other week - you then need to use more time and energy to "spin back up" every time. You also run a higher risk of falling off the wagon completely if you miss one or two  of those long sessions. Instead you want to ingrain a steady, regular habit which feels as natural as brushing your teeth every evening.

Don't force it

Like woodworkers say: don't work against the grain. If you hit a serious wall in some task, switch to something completely different to keep your momentum going. There's always other stuff that also needs to be worked on. Some code proving hard to debug? Jump to, say, user interface design instead. Then come back to the original problem later on. Problems have a way of solving themselves if you let your subconcious chew on it for a while.

Iterate, iterate, iterate

You won't get every task right the first time. Allow yourself to come back to each area of your product multiple times with fresh eyes. You'll see more clearly the second and third time you return to that piece of code or functionality.

Sustainable pace

Slow and steady will get you there in the end, full sprint might not. I think that taking the tortoise route is the safest approach. Avoid burning yourself out by overworking. This is especially important in the beginning when you have lots of enthusiasm. You will feel less optimistic in a few weeks or months, it's just a matter of time - so pace yourself.

Timebox everything

Perform an initial rough estimate of how much time and effort the project will take, given how ambitious it is. Then set aside fixed amounts of time you are willing to spend on your project. "I have to be done in three months, using no more than ten hours a week". Work on each specific task for set amounts of time.  This maximizes your focus. Timeboxing is especially useful if you're in a relationship; your girlfriend/boyfriend/wife/husband/children will thank you for this one.

Ruthlessly trim scope

This is the flip side of the technique above. You now have strictly limited time to burn on the project, so get the most out of your available hours. We have a tendency to get carried away, dream up new features and let the scope of our projects grow. Try to constantly remove instead. Paraphrasing Einstein: "Everything should be made as simple as possible, but not simpler." Do you really need this, that or the other to be satisfied with the finished product? If not, just archive the idea, then move along.

Let life intrude

Accept that Everyday Life can and will mess up your schedule sometimes. That's ok. Don't stress out about it - as long as you're moving forward you'll get there eventually. Just keep plugging away. Stick with it!

stonePath

I've described the techniques above in the context of software development, but they should be fairly universal and applicable for anyone practicing some sort of craft in their spare time. If you have any other methods which work well for you, I'd love to hear about them!

Are there areas in which any of these techniques don't work or are actually harmful? I don't know - feel free to tell me if you know of specific counter-examples.

Now, time to get back to work on that cool new feature...

Painless Estimates

14 April, 2009 (15:22) | Craftsmanship, Software development | 2 comments

How do you determine how long something will take to build?

In an ideal world, many of us would probably like to simply work until the stakeholder/product owner decides we're done, keeping our expense meter running all along. This is (very roughly) the approach taken by agile software development methodologies such as Scrum.

Unfortunately, in the real world we often need to know roughly how long something will take before we start working on it. This is basic product management: the feasability of a new project, product or feature is (in part) derived from the initially estimated cost of building it. "That new nifty feature will take more than four months to add to our product? Maybe we have better things to do with our time, then."

What's the best way of doing this up-front estimation? There's certainly lots of approaches out there. Personally, I've settled on the following method:

  1. Start by getting your bearings somewhat. This means doing enough design and requirement gathering up front. Talk to stakeholders and users. Play around with any new unfamiliar technology that the work will require.   

  2. Extract the concrete tasks that must be done. Each task should take less than eight ideal hours to complete (see below). Tasks larger than this are often opaque "lumps" of many tasks, which are harder to estimate accurately- so divide the work into subtasks as needed. Don't forget work related to polish and testing: integration testing, documentation, release routines, etc.  

  3. Estimate each task in ideal hours: "how many hours would this take if I could focus 100%, no interruptions, closed office?" Another approach is to estimate using abstract or relative units, before translating to actual ideal hours. The Poker Planning Game and the Pomodoro Technique are good examples of this approach.  

  4. Add up total ideal hours. Then multiply by a risk factor, to allow for Murphy's Law. My personal minimum is usually 1.2 (20%) - and that's if I have a very good handle on both the technology, the requirements and most other significant factors.  

  5. Figure out how many ideal hours you actually get done each week. How much effective time do you really have left when you subtract meetings, interruptions, lunch, motivation lapses, etc etc? Divide the hour number from step 4 by these actual hours accomplished each week. Now you know roughly how many actual hours the work will take.  

  6. Finally, take external dependencies into consideration. Will Joe Developer be there week one or is he tied up? Will Sue Tester go for a three week holiday to Hawaii at some point? Set up the project schedule based on these known constraints.  

This method is heavily inspired by Mike Cohn's Agile Estimating and Planning, and I use it both at my dayjob and for private side projects. I've found this to yield quite accurate estimates for small projects - eg. where the scope is less than, say, 3 months with less than four developers.

For larger projects you may find that estimating work up in such fine grained tasks involves a lot of uncertainty. "How can I know exactly what specific tasks will be required all through my project?". Well, yes - for projects with larger scopes, this quickly turns into riskful guesswork.  This is what makes estimating entire large projects up front (and, by extension, taking on large fixed cost projects) such a dicey proposition.

Eggs, Tomatoes and Time Management

30 March, 2009 (16:47) | Craftsmanship, Productivity, Software development | 2 comments

It's evening, and my home office door is closed. No email or IM clients are running on my computer. My daughter is asleep, my Significant Other is aware that I'm working. I wind up the egg timer, the clock starts ticking. My mind quickly enters a state of Flow. 25 minutes later the timer rings. The feeling is akin to waking up from a dream. I stop working, and jot down a mark in my task list. A solid unit of work accomplished; another egg completed.

eggtimer

I have trouble maintaining a consistent level of productivity - especially for side projects that I work on in my spare time. Both at work and privately I find that my productivity fluctuates wildy. Sometimes I'm able to crank out quality stuff for 10 hours straight, while other days simply vanish in trivial distractions.

A possible remedy to this problem presented itself recently in the Pomodoro Technique ("Tomato Technique"), a time management method I'd never heard of before last week. I've currently only used this system for a few days, but the early results are quite promising.

Getting started is fairly simple:

  1. Set up some sort of timer. A software clock works, but a physical clock is better.
  2. Select a task that you need to accomplish, and remove possible distractions.
  3. Set the timer to 25 minutes.
  4. Work on the task until the timer rings.
  5. One "tomato" is now accomplished for the task - add a mark to the task record.
  6. Take a short break before restarting the timer - 5 minutes or so.
  7. Take a longer break once every four tomatoes.

To me, the most obvious benefit of the technique is that it forces you to timebox and really focus on your work. One resulting effect for me is that I get into the elusive "flow" state much earlier than before. There's more to it, though.

The regular breaks provide an opportunity to periodically step back and look at the current task from a different perspective: "Am I going about this in the wrong way? Maybe I'm even solving the wrong problem?" This is valuable - it's easy to lose sight of the larger picture when you're head down into the specifics of a task.

Over time your ability to estimate future tasks is likely to improve, since you have a more solid appreciation (and written record) of how much effort your past work took. Besides, it's generally a good idea to measure your work in abstract work units rather than directly in clock hours (the Poker Planning Game is another example of this phenomenon).

The final benefit of the system is the moral boost you get from continuously marking down those completed "tomatoes" (I personally refer to them as "eggs", since I use an egg-shaped timer). Think about it; don't you feel good when you complete a feature, article or bug fix? I find that this technique gives me that same satisfaction every 30 minutes - I may not finish that new feature tonight, but I know that every egg takes me closer to completion.

It will be interesting to see what this does for my productivity long-term. The next step in the technique is to actually start estimating future tasks in tomatoes instead of hours; I'll try that once I've gotten used to the basic workflow. I'll probably post an update in a few weeks.

pomodoroTechniqueLogo

If you found this interesting I strongly encourage you to visit the Pomodoro website and read more yourself; there's a nice, free eBook summary available there (pdf).

UPDATE: I wrote a follow-up post a few months later.

Invest In Yourself

22 February, 2009 (23:17) | Craftsmanship, Software development | No comments

I wish I could go back in time and give myself career advice.

BackToTheFutureAdvice

Actually, I'd probably hold off on the work-related issues. Essentials first: women, lottery numbers, financial advice. Back To The Future 101, right? But with that out of the way: career tips! What would I say to my younger self?

1. Active knowledge management

Cultivate an active approach to learning and growing as a craftsman. Set and follow a clear personal path - don't just let corporate whims dictate the areas of your expertise. Take charge! If you absolutely have to work with dead-end or irrelevant technology at your day job, then learn what you need in your free time.

2. Timeless skills > buzzwords

On a related note, focus your spare time on diversified and technology agnostic skills, rather than enterprise technology of the week mandated by the corporate overlords.

While there may be something to be said for staying painfully up to date on the latest industry trends / Gartner approved buzzwords, I personally find it more rewarding to go back and improve my core skills. There's always basic stuff I could be much better at. Math, OOP, programming technique: skills which will still endure when the Spring framework draws it last breath (or last download, I guess).

3. Produce in your spare time

When learning a useful new skill in your free time (see above), don't limit yourself to 'Hello World' or a dinky O'Reilly tutorial. Build something concrete. Add new stuff to your portfolio.

Pour your energy and love of learning into tangible side projects. Create open source software, write articles, start an mISV, work for non-profits/charities... Do whatever appeals most to you. Just produce something!

4. You != The Company

I wrote blog posts exclusively inside a corporate intranet for a while. I'm kicking myself for that now. Most of what I wrote was rubbish, but it would still be nice to have it pad out my own blog archives rather than the graveyard of some internal company webserver (which is where my old blog posts currently reside).

If you enjoy holding presentations, focus on external meetups and conferences. Don't hide your work in internal company venues (unless your topic concerns company secrets). You want to invest in extracurricular work that benefits both your company and your public profile; when you switch jobs you only benefit from the latter.

Make sure your employment contract doesn't state that your employer owns everything you create outside of work. Why should you freely give away all your potential off-hours creativity to a faceless corporation (unless you're strictly a 9-5 programmer, in which case I suppose it doesn't matter)?

And please think twice before spending your spare time on certificatons mandated by your employer. Certifications can be really useful learning excercises, but spending time outside office hours to study for them?  Only if  it clearly makes you a better craftsman.

Wrapping up

So, in summary: Take charge of your career. Improve your craftsmanship. Produce stuff. Make sure you own your work and ideas.

I didn't give the above issues much active thought until these last two years, and I'd love to be able to give my former self some of these pointers. Fortunately, however, there's plenty of time to remedy my previous career coma. Which reminds me: I'd better get back to work on my secret side project. :)

Loosely related stuff

Paul Graham on "How To Do What You Love".

Also, check out the video below. Zed Shaw on intrigue, suspense, corporate autism, stakes and strippers. Very funny talk!

Javascript Tetris Pt 8: Post Mortem & References

28 January, 2009 (21:29) | Gaming, Javascript, Quicktetris, Software development | 7 comments

Part 1, 2, 3, 4, 5, 6, 7, 8

This was a fun project! Time to wrap it up...

What did I take away from all this?

Well, putting together the game (and these blog posts) helped me achieve my goal: I've got a better grip on core Javascript syntax and idioms now. I find I actually like working in the language. It's very flexible, mainly because of its functional aspects and malleable Prototype object system. Ruby is still a more pleasant alternative, though. :)

Development is rapid... as long as I use disciplined regression tests. This is key - the only reason I was able to code (and constantly refactor) this little project relatively quickly was the constant safety net of my tests. Refreshing the browser and quickly hopping through the visual tests took about 10 secs each time, making for fairly rapid dev cycles.

I ended up with a basic but effective dev environment for dynamic web apps. I'm planning on extracting a stripped down template for future projects (with some improvements, see below).

Finally, rapidly building something concrete and visual is a rewarding feeling in and of itself... even for a trivial toy like my dinky little game.

Room for improvement

There are, apart from the myriad candidates for refactoring, some major issues to consider in the finished product as it stands now.

More of the code could be programmatically testdriven. For instance, much of the collision detection and state handling of Piece and Field could be tested and developed without relying on manual, visual tests. I managed without extensive unit tests here, however if the project had been a less trivial one I probably would've been more rigorous.

Piece shape matrices could be expressed in a more compact way if I'd defined each shape once, then used matrix rotation on them as needed. Unfortunately my math is a wee bit rusty, so I opted for "readability" instead. ;)

My use of OOP in this project could be a bit more disciplined. I reach right inside the Field and Piece objects and grab their state variables - so much for encapsulation, eh? I should've defined accessor functions, using closures to hide the actual state variables (this didn't really occur to me until I was close to finishing the project).

Also, all the code should be hidden within the Quicktetris object (our application namespace). One of the quirks of Javascript is its notion of linkage through global variables - every library, function and general flotsam of Javascript code loaded in the current browser window ends up in the the same global namespace. Given the possible amount of library code that a serious application can load, our generic Test, Piece, Field , Graphics names could easily trigger naming conflicts.

How much thought did I put into performance? Nada. Zip. It loads fast enough, and runs fairly smoothly on my laptop. Works for me. However, if general web application performance was more of a concern I'd probably look into some of the most obvious remedies:

  • Compression of the javascript code. All that generous whitespace adds to the size of the transmitted script.
  • Concatenating all javascript into one .js file to avoid overhead of multiple http requests
  • Compressing the image and sound assets. Lower bitrate for sound, reduced color debth for images
  • Using YSlow to profile and suggest further performance tweaks

Using straight DOM scripting combined with styled div elements works for our game. Every visual element is nice and rectangular; because of this we don't need more organic functionality such as lines, circles and curves. More flexible graphics would probably have called for a different approach. There are a few ways of doing this. The canvas approach is one, SVG based graphics another. Unfortunately, Internet Explorer doesn't support either of them out of the box (without installing third party extensions).

Time spent

The code didn't initially leap out in clean increments, as suggested throughout these blog posts. Being a relative newbie to serious Javascript development, I went through quite a few iterations - refactoring the code as I learned more.

Finishing the basic gameplay mechanics took roughly one week, using spare time in evenings and over the weekend. Improved graphics, animation, refactoring and general cleanup was finished after another week. Planning and preparing for this series of companion blog posts added overhead to the whole process.

Tools used:

  • Firebug is an absolute must for debugging Javascript code, enabling you to set breakpoints, step through the code, inspect DOM/CSS/script state at all times... One particularly handy feature it offers is its text console - console.log() is so much nicer for debugging than the old school practice of dumping debug messages in a dialog box with alert().
  • JSLint is, as previously mentioned, the closest you'll get to compiling your Javascript (for now). It checks code for typical Javascript code smells. Like the author of the tool states: "JSLint will hurt your feelings".
  • Rake is my preferred build tool. Writing procedural build scripts in Ruby is very expressive, fast and readable, especially compared to certain other xml-based, declarative monstrosities. :)
  • Beautify Javascript is a handy online tool for prettifying snippets of Javascript code.
  • Any editor will do, but I personally prefer Textmate when I work in OS X. Well worth the money.

Reference material

I usually find the W3Schools pages to be an ok starting point when I research unfamiliar web standards. Their tutorials and examples are uneven, but the site works well for quickly looking up stuff like API details and HTML DOM events.

For Norwegian readers: this is a very nice blog about Javascript and assorted web technologies. Kudos to Christian Johansen for a solid resource!

javascriptgoodpartscover

My main Javascript source, however, is Douglas Crockfords work. Crockford is the author of JsLint, the JSON standard, and general champion of Javascript. Crockford has essentially carved out and evangelized a subset of Javascript / EcmaScript, discouraging use of the more ugly parts in the language spec. You'll find a lot of useful articles at his site, as well as a bunch of videos at the Yahoo YUI site.

I strongly recommend his book, which summarizes much of the material from the articles and videos mentioned above. At 153 pages it's one of the most dense, concise language reference books I've ever seen.


Special thanks

My friend and colleague Alexander Odden (aka Flipside) was kind enough to whip up some sound and music - much appreciated!

I'm grateful to Johannes Brodwall, Christian Johansen, Lars Juel Jensen, Thomas Kristensen, Henrik Storm Ofteland and Bente Storåker for (sometimes heeded) feedback, suggestions and criticism. Thanks guys (and gal)!

Javascript Tetris Pt 7: Gameplay

28 January, 2009 (21:26) | Gaming, Javascript, Quicktetris, Software development | No comments

Full source code can be downloaded from project home at kjeldahlnilsson.net.

Part 1, 2, 3, 4, 5, 6, 7, 8

Today we finally get to strap together the actual game. Most of the work is already done by now - we just need to assemble the components. Let's start by handling transitions between three basic game states; intro screen, playing the game, and game over.

main.js:

var QuickTetris = {
 
    gameModes: {
        titleScreen: "titleScreen",
        gamePlay: "gamePlay",
        gameOver: "gameOver"
    },
 
    gameMode: null,
 
    gotoTitleScreen: function() {
        this.gameMode = this.gameModes.titleScreen;
        Graphics.clearGameContainer();
 
        Graphics.drawString("- PRESS SPACE TO START -", 0, 0);
 
        setKeyReaction(function(keyCode) {
            if (keyCode === SPACE_KEY) {
                QuickTetris.gotoGamePlay();
            }
        });
    },
 
    gotoGameOver: function() {
        this.gameMode = this.gameModes.gamePlay;
        Graphics.clearGameContainer();
 
        Graphics.drawString("- PRESS SPACE TO RETRY -", 0, 0);
 
        setKeyReaction(function(keyCode) {
            if (keyCode === SPACE_KEY) {
                QuickTetris.gotoGamePlay();
            }
        });
    },
 
    gotoGamePlay: function() {
        this.gameMode = this.gameModes.gamePlay;
        Graphics.clearGameContainer();
 
        this.dropSpeed = 3;
 
        var fieldXPos = this.getFieldCenteredXPos();
 
        Field.init("white", "white", fieldXPos, 50);
        Piece.init("white");
 
        setKeyMemory();
    }
 
};



See that final call to setKeyMemory()? Instead of immediately reacting to keypresses, like we did in the tests previously, we instead store the last pressed key in a global variable. Our game then reacts to that stored event regularly during each pass of the game loop, preventing user input from disrupting the flow of the game.

util.js:

var currentKeyPress = null;
function setKeyMemory() {
    document.onkeydown = function(e) {
        if (window.event) // IE
        {
            currentKeyPress = window.event.keyCode;
        }
        else if (e.which) // Netscape/Firefox/Opera
        {
            currentKeyPress = e.which;
        }
    };
    document.onkeyup = function(e) {
        currentKeyPress = null;
    };
}


The heart of a typical game is the game loop. For every pass of this loop we react to user input, move the piece downwards in the playing field, and (sometimes) adjust the difficulty of the game. Let's add that to the Quicktetris object above:

main.js:

    gameLoop: function() {
        if (QuickTetris.gameMode === QuickTetris.gameModes.gamePlay) {
            QuickTetris.reactToKeyPress(currentKeyPress);
            QuickTetris.adjustDifficulty();
            Piece.moveDown(QuickTetris.dropSpeed);
        }
    },
 
    reactToKeyPress: function(keyCode) {
        if (currentKeyPress === null) {
            return;
        }
 
        switch (keyCode) {
        case DIR_KEY_DOWN:
            Piece.moveDown(15);
            break;
        case DIR_KEY_LEFT:
            Piece.moveLeft(Piece.State.tileWidth);
            break;
        case DIR_KEY_RIGHT:
            Piece.moveRight(Piece.State.tileWidth);
            break;
        case SPACE_KEY:
            Piece.rotate(true);
            break;
        }
 
        //Reset key
        currentKeyPress = null;
    }


Finally we need a way of launching the game. We create our default index.html page, which, after loading, calls Quicktetris.startDefaultGameLoop():

main.js:

    startDefaultGameLoop: function() {
        this.gotoTitleScreen();
 
        // Launch game loop - set it to fire every X milliseconds
        setInterval(this.gameLoop, 50); // Attempting 20 FPS
    }


Aaand we're done! Go on, try it out yourself!:)

We'll do a brief post mortem summary of the project in the next and final part.

Javascript Tetris Pt 6: Lights, Action, Music!

28 January, 2009 (21:23) | Gaming, Javascript, Quicktetris, Software development | No comments

Full source code can be downloaded from project home at kjeldahlnilsson.net.

Part 1, 2, 3, 4, 5, 6, 7, 8

The game looks very prototype-ish right now. We're not shooting for blockbuster level presentation here, but we should at least provide a bare minimum of animation and audio feedback. Let's do something about that by adding animation, making the playing field a little more interesting, plus some support for sound effects and music.

First off; some sort animation payoff when the player clears one or more rows. We want a sort of stylized explosion to occur. Let's create that separately first. We'll achieve this by applying a JQuery UI effect to a div while hiding it.

test.js:

    testExplodeAnimation: function() {
        Graphics.clearGameContainer();
        var square = Graphics.createRectangleDiv("black", 400, 400, 100, 100);
        $(square).hide("explode", {},
        1000);
    }



This works, and looks cool. Now we'll finish the Field.doRowClears() method from yesterday, including some animation when we remove the filled rows in the field.

field.js:

    doRowClears: function() {
        var rowsToClear = [];
 
        this.State.gridState.eachRowWithIndex(function(row, rowNumber) {
            var entireRowFilled = true;
 
            // Is row filled?
            for (var tile in row) {
                if (row[tile] === 0) {
                    entireRowFilled = false;
                    break;
                }
            }
 
            // Set row to be cleared
            if (entireRowFilled) {
                rowsToClear.push(rowNumber);
            }
        });
 
        if (rowsToClear.length > 0) {
            this.explodeAndClearRows(rowsToClear);
        }
    },
 
    explodeAndClearRows: function(rowsToExplode) {
 
        // Set up big animation rectangle to cover the disappearing rows
        var topRow = 1000;
        var bottomRow = 0;
        for (var row in rowsToExplode) {
            if (rowsToExplode.hasOwnProperty(row)) {
                if (topRow > rowsToExplode[row]) {
                    topRow = rowsToExplode[row];
                }
                if (bottomRow < rowsToExplode[row]) {
                    bottomRow = rowsToExplode[row];
                }
            }
        }
 
        var rowsTotalTopY = this.State.posY + (topRow * Piece.State.tileHeight);
        var rowsTotalBottomY = this.State.posY + (bottomRow * Piece.State.tileHeight) + Piece.State.tileHeight;
        var rowsTotalHeight = rowsTotalBottomY - rowsTotalTopY;
 
        var explodingRect = Graphics.createRectangleDiv("#C0ADFF", this.State.posX, rowsTotalTopY, Piece.State.tileWidth * this.WIDTH, rowsTotalHeight, 10);
 
        // Clear the actual tiles in grid before animating the large rectangle
        for (row in rowsToExplode) {
            if (rowsToExplode.hasOwnProperty(row)) {
                this.clearRow(rowsToExplode[row]);
            }
        }
 
        // Use JQuery UI effect to "explode" the big rectangle
        $(explodingRect).hide("explode", {},
        1500);
 
        // Clean up
        Graphics.removeNodeFromGameContainer(explodingRect);
 
        // Shuffle remaining higher tiles downwards in field
        for (row in rowsToExplode) {
            if (rowsToExplode.hasOwnProperty(row)) {
                this.shiftTilesDownToRowX(rowsToExplode[row]);
            }
        }
    },
 
    clearRow: function(rowNo) {
        for (x = 0; x < this.State.gridState.length; x++) {
            this.tileOff(x, rowNo);
        }
    },
 
    shiftTilesDownToRowX: function(clearedRowY) {
        for (var y = (clearedRowY - 1); y >= 0; y--) { // Start at bottom to cascade tiles
            for (var x = 0; x < this.State.gridState.length; x++) {
                // Shuffle tile state down
                if (this.isTileOn(x, y)) {
                    this.tileOff(x, y);
                    this.tileOn(x, y + 1);
                }
                else {
                    this.tileOff(x, y + 1);
                }
            }
        }
 
    }


We also want to improve the appearance of the playing field somewhat; solid magenta is handy for raw testing but not exactly visually appealing in a finished game. Let's add a background graphic by updating Graphics.createFieldBackground():

graphics.js:

    createFieldBackground: function(bgcolor, x, y, width, height) {
        var rect = document.createElement('div');
 
        rect.style.position = "absolute";
        rect.style.top = y + "px";
        rect.style.left = x + "px";
        rect.style.zIndex = "-1";
        rect.style.height = height + "px";
        rect.style.width = width + "px";
        rect.style.backgroundColor = bgcolor;
 
        rect.style.backgroundImage = "url('assets/images/gameplayScreen.png')";
        rect.style.backgroundRepeat = "no-repeat";
        rect.style.backgroundPosition = "0px 0px";
 
        this.getGameContainer().appendChild(rect);
 
        return rect;
    },


collisiontestUpdatedBackground

Much better. The background picture is simply an image pulled from a random "mountains" search on Flickr, then cropped and tweaked a bit in Paint.Net.

We'll wrap up todays installment by adding support for sound and music. I found an elegant little library called Soundmanager. Soundmanager creates and wraps a hidden Flash component in the page, enabling us to seamlessly load and play mp3 files (or other media):

test.js:

    testPlaySound: function() {
	Sound.playLandingSound();
    },
 
    testPlaySoundLooped: function() {
	Sound.playLoopedLandingSound();
    },
 
    testPlayMusic: function() {
	Sound.playAmbientMusic();
    },


We then create our Sound object, wrapping the functionality we need from SoundManager to load and play audio.

sound.js:

var Sound = {
 
    SoundBank: {
        rotation: "rotation",
        landing: "landing",
 
        clearedOneRow: "clearedOneRow",
        clearedTwoRows: "clearedTwoRows",
        clearedThreeRows: "clearedThreeRows",
        clearedFourRows: "clearedFourRows",
 
        ambientMusic: "ambientMusic"
    },
 
    loadSounds: function() {
        soundManager.createSound(this.SoundBank.rotation, 'assets/sound/rotation.mp3');
        soundManager.createSound(this.SoundBank.landing, 'assets/sound/landing.mp3');
        soundManager.createSound(this.SoundBank.clearedOneRow, 'assets/sound/clearedOneRow.mp3');
        soundManager.createSound(this.SoundBank.clearedTwoRows, 'assets/sound/clearedTwoRows.mp3');
        soundManager.createSound(this.SoundBank.clearedThreeRows, 'assets/sound/clearedThreeRows.mp3');
        soundManager.createSound(this.SoundBank.clearedFourRows, 'assets/sound/clearedFourRows.mp3');
        soundManager.createSound(this.SoundBank.ambientMusic, 'assets/sound/ambientMusic.mp3');
    },
 
    playAmbientMusic: function() {
        playLooped(this.SoundBank.ambientMusic);
    },
 
    playRotationSound: function() {
        soundManager.play(this.SoundBank.rotation);
    },
 
    playLandingSound: function() {
        soundManager.play(this.SoundBank.landing);
    },
 
    playLoopedLandingSound: function() {
        playLooped(this.SoundBank.landing);
    },
 
    playClearedSound: function(level) {
        if (!level || level < 4 || level > 1) {
            return;
        }
 
        switch (level) {
        case 1:
            soundManager.play(this.SoundBank.clearedOneRow);
            break;
        case 2:
            soundManager.play(this.SoundBank.clearedTwoRows);
            break;
        case 3:
            soundManager.play(this.SoundBank.clearedThreeRows);
            break;
        case 4:
 
            soundManager.play(this.SoundBank.clearedFourRows);
            break;
        }
    },
 
};
 
// Looping sound support
playLooped: function playLooped(soundID) {
    window.setTimeout(function() {
        soundManager.play(soundID, {
            onfinish: function() {
                playLooped(soundID);
            }
        });
    },
    1);
};
 
soundManager.onload = function() {
    Sound.loadSounds();
}



Sound effects and music can now be launched from the rest of the game logic.

We have most of what we need now; in the next installment we glue it all together to create a playable game!

Javascript Tetris Pt 5: The Life Of A Piece

28 January, 2009 (21:22) | Gaming, Javascript, Quicktetris, Software development | No comments

Full source code can be downloaded from project home at kjeldahlnilsson.net.

Part 1, 2, 3, 4, 5, 6, 7, 8

In this installment we are going to set up the proper four-tile tetris piece and its interaction with the playing field. Be warned; this is the installment where we write most of our code. Grab some coffee before we start. :)

We will add a single functional, visual test for the piece and field interaction. I started out with separate tests for painting the piece, moving it, collision detection and so forth. However, in the end I found a single test sufficed to check all these things - so we'll simply use that, keeping our code walkthrough somewhat brief.

The test sets up the playing piece, the play field, and behavior for user input: movement, rotation and switching the shape of the tetris piece.

test.js:

 testPieceCollision: function() {
        Graphics.clearGameContainer();
 
        Field.init("blue", 400, 100);
        Piece.init();
 
        // Register key mapping
        setKeyReaction(function(keyCode) {
            switch (keyCode) {
            case DIR_KEY_DOWN:
                Piece.moveDown(15);
                break;
            case DIR_KEY_UP:
                Piece.moveUp(15);
                break;
            case DIR_KEY_LEFT:
                Piece.moveLeft(Piece.State.tileWidth);
                break;
            case DIR_KEY_RIGHT:
                Piece.moveRight(Piece.State.tileWidth);
                break;
            case NUM_KEY_ONE:
                Piece.toggleSquareShape();
                break;
            case NUM_KEY_TWO:
                Piece.toggleLineShape();
                break;
            case NUM_KEY_THREE:
                Piece.toggleTeeShape();
                break;
            case NUM_KEY_FOUR:
                Piece.toggleRHookShape();
                break;
            case NUM_KEY_FIVE:
                Piece.toggleLHookShape();
                break;
            case NUM_KEY_SIX:
                Piece.toggleRightLShape();
                break;
            case NUM_KEY_SEVEN:
                Piece.toggleLeftLShape();
                break;
            case SPACE_KEY:
                Piece.rotate(true);
                break;
            default:
                Graphics.drawString('Direction keys moves, space rotates, 1-5 changes piece type', 400, 400);
            }
        });
    },


In Tetris, the playing piece is made up of four tiles. We have seven shapes - seven basic ways of ways of grouping the four tiles.

tetrispiecetypes

All of these piece types can be rotated in ninety degree steps, giving us up to four different shapes per piece type. All piece shapes, no matter their rotation, fit inside a 4*4 grid... another two dimensional array. We'll define the possible shapes of the tetris piece as array literals. I'll limit the code listing to the possible shapes for the "T" piece type, for brevitys sake:

piece.js:

//   x
//  xxx : tee
var tee0dg =
[[0, 0, 1, 0],
 [0, 1, 1, 1],
 [0, 0, 0, 0],
 [0, 0, 0, 0]];
 
var tee90dg =
[[0, 0, 1, 0],
 [0, 0, 1, 1],
 [0, 0, 1, 0],
 [0, 0, 0, 0]];
 
var tee180dg =
[[0, 0, 0, 0],
 [0, 1, 1, 1],
 [0, 0, 1, 0],
 [0, 0, 0, 0]];
 
var tee270dg =
[[0, 0, 1, 0],
 [0, 1, 1, 0],
 [0, 0, 1, 0],
 [0, 0, 0, 0]];
 
var teeRotations = [tee0dg, tee90dg, tee180dg, tee270dg];


Finally we wrap the possible rotated shapes in an array, so we hold all possible rotated shapes of that piece type in one place. We do the same for all other piece shapes.

Now we have everything we need to define the playing piece and its behavior.

piece.js:

var Piece = {
 
    State: {
        piecePos: {
            x: 0,
            y: 0
        },
        color: "black",
        currRotation: squareRotations[0],
        currShape: squareRotations,
        rotationCounter: 0,
        // The four sprites that make up the piece
        tiles: [null, null, null, null],
        tileWidth: 23,
        tileHeight: 30
    },
 
    init: function(color) {
 
        rotationCounter = 0;
 
        var width = this.State.tileWidth;
        var height = this.State.tileHeight;
 
        if (!color) { // Assume colorful diagnostic pattern
            this.State.tiles[0] = Graphics.createRectangleDiv("green", 0, 0, width, height);
            this.State.tiles[1] = Graphics.createRectangleDiv("yellow", 0, 0, width, height);
            this.State.tiles[2] = Graphics.createRectangleDiv("orange", 0, 0, width, height);
            this.State.tiles[3] = Graphics.createRectangleDiv("red", 0, 0, width, height);
        }
        else {
            this.State.tiles[0] = Graphics.createRectangleDiv(color, 0, 0, width, height);
            this.State.tiles[1] = Graphics.createRectangleDiv(color, 0, 0, width, height);
            this.State.tiles[2] = Graphics.createRectangleDiv(color, 0, 0, width, height);
            this.State.tiles[3] = Graphics.createRectangleDiv(color, 0, 0, width, height);
        }
 
        this.reset();
    },
 
    // Reset piece pos to middle of middle, top
    reset: function() {
        this.State.piecePos.x = Field.State.posX + ((Field.WIDTH / 2) * this.State.tileWidth) - (2 * this.State.tileWidth);
        this.State.piecePos.y = Field.State.posY - (this.State.tileHeight * 2);
        this.setRandomShape();
        this.redraw();
    },
 
    drawSingleTile: function(xSlot, ySlot, tileNo) {
        var derivedX = this.State.piecePos.x + (xSlot * this.State.tileWidth);
        var derivedY = this.State.piecePos.y + (ySlot * this.State.tileHeight);
        this.State.tiles[tileNo].style.top = derivedY;
        this.State.tiles[tileNo].style.left = derivedX;
    },
 
    redraw: function() {
        var tileCounter = 0;
        this.State.currRotation.eachWithIndexes(function(element, x, y) {
            if (element === 1) { // Is the matrix slot ticked?
                Piece.drawSingleTile(x, y, tileCounter);
                tileCounter++;
            }
        });
        tileCounter = 0;
    },
 
    move: function(dx, dy) {
        var directionIsDown = (dy > 0);
 
        var collisionCheck = Field.checkCollisions(this.State.piecePos.x, this.State.piecePos.y, this.State.currRotation, directionIsDown, dx, dy);
        if (collisionCheck.collides) {
            if (collisionCheck.sticks) {
                Field.mergeShapeIntoField(this.State.piecePos.x, this.State.piecePos.y, this.State.currRotation);
                this.reset();
                this.isGameOver();
            }
        }
        else {
            this.State.piecePos.x += dx;
            this.State.piecePos.y += dy;
            this.redraw();
        }
    },
 
    moveUp: function(speed) {
        this.move(0, -(speed));
    },
    moveDown: function(speed) {
        this.move(0, speed);
    },
    moveLeft: function(speed) {
        this.move( - (speed), 0);
    },
    moveRight: function(speed) {
        this.move(speed, 0);
    },
 
    setRandomShape: function() {
        var random = Math.floor(Math.random() * 7);
 
        switch (random) {
        case 0:
            this.toggleSquareShape();
            break;
        case 1:
            this.toggleLineShape();
            break;
        case 2:
            this.toggleTeeShape();
            break;
        case 3:
            this.toggleRHookShape();
            break;
        case 4:
            this.toggleLHookShape();
            break;
        case 5:
            this.toggleRightLShape();
            break;
        case 6:
            this.toggleLeftLShape();
            break;
        }
    },
 
    rotate: function(doCollisionCheck) {
        this.State.rotationCounter++;
        if (this.State.rotationCounter == this.State.currShape.length) {
            this.State.rotationCounter = 0;
        }
 
        if (doCollisionCheck) {
            var collisionCheck = Field.checkCollisions(this.State.piecePos.x, this.State.piecePos.y, this.State.currShape[this.State.rotationCounter], false, 0, 0);
            if (collisionCheck.collides) {
                return;
            }
        }
 
        this.State.currRotation = this.State.currShape[this.State.rotationCounter];
        this.redraw();
    },
 
    resetRotation: function() {
        this.State.currRotation = this.State.currShape[0];
        this.State.rotationCounter = 0;
        this.redraw();
    },
 
    toggleSquareShape: function() {
        this.State.currShape = squareRotations;
        this.resetRotation();
    },
 
    toggleLineShape: function() {
        this.State.currShape = lineRotations;
        this.resetRotation();
    },
 
    toggleTeeShape: function() {
        this.State.currShape = teeRotations;
        this.resetRotation();
    },
 
    toggleRHookShape: function() {
        this.State.currShape = rhookRotations;
        this.resetRotation();
    },
 
    toggleLHookShape: function() {
        this.State.currShape = lhookRotations;
        this.resetRotation();
    },
 
    toggleLeftLShape: function() {
        this.State.currShape = leftLRotations;
        this.resetRotation();
    },
 
    toggleRightLShape: function() {
        this.State.currShape = rightLRotations;
        this.resetRotation();
    }
 
};


Whew. The final task is to define how the field behaves when the playing piece touches its borders, or other tiles on the field. In other words, collision detection. The Field object will take the playing piece position, shape, direction and speed and determine two things: will the piece collide with anything? If it collides, does it also stick to that surface? If it does, the Piece will, as defined above, ask Field to merge its shape into the current position in the Field grid.

We add the following members to the Field object literal (which we started defining in yesterdays blog post):

field.js:

    CollisionData: {
        collides: false,
        sticks: false
    },
 
    checkCollisions: function(xPos, yPos, shapeArray, directionIsDown, dx, dy) {
        if (this.State.gridState) {
            var fieldCollision = this.pieceCollidesWithField(xPos, yPos, shapeArray, directionIsDown, dx, dy);
            var boundaryCollision = this.pieceCollidesWithFloorOrWall(xPos, yPos, shapeArray, directionIsDown, dx, dy);
            var collisionResult = Object.create(this.CollisionData);
            collisionResult.collides = fieldCollision.collides || boundaryCollision.collides;
            collisionResult.sticks = fieldCollision.sticks || boundaryCollision.sticks;
            return collisionResult;
        }
    },
 
    pieceCollidesWithField: function(xPos, yPos, shapeArray, directionIsDown, dx, dy) {
        var collision = Object.create(this.CollisionData);
 
        shapeArray.eachWithIndexes(function(element, x, y) {
            if (!element || (collision && collision.collides)) {
                return;
            }
 
            var tileXPos = xPos + (Piece.State.tileWidth * x) + dx;
            var tileYPos = yPos + (Piece.State.tileHeight * y) + 1;
            var movingRect = makeRect(tileXPos, tileYPos, Piece.State.tileWidth, Piece.State.tileHeight);
 
            Field.State.gridTiles.eachWithIndexes(function(tile, arrX, arrY) {
                if (collision.collides) {
                    return;
                }
 
                if (Field.isTileOn(arrX, arrY)) { // Only  collision if tile is actually switched on
                    var tileX = Field.State.posX + (Piece.State.tileWidth * arrX);
 
                    var tileY = Field.State.posY + (Piece.State.tileHeight * arrY);
                    var fieldRect = makeRect(tileX, tileY, Piece.State.tileWidth, Piece.State.tileHeight);
                    collision.collides = intersectRect(movingRect, fieldRect);
 
                    if (collision.collides && directionIsDown) {
                        collision.sticks = true;
 
                    }
                }
            });
        });
 
        return collision;
    },
 
    pieceCollidesWithFloorOrWall: function(xPos, yPos, shapeArray, directionIsDown, dx, dy) {
        var collision;
 
        shapeArray.eachWithIndexes(function(element, x, y) {
            if (!element || (collision && collision.collides)) {
                return;
            }
 
            collision = Object.create(Field.CollisionData);
 
            // Check for floor collision
            var tileYPos = yPos + (Piece.State.tileHeight * y) + 1;
            var tileBottom = tileYPos + Piece.State.tileHeight;
            var fieldBottom = Field.State.posY + (Piece.State.tileHeight * Field.HEIGHT);
            collision.collides = (tileBottom > fieldBottom);
            collision.sticks = directionIsDown;
 
            // Check for wall collision (if no floor collision)
            if (!collision.collides) {
                var tileXPos = xPos + (Piece.State.tileWidth * x) + dx;
                var tileLeft = tileXPos;
                var tileRight = tileXPos + Piece.State.tileWidth;
                var fieldLeft = Field.State.posX;
                var fieldRight = Field.State.posX + (Piece.State.tileWidth * Field.WIDTH);
                collision.collides = (tileLeft < fieldLeft || tileRight > fieldRight);
            }
        });
 
        return collision;
    },
 
    mergeShapeIntoField: function(xPos, yPos, shapeArray) {
        shapeArray.eachWithIndexes(function(element, x, y) {
            if (element) {
                var tileAbsoluteXPos = xPos + (Piece.State.tileWidth * x);
                var tileAbsoluteYPos = yPos + (Piece.State.tileHeight * y);
                var tileXPosInField = tileAbsoluteXPos - Field.State.posX;
                var tileYPosInField = tileAbsoluteYPos - Field.State.posY;
                var tileXLocationInField = tileXPosInField / Piece.State.tileWidth;
                var tileYLocationInField = Math.round(tileYPosInField / Piece.State.tileHeight);
                Field.tileOn(tileXLocationInField, tileYLocationInField);
            }
        });
 
        Field.doRowClears();
    }


I'm not completely happy with the pieceCollides*() methods. Some of the variable names could be clearer. Checking the entire field for collisions is a little brute force (collision can only occur in the field tiles overlapping and directly surrounding the piece). The calculation of coordinates could be simplified by having Piece use coordinates relative to Field. And methods with more than two levels worth of nested blocks are just asking for an additional method extract. This implementation does the job well enough for now, however.

Once the playing piece has "stuck" and been merged into the field, we check if any rows have been completely filled in the playing field - these should be cleared, and the pieces above should be shuffled down. We'll hold off implementing doRowClears(), however - todays installment is already running a little long. :)

In the next part we'll finish the piece-field interaction. We'll also add some visual and aural interest to the game.