Arduino Based SUPER MARIO game using tobiaso marduino library

in #utopian-io6 years ago (edited)

What Will I Learn?

In this instructable we will learn how to make the popular super mario game on arduino using the tobiaso marduino or SUPER MARDUINO library on github. how to properly connec the comonents on the arduino board and howsto calibrate game with push buttons.

20180216_141526.jpg

Requirements

We need these couples of arduino components in this tutorial

  • Nokia 5110 LCD display

20180215_125201.jpg

If you dont have this module you can get these on your old nokia 3310 or 5110 cellphone or you can just bought it online. I bought mine for just $5 on ebay when i was in college, These displays are small, but very readable and come with backlight. This display is made of 84x48 individual pixels, so you can use it for graphics, text or bitmaps. so less expensive than using oled display.

  • Push Buttons

20180215_125306.jpg

These buttons gives a nice soft click every time it's pressed so you know that you've definitely activated it. Their almost instant return make them great for building your own homemade button pad. it also make a good reset switch or user feedback for a microcontroller circuits.

  • Arduino Uno R3 board

20180215_102432.jpg

In this tutorial i am using the clone arduino r3 board,

It has 14 digital input/output pins (of which 6 can be used as PWM outputs), 6 analog inputs, a 16 MHz quartz crystal, a USB connection, a power jack, an ICSP header and a reset button.
It contains everything needed to support the microcontroller components i used this in any of my previous tutorials i have mega but i prepare to use this for easy breakdown.

  • Jumper wires

20180214_140431.jpg

We will use jumpers to connect on a breadboard or female header connector, size and color to distinguish the different working signals. we will use the male to male jumper for 7 segment and the buttons to connect to arduino.

  • Breadboard

20180214_140331.jpg

We will be using a Single Panel Breadboard it is a solderless device for temporary prototype with electronics and test circuit designs. both side of the breadboard is the power rail it is horizontal lining and the middle is the vertical rail for arduino components.

Difficulty

  • Basic

Tutorial Contents

  • SOFTWARE

we are going to use the arduino ide, to set the sketch for this, if you dont have make sure to download the Arduino IDE for your specific operating system. I’ll leave a link to where you can download this software: https://www.arduino.cc/en/Main/Software

  • LIBRARIES

To run the program and to make sketching a code easily we need to download these couples of libraries.

Adafruit-GFX-Library; https://github.com/adafruit/Adafruit-GFX-Library

Adafruit-PCD8544-Nokia-5110-LCD-library; https://github.com/adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library/

To run the marduino we need to download this library the sketch code for marduino is already on the zip file with .ino file for arduino IDE
GET HERE; https://github.com/tobiasbu/marduino

After downloading the ZIP file libraries add it to your arduino IDE libraries by locating the SKETCH include library then add ZIP library and then look for your zip file on your download folder.

To run the NOKIA 5110 display we need 5 digital output pins. the LIGHT pin can be used to control (via on/off or PWM) the backlight, the GND and the LIGht pin should connected to GND on the arduino board, The display driver is a PCD8544 chip which is on the library weve recently downloaded, VCC level must be 3.3V to prevent damage so you must use some kind of resistance. or we can use resistor between the light pin and the GND pin on the arduino. the remaining pin on the LCD will be conneted to the specified digital pin out on the arduino board llisted below.

  • NOKIA DISPLAY CIRCUIT DIAGRAM

nokia.png

Adafruit_PCD8544 display = Adafruit_PCD8544(8, 9, 10, 11, 12);

  • pin 8 - CLK
  • pin 9 - DIN
  • pin 10 - DC
  • pin 11 - CE
  • pin 12 - RST
  • pin GND - GND
  • pin GND - resistor - LIGHTpin
  • 3.3V - VCC

PUSH BUTTONS DIAGRAM

butt.png

push buttons has 4 set of legs but we will using 2 legs, both the right leg is connected to the GND pin on the arduino, the left one is connected to specified arduino pin depends on the use of it.

  • to run mario back ward place in pin 5 with button 1

  • to jump/select or enter the game place pin 5 with button 2

  • to run mario forward place pin 7 with button 3

  • combine all the components together in one single panel breadboard

20180216_150709.jpg

Connect the arduino uno board to your computer using the Type B usb cable included in the package. open the arduino Desktop IDE locate the TOOLS verify the type of board you are using PORT should be on the COM# and the board should be on the arduino/genuino uno if youre using the same board as mine.

