hello all, i have been bored this week and made a few old school games "Asteroids and Space invaders" and today i decided to make snake, yes i know many have made this but i like to learn by myself as much as possible. I designed the game so it can grow the snake however much "unsigned int max" and up to 128 turns using a byte array. The array pushes forward one each time the snake moves thus the movements of the snake go back 1px each time. Any how the snake part was easy and i am trying to make it as efficient as possible and to that extent i am struggling to work out how to generate a position to load the coins and bonus treat in relation to the space NOT occupied by the snake, i don't even want to try a random seed and compare it to the snake occupied space, then re roll if a collision occurs as that could loop forever and i can't think what else i can try while maintaining a random position to load the coins?
Oh i amusing the u8g2lib so i have to implement an extra functions for increment outside the picture loop, in case you wonder about the duplication.
What would be the best way to load a coin - treat in a space not occupied by the snake while keeping it random?
Here is my code so far for snake
#include <Arduino.h>
#include <U8g2lib.h> //#include "U8glib.h"
#include <EEPROM.h>
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif
// ====================== Pins used ============================
const byte top_left_Button_Pin = 4;
const byte bottom_left_Button_Pin = 16;
const byte center_Button_Pin = 18;
const byte top_right_Button_Pin = 15;
const byte bottom_right_Button_Pin = 2;
// ====================== SET SCREEN ADDRESS ===================
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
// ======================= SYSTEM VARIABLES ====================
byte user_x = 64, user_y = 32;
byte coin_x = 0, coin_y = 0;
byte bonusTreat_x = 0, bonusTreat_y = 0;
static unsigned int treatTimer = 1000;
int snakeLength = 10;
byte directions[128] {2}; // start with moving right
byte directionPosition[128] {0}; // the position the direction relates too within the snake
unsigned int score = 0;
byte lifes = 3;
unsigned int highScore = 0;
bool pauseGame = false;
// TO DO's
// load coins and treats in a zone not occupied by the snake
// coins and bonus treats
// collision with snake body
// score, lifes - pause game
void setup() {
Serial.begin(115200);
u8g2.begin();
u8g2.setColorIndex(1);
u8g2.setFontPosTop();
u8g2.setFont(u8g_font_profont12);
randomSeed(analogRead(36));
loadHighScore();
}
void loop() {
buttons();
unsigned long currentMillis = millis();
static unsigned long previousMillis = 0;
const int speed = 100;
if (currentMillis - previousMillis >= speed) {
u8g2.firstPage();
do {
loadBlock();
loadCoin();
}
while (u8g2.nextPage());
movement();
previousMillis = currentMillis;
}
loadCoin();
collisions();
}
void loadHighScore() {
const byte EEPROM_Key = 101;
if (!EEPROM.begin(64)) { // try to allocate 64 bytes
Serial.println(F("Failed to initialise EEPROM"));
}
if (EEPROM.read(0) != EEPROM_Key) {
EEPROM.put(0, EEPROM_Key);
EEPROM.commit();
Serial.println(F("First save ?"));
}
else {
EEPROM.get(1, highScore);
Serial.print(F("Loaded highScore ")); Serial.println(highScore);
}
}
void buttons() { // 1 up, 2 right, 3 down , 4 left
if (digitalRead(bottom_left_Button_Pin) == HIGH && directions[0] != 2) {
pushArray(4);
}
else if (digitalRead(bottom_right_Button_Pin) == HIGH && directions[0] != 4) {
pushArray(2);
}
else if (digitalRead(top_left_Button_Pin) == HIGH && directions[0] != 3) {
pushArray(1);
}
else if (digitalRead(top_right_Button_Pin) == HIGH && directions[0] != 1) {
pushArray(3);
}
else if (digitalRead(center_Button_Pin) == HIGH) {
unsigned long currentMillis = millis();
static unsigned long previous_Center_Button_Millis = 0;
if (currentMillis - previous_Center_Button_Millis >= 500UL) {
pauseGame = !pauseGame;
previous_Center_Button_Millis = currentMillis;
}
}
}
void pushArray(byte num) {
if (directions[0] != num) {
for (byte i = 127; i > 0; i--) {
directions[i] = directions[i - 1];
directionPosition[i] = directionPosition[i - 1];
}
directions[0] = num;
directionPosition[0] = 1;
}
}
byte temp_x = user_x, temp_y = user_y;
void drawSnake(byte pos) {
if (directions[pos] == 1) { // 1 up
if (temp_y < 64) {
temp_y += 2;
}
else {
temp_y = 0;
}
}
else if (directions[pos] == 2) { // 2 right
if (temp_x > 0) {
temp_x -= 2;
}
else {
temp_x = 128;
}
}
else if (directions[pos] == 3) { // 3 down
if (temp_y > 0) {
temp_y -= 2;
}
else {
temp_y = 64;
}
}
else if (directions[pos] == 4) { // 4 left
if (temp_x < 128) {
temp_x += 2;
}
else {
temp_x = 0;
}
}
u8g2.drawBox(temp_x, temp_y, 2, 2); // draw snake
}
void loadBlock() {
// how many increments before next dir block
temp_x = user_x, temp_y = user_y;
byte pix = 0;
for (int i = 1; i < 128; i++) {
if (directionPosition[i] > 0 && directionPosition[i] < snakeLength) { // load the next direction position
for (int n = 0; n < directionPosition[i]; n++) {
if (pix < snakeLength) {
drawSnake(i - 1); // draw snake in current direction until next direction position
pix++;
}
else {
break;
}
}
}
else if (directionPosition[i] == 0 || directionPosition[i] >= snakeLength) {
for (int n = pix; n < snakeLength; n++) { // if no next direction block, continue with current
drawSnake(i - 1);
}
break;
}
}
}
void loadCoin() {
if (coin_x == 0) {
coin_x = random(2, 126);
coin_y = random(2, 62);
}
u8g2.drawDisc(coin_x, coin_y, 3);
}
void collisions() {
// TO DO
// coins and bonus treats
// collision with snake body
}
void movement() {
if (directions[0] == 1) { // 1 up
if (user_y > 0) {
user_y -= 2;
}
else {
user_y = 64;
}
}
else if (directions[0] == 2) { // 2 right
if (user_x < 128) {
user_x += 2;
}
else {
user_x = 0;
}
}
else if (directions[0] == 3) { // 3 down
if (user_y < 64) {
user_y += 2;
}
else {
user_y = 0;
}
}
else if (directions[0] == 4) { // 4 left
if (user_x > 0) {
user_x -= 2;
}
else {
user_x = 128;
}
}
// keep track of direction in relation to snake position
for (byte i = 1; i < 128; i++) {
if (directionPosition[i] > 0 && directionPosition[i] < snakeLength) {
directionPosition[i]++;
}
}
}