Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //DISPLAY INI start
- #include <SPI.h>
- #include <Wire.h>
- #include <Adafruit_GFX.h>
- #include <Adafruit_SSD1306.h>
- #define OLED_RESET 4
- Adafruit_SSD1306 display(OLED_RESET);
- #define NUMFLAKES 10 //probably not needed leftovers from OLED demo
- #define XPOS 0
- #define YPOS 1
- #define DELTAY 2
- #define LOGO16_GLCD_HEIGHT 64
- #define LOGO16_GLCD_WIDTH 128
- static const unsigned char PROGMEM logo16_glcd_bmp[] = //Here I make the initial splash screen
- {
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
- 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
- 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
- 0xC0, 0x3F, 0xC0, 0xFF, 0x80, 0x1F, 0xF0, 0x03, 0xF8, 0x7E, 0x00, 0x00, 0xFE, 0x03, 0xF8, 0x07,
- 0xC0, 0xFF, 0xC3, 0xFF, 0xC0, 0x7F, 0xFC, 0x03, 0xF8, 0xFE, 0x00, 0x03, 0xFF, 0x87, 0xF8, 0x07,
- 0xC3, 0xFF, 0xC7, 0xFF, 0xC0, 0xFF, 0xFF, 0x03, 0xF8, 0xFE, 0x00, 0x07, 0xFF, 0xC7, 0xF8, 0x07,
- 0xC3, 0xFF, 0xCF, 0xFF, 0xC3, 0xFF, 0xFF, 0x83, 0xF9, 0xFC, 0x00, 0x0F, 0xFF, 0xE7, 0xF8, 0x07,
- 0xC7, 0xFF, 0xDF, 0xFF, 0xC3, 0xFF, 0xFF, 0x03, 0xF9, 0xFC, 0x00, 0x0F, 0xFF, 0xF7, 0xF8, 0x07,
- 0xC7, 0xFF, 0xDF, 0xFF, 0xC7, 0xFF, 0xFE, 0x03, 0xF9, 0xFC, 0x00, 0x0F, 0xFF, 0xF7, 0xF8, 0x07,
- 0xC7, 0xFF, 0xDF, 0xFF, 0x87, 0xFF, 0xFC, 0x03, 0xFB, 0xFC, 0x00, 0x0F, 0xE7, 0xF3, 0xF8, 0x07,
- 0xC7, 0xF0, 0x1F, 0xE0, 0x0F, 0xF8, 0x18, 0x03, 0xFB, 0xF8, 0x00, 0x1F, 0xC3, 0xFB, 0xF8, 0x07,
- 0xC7, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x00, 0x03, 0xFF, 0xF8, 0x00, 0x1F, 0xC3, 0xFB, 0xF8, 0x07,
- 0xC7, 0xF0, 0x07, 0xF8, 0x0F, 0xE1, 0xFF, 0xF3, 0xFF, 0xF0, 0x00, 0x1F, 0xC7, 0xF3, 0xF8, 0x07,
- 0xC7, 0xFF, 0xC7, 0xFE, 0x0F, 0xE3, 0xFF, 0xF3, 0xFF, 0xF0, 0x00, 0x1F, 0xCF, 0xF7, 0xF8, 0x07,
- 0xC7, 0xFF, 0xC3, 0xFF, 0x0F, 0xE3, 0xFF, 0xF3, 0xFF, 0xFC, 0x00, 0x1F, 0xDF, 0xF7, 0xF8, 0x07,
- 0xC7, 0xFF, 0xC0, 0xFF, 0x8F, 0xE3, 0xFF, 0xE3, 0xFF, 0xFC, 0x00, 0x1F, 0xDF, 0xE7, 0xF8, 0x07,
- 0xC7, 0xFF, 0xC0, 0x7F, 0xCF, 0xE3, 0xFF, 0xE3, 0xFF, 0xFE, 0x08, 0x1F, 0xDF, 0xE7, 0xF8, 0x07,
- 0xC7, 0xFF, 0xC0, 0x3F, 0xCF, 0xE1, 0xFF, 0xE3, 0xF8, 0xFE, 0x01, 0x1F, 0xDF, 0xC7, 0xF8, 0x07,
- 0xC7, 0xF0, 0x00, 0x3F, 0xCF, 0xF0, 0x1F, 0xE3, 0xF8, 0xFE, 0x00, 0x5F, 0xCF, 0x07, 0xF8, 0x07,
- 0xC7, 0xF0, 0x00, 0x7F, 0xC7, 0xFC, 0x3F, 0xC3, 0xF8, 0xFE, 0x03, 0xFF, 0xC0, 0x03, 0xFC, 0x07,
- 0xC7, 0xF0, 0x1F, 0xFF, 0xC7, 0xFF, 0xFF, 0xC3, 0xF8, 0xFE, 0x23, 0xFF, 0xC0, 0x03, 0xFF, 0xE7,
- 0xC7, 0xF0, 0x1F, 0xFF, 0xC3, 0xFF, 0xFF, 0x83, 0xF8, 0xFE, 0x7F, 0xFF, 0xC0, 0x03, 0xFF, 0xE7,
- 0xC7, 0xF0, 0x1F, 0xFF, 0xC1, 0xFF, 0xFF, 0x03, 0xF8, 0xFE, 0x7F, 0xDF, 0xC0, 0x03, 0xFF, 0xE7,
- 0xC7, 0xF0, 0x1F, 0xFF, 0x80, 0xFF, 0xFE, 0x03, 0xF8, 0xFE, 0x3F, 0x1F, 0xC0, 0x01, 0xFF, 0xE7,
- 0xC7, 0xF0, 0x1F, 0xFF, 0x00, 0x7F, 0xFC, 0x03, 0xF8, 0xFE, 0x06, 0x1F, 0xC0, 0x00, 0xFF, 0xE7,
- 0xC7, 0xF0, 0x1F, 0xFC, 0x00, 0x1F, 0xF8, 0x03, 0xF8, 0xFE, 0x00, 0x1F, 0xC0, 0x00, 0x7F, 0xE7,
- 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
- 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
- 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x87, 0xFF, 0xE7, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0x8E, 0x3F, 0xFF, 0x9F, 0xFF, 0xFF, 0xFF,
- 0xDB, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0x7F, 0xFB, 0xDF, 0xFF, 0xFF, 0xFF,
- 0xDB, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0x7F, 0xFB, 0xDF, 0xFF, 0xFF, 0xFF,
- 0xDB, 0x18, 0x34, 0xD3, 0x1C, 0x73, 0xF7, 0xF8, 0x3F, 0xDF, 0x7C, 0x71, 0xC7, 0x3D, 0x31, 0x97,
- 0xC6, 0xEB, 0xB5, 0xEE, 0xEB, 0xAD, 0xE7, 0xFB, 0xBF, 0xDF, 0x7B, 0xBB, 0xDA, 0xDE, 0xEE, 0xAB,
- 0xCE, 0xEE, 0x73, 0xEE, 0x0B, 0xF1, 0xF7, 0xFE, 0x7F, 0xDF, 0x7B, 0xBB, 0xDB, 0x1E, 0xE0, 0xAB,
- 0xD6, 0xED, 0xF3, 0xEE, 0xFB, 0xED, 0xF7, 0xFD, 0xFF, 0xDF, 0x7B, 0xBB, 0xDA, 0xDE, 0xEF, 0xAB,
- 0xD6, 0xEB, 0xB5, 0xEE, 0xEB, 0xAD, 0xF7, 0xFB, 0xBF, 0xDB, 0x6B, 0xBA, 0xDA, 0xDE, 0xEE, 0xAB,
- 0x93, 0x18, 0x24, 0xC7, 0x1C, 0x72, 0xF7, 0xF8, 0x3F, 0x82, 0x0C, 0x7D, 0xDB, 0x2C, 0x71, 0xAB,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xB7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
- };
- #if (SSD1306_LCDHEIGHT != 64) //probably not needed
- #error("Height incorrect, please fix Adafruit_SSD1306.h!");
- #endif
- //DISPLAY INI END
- //bullet
- byte rounds = 1; //round counter
- byte led = 13; //default LED
- byte speaker = 11; //speaker pin
- byte knob = 0; //analog knob
- byte landscape[128]; //landscape is an array containing height data. This is a byte, not int, as I am running out of memory. Adafruit takes 82% of RAM so no much left for the game itself
- byte tankAX = 15; //hard coded tank A position in X axis
- byte tankBX = 113; //hard coded tank B position in X axis
- bool playerA = true; //PlayerA starts. When false that means player B is playing
- void GenerateLandscape(){ //function to generate landscape -
- landscape[0] = 63; //very left is at zero. Note that adafruit library has 0,0 on the top left corner, thats why it is 63, so pixel no.64
- landscape[31] = random(32,63); // 1/4 from the left edge, random height from a range
- landscape[63] = random(20,63); // middle of the screen, again a random height.
- landscape[95] = random(32,63); // 3/4 towards right edge, random height.
- landscape[127] = 63; //right edge, at zero
- float increment = landscape[31] - landscape[0]; //this + below function generates slopes between the randomly generated heights. This should be a loop, but there are just 3 gaps to fill and I was lazy.
- increment = increment/32;
- for (byte i = 1; i <= 31; i++){
- landscape[0+i] = landscape[0]+increment*i;
- }
- increment = landscape[63] - landscape[31];
- increment = increment/32;
- for (byte i = 1; i <= 31; i++){
- landscape[31+i] = landscape[31]+increment*i;
- }
- increment = landscape[95] - landscape[63];
- increment = increment/32;
- for (byte i = 1; i <= 31; i++){
- landscape[63+i] = landscape[63]+increment*i;
- }
- increment = landscape[127] - landscape[95];
- increment = increment/32;
- for (byte i = 1; i <= 31; i++){
- landscape[95+i] = landscape[95]+increment*i;
- }
- }
- void draw_terrain(){ //for drawing terrain. I use fast line drawing.
- for (int i = 0; i < 129; i++) {
- display.drawFastVLine(i,landscape[i],63, 1);
- }
- }
- void draw_tanks(){ //tanks are just circles of a set radius. X position fixed, Y position taken from the landscape array.
- display.drawCircle(tankAX, landscape[tankAX], 4, 1);
- display.drawCircle(tankBX, landscape[tankBX], 4, 1);
- display.setCursor(80,0); //drawing the rounds number
- display.print("Round ");
- display.print(rounds);
- }
- void shoot(){ //this really is the main loop of the game. Everything takes place here.
- int tankX; //tank is the current tank Variable for X position
- int tankY;
- int targetX; //target is the enemy tank
- int targetY;
- float bulletX; //variable for bullets This is position on X axis
- float bulletY; //variable for bullets This is position on Y axis
- float bulletXX; //convention is that XX is the velocity of the bullet in the X direction
- float bulletYY; //
- float angle = 1; //angle in radians. All calculations are in radians by default
- float power = 45;
- bool aim1 = true; //aim1 is for angle
- bool aim2 = true; //aim2 is for power
- int button;
- if (playerA == true){ //assign correct coordinates for tank (current player) and target (enemy)
- tankX = tankAX;
- tankY = landscape[tankAX];
- targetX = tankBX;
- targetY = landscape[tankBX];
- }
- if (playerA ==false){
- tankX = tankBX;
- tankY = landscape[tankBX];
- targetX = tankAX;
- targetY = landscape[tankAX];
- }
- while (aim1 == true){ //in this loop you make angle aim
- angle = analogRead(knob); //read the analog input
- angle = angle / 670 * 3.1416; //convert analog input to radians. I divide by 670 and not 1023 because I used 3.3V as reference. I just had it on the board for the OLED and was easier than dragging 5V just for potentiometer. Zero to Pi is 0 to 180 degrees.
- display.setCursor(0,0); //writing the current angle value
- display.print("Angle:");
- display.println(angle);
- display.drawLine(tankX, tankY, tankX + cos(angle)*15, tankY - sin(angle)*15,1); //this draws the turret.
- draw_terrain();
- draw_tanks();
- display.display();
- display.clearDisplay();
- delay(10); //delay so I won't work at crazy framerates (can cause screen flickering in OLED). ~100FPS should be fast enough.
- button = digitalRead(2); //read button state
- if (button == 0){ //detect click.
- delay(50); //wait 50ms and see if it was really pressed. Lame button noise detection.
- if (button ==0){
- aim1= false;
- }
- }
- }
- delay(100); //I give you 100ms to get your finger off that button. Kinda Lame as well, and should be easy to fix with few lines.
- while (aim2 == true){//now power selection
- power = analogRead(knob);
- power = power / 670; //again, divide by 670 due to 3.3v as reference. This makes power to be a range of 0 to 1. I use floats so that's cool.
- display.setCursor(0,0);
- display.print("Angle:");
- display.println(angle); //display the angle
- display.print("Power:");
- display.println(power); //and current power
- display.drawLine(tankX, tankY, tankX + cos(angle)*15, tankY - sin(angle)*15,1); //draw turret Would be cool to modify it so it gets larger when the power is higher ;)
- draw_terrain();
- draw_tanks();
- display.display();
- display.clearDisplay();
- delay(10); //100FPS limiter here as well
- button = digitalRead(2); //read button state
- if (button == 0){ //detect click, lame way again, sorry
- delay(50);
- if (button ==0){
- aim2= false;
- }
- }
- }
- //now angle and power is set. Let's get this bullet going!
- bool hit = false; //hit is true when you hit.
- bulletXX = cos(angle)*5*power; //calculating bullet velocity. I multiply by 5 to get a nice distance between calculations. This was trial end error. I do not need to calculate sub-pixel movement of the bullet, so if at high power I get movement by ~3 pixels that's ok.
- bulletYY = -sin(angle)*5*power;
- bulletX = tankX; //bullet starts at current player position
- bulletY = tankY;
- float distance; //distance is used for hit-miss calculations. I wanted to have doppler effect driven sounds, but it turned out to be weird. It worked and all, but was not ear-pleasing.
- float distanceX;
- float distanceY;
- while(hit == false){ //loop for the bullet to fly
- display.drawLine(tankX, tankY, tankX + cos(angle)*15, tankY - sin(angle)*15,1); //draw turret
- draw_terrain();
- draw_tanks();
- display.drawPixel(bulletX, bulletY, WHITE); //this is the bullet trace. I do not clear the screen inside of this while-loop, so I do not need an array to store the old bullet positions.
- distanceX = targetX - bulletX; //calculat the distance between the bullet and the target
- distanceY = targetY - bulletY;
- distance = sqrt(distanceX*distanceX+distanceY*distanceY);
- display.display();
- if (distance < 5){ //if you are closer than 5 pixels - consider this a hit
- display.setCursor(10,30);
- display.print("Player "); //some congratulations
- if (playerA == true){
- display.print("1 WINS!!!");
- }else{
- display.print("2 WINS!!!");
- }
- display.display();
- tone(speaker,440,2000); //a monotone noise for the winner!
- hit = true; //hit! leave that while loop!
- delay(5000); //5 sec delay after hitting a target
- }
- int intbulletX = bulletX; // convert the bullet X position to int.
- if (bulletY > landscape[intbulletX] || bulletY > 63 ){ //detect hitting the ground or going below the screen.
- hit = true; //yeah, I make it hit=true, but you are hitting the ground buddy ;)
- }
- bulletYY = bulletYY + 0.07; //bullet Y velocity changes due to gravity. I add a number (got by trial and error) so that velocity will "increase", but increase is in "down" direction - remember the adafruit having 0.0 at top left.
- bulletX = bulletX + bulletXX; //position X affected by velocity
- bulletY = bulletY + bulletYY; //position Y affected by velocity
- tone(speaker,440+bulletY); //tone o 440Hz plus the height of the bullet
- }
- //this part is when you leave the while loop of the current bullet flight.
- noTone(speaker);
- aim1= true;
- aim2 = true;
- }
- void setup() {
- Serial.begin(9600);
- // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
- display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3D (for the 128x64)
- // init done
- display.clearDisplay(); // Clear the buffer.
- // initialize the digital pin as an output.
- pinMode(led, OUTPUT);
- pinMode(speaker, OUTPUT);
- pinMode(knob, INPUT);
- pinMode(2, INPUT); //button
- digitalWrite(2, HIGH); //enabled pull-up, so no resistor needed for button operations. Neat-o.
- randomSeed(analogRead(0)); //random seed for landscape generation
- display.drawBitmap(0, 0, logo16_glcd_bmp, 128, 64, 1); //splash screen
- display.display();
- delay(3000);
- display.clearDisplay();
- display.setTextSize(1);
- display.setTextColor(WHITE);
- GenerateLandscape();
- }
- // the loop routine runs over and over again forever:
- void loop() {
- shoot(); //call shooting
- display.display();
- display.clearDisplay();
- delay(1000); //one second delay between shots
- if (playerA == true){ //switch between player A and B
- playerA = false;}else{
- playerA = true;
- rounds++;} //increment round count after switch from B to A
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement