You can do it Sssisssyphusss! Be the boulder! Keep on rollin’! Don’t ssstop! Never give up! No retreat! No sssurrender! No end in sssight! Just deliciousss Greek torment asss far asss the eye can sssee and asss fassst asss the fingersss can type or ssswipe!
Let's Snake: Ancient Greek Punishment is an adaptation of my 2011 game Let's Play: Ancient Greek Punishment into the videogame language of Snake.
Let's Snake: Ancient Greek Punishment was created using Phaser 3 along with Hammer.js for touch gestures (swipes).
Timeline
Revisionist history
I'm swooping in to add a precursor image of the index cards I wrote in June as I tried to come up with ideas for a game to make:
Start-up Culture
Well I started something. I figured (as per the Why) I should just make something that should be "easy". I really hope it doesn't end up being, you know, not-easy.
But in principle I just need to implement snake, which I've done before, and then design snake levels and mechanical tweaks that turn it into the five punishment myths I always do.
First pass:
Sisyphus
A stair (hill) of walls; apple at the bottom; each time you eat it the next one is up a step; at the top it resets to the bottom;
Questions:
- what about points? A global no points? Or you can get points? Do I care about the drama of reaching the infinite points? I do not. I kind of like the idea of points because it validates Sisyphus for carrying on. There is a reason. Punished but progressing.
Prometheus
A rock of walls (in the form of the previous games); snake is laid across the top; ... and then?
Questions:
- how to represent a struggle? you can push a key that raises your snake head but it just falls back?
- how to represent the eagle? a wall that flies down from the sky and hits and kills you (instantly since there's no incremental death); is it scare away by the struggle? I suppose so? Might end up seeming a bit awkward...
Tantalus
An apple above you, an apple below you; when you approach either it zips up and off the screen or behind a wall to become unattainable; returns once you're out of range; (this could be fiddly)
Danaids
An apple to the left; an apple to the right? The left apple gives you a point and the right apple takes it away?
Zeno
Maybe the effect is on time instead of distance? Is that fair? Like at the half-ways you take exponentially longer?
Or the tile increment gets smaller and smaller until there's no motion?
How to handle the two-dimensionality?
Don't reinvent the ouroboros
I caught myself thinking about how I would engineer a new version of Snake for Let's Snake and it would be so clean and beautiful and also arguing that the previous version was written in Phaser 2 etc.
But NO PIPPIN. Just use the Snake you've already written, that works, and move fast. In honour of that I'm going to do it now BEFORE I do anything else today. Let's see if I can do the conversion to Phaser 3 quickly... or is it a hell waiting in there for me? LET'S SEE.
This is a bigger picture thing about game making too. And maybe especially for how I'm feeling about it just lately? I've spent a lot of time quite embedded in the specifics of implementations and surfacing them... and that has led to dwelling a lot on technical matters, luxuriating even... which takes time. And is interesting, but it's a timeline I don't think I want right now. I'd like to go idea->thing a little faster.
So, less love of code and more love of game.
- Per my thoughts in the journal, I went ahead and translated the Snake implementation from SNAKISMS from Phaser 2 to Phaser 3
- It's largely all in working order except for:
- an oddity around wall collision (head collides AFTER the wall)
- text alignment seems to be off
- probably more than that
- One was around the way Phaser 3 changed the default alignment of sprites/images to the centre whereas SNAKISMS relied on the top-left version, so I just hardwired it back to top-left (path of least resistance and understanding)
- The other was the head colliding the tick after a collision which seems to be something to do with the body position updates being out of step, probably because of the way I move the snake tile by tile instead of via physics right? Yeah.
- I'd be willing to say that it's plausible to start building the individual levels now, god help us all
- Have the level shape
- Have the idea of "eating an apple up the hill"
- Need to work on it rolling back down (both on reset and on failing to continuing eating it up the hill)
- Probably should remove restart and menu
- Need to think about "death", probably just a respawn with no fuss?
- Lotta progress anyway
Sisyphusssed
Well I guess I got Snake working yesterday and then also got the Sisyphus level pretty tidied away? It came together pretty easily because of... the constraints! Yay constraints! Things fall into place in this kind of hybridization and adaptation, fewer choices.
I suspect Sisyphus was the easiest but that's alright, I'll pop away the others over the next days. As it comes so it goes.
Feels good to be making something that makes sense.
- In the light of day I was able to get the rollback timer working nicely
- Most of my problem last night? Forgot that the SNAKE_TICK needs a multiplier into millis, sighhhhh
- It's a pretty good sisyphus
- It's really hard to eat the apple up the hill
- Still need a decision on score... but I think I landed mostly with the idea of forever accumulating
- Oh and I need no game over! Let me do that now! Done. You die, flash, and go back to starting position... it's possible I'll need some of these for other levels so may want to bake them into Snake.js
- Basic shape of the rock in place
- Snake lying on top of it
- Restricted wiggle movement
- Next up is the eagle (wall)
- It essentially works in a way that I find reasonable as of now???
- But only the base is there, no actual implementation of ideas
Danaidssssss?
As of this morning we now have
- Sisyphus
- Prometheus
- Tantalus
in the can. As I started the structure for Danaids I wondered if it's somehow a bit incorrect?
So the point/idea in Danaids is you're trying to carry something from one place to another but it runs away before you get there.
In the game version I did a different version, which was that you get there but the receptacle itself drains away the water.
In terms of Snake it's a bit tricky. There are some "obvious" ideas:
- The thing you carry probably has to be an apple since you pick it up
- The representation of that apple draining away probably has to be your points going down (maybe one by one)
But how do you indicate the idea of taking the apple to a place. The Snake only consumes, it doesn't transport...
The initial thought was to use another apple that represents the destination... so the first apple appears, you eat it and get points, the other apple appears, you eat it and lose the points...
That recreates the to and fro and the idea of loss. Arguably the behaviour of the second apple makes very little sense though... inconsistent.
A simpler version would be to say
- "The snake is the bathtub"
- "The apple is the water"
- You eat the water to gain points
- But the points drain away
You know, that's better I think... no need to be wedded to the visual dynamics of the original game...
So you eat an apple and before the next one shows up your points have drained away. Love. Probably want a sound effect?
Zeno?
If I could conquer the Zeno concept I could probably have this game finished today which would mean I'd made it in four days which is LIKE THE GOOD OLD FUCKING DAYS.
As per my initial thought, how do you handle it being 2D? The point of Zeno is you're trying to go SOMEWHERE - there's a point of reference - and if the player can direct the snake away from that somewhere it doesn't work...
In the original game you can only apply effort to moving forward toward the flag (should I have a flag?).
So in the Snake it wouldn't be totally unreasonable to have the snake "on the ground" and only able to move right...
I could literally recreate the original with a repeated "half-way and slide-back" but it sort of seems wrong?
You could do the thing of progressively zooming in to show the (lack of) progress. Eventually you'd just see an edge of the snake moving one pixel... but nothing about the game so far has involved the idea of a camera that can be manipulated...
You could also switch over to time and double the number of tickets required to get halfway? With an Infinite number of tickets when you're right there to cheat... I mean one funny thing with Zeno in Snake's world, actually (and in all game worlds potentially) is that the world is quantized or whatever... there's a very specific measure of moving one unit and it takes a very specific amount of time... there's no such thing as moving halfway between two tiles on a Snake board...
... so does that open up the idea of actually getting the apple? Is that funnier than not? Let me try it out at least.
- The game is alllllmost done?
- Some niggles remain around timing, I wonder how hard they will be to chase down?
- That one was really easy
- I mean, that was the point of this project obviously - that these things are almost "pre-designed" by the constraints
- But it's... actually working
- Danaids next
- No actual implementation because this one feels like I should probably pause to think a little bit about how it works
- Well gee
- Not much to report
- Draining points sound effect is really satisfying though might have clipping issues because it relies on restarting a sound before it's done a believe
- Honestly this is a great representation of Danaids, better than the original game
- Is in place
- This one will again require some meditation (probably more than Danaids!) to figure out
- Playing with the timescale probably makes more sense than playing with the distance moved? But switching it to time also seems a bit... wrong?
- Oh how terribly funny
- I implemented a version where the tick time doubles every tick and that is visually very funny because the snake takes progressively longer and longer to move one square
- But then I realized that isn't really much of a reflection of Zeno's paradox and so I stopped laughing and felt a bit sad
- I start converting it so the tick time would double every time you got "half-way" to the apple, but that won't make a very good point because in that case you'll get there in not much time
- Because one of my observations I thought was fun was just to let the snake get the apple in this version, because the nature of the world almost doesn't have Zeno's paradox? But it won't be funny if it happens too fast... there needs to be the "will it happen?" moment first
- So now I'm a little bit back to the drawing board
- I'm not 1000% on this, but I feel like the current solution sort of works visually... albeit with a kind of visual cheat... and a bit of weird happenstance
- So I halve the tile-size for movement each time the snake gets halfway from its position to the apple
- And I secretly target the tile before the apple because that way you see the apple the whole time
- And for SOME REASON I don't 100% get but is doubtless to do with float accuracy in JS the snake effectively stops right in front of the apple, never getting there... I think there's a point of preceision where you are trying to add the grid size but it's so small it gets rounded away when added to the position... which might be something about a difference between the "normal" float representation (0.327472389423 etc.) and the e representation (1.2e3247237894 etc.)?
- I don't know, but I quite like it and I like the ways in which it gestures at a version of a world where Zeno is ACTUALLY RIGHT in a weird way...
- On to the menu
- In that it looks like a menu but doesn't work like one
- Got the Atari font back in
- Now I "just" need to implement the ability to actually select menu items and go to the appropriate game, whee
- I thought it was to do with using physics bodies, so I removed them, but turns out it wasn't that
- Although it's nice not having the physics there anymore anyway
- It was just the order of operations in the tick() which I was able to fix up pretty easily in the end
- I should change the version of the library I'm using to omit physics since I don't use it at all
- Trying to load Rex's gesture plugin but it seems like there's a disconnect in there somewhere
- Could roll my own but would really rather not
- Will have another go later
- Used hammer.js in the end, couldn't get rex's plugin going
- Seems to "just work" though I think something like Sisyphus is pretty unplayable with swipes, c'est la vie
- Is this thing "done"?
Closing Statement
That'sss all folksss
I'm not going to attempt to weave a beautiful narrative around this, but I am going to try to just draw out a few of the ideas and moments that came up during this game. Because it's such a constrained one I'm not sure there's a lot of stuff that cross-cutting, but it did raise a fair few key design ideas that have been part of my life for a long time.
Going back to the well
Fairly recently when I was trying to come up with incredibly simple games I could plausibly make this summer (while also being department chair and trying to revamp my programming course) I wrote a bunch of stuff on index cards. One of the recurring themes was to return to familiar projects and formats, such as variations (e.g. PONGS etc.), Snake (e.g. SNAKISMS etc.), and also Let's Play: Ancient Greek Punishment (e.g. all of those things). Let's Play: Ancient Greek Punishment, in particular, has been a real bastion in the storms of life - I made a lot of them while Felix was small.
The point here is that design and development isn't something you can always just leap into full force, or at least not with a brand new and ambitious project. It feels like something you have to warm up. Returning to well established design ideas and conventions is also a really helpful way to make something without it needing to take over my life. And that worked out, I finished the game in five days:
LIKE THE GOOD OLD FUCKING DAYS
Don't reinvent the ouroboros
NO PIPPIN. Just use the Snake you’ve already written, that works, and move fast.
A major struggle for me, and perhaps especially because I'm currently working on my introductory programming course, is that by default I always want to engineer projects from the ground up. So my instinct was to implement Snake afresh because... well I guess I just figured it would be so clear and gleaming and beautiful as I discuss in that journal entry.
I was able to pull out of that and "only" port my Snake code from SNAKSIMS from Phaser 2 to Phaser 3. I could totally have just implemented Let's Snake: Ancient Greek Punishement in Phaser 2 and kept the whole thing, but I do think there was a little bit of value in the port because it did serve to familiarize me with the code base and it's not a bad thing to update to the latest big-version-number of a framework. It also only took an hour or two.
This process is part of a much larger question about design/ideas and/versus development/implementation I think. Perhaps especially for me, I find I'm very interested in the relationships between the technical underpinnings of a project and the project itself - a lot of the time I'm either explicitly trying to signal that in the resulting game (to the audience), or I'm thinking about it extensively in the process documentation. But, it's also true that that kind of thinking can "hold you back" or generate obsessions that don't always serve the project itself?
For me at least, this is a message to think more seriously about working at a slightly different "level" more often - embracing the idea of "premade" stuff, even if it was made by me earlier on. But this could extend to sort of Asset Store work or, gasp, collaborations where I don't do everything myself!
Snake versus Myth versus The Original
An apple to the left; an apple to the right? The left apple gives you a point and the right apple takes it away?
That was my original idea for the Danaids level/minigame for this Snake version. Given the number of question marks it's obvious I wasn't sold on this, but I was just blitzing out ideas at the time. Importantly, this version of the idea is mostly an attempt to recreate the existing game (Let's Play: Ancient Greek Punishment in its standard 2D incarnations). And that's a question of what's being adapted/translated here: was this meant to be a Snake version of my previous game, or a Snake version of the same myths?
As soon as I was sitting down to work on the implementation of the above idea:
As I started the structure for Danaids I wondered if it’s somehow a bit incorrect?
I suppose because it was "incorrect," but that's such a weird thing in general. How do we know that a design approach isn't the right thing? Being able to answer that (rather than only feel it) is a huge indicator that you understand and are in tune with what the game you're making is. Part of design is building up that sense (I suppose it's like taste) and part of accountable design-research is being able to actually explain that sense.
So, yeah this case it was about the relationship between the game I was working on and its two referents. I had essentially defaulted to thinking I was adapting/porting the previous game (Let's Play: Ancient Greek Punishment), but really my design-heart knew that I should have been thinking more about adapting the original myths.
In going with that sense of incorrectness I was able to rethink the Danaidsss in terms of the original myth, which is about gathering something (water) only to have it slip away (sieve). And that framing allows you to actually connect up the elements to the mechanics/affordances of Snake as a world:
- "The snake is the bathtub"
- "The apple is the water"
- "You 'drink' (eat) the 'water' (apple) to gain points"
- "But the points drain away"
This is a much better representation of the myth. In fact, as I noted in the journal, I think it's actually better than what I made in the original game. And this is also really about the heart of this kind of adaptation-oriented project for me: it's about seeing and elaborating the potential connections between the mechanics and imagery and elements of the target system (Snake in this case) with the source system (shifted from the previous game to the original myths in this case).
Comic timing and Math
There was at least one key moment of implementation-level design thinking, and it showed up with Zeno, which I think was the most difficult to think through in the context of Snake.
When it came time to grapple with Zeno specifically I struggled again to immediately see how that myth could make sense in the specific setup of a Snake world. I identified a couple of problems quickly:
- The issue of the world being in 2D made it harder to think in terms of a set, linear destination
- Just reusing the solution from the original game (essentially a kind of repeated zooming in) felt wrong given that Snake doesn't traditionally involve any camera movements
In a way, these reflections are examples of prioritizing the target system when it comes to making design decisions. That is, if there's a conflict between how the target system works (at least conventionally) and what the source system "wants," you should try to resolve in favour of the target system. I'm not sure why I feel that way about it, and it's very likely that interesting design possibilities would come out of reversing this! I think for me there's an attraction to holding the target system relatively set because it creates a bunch of constraints that a) make design a bit easier and b) kind of surface your design thinking more clearly.
I eventually "zoomed in" on the idea of time being used to represent the paradox rather than space: it takes progressively longer and longer to move "half-way" to the destination. I started out with the idea that the tick time would double each time you reached half-way, and found this especially funny because it would mean that Zeno would actually reach the apple:
I mean one funny thing with Zeno in Snake’s world, actually (and in all game worlds potentially) is that the world is quantized or whatever… there’s a very specific measure of moving one unit and it takes a very specific amount of time… there’s no such thing as moving halfway between two tiles on a Snake board...
This relationship between representations of time as kind of conintuous and infinitely divisible versus tick-based time in Snake was one of the more fun realizations that came out of this project. When I actually started working on it though:
I start converting it so the tick time would double every time you got "half-way" to the apple, but that won't make a very good point because in that case you'll get there in not much time
Which is to say it was kind of a fair representation of the paradox, but in ending so quickly it losing the comedy you could get out of seeing the snake inch its way to the apple... and then actually eat it! That last moment, where it finally crests the final tile and you hear the sound, that would actually be really funny. But it needed to be significantly delayed and I couldn't think of a reasonable way to do it.
Instead, I went with the idea of halving the snake's move-distance each time it reached a half-way point. It slows down more and more and more. This works visually because you get that sense of an expansion of time which is sort of what Zeno's paradox does to you.
But then a weird thing happened: Zeno eventually just... stopped! Because of some math stuff:
And for SOME REASON I don't 100% get but is doubtless to do with float accuracy in JS the snake effectively stops right in front of the apple, never getting there... I think there's a point of preceision where you are trying to add the grid size but it's so small it gets rounded away when added to the position... which might be something about a difference between the "normal" float representation (0.327472389423 etc.) and the e representation (1.2e3247237894 etc.)?
Which was... perfect. Fuck you, Zeno.