I'm currently working on a small spaceship game project to help me learn Arduino code. The hardware is simply an OLED display with some buttons, and I'm programming an ESP32 devkit.
Right now I have the spaceship moving around and I've started adding in a gun effect of shooting a pixel across the screen. It's quite simple when shooting just 1 bullet, but to fire a second one while the first is still on the screen is where it gets difficult for me. The temporary way I've gone about this is to make a separate variable set for each potential bullet that could be fired. This works fine, but is very repetitive and I have a feeling there could be a much more efficient way to go about it. I have looking into different ways of creating and storing values in variables, but I haven't been able to find a good way to create temporary bullet position values without throwing off something running simultaneously.
Here's my code. I think I labeled everything fairly well, let me know if anything is unclear with what I'm going for. Thanks in advance
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// Timer set up
hw_timer_t *timer = NULL;
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS1 0x3c
Adafruit_SSD1306 display1(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
//PinMode Var
const int A = 17;
const int B = 16;
const int start = 4;
const int trig = 2;
const int up = 13;
const int left = 27;
const int right = 12;
const int down = 14;
// Spaceship Var
// x and y are ship position. I know it's bad for variable to be so nondescriptive. this program got too big before I started giving things better variables.
int x = (SCREEN_WIDTH - 5) / 2;
int y = (SCREEN_HEIGHT - 5) / 2;
int xdir = 0; // ship x facing direction (0 is not facing left or right, 1 is left, 2 is right)
int ydir = 1; // ship y facing direction (0 is not facing up or down, 1 is up, 2 is down)
// Shoot right Var
bool r1bullet = false; // Variable for if bullet is active
int r1xbul; // bullet x position
int r1ybul; // bullet y position
int r1move; // bullet movement value
bool r2bullet = false;
int r2xbul;
int r2ybul;
int r2move;
bool r3bullet = false;
int r3xbul;
int r3ybul;
int r3move;
// Shoot left Var
bool l1bullet = false;
int l1xbul;
int l1ybul;
int l1move;
bool l2bullet = false;
int l2xbul;
int l2ybul;
int l2move;
bool l3bullet = false;
int l3xbul;
int l3ybul;
int l3move;
// Bullet Speed
int sbul = 5;
// Reload time
int reload = 500;
// Delay to set Game Speed
int gameSpeed = 30;
void setup() {
pinMode(A, INPUT_PULLUP);
pinMode(B, INPUT_PULLUP);
pinMode(start, INPUT_PULLUP);
//pinMode(trig, INPUT_PULLUP);
pinMode(up, INPUT_PULLUP);
pinMode(left, INPUT_PULLUP);
pinMode(right, INPUT_PULLUP);
pinMode(down, INPUT_PULLUP);
Serial.begin(9600);
display1.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS1);
display1.clearDisplay();
display1.display();
display1.setTextColor(WHITE);
display1.setTextWrap(false);
display1.setTextSize(1);
// Set timer frequency to 1Mhz
timer = timerBegin(1000000);
}
void loop() {
/*
// Button Testing
display1.setCursor(0,0);
if (!digitalRead(A)){
display1.println("A");
}
if (!digitalRead(B)){
display1.println("B");
}
if (!digitalRead(start)){
display1.println("start");
}
*/
// Move unless touching edge
// Move up
if (!digitalRead(up) && digitalRead(down) && y >= 2) {
y = y - 1; // Move Ship 1 pixel
ydir = 2; // Change facing pixel
xdir = 0;
}
// Move down
else if (!digitalRead(down) && digitalRead(up) && y <= SCREEN_HEIGHT - 7) { // <- Change these values to fit screen size (64-7)
y = y + 1;
ydir = 1;
xdir = 0;
}
// Move left
if (!digitalRead(left) && digitalRead(right) && x >= 2) {
x = x - 1;
xdir = 1;
ydir = 0;
}
// Move right
else if (!digitalRead(right) && digitalRead(left) && x <= SCREEN_WIDTH - 7) { // <- Change these values to fit screen size (128-7)
x = x + 1;
xdir = 2;
ydir = 0;
}
// Draw SpaceShip
if (xdir == 1) {
display1.drawPixel(x - 1, y + 2, WHITE);
}
if (xdir == 2) {
display1.drawPixel(x + 5, y + 2, WHITE);
}
if (ydir == 2) {
display1.drawPixel(x + 2, y - 1, WHITE);
}
if (ydir == 1) {
display1.drawPixel(x + 2, y + 5, WHITE);
}
display1.fillRect(x, y, 5, 5, WHITE);
// If Shoot Button is pressed, fire a bullet. This is the clunkiest part of the code, that I want to know if there is a better way of doing that achieves an equivilant result.
if (!digitalRead(A) && timerReadMilis(timer) >= reload) {
timerWrite(timer, 0);
if (ydir == 1) {
}
else if (xdir == 1) {
if (l1bullet && l2bullet && !l3bullet) {
l3bullet = true;
l3xbul = x - 1;
l3ybul = y + 2;
}
if (l1bullet && !l2bullet) {
l2bullet = true;
l2xbul = x - 1;
l2ybul = y + 2;
}
if (!l1bullet) {
l1bullet = true;
l1xbul = x - 1;
l1ybul = y + 2;
}
}
else if (ydir == 2) {
}
else if (xdir == 2) {
if (r1bullet && r2bullet && !r3bullet) {
r3bullet = true;
r3xbul = x - 1;
r3ybul = y + 2;
}
if (r1bullet && !r2bullet) {
r2bullet = true;
r2xbul = x + 5;
r2ybul = y + 2;
}
if (!r1bullet) {
r1bullet = true;
r1xbul = x + 5;
r1ybul = y + 2;
}
}
}
// More clunkyness
// If bullet is being fired, draw it and move it by bullet speed every cycle
if (r3bullet) {
display1.drawPixel(r3xbul + (r3move * sbul), r3ybul, WHITE);
r3move = r3move + 1;
if (r3xbul + (r3move * sbul) >= 128) {
r3move = 0;
r3bullet = false;
}
}
if (r2bullet) {
display1.drawPixel(r2xbul + (r2move * sbul), r2ybul, WHITE);
r2move = r2move + 1;
if (r2xbul + (r2move * sbul) >= 128) {
r2move = 0;
r2bullet = false;
}
}
if (r1bullet) {
display1.drawPixel(r1xbul + (r1move * sbul), r1ybul, WHITE);
r1move = r1move + 1;
if (r1xbul + (r1move * sbul) >= 128) {
r1move = 0;
r1bullet = false;
}
}
if (l3bullet) {
display1.drawPixel(l3xbul - (l3move * sbul), l3ybul, WHITE);
l3move = l3move + 1;
if (l3xbul - (l3move * sbul) <= 0) {
l3move = 0;
l3bullet = false;
}
}
if (l2bullet) {
display1.drawPixel(l2xbul - (l2move * sbul), l2ybul, WHITE);
l2move = l2move + 1;
if (l2xbul - (l2move * sbul) <= 0) {
l2move = 0;
l2bullet = false;
}
}
if (l1bullet) {
display1.drawPixel(l1xbul - (l1move * sbul), l1ybul, WHITE);
l1move = l1move + 1;
if (l1xbul - (l1move * sbul) <= 0) {
l1move = 0;
l1bullet = false;
}
}
// Display everything
display1.display();
display1.clearDisplay();
delay(gameSpeed);
}