com.png

SOURCE CODE

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include "marduinotypes.h"
#include "tilemap.h"
#include "mariobitmap.h"
#include "levels.h"
Adafruit_PCD8544 display = Adafruit_PCD8544(8, 9, 10, 11, 12);
TileMap gameTilemap;
#define DELAY 75 // delay for fixed update interval 
#define P_STILL 0
#define P_MOVE 1
#define P_JUMP 2
#define P_DEAD 3
#define GAME_INTRO 100
#define GAME_TITLE 101
#define GAME_CREDITS 102
#define GAME_LEVEL 103
#define GAME_PLAY 104
#define GAME_GAMEOVER 105
unsigned int gamestate = GAME_INTRO; // game state
long TIMER_PREV = 0; // timer 
unsigned long TIMER_CURRENT = 0;
//mario img
int const pimagew = 16;
int const pimageh = 16;
//marduino settings
int player_state = P_STILL; //player state 
int player_direction = 1;
int last_direction = 1;
int life = 3;
long playertimer = 0;
long playertimer_prev = 0;
//posicao do mario
Vector2f player_position(0,display.height()-pimageh-8);
Vector2f player_position2(0,display.height()-pimageh-8);
Vector2f last_safe_position(0,display.height()-pimageh-8);
//horizontal speed vars
float hspd = 0;
float hspd_speed = 3.0;
//jump vars and gravity control
float grav = 0.6;
float jumpspd = 4.0;
float vspd = 0;
boolean onAir = false;
boolean check_pulo = false;
//animation vars
int frame = 0;
int frameMax = 4;
float frameSpd = 1;
float frameCounter = 0;
boolean animInit = false;
//collision box offset
float pboxoffsetx = 3; 
// camera control
Vector2f camera = {0,0};
Vector2f last_camera = {0,0};
int camera_player_side = 0;
float sign(float x) {
  if (x > 0)
    return 1;
  else if (x < 0)
    return -1;  
  return 0;  
};
boolean buttonPressing[] = {false,false,false}; // button is pressing
boolean buttonRelease[] = {false,false,false}; // button is released
boolean buttonPressed[] = {false,false,false}; // button has pressed one time 
boolean buttonPressedCheck[] = {false,false,false};
boolean buttonReleaseCheck[] = {false,false,false};
void inputManager(unsigned int pin0, unsigned int pin1, unsigned int pin2) {
  //input manager in loop || gerenciador de inputs em loop  
  int p[3];
  p[0] = digitalRead(pin0);//Lê o pino 5
  p[1] = digitalRead(pin1);//Lê o pino 6
  p[2] = digitalRead(pin2);//Lê o pino 7  
  for (int i = 0; i < 3; i++) {  
      if (buttonPressed[i]) { // pressed ok
        buttonPressed[i] = false;
        buttonPressedCheck[i] = true;
      }     
      if (buttonRelease[i]) { // release ok
        buttonRelease[i] = false;
        buttonReleaseCheck[i] = true;
      }    
    if (p[i] == LOW) { // arduino check    
      buttonPressing[i] = true; // pressing button      
      buttonRelease[i] = false; //turn release off
      buttonReleaseCheck[i] = false;         
      if (!buttonPressedCheck[i]) 
        buttonPressed[i] = true;        
    } else {
      //turn off all
      buttonPressing[i] = false;
      buttonPressed[i] = false;
      buttonPressedCheck[i] = false;      
      if (!buttonReleaseCheck[i]) //released button!
        buttonRelease[i] = true;
    }   
  } 
}
boolean intersectionRect(float * rect1, float * rect2) {  
  if (rect1[0] < rect2[0] + rect2[2] && rect1[0] + rect1[2] > rect2[0]) {
     if (rect1[1] < rect2[1] + rect2[3] && rect1[3] + rect1[1] > rect2[1]) {
      return true;
    }
  }
  return false;
}
void playerCollisionChecker(float hs, float vs) {
  float playerRect[4] = {player_position.x+pboxoffsetx+hs+camera.x, player_position.y+vs,10,16};  
  for (int i = 0; i < CollisionMap0Size*4; i += 4) {  
    float rectTest[] = {pgm_read_word_near(&CollisionMap0[i]), pgm_read_word_near(&CollisionMap0[i+1]), pgm_read_word_near(&CollisionMap0[i+2]), pgm_read_word_near(&CollisionMap0[i+3])};    
        if (intersectionRect(playerRect,rectTest)) {
          if (hs != 0) {          
              hspd = (int)hspd;
              player_position.x = (int)player_position.x;
              boolean corrector = false;    
              while (!corrector) {                         
                  playerRect[0] = player_position.x+pboxoffsetx+camera.x+sign(hspd);                  
                  if (!intersectionRect(playerRect,rectTest))  
                    player_position.x += sign(hspd);
                  else 
                    corrector = true;
              }              
               hspd = 0;              
              break;
          }          
          if (vs != 0) {             
              vspd = (int)vspd;
              player_position.y = (int)player_position.y;
              boolean correctorY = false;    
              while (!correctorY) {                         
                  playerRect[1] = player_position.y+camera.y+sign(vspd);                  
                  if (!intersectionRect(playerRect,rectTest))  
                    player_position.y += sign(vspd);
                  else 
                    correctorY = true;
              }              
               vspd = 0;
               check_pulo = false;
              break;
          }
        }               
  }
}
boolean verifyCollision(float * rect) {
    for (int i = 0; i < CollisionMap0Size*4; i += 4) {  
      float rectTest[4] = {pgm_read_word_near(&CollisionMap0[i]), pgm_read_word_near(&CollisionMap0[i+1]), pgm_read_word_near(&CollisionMap0[i+2]), pgm_read_word_near(&CollisionMap0[i+3])};    
        if (intersectionRect(rect,rectTest)) {
               return true;
        }        
    }    
    return false;
}
void playerLogic(boolean move_esq, boolean move_dir, boolean jump) {
  //HORIZONTAL MOVEMENT
  if (player_state != P_DEAD) {  
      hspd = 0;
      boolean moving = false;     
      if (move_esq == true && move_dir == false) {
          player_direction = 1;
          moving = true;
      } else if (move_dir == true && move_esq == false) {
          player_direction = -1;
          moving = true;
      }      
      if (moving)
          hspd = hspd_speed * (float)player_direction;    
      playerCollisionChecker(hspd,0);      
      player_position2.x += hspd;      
       if (camera_player_side == -1) {
          if (player_position.x > (display.width()/2)-10)
            camera_player_side = 0;
          else
            player_position.x += hspd;    
          // screen limit <
          if (player_position.x < 0) {
            player_position.x = 0;
            hspd = 0;
          }      
       } else if (camera_player_side == 1) {
          if (player_position.x < (display.width()/2)-10)
            camera_player_side = 0;
          else
            player_position.x += hspd;            
          // screen limit >
          if (player_position.x > display.width()) {
            gamestate = GAME_TITLE;
            /*player_position.x = display.width()-pimagew;
            hspd = 0;*/
          }
        }        
        if (camera_player_side == 0) {
          //verify for limit side >
          if (camera.x >= 0 && camera.x <= gameTilemap.getMapWidth()*8-display.width()) {
            camera.x += hspd;
          } if (camera.x > gameTilemap.getMapWidth()*8-display.width()) {
            camera_player_side = 1;
            camera.x = gameTilemap.getMapWidth()*8-display.width();
            player_position.x += hspd;
          } if (camera.x < 0) {
            camera_player_side = -1;
            player_position.x += hspd; 
            camera.x = 0;  
          }
        }   
      //VERTICAL MOVEMENT    
      //gravidade (esta no ar)
     float playerRect[4] = { camera.x+player_position.x+pboxoffsetx,camera.y+player_position.y+1, 10, 16 };      
      if (!verifyCollision(playerRect)) {
        vspd += grav;
        check_pulo = true;
        onAir = true;
      } else {
        onAir = false;
      }    
      // checa colisao com chao
      if (vspd != 0) {
          playerCollisionChecker(0,vspd);
      }      
      if (jump == true && check_pulo == false) {
        vspd -= jumpspd;
        check_pulo = true;  
      }      
      player_position.y += vspd;
      player_position2.y += vspd;      
      if (vspd == 0 && !onAir) {
          last_direction = player_direction;
          last_camera.x = camera.x;
          last_camera.y = player_position2.y;
          last_safe_position.x = player_position.x;
          last_safe_position.y = player_position.y;
      }      
      //fall
      if (player_position.y+camera.y > gameTilemap.getMapHeight()*gameTilemap.getTileHeight()) {
          if (player_state != P_DEAD)
              player_state = P_DEAD;
      }    
    if (player_state != P_DEAD) {
       if (hspd == 0 && vspd == 0) {
        if (player_state != P_STILL) {
          player_state = P_STILL;
          animInit = true;
        }
      } else  if (hspd != 0 && vspd == 0) {
         if (player_state != P_MOVE) {
          player_state = P_MOVE;
          animInit = true;
        }
      }       
      if (vspd != 0) {
        if (player_state != P_JUMP) {
          player_state = P_JUMP;
          animInit = true;
         }   
      }          
     }
  } else {  
   playertimer++; // every DELAY | 1 = 75 millis    
    if (playertimer > 1000/75) { // 1 sec    
          playertimer = 0;
          life--;          
          if (life > 0) {  
            player_position.x = (int)((last_safe_position.x/8)*8);/*+(8*-last_direction);*/
            player_position.y = (int)((last_safe_position.y/8)*8);
            player_position2.x = player_position.x;
            camera.x = (int)((last_camera.x/8)*8);/*+(8*last_direction);*//*-(display.width()/2)-8;*/
            camera.y = 0;
            player_state = P_STILL;
            vspd = 0;
            hspd = 0;
            check_pulo = false;
        } else {
            gamestate = GAME_GAMEOVER;
        }
   }
  }  
}
void playerDraw() {
  //BMP * frameAtual;
  const unsigned char * frameAtual;  
  //animation setup
  if (animInit) {  
    frame = 0;
    frameCounter = 0;       
    if (player_state == P_STILL || player_state == P_JUMP) {
      frameSpd = 0.;
      frameMax = 1; 
    } else if (player_state == P_MOVE) {
      frameSpd = 0.8;
      frameMax = 4;
    }  
     animInit = false;
  }  
  //controlador de tempo de frames
  if (frameMax > 1) {
    frameCounter += frameSpd*DELAY;    
    if (frameCounter > DELAY) {
      frame++;
      frameCounter = 0;
      if (frame > frameMax-1) {
        frame = 0;
      }
    }
  }  
  //frames manager   
  if (player_state == P_STILL) {
   if (player_direction == 1) 
    frameAtual = frameMario0;
   else
    frameAtual = frameMario4;
  } else if (player_state == P_JUMP) {
    if (player_direction == 1) 
      frameAtual = frameMario3;
    else
      frameAtual = frameMario7;
  } else if (player_state == P_MOVE) {  
    if (player_direction == 1) {
      switch (frame) {
        case 0: frameAtual = frameMario1; break;
        case 1: frameAtual = frameMario0; break;
        case 2: frameAtual = frameMario2; break;
        case 3: frameAtual = frameMario0; break;
      }
    } else {
      switch (frame) {
        case 0: frameAtual = frameMario5; break;
        case 1: frameAtual = frameMario4; break;
        case 2: frameAtual = frameMario6; break;
        case 3: frameAtual = frameMario4; break;
      }
    }  
  }    
  display.drawBitmap(player_position.x, player_position.y, frameAtual, pimagew,pimageh,1);
  // debug collision box
  //display.fillRect(player_position.x+pboxoffsetx, player_position.y, 10, 16, BLACK);
}
void drawGui() {
  String stringint = String(life,DEC);
  String string = String("x" + stringint);  
  display.setTextSize(1);
  display.setTextColor(BLACK,WHITE);
  display.setCursor(0,0);
  display.print(string);
}
void sceneIntro() {  
  display.clearDisplay(); //clean screen   
  float sizex = 13*6;
  display.setTextSize(1);
  display.setTextColor(BLACK);
  display.setCursor((display.width()-sizex)/2,display.height()/2-12);
  display.print("Regi and Tobi");
  sizex = 8*6;
  display.setCursor((display.width()-sizex)/2,display.height()/2-4);
  display.print("presents");
  display.display();  
  TIMER_CURRENT = millis();    
   if (TIMER_CURRENT - TIMER_PREV > 2500) {       
        TIMER_PREV = TIMER_CURRENT;
        display.clearDisplay();
        gamestate = GAME_TITLE;
   }
}
void sceneTitle() {
    // loop title screen
    float sizex = 14*6;
   int select = 0; 
   int selectMax = 3;
   unsigned int triggerSelect = 0;
   unsigned int counter = 0;
   unsigned int counterMax = 0;     
  while (gamestate == GAME_TITLE) {
   TIMER_CURRENT = millis();    
   if (TIMER_CURRENT - TIMER_PREV > DELAY) {       
        TIMER_PREV = TIMER_CURRENT;    
        inputManager(5,6,7);        
        if (triggerSelect == 0) {
            if (buttonPressed[2]) {
              select++;
              if (select >= selectMax) 
                select = 0;                
            } else if (buttonPressed[0]) {
                  select--;
              if (select < 0)
                select = selectMax-1;    
            }                      
           if (buttonPressed[1]) {
            triggerSelect = 1;
            counterMax = 3;
          }
         }                 
       String str = "test";      
        switch (select) {
          case 0: {str = "< START GAME >"; sizex = 14*6; break;};
          case 1: {str = "< CREDITS >"; sizex = 11*6; break;};
          case 2: {str = "< EXIT GAME >"; sizex = 13*6; break;};  
        }        
        display.clearDisplay();
        display.drawBitmap(0, 0, gameLogo, 84, 24,1);
        display.setTextSize(1);        
        if (triggerSelect == 1)
          display.setTextColor(WHITE,BLACK);
        else
          display.setTextColor(BLACK);        
        display.setCursor((display.width()-sizex)/2,24+8);
        display.print(str);        
        display.display();                   
       if (triggerSelect != 0) {
        if (counter > counterMax) {
            counter = 0;
            triggerSelect++;
        } else {
            counter++;
        }
      }
      }            
        if (triggerSelect == 3) {          
          if (select == 0) {
            gamestate = GAME_LEVEL;
          } else if (select == 1) {
            gamestate = GAME_CREDITS;
          } else {
            triggerSelect = 0;
          }   
        }             
   }   
  }
