overpower Δημοσ. 25 Ιανουαρίου 2017 Δημοσ. 25 Ιανουαρίου 2017 Καλησπερα, εχω μια εργασια οπου πρεπει να φτιαξουμε το κλασικο παιχνιδι με τα τουβλακια, την μπαλα και ενα πλαισιο, οπου πρεπει να σπασουμε ολα τα τουβλακια για να κερδισουμε. Εχουμε φτιαξει το "γηπεδο", το πλαισιο οπου παει δεξια-αριστερα και την μπαλα. ΑΛΛΑ, δεν μπορουμε να δωσουμε κινηση στο πλαισιο δεξια-αριστερα. Επισης, εχουμε κανει και τον ελεγχο για να χτυπαει η μπαλα στο γηπεδο, αλλα δεν ξερουμε πως να το κανουμε ωστε να "χανει" οταν χτυπαει στην κατω πλευρα του γηπεδου. Μας εχουν πει οτι τα bricks θα γινουν με μια κλαση. Δεν ξερουμε πως να την φτιαξουμε. any help? #include <stdlib.h> // for "exit" #include <GL/glut.h> #include <math.h> /* Initialize global variables */ // Drawing area static float draw_width = 15; static float draw_height = 30; // ---------------------------------------------------------------------------------------------- // Pitch size float pitch_width = draw_width; float pitch_height = (2.*draw_height) / 3.0; // ---------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------- //Paddle size float paddle_width = 5; float paddle_height = 0.5; //------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------ //Paddle motion float paddle_pos[] = { pitch_width / 2.,0 }; float paddle_dir[] = { 10,10 }; float paddle_velocity = 0.05; float paddleX = pitch_width / 2.; // ---------------------------------------------------------------------------------------------- // Ball motion float ball_r = 0.5; float ball_pos[] = { pitch_width / 2., paddle_height+ball_r }; float ball_dir[] = { 10, 10 }; float ball_velocity = 0.05; //Bricks size float brick_width = 5; float brick_height = 0.5; // ---------------------------------------------------------------------------------------------- inline void normalize(float vec[2]) { float d = sqrt(vec[0] * vec[0] + vec[1] * vec[1]); vec[0] /= d; vec[1] /= d; } // ---------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------- // GEOMETRIC LIBRARY #define PI 3.1415926535897932384626433832795 #define NO_POINTS 20 inline float DEGREES(float rads) { return rads*180.0 / PI; } inline float RADIANS(float degs) { return degs*PI / 180.0; } inline float cosd(float theta) { return cos(RADIANS(theta)); } inline double sind(double theta) { return sin(RADIANS(theta)); } // Functions for drawing circles void CircleFast(float xc, float yc, float R, float r, float g, float /* Fast and recursive circle drawing */ { glColor3f(r, g, ; float x0 = xc + R; float y0 = yc; float Du = 360.0 / NO_POINTS; float cosDu = cosd(Du); float sinDu = sind(Du); float x = x0, y = y0; glBegin(GL_LINE_LOOP); for (int i = 0; i<NO_POINTS; i++) { glVertex2f(x, y); float xi = xc + (x - xc)*cosDu - (y - yc)*sinDu; float yi = yc + (y - yc)*cosDu + (x - xc)*sinDu; x = xi; y = yi; } glEnd(); } void CircleDiskFast(float xc, float yc, float R, float r, float g, float { glColor3f(r, g, ; float x0 = xc + R; float y0 = yc; float Du = 360.0 / NO_POINTS; float cosDu = cosd(Du); float sinDu = sind(Du); float x = x0, y = y0; glBegin(GL_POLYGON); for (int i = 0; i<NO_POINTS; i++) { glVertex2f(x, y); float xi = xc + (x - xc)*cosDu - (y - yc)*sinDu; float yi = yc + (y - yc)*cosDu + (x - xc)*sinDu; x = xi; y = yi; } glEnd(); } // ---------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------- /* Draw the scene */ void my_display(void) { glClearColor(1, 1, 1, 1); // white background glClear(GL_COLOR_BUFFER_BIT); // clear background glLoadIdentity(); // draw a dummy court glColor3f(0, 0, 0); glLineWidth(8); glBegin(GL_LINE_STRIP); glVertex2f(0, 0); glVertex2f(0, pitch_height); glVertex2f(pitch_width, pitch_height); glVertex2f(pitch_width, 0); glEnd(); glLineWidth(1); //translate/draw paddle glColor3f(0, 0, 1); glLineWidth(1); glBegin(GL_POLYGON); glVertex2f(5,1); glVertex2f(5, paddle_height+1); glVertex2f(paddle_width+5, paddle_height+1); glVertex2f(paddle_width+5, 1); glTranslatef(paddle_pos[0],paddle_pos[1],0); glEnd(); glLineWidth(1); // translate/draw ball glPushMatrix(); glLoadIdentity(); glTranslatef(ball_pos[0], ball_pos[1], 0); CircleDiskFast(0, 0, ball_r, 1, 0, 0); glPopMatrix(); //draw brick glColor3f(0, 1, 0); glLineWidth(1); glBegin(GL_POLYGON); glVertex2f(0.5, 20.5); glVertex2f(0.5, brick_height + 20.5); glVertex2f(brick_width + 0.5, brick_height + 20.5); glVertex2f(brick_width + 0.5, 20.5); glTranslatef(paddle_pos[0], paddle_pos[1], 0); glEnd(); glLineWidth(1); glutSwapBuffers(); // swap & flush drawing commands } // --------------------------------------------------------------------------------------------- inline void MoveBall() { float x = ball_pos[0] + ball_velocity*ball_dir[0]; float y = ball_pos[1] + ball_velocity*ball_dir[1]; // check collision with pitch if ((x<ball_r) || (x>pitch_width - ball_r)) { ball_dir[0] = -ball_dir[0]; x = ball_pos[0] + ball_velocity*ball_dir[0]; } if ((y<ball_r) || (y>pitch_height - ball_r)) { ball_dir[1] = -ball_dir[1]; y = ball_pos[1] + ball_velocity*ball_dir[1]; } ball_pos[0] = x; ball_pos[1] = y; } void IdleFunc() { MoveBall(); glutPostRedisplay(); } /* --------------------------------------------------------------------------------------------- * CUSTOM CALLBACK FUNCTIONS * --------------------------------------------------------------------------------------------- */ void my_reshape(int w, int h) { float left = 0, right = 20, top = 20, bottom = 0, znear = 0, zfar = 100; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(left, right, bottom*float(h) / float(w), top*float(h) / float(w), znear, zfar); else glOrtho(left*float(w) / float(h), right*float(w) / float(h), bottom, top, znear, zfar); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } /* Esc terminates the program */ void my_keyboard(unsigned char key, int x, int y) { switch (key) { case 'p': glutIdleFunc(IdleFunc); break; case 'q': glutIdleFunc(0); break; case '+': ball_velocity += 0.01; if (ball_velocity>0.5) ball_velocity = 0.5; break; case '-': ball_velocity -= 0.01; if (ball_velocity<0.001) ball_velocity = 0.001; break; case 27: exit(0); break; } glutPostRedisplay(); } void specialkeyboard(int key, int x, int y) { switch (key) { case GLUT_KEY_LEFT: paddle_velocity += 0.01; break; case GLUT_KEY_RIGHT:paddle_velocity -= 0.01; break; } glutPostRedisplay(); } /* Main Loop * Open window with initial window size, title bar, * RGBA display mode, and handle input events. */ int main(int argc, char** argv) { glutInit(&argc, argv); // initialize GLUT glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); // create double-buffered RGB window glutInitWindowSize(600, 600); // set window size in pixels glutInitWindowPosition(100, 100); // set window pos (relative to upper-left display corner) glutCreateWindow("Breakout"); // create the window glutReshapeFunc(my_reshape); // register callback function for reshapes glutDisplayFunc(my_display); // register callback function for display glutKeyboardFunc(my_keyboard); // register callback function for keyboard events glutSpecialFunc(specialkeyboard); normalize(ball_dir); glutMainLoop(); // enter main loop return 0; /* ANSI C requires main to return int. */ }
ChRis6 Δημοσ. 25 Ιανουαρίου 2017 Δημοσ. 25 Ιανουαρίου 2017 πρώτα δίνεις πίνακες μετασχηματισμού , δηλαδή translate,rotate,scale και μετά δινεις τα σημεία ανάμεσα στα glBegin() και glEnd(), όπως δηλαδή κάνεις για τη μπάλα
AlexHello Δημοσ. 25 Ιανουαρίου 2017 Δημοσ. 25 Ιανουαρίου 2017 Disclaimer: Σε καμιά περίπτωση δεν είμαι βαθύς γνωστής ΟpenGL. Μερικές παρατηρήσεις παρ' όλα αυτά: 1) Το παιχνίδι αυτή την στιγμή δεν είναι γραμμένο σε C++ άλλα σε C 2) Το πλαίσιο (paddle) δεν μπορεί να μετακινηθεί γιατί αν και το paddle_velocity γίνεται updated δεν προστίθεται ποτέ στο paddle_pos 3) Ακόμα και να προστεθεί το velocity στο position, δεν θα παρατηρήσετε καμιά αλλαγή γιατί το glTranslate γίνεται μετά το glBegin ενώ θα έπρεπε να γίνεται πριν i.e.: //translate/draw paddle glColor3f(0, 0, 1); glLineWidth(1); glTranslatef(paddle_pos[0] + paddle_velocity, paddle_pos[1], 0); glBegin(GL_POLYGON); glVertex2f(5, 1); glVertex2f(5, paddle_height + 1); glVertex2f(paddle_width + 5, paddle_height + 1); glVertex2f(paddle_width + 5, 1); glEnd(); glLineWidth(1); 4) Δεν γνωρίζω αν ο τρόπος με τον οποίο έχετε φτιάξει το game loop είναι ο standardized τρόπος για glut apps, άλλα νομίζω ότι αν ακολουθούσατε το κλασικό game loop: while (running) { input(); update(); render(); } Θα ήταν πιο ξεκάθαρο το flow του κώδικα
Moderators Kercyn Δημοσ. 25 Ιανουαρίου 2017 Moderators Δημοσ. 25 Ιανουαρίου 2017 Όπως σου είπε και ο AlexHello, αυτό που έχεις γράψει είναι C. Θα σου πρότεινα με ιδιαίτερο ζήλο να φύγεις τελείως απ' τον όλο σχεδιασμό C που έχεις κάνει και να πας σε πιο αντικειμενοστρεφείς προσεγγίσεις. Επειδή σε τέτοια θέματα παρασύρομαι κι αρχίζω να λέω ένα σωρό πράγματα που έχουν ή δεν έχουν σχέση με το πρόβλημα, θα προσπαθήσω να συγκρατηθώ. Καταρχάς αυτό που είπα στην αρχή, μια αντικειμενοστρεφής προσέγγιση θα σε βοηθούσε. Σκέψου από τι αποτελείται το παιχνίδι σου, πώς αλληλεπιδρούν τα διάφορα αντικείμενα, πώς μπορείς να έχεις μια πιο ομαλή και προβλέψιμη ροή (δες το game loop του AlexHello). Δεύτερον, για το συγκεκριμένο πρόβλημα που έχεις με τη μπάλα, μπορείς αντί να έχεις ένα ορθογώνιο που να περικλείει την περιοχή του παιχνιδιού εσωτερικά, να έχεις τέσσερα αντικείμενα, τα οποία στις ιδιότητές τους θα έχουν κι ένα ορθογώνιο, που την περικλείουν εξωτερικά. Κάθε φορά που η μπάλα χτυπάει σε κάποιο απ' αυτά, μπορείς να τρέχεις κάποια συνάρτηση που θα έχεις ορίσει από πριν. Αυτόν τον σχεδιασμό μπορείς να τον επεκτείνεις για όλα τα "χειροπιαστά" αντικείμενα του παιχνιδιού σου (μπάλα, τούβλα, τοίχους). Δεν προλαβαίνω να στο δείξω με κώδικα τώρα, μπορεί να προλάβω αργότερα ή αύριο.
παπι Δημοσ. 26 Ιανουαρίου 2017 Δημοσ. 26 Ιανουαρίου 2017 Φιλε θα σου πω πως δουλευει το μαραφετι που λεγεταιι καρτα γραφικων. Λοιπον, αυτη εχει ενα cpu και μια ram. Η cpu εχει παρα πολλους πυρινες, μονο που δεν ειναι σα τα κλασικα cpu cores, ειναι για να κανουν πολλαπλασιασμους πινακων (matrix * vector), εχει και εναν κεντρικο που μπορει ναμκανει περισσοτερα πραματα. Η ram ειναι σχεδιασμενη για δυο τυπους μνημης, βασικα λεγεται vram, ενα για vertex και ενα για texture. Μιλαμε για τρανζιστορ λεβελ. Επισης ειναι αλλη μια μνημη που δεν ξερω αν ειναι στο cpu ή στη vram, αυτη ειναι για τους const buffer Ηνσχεδιαση των μνημων εχει να κανει με την ταχύτητα. Faster const buffer > vertex buffer > texture buffer. Η gpu ειναι αυτονομη, δηλαδη τρεχει προγραμματα, τα οποια λεγονται τετσνικς ή κερνελς. Ο τροπος ομως που τρεχει τα προγραμματα, διαφερει απο την κλασικη cpu. Ενα προγρμμα ειναι μια σειρα απο προγραμματα,που το ενα παιρνει ςνα input και βγαζει ενα output που το πασαρει στο επομενο προγραμμα. Αυτο λεγεται pipeline (αν γκγουγκλαρει opengl/d3d pipeline θα βρεις ενδιαφερον πραματα).αυτα τα προγραμματα λεγονεται τετσνκς/κερνελς και γραφονται σε γλωσσες hlsl/glsl που γινονται compile on the fly. Αν δουλευες σε d3d θα επρεπε να γραψεις και hlsl, σε αυτο που δουλευεις εχει ετοιμα μερικα κερνελς. Λοιπον, ετσι δουλευει η gpu. Βςβαια η gpu ειναι πανω στην motherboard η οποια εχει cpu ram μπλα μπλα. !αι το προγραμμα σου τρεχει πανω στην motherboard. Αυτο εχει την δυνατοτητα να φορτωνει δεδομενα απο την ραμ στην βιραμ και να εκτελει προγραμματα στη gpu. Ο σκοπος σου ειναι να εχεις την μικροτερη επικοινωνία απο cpu σε gpu για να αποφυγεις το botleneck. Ενα προγραμμα το οποιο δουλευει με gpu θα πρεπει πρωτα να φορτωσει τα vertex buffers/kernels/texture και μετα απλα να κανει update δι;φορες μετ;βλητες και να καλει τον καθε κερνελ. Στο προγραμμα σου το σοβαρο λαθος ει αι πως κανεις update τους vertex buffers σε καθε call του pipeline. Βαριεμαι να γραψω αλλα, αν εχεις απορια πες την. 1
ChRis6 Δημοσ. 26 Ιανουαρίου 2017 Δημοσ. 26 Ιανουαρίου 2017 @παπι Ολόκληρο σεντόνι έγραψες (με τελείως offtopic και με λάθος περιγραφή για το πως δουλεύει η GPU...Αυτό που προσπαθείς να περιγράψεις είναι από την οπτική της OpenGL/DX ). Πού να μην βαριόσουν δηλαδή... TS: Εφόσον πρέπει να το κάνετε σε glut, δεν μπορείς να φτιάξεις το δικό σου game loop, αφού η glut έχει το δικό της. Αν δεν έχετε τον περιορισμό της glut, τότε μια καλή εναλλάκτική είναι η glfw στην οποία μπορείς να γράψεις το δικό σου game loop. Αλλά για την πολυπλοκότητα του project, δεν χρειάζεται. Αυτό που μπορείς να κάνεις είναι να τα βάλεις όλα μέσα στη my_display(), δηλαδή game logic ( collisions, πότε "χάνεις", αλλάζεις τη θέση των αντικειμένων κτλ) και draw calls (δηλαδή αυτά που βάζεις ανάμεσα στα glBegin() και glEnd()). Αυτή τη στιγμή το "game logic" τρέχει μέσα στην idle callback της glut, που σημαίνει ότι όταν η glut δεν έχει τι να κάνει (δηλαδή να ζωγραφίσει frame, να πάρει input από το πληκτρολόγιο, το ποντίκι κτλ), εκτελεί το "logic" του παιχνιδιού. Μπορείς να κάνεις το "logic" μέσα στην idle callback για τώρα.... Αυτό που θα σε βοηθήσει είναι να ακολουθήσεις τον "τρόπο" που διαχειρίζεσαι τη μπάλα ( το οποίο είτε το τσίμπησες από κάπου online είτε σας το έδωσαν, γιατί δείχνεις να μην καταλαβαίνεις πως δουλεύει η μπάλα κοιτώντας τον κώδικα για το paddle ). Αρχικά ξέχνα πως θα μετακινείς τη μπάρα. Απλά γράψε κώδικα που να ζωγραφίζει τη μπάρα από το (0,0) μέχρι (paddleSizeX, paddleSizeY), ζωγραφίζοντας τη δηλαδή με σημείο αναφοράς το (0,0) και σαν παράμετρο το μέγεθος της. Δηλαδή: // input paddle sizeX void DrawPaddle( float sizeX, float sizeY){ glBegin(GL_QUADS); glVertex3f(0.0f, 0.0f, 0.0f); glVertex3f(... , ... , 0.0f); glVertex3f(... , ... , 0.0f); glVertex3f(... , ... , 0.0f); glEnd(); } Μετά για να τη μετακινήσεις, καλείς την glTranslate3f(posX, posY) με τον MODELVIEW ενεργό και μοναδιαίο. // draw paddle at (positionX, position Y) glLoadMatrix(GL_MODELVIEW); glLoadIdentity(); // move paddle's (0, 0) at (positionX, positionY) // This will draw the paddle at: (positionX, positionY) (positionX + paddleSizeX, positionY + paddleSizeY) glTranslate3f( positionX, positionY, 0.0f); // Vertex z coordinate is 0 DrawPaddle(); Μετά για να μετακινείς τη μπάρα, σε κάθε επανάληψη (είτε στην my_display() είτε στην idle) αλλάζεις την τιμή των μεταβλητών positionX και positionY, μέ βάση ποια πλήκτρα πατάει ο χρήστης (πχ βελάκι πανω, κάτω, δεξιά, αριστερά). Τώρα μπορείς να φτιάξεις μια class που να περιγράφει τις ιδιότητες της μπάρας. Πχ : class Paddle{ public: Paddle(){} Paddle(float size_x, float size_y): sizeX(size_x), sizeY(size_y){} // set/get position of paddle void SetPosX(float x) { posX = x;} float GetPosX() const { return posX;} // You can also have the draw call as a method, // but that mixes drawing with logic. It's ok for now... void Draw(){ DrawPaddle(sizeX, sizeY); } private: float posX; // top left cornerX float posY; // top left cornerY float sizeX; // size in X axis (bottom left vertex at (posX + sizeX)) float sizeY; // size in Y axis }; // Global variable: Paddle myPaddle(...); // or init (set/get whatever you want in main but before entering glut's loop) // in my_display() // clear color buffer etc... glLoadMatrix(GL_MODELVIEW); glLoadIdentity(); glTranslate3f(paddle.GetPosX(), paddle.GetPosY(), 0.0f); paddle.Draw(); glLoadIdentity(); glTranslate3f( ballPosX, ballPosY) DrawBall(); //... // then flush or just swap buffers. Probably glut will flush anyway glutSwapBuffers() Με τον ίδιο τρόπο μπορείς να φτιάξεις και μια κλάση για τα τουβλάκια, η οποία θα είναι παρόμοια με την Paddle. Εφόσον χρειάζεσαι πολλά τουβλάκια, μπορείς να φτιάξεις πολλά τουβλάκια και να τα βάλεις σε ένα πίνακα. Αν ζωγραφίζεις πολλά τουβλάκια στην οθόνη, πρόσεχε ποιον μετασχηματισμό δίνεις στα σημεία. Δηλαδή : glLoadMatrix(GL_MODELVIEW); // draws ball at (ballPosX, ballPosY) glLoadIdentity(); glTranslate3f(ballPosX, ballPosY, 0.0f); DrawBall(); // draws ball at (ballPosX + x, ballPosY + y) // previous call of glTranslate3f() adds to this one glTraslate3f(x, y, 0.0f); DrawBall(); // draws ball at (newX, newY) glLoadIdentity(); // set identity matrix glTraslate3f(newX, newY, 0.0f); DrawBall(); Συνεπώς για να ζωγραφίσεις πολλά τουβλάκια: // array of bricks const int numBricks = 5; Brick myBricks[5]; // init somewhere in main, before entering game loop // in my_display(): glLoadMatrix(GL_MODELVIEW); // draw bricks for( int i = 0; i < numBricks; i++){ glLoadIdentity(); glTranslate3f(myBricks[i].posX, myBricks[i].posY, 0.0f); myBricks[i].Draw(); } // flush etc at the end of my_display() Όταν φτάσεις σε αυτό το σημείο στον κώδικα, μπορείς να κάνεις κι άλλα ωραία πράγματα, δηλαδή να μην κάνεις συνέχεια glLoadIdentity() πριν από κάθε νέο draw call, αλλά να κάνεις push και pop τον πίνακα μετασχηματισμού, όπως λέει ο παπι να μην δίνεις σε κάθε επαναληψη τα σημεία ( μεταξύ glBegin() και glEnd() ) και τα μεταφέρεις συνέχεια στη GPU κτλ. Αυτά είναι όμως optimizations, δεν χρειάζεται να τα κάνεις για να τρέχει "γρήγορα και σωστά" ένα τέτοιο παιχνίδι με το σημερινό hardware. Ελπίζω να σε βοήθησα να καταλάβεις πάνω κάτω τι πρέπει να κάνεις και με ποιο τρόπο να αντιμετωπίσεις το project σου. Τελευταία κουβέντα: τελείως fail για τον καθηγητή σας να σας βάζει να γράφετε σε τόσο παλιά έκδοση της OpenGL. Καταλαβαίνω οτι είναι απλά μάθημα για να μπείτε στο νόημα, αλλά στην εποχή που κυριαρχούν shaders και programmable pipelines, είναι κουλό να σας μαθαίνουν deprecated OpenGL. Βέβαια με την "καινούρια" έκδοση, glBegin(), glVertex() και τα σχετικά δεν υπάρχουν και για να ζωγραφίσεις έστω και ένα τρίγωνο στην οθόνη πρέπει να κατανοήσεις πως δουλεύει η OpenGL και στην τελική ίσως να αποθαρρύνει τους μαθητές. Who knows... 2
παπι Δημοσ. 26 Ιανουαρίου 2017 Δημοσ. 26 Ιανουαρίου 2017 Αν δςν κααλαβεις πως δουλευει η τζιπιιου δεν εχεινκανα νοημα να προσπαθεις... Οταν παω σπιτο και εχω ορεξη θα γεαψω ενα παραδειγμα
παπι Δημοσ. 27 Ιανουαρίου 2017 Δημοσ. 27 Ιανουαρίου 2017 Εδω ενα απλο παραδειγμα https://github.com/AnonymoPapaki/glut-me-trigona-kai-mpoygatsa/blob/master/glutexample/Source.cpp με το 1,2 επιλεγεις ενα απο τα δυο τριγωνα με a,d πας αριστερα δεξια το επιλεγμενο με z,x το περιστρεφεις αριστερα δεξια ο κωδικας ειναι γτπκ, αλλα δεν κανω εμφαση σε αυτο, αυτο που θελω να σου δειξω ειναι πως δουλευεις με την gpu, το pipeline, τα state και οι buffers. Εχεις ενα mesh (το οποιο ειναι τριγωνο, αλλα αν θες πας στο blender και φτιαχνεις οτι θες) και δυο model που το κανουν share. 1
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα