This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
H4X0RZ's profile picture

Snake on an LED Matrix.

Started by H4X0RZ, 22 June 2016 - 03:54 PM
H4X0RZ #1
Posted 22 June 2016 - 05:54 PM
Hello community,

I have to build a project for CS using an Arduino (UNO). I decided to build my own (5x5) LED Matrix and program a game on it. Because 5x5 isn't too big (but an UNO can't handle "much" more.) I decided to build Snake on it.

Now… The game itself is "working". You can move (I even added difficulty levels) and you can collect the "point" (called apple in the code because I'm using red LEDs). But the "trail" isn't working at all. It's lighting LEDs up, but not the way I want it to happen.

Could someone please help me a bit? The code is located here. (Matrix.h/Matrix.cpp is just a wrapper for my Matrix. The actual "Magic" is happening inside Game.cpp. The "trail" should be updated on line 99-105).
If needed I could upload a video showing how it's looking right now. Maybe I just messed up some logic. Also, most comments are in german and I hope that won't be a problem. But I will translate every comment you think is useful :)/>

I would appreciate all the help I can get. Thanks. :)/>

~H4X0RZ
Edited on 22 June 2016 - 03:56 PM
CrazedProgrammer #2
Posted 23 June 2016 - 01:20 PM
Hi, it would help if you show us a video of what is going wrong.
As I see from your code, positionBuffer is not being written to at all.
H4X0RZ #3
Posted 23 June 2016 - 04:36 PM
Hi, it would help if you show us a video of what is going wrong.
As I see from your code, positionBuffer is not being written to at all.

I messed up and decided to push a version without the tail/trail. If you have the time, you could look at the last few commits (there shouldn't be many).

I don't have much time left (it should be finished tomorrow) so… if nobody comes up with a fix I'll just leave it the way it is now I guess. I still have to document it and I wanted to put it into a box… ;-;
Edited on 23 June 2016 - 02:36 PM
CrazedProgrammer #4
Posted 23 June 2016 - 04:57 PM
That sucks…
You could look up a tutorial on how to do snake but I think your core logic is flawed.

I think positionBuffer should have the positions of all elements of the snake, including the head (player).
In the update function, you should create a new buffer called newPositionBuffer.
Then you calculate the new position of the head, and store it in newPositionBuffer at the first position.
Then you copy all the positions from positionBuffer into newPositionBuffer with the index increased by 1.
Then you check if the head touches the apple, and if so, then increase trailLength by 1, otherwise, delete the last position from newPositionBuffer.
Then positionBuffer = newPositionBuffer.

In order for this to work, positionBuffer has to have at least 2 positions from the start.
I hope this works, and don't forget to make a backup in case I was wrong and everything breaks.
Good luck!
Edited on 23 June 2016 - 02:57 PM
H4X0RZ #5
Posted 23 June 2016 - 05:21 PM
That sucks…
You could look up a tutorial on how to do snake but I think your core logic is flawed.

I think positionBuffer should have the positions of all elements of the snake, including the head (player).
In the update function, you should create a new buffer called newPositionBuffer.
Then you calculate the new position of the head, and store it in newPositionBuffer at the first position.
Then you copy all the positions from positionBuffer into newPositionBuffer with the index increased by 1.
Then you check if the head touches the apple, and if so, then increase trailLength by 1, otherwise, delete the last position from newPositionBuffer.
Then positionBuffer = newPositionBuffer.

In order for this to work, positionBuffer has to have at least 2 positions from the start.
I hope this works, and don't forget to make a backup in case I was wrong and everything breaks.
Good luck!

My original idea was "caching" the positions in the array and then drawing all the positions I need. (It would delete the oldest entry if it reached the max size) but that made random LEDs glow.

EDIT: This is how it looks right now (the video is rotated thanks to my phone camera though.)
http://www.youtube.com/watch?v=n1uSOiyWxow
Edited on 23 June 2016 - 05:43 PM
Bomb Bloke #6
Posted 24 June 2016 - 02:35 PM
My original idea was "caching" the positions in the array and then drawing all the positions I need. (It would delete the oldest entry if it reached the max size) but that made random LEDs glow.

Difficult to tell you why that happened if you don't reveal the code.

Anyway, the way I'd do things:

Move all the snake-rendering code out of Game::updateDrawing(), and rig it so that it doesn't clear the matrix all the time. Instead, simply draw gameplay to the grid on the fly; you only need to alter two pixels per movement at the most.

You need two index counters for your positionBuffer array, each starting at 0 (and positionBuffer[0] should store the initial head position immediately when play begins); one counter to track where the tail is, and one to track where the head is. Whenever the snake moves, and the distance between these two counters is equal to the length of the snake, increment both. If the distance is less, then simply increment the head counter. If either counter exceeds 24 then loop it back to 0. If the head counter is less than the tail counter than add 25 to the former within the comparison.

With each movement, put the snake's new head location into the positionBuffer array where the head counter specifies. Disable the pixel of the position in the array the tail counter specifies (no need to change the positionBuffer entry for the tail, the head will eventually overwrite it again anyway), then use a matrix.getPixel() to check if the new head position already contains a lit pixel. If it does, and it's the apple, then increment length and draw a new apple (again use matrix.getPixel() to find a safe location). If it's not the apple then game over. If it's not lit at all then enable that pixel for the new head position.
H4X0RZ #7
Posted 24 June 2016 - 05:06 PM
My original idea was "caching" the positions in the array and then drawing all the positions I need. (It would delete the oldest entry if it reached the max size) but that made random LEDs glow.

Difficult to tell you why that happened if you don't reveal the code.

Anyway, the way I'd do things:

Move all the snake-rendering code out of Game::updateDrawing(), and rig it so that it doesn't clear the matrix all the time. Instead, simply draw gameplay to the grid on the fly; you only need to alter two pixels per movement at the most.

You need two index counters for your positionBuffer array, each starting at 0 (and positionBuffer[0] should store the initial head position immediately when play begins); one counter to track where the tail is, and one to track where the head is. Whenever the snake moves, and the distance between these two counters is equal to the length of the snake, increment both. If the distance is less, then simply increment the head counter. If either counter exceeds 24 then loop it back to 0. If the head counter is less than the tail counter than add 25 to the former within the comparison.

With each movement, put the snake's new head location into the positionBuffer array where the head counter specifies. Disable the pixel of the position in the array the tail counter specifies (no need to change the positionBuffer entry for the tail, the head will eventually overwrite it again anyway), then use a matrix.getPixel() to check if the new head position already contains a lit pixel. If it does, and it's the apple, then increment length and draw a new apple (again use matrix.getPixel() to find a safe location). If it's not the apple then game over. If it's not lit at all then enable that pixel for the new head position.

Thank you so much for this detailed explaination, but unfortunately it's too late. I already gave all the stuff back to my teacher, so I can't change it anymore :/