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 | }
|