World of Goo Cursor Sample Thoughts

As I promised a while ago, I’m going to talk about how I built the World of Goo Cursor Sample. I’m not any sort of design analyst or critic, so I can’t give any in depth insight about what makes the World of Goo cursor special ( but if you are interesting in that kind of analysis, here’s an interesting one).

I’ll start by saying what I liked about the cursor, which should be very easy to guess: yup, the trail it leaves behind when it moves, and the nice border that makes it visible anywhere on the screen. So those were two goals that I set for my samples.

If I had been a good developer, I first would have started World of Goo and would have spent a couple of minutes just looking at the cursor and how it behaves, but I didn’t. I just started coding, and ended up rewriting all the sample after a while. At least I learned a good lesson: do your research first.

So the first thing I wanted to do was the trail. My first idea was to keep a list of positions where the cursor has been. The list was limited in size, which caused the oldest positions to be removed each frame. When moving the mouse, I stored the new position each frame, and removed the oldest one. Then, when drawing the cursor, for each position stored in the trail, I rendered a circle from a texture. When I ran the code, the first problems appeared: when moving the mouse too fast, gaps appeared between different circles, and instead of having one continuous trail, I had several distanced circles. This is when I decided to go back to the basics, and start up World of Goo to take a closer look at the cursor.

After spending a few minutes in the game’s menu, I took note of the following:

  • The cursor is indeed made up of many circles, as I suspected, but they are kept close enough so you don’t notice them most of the time.
  • The trail has a certain elasticity to it. When you move the cursor, the trail stays a little behind, and recovers with a different speed than the one you moved with
  • I still haven’t finished the second world of the game.

With that new information (namely the second points), I scraped the code, and started fresh. The first thing I had to deal with was that elasticity. The knowledge on how to do that came from an unexpected place. The Chase Camera Sample found on the XNA Creator’s Club webpage deals with a chase camera that uses spring physics for nice camera movement. The documentation found in the project’s folder was especially useful, because it contained some description on how the spring for the camera was implemented.

My idea was that if I built a trail composed of a chain of nodes, tied to each other with springs that had the resting length of 0 (each node always tries to reach the position of the previous node), it would work as expected.

The result can be seen in the sample, in the UpdateTrailNodes function, where a force is computed for each node, such that it pulls the node towards the previous one in the list. Then after some trial-and-error for the values of different parameters (now settable through the sample’s interface), I obtained a pretty good approximation of the behavior. By keeping the springs stiff enough, the nodes rarely get too far apart, so the circles appear as a continuous trails.

All left to do was the border. For this, the solution is rather simple. First, I draw all the nodes using the color I want for the border (White), and scaling them to make them slightly larger than normal. After this, I go again through the list of nodes, and draw them with their normal color (Black), at their normal scale. The black nodes overlap the central area of the white ones, and thus the border is created.

After using these two techniques I was satisfied enough to release the sample into the wild, and I hope the explanations help with a better understanding of the code.

Categorized: XNA
  • Miguel

    Nice. I was looking forward to this post. It’s always interesting to see the thought process behind the code.

  • Pingback: edg3’s reflections » Time Constraints

  • daniel

    i just thought i would tell you that this breaks “badly” if the game is not running at a constant 60 fps even 55 or 65 breaks it

  • Pingback: XNA Today » XNA Japan Team Blog クリエイターズ クラブ 公報 17 を公開

  • Catalin Zima

    @daniel: thanks, I’ll look into that. The computations for the spring are done under the assumption that it’s running under FixedTimeStep, but it should be easily fixed.

    Actually, the code was taking the elapsed time into consideration. However, the strange behaviour seems to be related to the instability of the euler integration. It can be fixed with appropriate values for the parameters of the simulations. Just change them until you get a satisfying behaviour. Doing the whole math to avoid euler instability isn’t worth it just for a cursor.

  • Wholesale

    Goo cursor special,the euler integration.

  • Pingback: Catalin’s XNA Experiments » Re-awarded XNA/DirectX MVP for 2010