Objekt orienterad programmering med arduino/c++, polletten har inte trillat ner!

Permalänk
Medlem

Objekt orienterad programmering med arduino/c++, polletten har inte trillat ner!

Hej!

Har knopat ihop ett fungerande Pong för att komma igång med lite mer programmering, jag ser det som något efter "hello world". Efter att jag fått det att fungera började jag fundera på är detta jag knåpat ihop objekt orienterat? Använder jag klasser, funktioner eller metoder m.m. Jag insåg att jag har inte en aning! Försöker just nu klura ut om ett library i arduino IDE är samma sak som en klass? Ju mer jag letar inser jag att ge sig på C++ som ett första språk verkar vara en resa men nu är den på börjad. Köpte mig en bok som ej har kommit än hoppas det skall hjälpa lite.

iaf nu till mitt program jag använder, koden kommer sist i inlägget.

När jag började projektet tänkte jag vad är Pong. Var skall jag börja? För min del så är slut målet att bygga en liten låda med knappar i varje hörn på ovansidan och en lite 0,96" OLED i mitten. Jag började med att bygga en kvick krets på en breadboard, jag går inte in för mycket på hårdvaran men tänkte att det behövs för koden. Ville även utforska lite analog data så byggde knapparna på en analogpinne.

För själva spelet så tänkte jag att det består av:
2st paddlar
1st boll
1st spelplan
1st bild för poäng

Började med att koda paddlarna för att forsätta med paddlarna och vidare till poängen. När jag fått ihop allt till något som fungerar slog det mig att jag skapar något som är objekt orienterat. Borde inte paddlarna vara en klass, bollen en, spelplanen en och poängen en. Ett försök att skapa något som jag tyckte skulle vara rätt. Så det blev en void scoreScreen för att visa poängen. Efter lite funderande och tänkade tror jag idag att det är en Function jag skapat. När jag sedan tänkte på det jag skriver i början "include" borde ju vara det som är klasserna jag vill använda i spelet.

Dock fungerar programmet men det är inte onödig mycket objekt orienterat. Vilket jag skulle vilja för att försöka få ordning på konceptet. Metoder är något jag inte förstått alls än.

Så nu till några frågor:
Är det jag skriver #include de klasser jag vill använda?
När jag tänker på vad spelet består av (paddlar, boll...) något som skall vara en egen klass? För att få koden objekt orienterad.

När jag skriver detta inser jag att jag inte skrivit något om objekt någonstans, så jag inser att jag inte har förstått detta riktigt men jag börjar såhär.

