guest@BipbopPC:~/writing$ less jank-invaders.md
Fitting Space Invaders into 2 KB of SRAM
Dec 2020 · Arduino · C++ · embedded
The whole game board is one 1-D array mapped onto the serpentine wiring of a 10x10 NeoPixel matrix. Pretty much everything else in the design came from that decision, and from having 2 KB of SRAM to work with.
Merced College CPSC-42, Computer Architecture & Organization. Professor Kanemoto, December 13th, 2020. Jank Invaders: In Space, No One Can Hear You ¬¾ְֲ؇—▒☻ﷺ
## Abstract
Jank Invaders is a game I’ve created using a simulated Arduino controller on Tinkercad. It is meant to somewhat resemble Space Invaders on the Atari with a few elements born out of necessity that make it different. To play Jank Invaders, the player must fire beam lasers at the quickly spawning aliens to keep them at bay for as long as possible. There is a short cooldown after firing, but instead of shooting bullets, the beam will destroy any alien ship directly that is either in front of the player, or is about to pass in front of the player. Once the aliens have reached the bottom row, the screen will begin flashing in a beautiful, hopefully Hotline Miami-esque, collage of colors.
## Parts and Materials
(All parts are digital, from Tinkercad)
- * Arduino Uno
- * 3 10 KΩ Resistors
- * 3 Push Buttons
- * Breadboard
- * Wires
- * An [X by X] NeoPixel Matrix where X is an even number
## Construction
The physical build for this project is very simple. It may even be too simple, and I’m starting to get worried it won’t be enough for me to get a good grade. The protoboarding portion of this project simply includes three push buttons with pulldown resistors going into the digital input pins of the Arduino controller. The other physical component of this project was the NeoPixel matrix. They are individual RGB LED components that can be placed in any configuration. Each line in the LED matrix isn’t laid upon another in the same orientation. To make programming the alien movement easier, I flipped each line of LEDs so that the end of one line doesn’t have to be wired to the opposite end of the matrix, it can just be wired to an adjacent NeoPixel component. This ended up causing issues that will be mentioned later.
## Circuit Diagrams

The diagram above shows the WS2811 components used, as well as the way they must be configured. Any square amount of these components may be used, with slight adjustments to the code being needed.

This diagram shows how digital input is received from the pushbuttons.
## Code
The main challenge of this assignment, with a very simple physical layout, was programming. When I first started, it seemed a lot more complicated than it ended up being, but I managed to simplify the game of space invaders enough to make it fairly easy to pull off making inside of the Arduino C code. I broke the game down into two completely different areas. The bottom row of the matrix is always reserved for the player, and may as well be its own game, since it technically has no interaction with the rest of the LED matrix. The rest of the rows are for aliens and projectiles. From the perspective of the code, the matrix isn’t broken up into rows, but it is one long line. This isn’t important for the aliens, since the line is their path of movement, but it proves that I didn’t think too far ahead, since projectiles, without having some kind of code to correct it, mirror back and forth across the Y axis. To correct this, I sketched out an algorithm (image below) in notepad and then integrated it into the code.

After having the game board abstracted into a long line with imaginary rows, creating the rest of the game was fairly simple. I decided that aliens would spawn infinitely for no real reason. It was just an impulsive decision. The board was now one integer array, and I decided to make aliens, the player, and projectiles all have their own integer value. I had originally planned to make the aliens have up to three hit points, being various colors depending on how many remaining hit points they had, but decided to leave only one alien type, the red LED alien. I had already revamped my code entirely three times, so I was getting sick of having to restart, and small changes like that ended up being what made me have to restart, and because of this, the alien int value remains between 1 and 3. When an update method is called, it will check the value at each index of the array, and light the assigned pixel the correct color to represent the element at that index of the array.

## Implementation
Hopefully this doesn’t end up being a problem, but I didn’t physically build the project. Since we are doing everything remotely, and I don’t physically have the NeoPixel components I ended up using, I did my project entirely in TinkerCad without making it physically. This ended up causing performance issues. Since TinkerCad has to treat the components as actual electronic components, the calculations get very complicated with three hundred LEDs wired in parallel in the 100 WS2811 components. The simulator will often run at 10 to 20 milliseconds per second of real time. This has made it practically impossible to test the game as it’s intended to be played, so I guess I’m creating it assuming that the player has lightning fast reflexes. The sped up version I show in my presentation will probably look weird.

