Forum: Projekte & Code PixelPipe_Game Arduino UNO mit OLED Display und Joystick


von Manuel B. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

habe gestern ein kleines Projekt umgesetzt, das an eine Art 
FlappyBird-Klon erinnert. Dabei geht es darum, einen per Joystick 
bedienbaren Pixel auf dem 128x32 OLED Display durch die sich annähernden 
Rohröffnungen zu bewegen. Bei einer Kollision ist das Spiel vorbei.

Bevor hier die Diskussion wieder anfängt, wieso ich denn Arduino gewählt 
habe, gleich vorab schon mal die Antwort. Obwohl ich mich in der Welt 
der 8-Bit Atmels und STM32-Controller sehr gut zurecht finde, so ging es 
mir hauptsächlich darum, neue Peripherie, wie beispielsweise das OLED 
Display und den Joystick ohne großen Aufwand in Betrieb zu nehmen. Da es 
Bibliotheken sowohl für Arduino, als auch für die blanken Controller 
gibt, macht es somit kaum noch Unterschied, welche Plattform ich wähle.

Der Sketch ist hier im Anhang und der Quellcode nachfolgend zu finden.

Ebenso ist ein Überblicksvideo auf YouTube auf meinem Kanal zu finden:
https://youtu.be/SqoWV4F428M

Der im Video enthaltene Schaltplan zu dem Ganzen hier noch zusätzlich im 
Anhang unter Schaltplan.png zu finden.

Bei Fragen, Erklärungen oder sonstiger Kritik, bin ich gerne Bereit mit 
Euch darüber zu diskutieren und Hilfestellung zu geben, falls jemand 
dieses Projekt nachstellen oder erweitern möchte.
Auch eine Erweiterung mit Highscore, alternativer Spielersymbole anstatt 
dem Pixel und optische Verbesserungen sind derzeit in Arbeit.

Hoffe Euch gefällt, was ich letzten Nachmittag zusammengebastelt habe 
und freue mich auf Antworten

1
/*  PixelPipe v0.5
2
 *  07.09.2016
3
 *  Arduino UNO
4
 */
5
/*
6
 *  OLED 128x32 
7
 *    5V->5V, GND->GND, SDA->A4(SDA), SCL->A5(SCL)
8
 *  Joysick 4duino (2 Potentiometer, 1 Button)
9
 *    5V->5V, GND->GND, VRX->A0, VRY->A1, SW->2 mit PULL-UP
10
 */