#include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> // If using software SPI (the default case): #define OLED_MOSI 9 #define OLED_CLK 10 #define OLED_DC 11 #define OLED_CS 12 #define OLED_RESET 13 Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS); //Paddle variables int xPlayerOne = 0; int yTopPlayerOne = 24; int yBottomPlayerOne = 40; int xPlayerTwo = 127; int yTopPlayerTwo = 24; int yBottomPlayerTwo = 40; int paddleLength = 14; //Ball variables int ballX = 10; int ballY = 31; int ballXDir = 1; int ballSpeed = 1; int ballYDir = 1; int ballAngle = 1; //Score variables int playerOneScore = 0; int playerTwoScore = 0; void setup() { //Setup display display.begin(SSD1306_SWITCHCAPVCC); display.setTextSize(1); display.setTextColor(WHITE); display.setCursor(0,0); display.clearDisplay(); } void loop() { // put your main code here, to run repeatedly: display.setCursor(100,0); display.print(ballX); //Player One Code //Read analog pin 5 int buttonValue = analogRead(A5); //Values for debugging display.setCursor(0,0); display.println(buttonValue); display.print(yTopPlayerOne); if (buttonValue >= 500 && buttonValue <= 513){ //Moving the paddle down yTopPlayerOne++; yBottomPlayerOne++; yTopPlayerTwo++; yBottomPlayerTwo++; } else if (buttonValue >= 5 && buttonValue <= 12){ //Moving the paddle up yTopPlayerOne--; yBottomPlayerOne--; yTopPlayerTwo--; yBottomPlayerTwo--; } //Check if paddles are on screen if (yTopPlayerOne <= 0){ yTopPlayerOne++; yBottomPlayerOne++; yTopPlayerTwo++; yBottomPlayerTwo++; } else if (yBottomPlayerOne >= 63){ yTopPlayerOne--; yBottomPlayerOne--; yTopPlayerTwo--; yBottomPlayerTwo--; } //Draw a paddles on the screen //format (xStart, yStart, xStop, yStop, color); display.drawLine(xPlayerOne, yTopPlayerOne, xPlayerOne, yBottomPlayerOne, WHITE); display.drawLine(xPlayerTwo, yTopPlayerTwo, xPlayerTwo, yBottomPlayerTwo, WHITE); //Ball code if (ballX >= 127 && ballY >= yTopPlayerTwo && ballY <= yBottomPlayerTwo){ ballXDir = -1; ballAngle = 1;//random(6); ballSpeed = random(3); } else if (ballX <= 0 && ballY >= yTopPlayerOne && ballY <= yBottomPlayerOne) { ballXDir = 1; ballAngle = 1;//random(6); uncommet for more ball variation ballSpeed = random(1,3); } else if (ballX >= 127 && (ballY <= yTopPlayerTwo || ballY >= yBottomPlayerTwo)){ delay(500); scoreScreen(); } else if (ballX <= 0 && (ballY <= yTopPlayerOne || ballY >= yBottomPlayerOne)){ delay(500); scoreScreen(); } if (ballY >= 63){ ballYDir = -1; } else if (ballY <= 0){ ballYDir = 1; } ballX = (ballX + (ballXDir * ballSpeed)); //ballX + ballXDir; uncomment for straight shot ballY = (ballY + (ballYDir * ballAngle)); //ballY; uncomment for straight shot display.drawPixel(ballX, ballY, WHITE); display.display(); display.clearDisplay(); } //Function to show the score void scoreScreen(){ if (ballX >= 127){ playerOneScore++; } else{ playerTwoScore++; } //Setting up the display to show current score display.clearDisplay(); display.setCursor(10,10); display.setTextSize(4); display.print(playerOneScore); display.setCursor(75,10); display.print(playerTwoScore); display.display(); // resetting the ball to middle of screen and reversing the x direction ballX = 63; ballXDir = ballXDir * -1; //Resetting text size for debugging numbers display.setTextSize(1); delay(1500); display.clearDisplay(); //while (analogRead(A5)< 500) }

Ber om ursäkt för ett kanske rörigt inlägg men detta är rörigt i huvudet just nu.

Visa signatur

Laptop: HP Elitebook 640 G9
Server: HP Microserver N54L, 8 GB ram, 8 TB hd.

Permalänk
Medlem

En klass är en beskrivning som säger vad ett objekt innehåller och vad den kan göra, t.ex.:

class Ball { public: Ball(int x, int y) : _x(x), _y(y) {} void move(int x, int y) { _x += x; _y += y; } void draw(const Adafruit_GFX &display) { display.drawPixel(_x, _y, WHITE); } private: int _x; int _y; };

move och draw är här metoder, vilket helt enkelt är vad funktioner kallas när de är i klasser. _x och _y är s.k. instansvariabler, och anledningen till att jag namnger dem med _ före är bara för att undvika namnkollisioner (se t.ex. move, där argumenten naturligt kallas för x och y).

Ball är en s.k. konstruktor, som används för att instansiera klassen, vilket resulterar i en instans av klassen (som också kallas objekt). T.ex.:

Ball ball1(10, 20); Ball ball2(15, 4); ball1.move(1, 0); ball2.move(2, 3); ball1.draw(display); ball2.draw(display);

ball1 och ball2 är alltså instanser av Ball här, och har sina egna instansvariabler. Som du ser så blir det enkelt att skapa flera bollar när man implementerar det på ett objektorienterat sätt.

I din kod så finns det en enda sak som är objektorienterad just nu, och det är att du använder Adafruits display-klass. När du skriver:

Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

så skapar du en instans av Adafruit_SSD1306-klassen. Orsaken till att jag i mitt exempel använder Adafruit_GFX istället är för att Adafruit_GFX är en basklass till Adafruit_SSD1306. Detta gör att om du skulle ändra typ av display till t.ex. en Adafruit NeoMatrix så kan du bara ändra till att använda Adafruit_NeoMatrix-klassen istället, som också ärver från Adafruit_GFX, utan att behöva ändra på Ball-klassen.

Det här är kanske lite mycket att ta in om du inte programmerat objektorienterat förr, och då har jag också utelämnat mycket. Men förhoppningsvis ger det dig lite motivering varför det kan vara värt att lära sig i alla fall. OO används ju i många andra språk än C++ också. Sen är OO bara ett av många verktyg i C++, och det är kanske inte alltid vettigt att köra OO 100% överallt.

