Answered step by step
Verified Expert Solution
Question
1 Approved Answer
C++Help with OOP This program animates several shapes, bouncing them around on the screen. Rewrite the program using principles of object-oriented programming. You should be
C++Help with OOP
This program animates several shapes, bouncing them around on the screen. Rewrite the program using principles of object-oriented programming. You should be able to eliminate the type variable. The rewritten program should behave the same as before (this is called refactoring) but make better use of objects, inheritance, and virtual functions.
Shape.h #pragma once class Shape { private: static const int WIDTH = 720; static const int HEIGHT = 480; float x; float y; float deltaX; float deltaY; int type; // Identifies type of shape being stored. See list below. int radius; // If its a circle this is the radius int diameter; // If its a square this is the diameter public: Shape(); Shape(int type, int value); // Type: 0=Square, 1=Circle, 2=MultiColorCircle. Value: Radius or Diameter ~Shape(); void draw(); void updateCoordinates(); };
Shape.cpp
#include "Shape.h" #include "gl/glut.h" #include "gl/gl.h" #include "gl/glu.h" #include #include using namespace std; Shape::Shape() { // By default, make this a circle of radius 20 pixels type = 1; radius = 20; // Start at a random position and speed x = (float)(rand() % WIDTH); y = (float)(rand() % HEIGHT); deltaX = ((static_cast(rand()) / RAND_MAX) * 8) - 4; deltaY = ((static_cast(rand()) / RAND_MAX) * 8) - 4; } Shape::Shape(int type, int value) { this->type = type; if (type == 0) { // Square diameter = value; } else if (type == 1) { // Circle radius = value; } else if (type == 2) { // Multicolorcircle radius = value; } // Start at a random position and speed x = (float)(rand() % WIDTH); y = (float)(rand() % HEIGHT); deltaX = ((static_cast(rand()) / RAND_MAX) * 8) - 4; deltaY = ((static_cast(rand()) / RAND_MAX) * 8) - 4; } Shape::~Shape() { } // This function draws the shape void Shape::draw() { // Square if (type == 0) { glColor3f(1, 0, 1); glBegin(GL_QUADS); glVertex2f(x - (diameter / 2), y - (diameter / 2)); glVertex2f(x + (diameter / 2), y - (diameter / 2)); glVertex2f(x + (diameter / 2), y + (diameter / 2)); glVertex2f(x - (diameter / 2), y + (diameter / 2)); glEnd(); } // Circle else if (type == 1) { glColor3f(1, 0, 0); glBegin(GL_TRIANGLE_FAN); glVertex2f(x, y); for (float angle = 0; angle < 360; angle += 1) { glVertex2f(x + sin(angle) * radius, y + cos(angle) * radius); } glEnd(); } else if (type == 2) // Multicolor circle { glColor3f(1, 0, 0); glBegin(GL_TRIANGLE_FAN); glVertex2f(x, y); for (float angle = 0; angle < 360; angle += 1) { glVertex2f(x + sin(angle) * radius, y + cos(angle) * radius); } glEnd(); glColor3f(0, 1, 0); glBegin(GL_TRIANGLE_FAN); glVertex2f(x, y); for (float angle = 0; angle < 360; angle += 1) { glVertex2f(x + sin(angle) * radius*2.0 / 3, y + cos(angle) * radius*2.0 / 3); } glEnd(); glColor3f(0, 0, 1); glBegin(GL_TRIANGLE_FAN); glVertex2f(x, y); for (float angle = 0; angle < 360; angle += 1) { glVertex2f(x + sin(angle) * radius*1.0 / 3, y + cos(angle) * radius*1.0 / 3); } glEnd(); } } // This function updates the location of the shape, by adding in deltaX to the x coordinate // and deltaY to the y coordinate. Since the delta's can be negative this allows for moving // up or down. // If the center of the ball goes off the edge of the screen, reverse the direction. void Shape::updateCoordinates() { x += deltaX; y += deltaY; // Check if we hit the edge of the screen and if we did // move it back so it fits and then change the direction if (x >= WIDTH) { x -= deltaX; // deltaX is positive, so make it negative deltaX *= -1; } else if (x < 0) { deltaX *= -1; // deltaX is negative, so make it positive x += deltaX; // add it in so we are not off the edge } if (y >= HEIGHT) { y -= deltaY; // Same for the Y directions deltaY *= -1; } else if (y < 0) { deltaY *= -1; y += deltaY; } }
main.cpp
#include "gl/glut.h" #include "gl/gl.h" #include "gl/glu.h" #include #include #include #include "Shape.h" #include #include #include #include #include using namespace std; // Function prototypes std::chrono::milliseconds delayTime(5); // Controls frame rate void init(); void display(); void updateShape(); // Globals const int WIDTH = 720; const int HEIGHT = 480; static int screenx = 0; static int screeny = 0; Shape* shapes[5]; // Array of pointers to 5 shapes int main(int argc, char** argv) { srand(time(NULL)); glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_MULTISAMPLE | GLUT_DEPTH); glutInitWindowSize(WIDTH, HEIGHT); glutInitWindowPosition(0, 0); glutCreateWindow("Bouncing Objects Demo"); init(); glutDisplayFunc(display); glutIdleFunc(updateShape); // The update function is called when the system is idle (not processing window events) // It is automatically called repeatedly so you don't have to put a loop in it! // In our case we have it update the location of the shapes display(); glutMainLoop(); return 0; } void init() { glClearColor(0.0, 0.0, 0.0, 0.0); glColor3f(1.0, 1.0, 1.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(screenx, screenx + WIDTH, screeny + HEIGHT, screeny); // This creates five shapes with either the specified radius or side of a square // Glut doesn't return from the main loop, so currently these ball objects are deleted only when the app exits. // If we had a keyboard handler or something we could check for an escape key or something and destroy these and exit. shapes[0] = new Shape(1, 5); // Circle with radius = 5 shapes[1] = new Shape(0, 30); // Square with diameter = 30 shapes[2] = new Shape(0, 70); // Square with diameter = 70 shapes[3] = new Shape(2, 50); // MultiColorCircle with radius = 50 shapes[4] = new Shape(2, 100); // MultiColorCircl with radius = 100 } // This function updates the position of each shape then redraws it on the screen by calling display. // This function is called by the GL framework for us when the window is idle. It is called repeatedly so // we can rely on it being invoked whenever there is CPU processing available. In other words, we don't need // to make a loop that keeps calling updateBall() because GLUT will call it for us over and over again // when the system is idle. void updateShape() { for (int i = 0; i < 5; i++) shapes[i]->updateCoordinates(); // The function updates the shape's location on the screen display(); // The line below implements a delay; it specifies how many milliseconds to wait before exiting. When this function // exits, GLUT will end up calling this function again when the system is idle, hence drawing the shapes in a new location. // If this line is removed then the display is updated as fast as possible. // Right now the delay is set at 5ms. Set to 1000 if you wanted to wait one second before each update (slow). std::this_thread::sleep_for(delayTime); } // This draws the shapes on the screen void display() { glClear(GL_COLOR_BUFFER_BIT); // Loop through each shape and draw it for (int i = 0; i < 5; i++) shapes[i]->draw(); glutSwapBuffers(); glFlush(); return; }
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started