void sceneCredit() {
  float sizex = 8*6;
  int page = 0;  
  while (gamestate == GAME_CREDITS) {  
    TIMER_CURRENT = millis();    
      if (TIMER_CURRENT - TIMER_PREV > DELAY) {       
        TIMER_PREV = TIMER_CURRENT;     
          inputManager(5,6,7);        
        if (buttonPressed[2] || buttonPressed[1] || buttonPressed[0]) {
          page++;
        }
         sizex = 8*6;      
         display.clearDisplay();    
          display.setTextSize(1);
          display.setTextColor(BLACK);
          display.setCursor((display.width()-sizex)/2,0);
          if (page < 2) 
            display.print("CREDITS:");
          display.setCursor(0,8);
          if (page == 0) {
            display.println("Created by:");
            display.println("Tobias Ulrich and Reginaldo da Silva.");
          } else if (page == 1) {
             display.println("Written in C  with Arduino  Uno.");
           sizex = 10*6;
           display.setCursor((display.width()-sizex)/2,32);
            display.print("Dec, 2014.");
          } else {
            gamestate = GAME_TITLE;
          }               
         display.display();
      }        
  }
}
void sceneLevel() {
  float sizex = 7*6;  
  while (gamestate == GAME_LEVEL) {    
         display.clearDisplay();   
          display.fillRect(0, 0, display.width(), display.height(), BLACK);
          display.setTextSize(1);
          display.setTextColor(WHITE,BLACK);
          display.setCursor((display.width()-sizex)/2,(display.height()/2)-3);
          display.print("LEVEL 1");                                   
         display.display();         
    TIMER_CURRENT = millis();    
      if (TIMER_CURRENT - TIMER_PREV > 2250) {       
        TIMER_PREV = TIMER_CURRENT;
        gamestate = GAME_PLAY;
      }        
  }
}
void sceneGameOver() {
  float sizex = 9*6;  
  while (gamestate == GAME_GAMEOVER) {    
         display.clearDisplay();   
          display.fillRect(0, 0, display.width(), display.height(), BLACK);
          display.setTextSize(1);
          display.setTextColor(WHITE,BLACK);
          display.setCursor((display.width()-sizex)/2,(display.height()/2)-3);
          display.print("GAME OVER");                                   
         display.display();         
    TIMER_CURRENT = millis();    
      if (TIMER_CURRENT - TIMER_PREV > 3000) {       
        TIMER_PREV = TIMER_CURRENT;
        gamestate = GAME_TITLE;
      }        
  }
}
void resetGame() {
  player_state = P_STILL; 
  life = 3;
  player_direction = 1;
  player_position.x = 0;
  player_position.y = display.height()-pimageh-8;
  vspd = 0;
  hspd = 0;
  camera.x = 0;
  camera.y = 0;
  camera_player_side = -1;
  check_pulo = false;
}
void sceneGame() {
  resetGame();    
  while (gamestate == GAME_PLAY) {  
    TIMER_CURRENT = millis();    
      if(TIMER_CURRENT - TIMER_PREV > DELAY) { // game loop      
        TIMER_PREV = TIMER_CURRENT;      
        inputManager(5,6,7); // 5 = 0        
        if (buttonPressing[2] && buttonPressing[1] && buttonPressing[0]) 
            gamestate = GAME_TITLE;                
        playerLogic(buttonPressing[2],buttonPressing[0],buttonPressed[1]);      
        display.clearDisplay();         
        gameTilemap.drawMap(camera.x,camera.y);
        playerDraw();
        drawGui();        
        display.display();
    }
  }  
}
void setup()   {
  Serial.begin(9600);
  display.begin();
  // init done
  // you can change the contrast around to adapt the display
  // for the best viewing!
  display.setContrast(50);  
  //song - DOSENT WORK - DO NOT USE
  //pinMode(3, OUTPUT);//buzzer
  //pinMode(13, OUTPUT);//led indicator when singing a note  
  // inputs
  pinMode(7, INPUT);//Define o pino 7 como entrada
  digitalWrite(7, HIGH);//Ativa o resistor de pull-up da porta 7
  pinMode(6, INPUT);//Define o pino 7 como entrada
  digitalWrite(6, HIGH);//Ativa o resistor de pull-up da porta 7
  pinMode(5, INPUT);//Define o pino 7 como entrada
  digitalWrite(5, HIGH);//Ativa o resistor de pull-up da porta 7
  gameTilemap.setMapSize(100,6);
  gameTilemap.setDisplayPointer(&display);
  gameTilemap.setTileMap(TileMap0);  
};
void loop() {
   switch (gamestate) { // "STATE MACHINE MANAGER"  
    case GAME_INTRO: {sceneIntro(); break;}
    case GAME_TITLE: {sceneTitle(); break;}
    case GAME_CREDITS: {sceneCredit(); break;}
    case GAME_LEVEL: {sceneLevel(); break;}
    case GAME_PLAY: {sceneGame(); break;}
    case GAME_GAMEOVER: {sceneGameOver(); break;}
  }     
}