#include är för övrigt ett preprocessor-direktiv. Preprocessorn körs på filerna innan kompilatorn börjar kompilera, och #include betyder "ta den här filen, och dumpa sedan hela innehållet på denna plats". Det har alltså ingenting med klasser att göra, utan betyder bara att den filen som anges kommer stoppas in på den platsen i koden innan koden kompileras.

Permalänk
Medlem

@perost:

Tackar tackar tackar! Tror f_n polletten åkte lite längre ner! eller så är det vinet som talar. Jag har läst ditt inlägg på datorn, iPad, iPhone och Samsung Gear VR, så nu blir det till att knappa lite.

Jag inser att jag saknar en hel del om objekt orientering men inser att jag ändå sysslat med det utan att veta vad jag gjort. Det är det fina med Arduino tycker jag, sjukt enkelt att slänga ihop något utan att veta vad man gör och det fungerar. Sedan har det massor av möjligheter att fördjupa sig.

Planen för mig just nu är att skapa en klass med minst en metod och sedan använda en funktion med objektet som får sina egenskaper av klassen. Hoppas det blev rätt där.

Därefter blir det att skapa klasserna ball och paddle, eventuellt scoreScreen.

En allmän fråga om OO eller är det C++ skriver man alltid sina klasser i en separat fil? Inser att de är enklare att återanvända i andra projekt om det är så.

Tackar igen för svaret och hoppas att det hjälper andra med!

Visa signatur

Laptop: HP Elitebook 640 G9
Server: HP Microserver N54L, 8 GB ram, 8 TB hd.

Permalänk
Medlem
Skrivet av zeem:

En allmän fråga om OO eller är det C++ skriver man alltid sina klasser i en separat fil? Inser att de är enklare att återanvända i andra projekt om det är så.

I C++ så är det vanligast att man deklarerar en klass i en header-fil (.h), och sedan definierar den i en implementations-fil (.cpp, .cc, etc). Andra filer inkluderar sedan header-filen, vilket gör att de inte behöver kompileras om ifall man bara ändrar i implementations-filen. Denna fördel är kanske inte så relevant för Arduino, där man sällan får plats med så mycket kod att kompileringstiden blir ett problem.

Men det går också att deklarera och definiera en klass på samma gång, som jag gjorde i mitt exempel, då lämpligtvis i en header-fil om den är menad att användas på andra ställen i programmet. Och det går att ha flera klasser i samma fil om man så vill, men att ha en klass per fil är oftast att föredra.

Här är mitt exempel uppdelat i deklaration (=vad det är) och definition (=vad det gör):

// Deklaration, stoppas i .h-fil. class Ball { public: Ball(int x, int y); void move(int x, int y); void draw(const Adafruit_GFX &display); private: int _x; int _y; }; // Definition, stoppas i .cpp-fil. Ball::Ball(int x, int y) : _x(x), _y(y) { } void Ball::move(int x, int y) { _x += x; _y += y; } void Ball::draw(const Adafruit_GFX &display) { display.drawPixel(_x, _y, WHITE); }

Permalänk
Medlem

@perost:
Jag tackar för alla dina svar! Har hjälpt massor tror jag fått ordning på själva konceptet i stort samt jag fått hem min bok jag köpte. Dock var det en lite mer avancerad bok än jag hade tänkt mig, men men.

Det som jag inte fått grepp om än är hur jag skall tänka när jag skapar mina klasser skall jag sträva efter allt som klassen gör skall vara i klassen och minimera output från den?

Har jag klasser som ärver(är det termen?) hirarkisk struktur, då behöver jag kanske en output?

Att skapa klasser verkar vara något när jag börja bli avancerad verkar det som men kul att försöka förstå vad som händer.

Har gett mig på att försöka skapa några klasser i arduino IDE men igår natt slog det mig att det är något jag måste sakna när jag skapar ett library till arduino IDE så helt enkelt RTFM verkar det vara.

Jag tackar även för den kod du skrev gav mig bra uppslag på att leta efter lite syntax. Gav mig bra mycket huvudvärk innan jag förstod.

_x(x), _y(y)
_x += x;

Tack igen

Visa signatur

Laptop: HP Elitebook 640 G9
Server: HP Microserver N54L, 8 GB ram, 8 TB hd.