11
#include <Adafruit_SSD1306.h>
12
#include <Adafruit_GFX.h>
13
#include <SPI.h>
14
#include <Wire.h>
15
#define OLED_RESET  4
16
17
//Settings
18
//  actual pipe speed = PIPESPEED * REFRESH_MS
19
#define PIPESPEED   2
20
#define REFRESH_MS  50
21
22
//State Overview
23
#define STATE_START               0
24
#define STATE_START_PRESS_BUTTON  1
25
#define STATE_PLAY                2
26
#define STATE_LOOSE               3
27
#define STATE_RESET_PRESS_BUTTON  4
28
29
//Define Variables
30
Adafruit_SSD1306 display(OLED_RESET);
31
int x_in,y_in,x,y;
32
char pipeCnt[10]; //Variable for the pipes moving from right to left on the screen
33
char pipeSpeed=0; //counter variable for the pipeSpeed
34
char startState=0;
35
bool hitState=false;
36
typedef struct sPipe{ //Variable for creating pipes
37
  bool active;        //active=true means show pipe on display
38
  unsigned x_o, x_u;  //coordinates for upper and lower pipe
39
  unsigned y_o, y_u;
40
  unsigned w_o, w_u;
41
  unsigned h_o, h_u;
42
  unsigned gap;       //size of the gap between the uper and lower pipe
43
  unsigned nextPipe;  //pixel-distance between the pipe and the next one
44
};
45
46
sPipe pipe[10];       //amount of available pipes
47
48
void setup() {
49
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
50
  display.clearDisplay();
51
  pinMode(2,INPUT);
52
}
53
54
void loop() {
55
  if(startState==STATE_START){    //Show Start Screen,if Button not pressed, go to the Wait for Press Button Screen
56
    display.clearDisplay();
57
    display.setTextColor(WHITE);
58
    display.setTextSize(2);
59
    display.setCursor(15,10);
60
    display.println("Start");
61
    if(digitalRead(2)==HIGH)
62
      startState++;
63
  }
64
  else if(startState==STATE_START_PRESS_BUTTON){  //Wait for the button being pressed, then start the game
65
    if(digitalRead(2)==LOW){
66
      createPipe(&pipe[0]); //Create a new pipe mit ID0
67
      startState++; 
68
    } 
69
  }
70
  else if(startState==STATE_PLAY){  //Loop for the actual game. Ends when pixel hits a pipe
71
    display.clearDisplay();
72
    getInput();//Get the coordinates for the pixel from the ADC's
73
    displayPlayer();//Show the pixel on the Screen
74
    displayPipes();//Show pipes on the Screen
75
    hitState=calculateHit();//Calculate if pixel hits a pipe
76
    if(hitState==true)//if pixel hit a pipe, then go to the loose state
77
      startState++;
78
  }
79
  else if(startState==STATE_LOOSE){   //Clear als pipes and show Verloren on the screen
80
    display.clearDisplay();
81
    display.setTextColor(WHITE);
82
    display.setTextSize(2);
83
    display.setCursor(13,10);
84
    display.println("Verloren");
85
    display.setCursor(1,0);
86
    display.setTextSize(1);
87
    for(int i=0; i<10;i++){
88
      pipe[i].active=false; //Set all pipes to active=false, so they are not displayed if a new game starts
89
      pipeCnt[i]=0; //set the pipe-Counter to 0
90
    }
91
    startState++;
92
  }
93
  else if(startState==STATE_RESET_PRESS_BUTTON){//Wait for Button to be pressed for starting a new game
94
    if(digitalRead(2)==LOW)
95
      startState=STATE_START;  
96
  }
97
  display.display();
98
  delay(REFRESH_MS);
99
}
100
//This function creates a new pipe witch uper and lower part of the pipe
101
//User can customize the values for more challenging pipe-spawns
102
void createPipe(sPipe *nPipe){
103
  nPipe->active=true;
104
  nPipe->x_o=nPipe->x_u=0;
105
  nPipe->y_o=0;
106
  nPipe->w_o=nPipe->w_u=random(7,30);
107
  nPipe->h_o=random(3,20);
108
  nPipe->gap=random(5,7);
109
  nPipe->y_u=nPipe->h_o+nPipe->gap;
110
  nPipe->h_u=31-nPipe->y_u;
111
  nPipe->nextPipe=random(nPipe->w_o+20,nPipe->w_o+50);
112
}
113
//Read the ADC to get information about the Joystick and convert the information to
114
//useable coordinates on the 128x32 OLED
115
void getInput(){
116
  y_in = 1023-analogRead(A0);
117
  x_in = analogRead(A1); 
118
  x=(float)x_in*127/1023;
119
  y=(float)y_in*31/1023;  
120
}
121
//show pixel player on the Screen with the coordinates from getInput()
122
void displayPlayer(){
123
  display.drawPixel(x,y,WHITE);
124
}
125
//Show the pipes
126
//for the exact algorithm study this code for studying purposes or ask in the thread
127
void displayPipes(){
128
  pipeSpeed++;
129
  if(pipeSpeed>=PIPESPEED){
130
    for(int i=0;i<10;i++){
131
      if(pipe[i].active){
132
        pipeCnt[i]++; 
133
        if(pipeCnt[i]==pipe[i].nextPipe){
134
          if((i>=9)&&(pipe[0].active==false))
135
            createPipe(&pipe[0]);
136
          else
137
            createPipe(&pipe[i+1]);
138
        }
139
        else if(pipeCnt[i]>=127){
140
          pipeCnt[i]=0; 
141
          pipe[i].active=false; 
142
        }      
143
      }
144
    }   
145
    pipeSpeed=0; 
146
  } 
147
  for(int i=0; i<10;i++){
148
    if(pipe[i].active){
149
      display.fillRect((127-pipeCnt[i]),pipe[i].y_o,pipe[i].w_o,pipe[i].h_o,WHITE);
150
      display.fillRect((127-pipeCnt[i]),pipe[i].y_u,pipe[i].w_u,pipe[i].h_u,WHITE);
151
      pipe[i].x_o=pipe[i].x_u=127-pipeCnt[i];
152
    }
153
  }
154
}
155
//Calculate if the player hits a pipe with its pixel Player
156
//for the exact algorithm study this code for studying purposes or ask in the thread
157
bool calculateHit(){
158
  for(int i=0;i<10;i++){
159
    if(pipe[i].active){
160
      if((x>=pipe[i].x_o)&&(x<=pipe[i].x_o+pipe[i].w_o)&&((y<=pipe[i].h_o)||(y>=(pipe[i].h_o+pipe[i].gap))))
161
        return true;
162
    }
163
  }
164
  return false; 
165
}

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.