20180216_151935.gif

I hope you enjoy this actitvity if want to learn how arduino works, and how to make a sketch, then maybe this site http://educ8s.tv/ might help you, all images on this blog are supposedly mine. thank you for stopping by..

please check my previous tutorials;

Light sensor LDR Monitor with a LCD Nokia 5110 Tutorial

Rotary Encoder with Nokia 5110 display Tutorial

Real time clock DS1302 module and Nokia 5110 DIY lcd tutorial



Posted on Utopian.io - Rewarding Open Source Contributors

Sort:  

@pakganern, Like your contribution, upvote.

Thank you for the contribution. It has been approved.


I would ask you for something: if you take over text passages from official websites, please mark these text passages as a quote and indicate the source.

For example, the following text section is taken over 1:1 from Arduino-Store:

16 MHz quartz crystal, a USB connection, a power jack, an ICSP header and a reset button.

https://store.arduino.cc/usa/arduino-uno-rev3


You can contact us on Discord.
[utopian-moderator]

Hey @pakganern I am @utopian-io. I have just upvoted you!

Achievements

  • Seems like you contribute quite often. AMAZING!

Suggestions

  • Contribute more often to get higher and higher rewards. I wish to see you often!
  • Work on your followers to increase the votes/rewards. I follow what humans do and my vote is mainly based on that. Good luck!

Get Noticed!

  • Did you know project owners can manually vote with their own voting power or by voting power delegated to their projects? Ask the project owner to review your contributions!

Community-Driven Witness!

I am the first and only Steem Community-Driven Witness. Participate on Discord. Lets GROW TOGETHER!

mooncryption-utopian-witness-gif

Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x

Coin Marketplace

STEEM 0.30
TRX 0.12
JST 0.033
BTC 64513.89
ETH 3155.04
USDT 1.00
SBD 4.00