## Conclusion
This project has ended up having many issues. I blame most of them on using TinkerCad. This project most likely would have shaped up much better if I could either create what I planned in person with my Elegoo controller, or if I could use a program that allows the use of hardware acceleration. The Eagle simulator is five hundred dollars, though, so I guess TinkerCad is the best I’m going to get. Otherwise, the game works, and I learned a fair bit about how display in general, now knowing how to actually create my own displays out of LED strips. My biggest regret is not initially deciding to build the project with real components.
## References
- * Adafruit. (na). WS2811 Circuit Diagram. Retrieved December 13, 2020, from https://cdn-learn.adafruit.com/assets/assets/000/036/085/original/leds_schem.png?1475009037
- * Array. (na). Retrieved December 13, 2020, from https://www.arduino.cc/reference/en/language/variables/data-types/array/
- * Bekathwia. (2018, November 29). Circuit design NeoPixel Strip. Retrieved December 13, 2020, from https://www.tinkercad.com/things/hMoLHIEK0Ny-neopixel-strip
- * Steve Dickie, S. (2017, March 20). 8.1 – Introduction to NeoPixels. Retrieved December 13, 2020, from http://www.highschoolmaker.com/electronics-with-micro-controllers/chapter-8-neopixels/8-1-introduction-to-neopixels/
## Appendices
### Appendix 1: Starting template
This is an image of Bekathwia’s project. I used this as a starting point to learn how the NeoPixel components worked. The code included in the project is very simple, and just changes the colors of the lights.


### Appendix 2: Code Dump
This is just a dump of the raw text of my Arduino code.
#include <Adafruit_NeoPixel.h>
#define PIN 2 // input pin Neopixel is attached to
#define NUMPIXELS 100// number of neopixels in Ring
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
int delayval = 100; // timing delay
int bLS = 0; // Left Button
int bMS = 0; // Middle Button
int bRS = 0; // Right Button
int cooldown = 0; // Checks if the player has shot in the last button press
int tick = 0; // Keeps track of game stage
int blueD = 0;
int sp[90]; // Screenspace for Alien and bullets
int playerPos = 0; // Position of player on bottom row
// Starts input channels and allows for serial logging
void setup() {
pinMode(5, INPUT);
pinMode(6, INPUT);
pinMode(7, INPUT);
pixels.begin(); // Initializes the NeoPixel library.
Serial.begin(9600);
for (int i = 0; i < 90; i++) {
sp[i] = 0;
}
}
// Fish?
void loop() {
gameTick();
Serial.print(bMS);
//setColor();
delay(delayval); // Delay for a period of time (in milliseconds).
pixels.show();
}
// Moves game state forward
void gameTick() {
checkButtons(); // Checks for player inputs
alienMovement(); // Moves every alien forward
if (tick == 1) spawnAlien(); // Spawns an alien every 2 frames
setColor(); // Refreshes screen
if (tick == 2)
{
tick = 0; // Resets game tick (Only two)
}
tick++; // Next tick
// Processes player input
if (bMS == 1 && cooldown == 0) {
shoot();
} else if (bRS == 1) {
if (playerPos != 0) {
playerPos--;
}
} else if (bLS == 1) {
if (playerPos != 9) {
playerPos++;
}
}
if (sp[89] == 3) {
miami();
}
if (cooldown > 0) cooldown--;
//updateBullets();
}
// Bang bang
void shoot() {
cooldown = 4;
for (int i = 0; i < 9; i++) {
if (i % 2 == 0) {
sp[i * 10 + (9 - playerPos)] = 5; // Even
} else {
sp[i * 10 - (9 - playerPos) + 9] = 5; // Odd
}
}
//sp[80 + (9 - playerPos)] = 5; // Even
}
void updateBullets() {
for (int i = 0; i < 9; i++) {
if (i % 2 == 0) {
sp[i * 10 + (9 - playerPos)] = 5; // Even
} else {
sp[i * 10 - (9 - playerPos) + 9] = 5; // Odd
}
}
}
// Spawns an alien
void spawnAlien() {
sp[0] = 3;
}
// Moves each alien forward per tick
void alienMovement() {
for (int i = 90; i > -1; i--)
{
if (sp[i] != 0 && sp[i] < 4)
{
if (sp[i + 1] == 5) {
sp[i] = 0;
}
if (i < 90) {
sp[i + 1] = sp[i];
sp[i] = 0;
} else {
//End State
}
}
}
}
// Refreshes screen with appropriate colors
void setColor(){
for (int i = 0; i < 90; i++)
{
if (sp[i] != 0 && sp[i] < 4) {
pixels.setPixelColor(i, 255, 0, 0);
}
else if (sp[i] == 0) {
pixels.setPixelColor(i, 0, 0, 0);
}
else if (sp[i] == 5) {
pixels.setPixelColor(i, 0, 255, 0);
sp[i] = 0;
}
}
if (cooldown != 0) blueD = cooldown * 20;
else blueD = 0;
// Shows player position with blue LED
for (int i = 0; i < 10; i++) {
if (i == playerPos) pixels.setPixelColor(i + 90, blueD, blueD, 255);
else pixels.setPixelColor(i + 90, 0, 0, 0);
}
}
// Player Inputs
void checkButtons() {
bLS = digitalRead(7);
bMS = digitalRead(6);
bRS = digitalRead(5);
}
void miami() {
int r;
int g;
int b;
int count;
while (true) {
r += random(-1, 1);
g += random(-1, 1);
b += random(-1, 1);
if (count < 100) {
pixels.setPixelColor(count, r, g, b);
count++;
} else {
count = 0;
}
pixels.show();
}
}