update: put helpful remarks in ALL of code now.
This is not a very complex cart, or perhaps it is.
The classic SNAKE game has been around for many years and during that time some innovative programmers have figured out unique, interesting, and compact ways of handling it.
It's not simply drawing a line, it creates a trail that disappears behind the player according to how far in the game they are.
There are many approaches to writing this. As for me, I have always opted to ID the entire screen, in this case, all 15x15 tiles and use a number to represent a part of the snake.
The higher the number the longer it will be in play. Albeit a lower number means it will vanish more quickly.
To update this I have a sweep of the entire playing area and if one of the tiles is a number that is greater to or equals one, then it decreases by one. So you need only plot a number behind where the player just was, to create this trail effect.
My question to you is how would =YOU= do it more efficiently ?
This is open to any and all programmers, not just you aces and veterans but those who are either learning to program in Pico-8 or have for a-while.
How would you code your SNAKE in the most efficient manner possible, and please, include the source.
Chances are one of us (likely me) will learn something from it. :)
Hey, remember me? :3
I saw this post and couldn't resist speaking up as my snake game is something I am so proud of. I've had a look at your code and honestly... I can't figure out how it works, there isn't even a _draw() function? But clearly it does work!
I had a lot of problems trying to figure out how to make my second snake game, the one you left comments on just over a year ago. Here's a link to the updated version of the cart (note: it no longer works on the pocket chip as I had intended it to)
I think my biggest problems came from how I was expecting the snake to move through the level. I wanted the snake to appear to be moving smoothly like it did in my first ever cart (https://www.lexaloffle.com/bbs/?tid=31571) but also be locked into a larger grid so that I could have better art opportunities, the sense of a smaller play area, and to make it slightly easier for the player to achieve the goal of eating the apples.
I've forgotten most of the details of how I made my second snake game but I do remember relying heavily on the idea of a "finite state machine" as that's the only powerful computational concept I had at my disposal at the time.
For example, the problem where the snake can turn back on itself and you lose the game instantly. I got around that problem by reducing the direction you could turn. If the snake is moving horizontally then the game would only take in an input if it was up or down and would ignore any other input. The program would see the snake as being in a horizontal state, and while in that state would only have access to vertical inputs. The reverse is true for the snake traveling in a vertical direction.
If you have a look in the code for "Snake for Pocket Chip" you'll notice the _update and _draw functions also act as a finite state machine, literally taking the variable "state" as the state of the game (ie, title screen, main game, game over screen)
One of the details I was proud of when making snake was the fact that everything except for the title screen was drawn in code and not as sprites. Even the apples are just a circle and a few dots!
I hope the kind of response you were hoping for <3
I really enjoy your content, keep up the good work!
OMy, @W_Rabbitt (White Rabbit?) your SNAKE game is just as good today as it was then.
How am I doing my code ?
Well you have to understand first off, I am REALLY old school. I know there is _draw() and _update() but I really don't like it.
Think of the Grinch and Christmas. That would be me, the Grinch, stubborn and set in my ways, even though Christmas might be better.
I wouldn't be here if I couldn't code the way I like to. And all my life on modern IBM-pc I've used little interrupts to write code with.
Back in the TRS-80, Apple ][, and Commodore Amiga, you didn't need that. You could just code and things ran as well as they did.
Now along comes IBM-pc and aside from GWBasic, Turbo Pascal, and QBasic, you MUST use a special command to give time back to the system, or you could hang the computer.
It all started with GFA. I was working in QBasic 4.5 on Scenario 1 at the time, a 16-color RPG Maker with high promises.
You see, back then QBasic could have a resolution of 640x480 B&W dots, 320x240 with 256-colors or 16-colors. And if you chose the 16-color 320x240 resolution, you could have 16-virtual graphic pages to work with. That was just too tasty for me to bypass. And indeed I wrote a great many tools and utilities to take full advantage of the 16-pages you could store and read not just pixels but interpreted data from.
And of course you could recolor the palette with POKE().
It was a year after this when I posted an incomplete version of my "Scenario 1 RPGMaker" on a BBS and a nice fellow named Russell got in touch with me via private message, looked at what my code was, and more importantly what it could become and said I'm a great coder, loves what I wrote.
Why don't I join him in the world of GFA-Basic writing Windows code and games ?
Now I had tried to write Windows code earlier but had limited success. QBasic was shaping up pretty nicely and at first, I resisted.
Then I said, okay, but it needs to provide a few things for me.
- It needs to be able to play .MID and .WAV on the fly. Something we note Pico-8 cannot do.
- It needs to be able to put graphics on the screen that don't vanish if you move the window.
- It needs to be able to create variables on the fly cause I'm lazy and don't like to define everything. Also something Pico-8 cannot do but I have since adapted.
- It needs to take advantage of that new 64-million colors I keep hearing about. Once again, Pico-8 cannot do.
And for GFABasic anyways - he came through, with all four, and more. What I got back was:
- Could play .MID, .WAV, and Mp3 (with libraries).
- Screen resolution of 1024x768 24-bit color ! My goodness did I have fun with that.
- You could indeed create variables on the fly, no definition. A$ was "" , A was zero, and a(1) was zero. All three were recognized as different variables.
- As #2 it provided me those "64-million colors." Well, not really, but it did provide 16,777,216 colors or simply RGB with 256 brightness levels to each. Close enough.
But because everything ran so fast in GFA I had to use a command called PEEKEVENT. This was my first introduction.
Peekevent would give time back to the computer, just a bit, and also update the screen. So I could indeed make 100% flicker free games and programs instead of using the old tried and true BASIC delay of:
for i=1 to 1000:next
About the time I was working on Scenario 2, painfully, as there was so much about GFA-Basic I knew so little about. Gustavo read my gripes and then presented me with over 10mb of Help Files for the language. That cinched it.
I carefully read every single line in those help files. From there I went on to write well over 1,000 programs in GFA-Basic, including a full Scenario 2, complete RPGMaker. Which is my lifetime achievement as it took 12-years to write, and I had hundreds of Worldbuilders for it.
Now, today ? Well, I dabble in BlitzMAX, not so much as I do in Pico-8 at the moment.
Why ? There is a primary reason and it's an important one for you guys out there making future programming languages and fantasy consoles.
Speed. I can press CTRL+R and even before my fingers are off of the button, it's already running. BlitzMAX is not quite that. It takes at minimal a good second to run and if it's a regular sized program can take 2-3 seconds.
Now you may be scoffing and saying geez David, can't you wait a few seconds ? And the answer is no, no I cannot.
You see I program a very particular way. I write a bit of code, run to check it, bit of code, run to check it, bit of code, run to check it. My Dad on the other hand would write code once, just once, then compile and run it, and of course it would work perfectly.
I'm not that way. Think of me as a caffeine-driven squirrel examining his stash of acorns every few seconds. That pretty well describes how I program.
And I wouldn't be here if Pico-8 did not have the command FLIP() or the more advanced YIELD(). @zep, if you're reading this, remember that please. I'm here and purchased Pico-8 only because it can use FLIP(). If I couldn't, I wouldn't be here. So please don't remove it in future releases. :)
With FLIP() you can bypass _DRAW() and _UPDATE() completely.
Here is a sample program:
repeat pset(rnd(128),rnd(128),rnd(16)) flip() until forever
Let's take a look at that briefly.
"repeat" is simple enough. It means to start a conditional loop, in this case it always runs the code within first at least one time.
"pset" with its rnd() means to plot a random position on the screen with a random colored pixel.
"flip" very critical not only updates the screen but gives time back to the computer (or you could wind up hanging Pico-8 without it).
"until" means we are now doing a comparison for our loop, and as "forever" is an unknown variable, it is set to NIL meaning, it will loop forever.
And that's it !
Now I know you can use _draw() and _update() to write code, I just - don't like it. I like to have 100% control over when and where my screen updates and when and where CPU time is given back to the system.
Now I =CAN= use _draw() and _update(). It's not like I can't. I just don't like it and I feel I don't have as much control over my code when I do.
And as BlitzMAX (the current big time language I program in) also has FLIP (without the parentheses), it was a simple matter for me to learn Pico-8 and it's nuisances and nuances from its petite included help file.
So - there you have it.
Hopefully now you can better understand the SNAKE game I wrote above with this information.
What I'm hoping from this thread is someone can show me in small code how to use ADD() and DEL() to make a simple snake game, because I'm not really sure - to get it just right.
That is something I could learn from today.
Here's a version that works by rotating (s1,s2,s3 -> s3,s1,s2) the snake segments at every frame, hence simplifying the movement logic greatly (down to 9 lines). Unfortunately only works for one-pixel square segments.
This next version works for larger segments. The movement logic is more complicated, up to 30 lines, and uses turn memory for segments 2+ to follow.
[Please log in to post a comment]