A video to start!
Today was an exciting day for Iris. Previously we’d made the ripples (as you can see here) circular rings which faded as they emanated outward. This was okay, and it served well enough as an indication of where the ripples were, but we weren’t moved. They were just sub-par, and I had tried to address it a few times by using masks to reduce the aliasing, but it just wasn’t quite good enough. They didn’t allow blending, they weren’t very expressive, and they didn’t look all that great. So today I went and completely rewrote how the ripples functioned and went in favor of a representation which would allow some more flexibility. Originally I was trying to put them on a grid and go for a cellular automata style, but quickly found the number of operations to be too cumbersome to be executing every frame1. I quickly took the approach to iterate over theta and position objects (squares initially) around the circle periodically, which results in the image to the right. This was all right, except as they move outward the representation of the circle gets sparser, which can make it a bit difficult to tell where it is. The solution here is to start rotating the squares, so that at each successive radius they’re being offset a little bit. This leads to the following: Not too shabby. I hit a couple of performance blockages when trying to go for finer resolutions and long fading animations, but those were fixed readily enough by basically killing the squares off on the next frame and persisting them in the ghost images taken of the entire ripple group snapshot. Given that it’s technically feasible to use this style of ripple, I began wondering what we could achieve with it. Here are a few results from some experiments
First you’ll see first a sinusoidal modulation in size, giving the sensation that the ripple is pulsing along with it’s growth or visualizing a wave traveling away from the source.
Next up we have circles instead of squares, and the rotation here isn’t quite as standard. It actually rotates them at each step proportional to the square of the radius (whereas the previous samples have linear relationships between angular offset and radius).
Finally there’s using random noise to determine the offset, except this noise is very well behaved. In fact, for each circle there’s a random sign that gets chosen (at each frame) of whether to rotate it CW or CCW by an amount linearly proportional to the radius. Thus it has something like a random interleaving of both CW and CCW spins of the red square sample above.
This is just the beginning of what can be done with this new ripple generation. Various blend modes are available now (and can be chosen at will), and the space of positioning is wide open for exploration. Hopefully this development will help give each of the colors something of their own personality, as well as adding to the aesthetic ceiling of the game (with infinite variations). I’m also excited to see it help immerse players in what is happening aesthetically rather than them keeping focused on getting to the next level.
1. Iterating over a grid of any fine enough resolution is fairly intensive–you can instead just check within the frame which is the square of side length 2r minus the inner square of side length 2r/sqrt(2) given that they circumsribe/inscribe the circle, but it can only do so much and there’s still a lot of useless computation
What started out as a simple sketch a few weeks ago has become our full-time efforts at Three Pixel Heart, and will ultimately lead to our first paid release on the app stores. Currently we’re calling it Iris, and it’s an ambient audiovisual puzzle game based on rhythm, spatial reasoning, and (attempts to) feature a wabi-sabi aesthetic. Here are a couple screenshots, busy and sparse
The basic mechanic of the game is the player sends out ripples from the enso by tapping, and attempts to fill all squares and triangles with their own color. Additional objects such as color changing circles (featured in the second picture) and amplifiers, as well as different types of movement, add to the complexity of the puzzles. But here I want to talk less about the game itself and more about the creation of it.
Takeaway lessons so far:
- PERSISTENCE IS KEY. Making a game has ups and downs. Most notably the ups when initially prototyping and realizing something can be fun, downs when getting blocked on technical details or how to expand content (take a break, go for a walk, let your mind off it), and further ups when after making changes you find out they’re improvements by how players enjoy it much more in playtesting. Keep your mental life varied (have other projects, think about different games, keep playing other people’s games) while also putting in substantial work on the current game, and it should pay off.
- When something confuses players and isn’t meant to, try to change it visually/through audio before adding help text (in Iris that meant changing the goals, which were originally circles, to squares and triangles–it helped a ton! In retrospect making everything circles was idiotic)
- People like easy puzzles when they are aesthetically rewarding. I have a habit of cutting to the difficult things too quickly and experienced a backlash in the playtesting by watching players get confused. After expanding the difficulty curve out, and even throwing in some extra levels which I thought were trivial and boring, we saw the players enjoy the game more and not get lost when the harder levels came about because they had some time to adjust their minds to the mechanics.
- Level design is much easier through a physical medium that you can move around to get different senses of what’s possible. Trying to see it all in your head all the time is an extra constraint that should be avoided when attempting to build better levels.
- Masking objects in corona sdk is terrible (this is a technical point but it’s caused such duress that I feel like including it for anyone who ever uses corona and considers masks–be warned)
- Listen to playtesters. Keep listening to them even when they tell you things you don’t like.
Thinking of something I didn’t cover? Let me know what I missed!
So a few days ago I started development on a new game called Iris. It takes some ideas from Circadia (see last post for a video) and expands the physics. Things we’re learning:
- refactoring code is awesome (I’ve refactored the same bits several times now and with each pass it becomes easier to implement new functionality)
- closures are amazing for making programmable objects (e.g. say you have a class that you want to move around, but you wan the movement to be generalizable; pass in a closure that keeps track of the movement and updates the object every time it’s called, and just bind that to the update() in the object. Done! Or even more generally, make a function that makes these closures for some parametrization and being DRY)
- level design via text is a pain (seriously, we’d be so much faster if we just made a level designer… time to get on that)
- people can enjoy playing something they don’t even understand! The first couple builds didn’t have any tutorial, and watching people play we saw them delighted by the audio/visual and aesthetic aspects of the game, without even being sure of what they were trying to do.
- it’s pretty easy to make VERY hard puzzles with fairly few mechanics–the bigger difficulty is in crafting a journey
Screenshots are below, and per usual if you want to get access to pre-release builds join us on Testflight, we love to share!