From 70ea8877ace50d2ce609d7d5f721c887b0ea83ec Mon Sep 17 00:00:00 2001 From: Logan Hunt Date: Wed, 12 Aug 2020 14:13:50 -0600 Subject: [PATCH] Added files --- UML DIAGRAM.png | Bin 0 -> 57860 bytes src/UFO.cpp | 65 ++++ src/UFO.h | 27 ++ src/bird.cpp | 27 ++ src/bird.h | 19 ++ src/bullet.cpp | 25 ++ src/bullet.h | 16 + src/driver.cpp | 45 +++ src/game.cpp | 320 +++++++++++++++++++ src/game.h | 103 +++++++ src/makefile | 79 +++++ src/point.cpp | 58 ++++ src/point.h | 48 +++ src/rifle.cpp | 45 +++ src/rifle.h | 60 ++++ src/sacredBird.cpp | 26 ++ src/sacredBird.h | 15 + src/standardBird.cpp | 27 ++ src/standardBird.h | 15 + src/toughBird.cpp | 41 +++ src/toughBird.h | 17 ++ src/uiDraw.cpp | 712 +++++++++++++++++++++++++++++++++++++++++++ src/uiDraw.h | 135 ++++++++ src/uiInteract.cpp | 331 ++++++++++++++++++++ src/uiInteract.h | 133 ++++++++ src/velocity.cpp | 58 ++++ src/velocity.h | 23 ++ 27 files changed, 2470 insertions(+) create mode 100644 UML DIAGRAM.png create mode 100644 src/UFO.cpp create mode 100644 src/UFO.h create mode 100644 src/bird.cpp create mode 100644 src/bird.h create mode 100644 src/bullet.cpp create mode 100644 src/bullet.h create mode 100644 src/driver.cpp create mode 100644 src/game.cpp create mode 100644 src/game.h create mode 100644 src/makefile create mode 100644 src/point.cpp create mode 100644 src/point.h create mode 100644 src/rifle.cpp create mode 100644 src/rifle.h create mode 100644 src/sacredBird.cpp create mode 100644 src/sacredBird.h create mode 100644 src/standardBird.cpp create mode 100644 src/standardBird.h create mode 100644 src/toughBird.cpp create mode 100644 src/toughBird.h create mode 100644 src/uiDraw.cpp create mode 100644 src/uiDraw.h create mode 100644 src/uiInteract.cpp create mode 100644 src/uiInteract.h create mode 100644 src/velocity.cpp create mode 100644 src/velocity.h diff --git a/UML DIAGRAM.png b/UML DIAGRAM.png new file mode 100644 index 0000000000000000000000000000000000000000..2cf75a4ed32acbe0abebaf92a8e4bd62693b2352 GIT binary patch literal 57860 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

*@_gP7kPr;fJP&$dWA`NG|Pqyjcx_X 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%0Dn6X2JLN{63TLHBj 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 b{EI=c@jVVlr^YTb!N2|cjP#z8ZG-<0&tX^a literal 0 HcmV?d00001 diff --git a/src/UFO.cpp b/src/UFO.cpp new file mode 100644 index 0000000..3739d21 --- /dev/null +++ b/src/UFO.cpp @@ -0,0 +1,65 @@ +#include "UFO.h" +#include "point.h" +#include "velocity.h" +#include +using namespace std; +// UFO Default constructor +UFO :: UFO() +{ + setAlive ( true ); +} + +// Get Ufo point +Point UFO :: getPoint() const +{ + return this->point; +} + +// Get UFO velocity +Velocity UFO:: getVelocity() const +{ + return this->velocity; +} + +// Get UFO alive +bool UFO :: isAlive() const +{ + return this->alive; +} + +// Set UFO point +void UFO :: setPoint( const Point &point ) +{ + this->point = point; +} + +// Set UFO velocity +void UFO :: setVelocity( const Velocity &velocity) +{ + this->velocity = velocity; +} + +// Set UFO velocity with dy & dx +void UFO :: setVelocity ( float dx , float dy ) +{ + velocity = Velocity ( dx , dy ); +} + +// Set UFO alive +void UFO :: setAlive ( const bool alive ) +{ + this->alive = alive; +} + +// Advance UFO +void UFO :: advance() +{ + setPoint ( this->velocity.updatePoint ( this->point ) ); +} + + +// Kill UFO +void UFO :: kill() +{ + this->alive = false; +} diff --git a/src/UFO.h b/src/UFO.h new file mode 100644 index 0000000..cf67461 --- /dev/null +++ b/src/UFO.h @@ -0,0 +1,27 @@ +#ifndef UFO_H +#define UFO_H + +#include "point.h" +#include "velocity.h" + +class UFO +{ + public: + UFO(); + Point getPoint() const; + Velocity getVelocity() const; + bool isAlive() const; + void setAlive ( bool isAlive ); + void setPoint( const Point &point ); + void setVelocity( const Velocity &velocity ); + void setVelocity ( float dx , float dy ); + void advance(); + void kill(); + virtual void draw() = 0; + protected: + bool alive; + Point point; + Velocity velocity; +}; + +#endif diff --git a/src/bird.cpp b/src/bird.cpp new file mode 100644 index 0000000..24e660c --- /dev/null +++ b/src/bird.cpp @@ -0,0 +1,27 @@ +#include "bird.h" +#include "point.h" +#include "velocity.h" +#include "uiDraw.h" +#include +using namespace std; +// Default constructor +Bird :: Bird() +{ + point.setX( -200.0 ); + point.setY( -200 ); // (float)random ( -100 , 100 ) + setRandomDx(); + setRandomDy( 5.0 , 8.7 ); +} + +void Bird :: draw() {} + +void Bird :: setRandomDx() +{ + float dx = random ( 1.0 , 3.0 ); + velocity.setDx ( dx ); +} + +void Bird :: setRandomDy( const float minDy , const float maxDy ) +{ + velocity.setDy ( random ( minDy , maxDy ) * ( point.getY() > 0 ? 1 : 1 ) ); +} diff --git a/src/bird.h b/src/bird.h new file mode 100644 index 0000000..3354f59 --- /dev/null +++ b/src/bird.h @@ -0,0 +1,19 @@ +#ifndef BIRD_H +#define BIRD_H + +#include "point.h" +#include "velocity.h" +#include "UFO.h" + +class Bird: public UFO +{ + public: + Bird(); + void setRandomDy( const float minDy , const float maxDy ); + void setRandomDx(); + void draw(); + virtual void applyGravity ( ) = 0; + virtual int hit() = 0; +}; + +#endif diff --git a/src/bullet.cpp b/src/bullet.cpp new file mode 100644 index 0000000..fc9961b --- /dev/null +++ b/src/bullet.cpp @@ -0,0 +1,25 @@ +#define BULLET_SPEED 10.0 +#define M_PI 3.14159 +#include +#include "bullet.h" +#include "uiDraw.h" +#include +using namespace std; + +Bullet :: Bullet() : UFO() +{ + +} + +void Bullet :: draw() +{ + drawDot( point ); +} + +void Bullet :: fire( Point point , float angle ) +{ + float dx = BULLET_SPEED * (-cos(M_PI / 180.0 * angle)); + float dy = BULLET_SPEED * (sin(M_PI / 180.0 * angle)); + setPoint( point ); + setVelocity( dx , dy ); +} diff --git a/src/bullet.h b/src/bullet.h new file mode 100644 index 0000000..ff9bb80 --- /dev/null +++ b/src/bullet.h @@ -0,0 +1,16 @@ +#ifndef BULLET_H +#define BULLET_H + +#include "velocity.h" +#include "point.h" +#include "UFO.h" + +class Bullet: public UFO +{ + public: + Bullet(); + void draw(); + void fire( Point point , float angle ); +}; + +#endif diff --git a/src/driver.cpp b/src/driver.cpp new file mode 100644 index 0000000..554ce19 --- /dev/null +++ b/src/driver.cpp @@ -0,0 +1,45 @@ +/***************************************************** + * File: Driver.cpp + * Author: Br. Burton + * + * Description: This file contains the main function + * that starts the game and the callback function + * that specifies what methods of the game class are + * called each time through the game loop. + ******************************************************/ +#include "game.h" +#include "uiInteract.h" + +/************************************* + * All the interesting work happens here, when + * I get called back from OpenGL to draw a frame. + * When I am finished drawing, then the graphics + * engine will wait until the proper amount of + * time has passed and put the drawing on the screen. + **************************************/ +void callBack(const Interface *pUI, void *p) +{ + Game *pGame = (Game *)p; + + pGame->advance(); + pGame->handleInput(*pUI); + pGame->draw(*pUI); +} + + +/********************************* + * Main is pretty sparse. Just initialize + * the game and call the display engine. + * That is all! + *********************************/ +int main(int argc, char ** argv) +{ + Point topLeft(-200, 200); + Point bottomRight(200, -200); + + Interface ui(argc, argv, "Skeet", topLeft, bottomRight); + Game game(topLeft, bottomRight); + ui.run(callBack, &game); + + return 0; +} diff --git a/src/game.cpp b/src/game.cpp new file mode 100644 index 0000000..d6b4d38 --- /dev/null +++ b/src/game.cpp @@ -0,0 +1,320 @@ +/************************************************************* + * File: game.cpp + * Author: Br. Burton + * + * Description: Contains the implementations of the + * method bodies for the game class. + * + * Please DO NOT share this code with other students from + * other sections or other semesters. They may not receive + * the same code that you are receiving. + *************************************************************/ + +#include "game.h" + +#include +#include "uiDraw.h" +#include "uiInteract.h" +#include "velocity.h" +#include "point.h" + +#include +using namespace std; + +#define OFF_SCREEN_BORDER_AMOUNT 5 + + +/*************************************** + * GAME CONSTRUCTOR + ***************************************/ +Game :: Game(Point tl, Point br) + : topLeft(tl), bottomRight(br), rifle(br) +{ + // Set up the initial conditions of the game + score = 0; + // TODO: Set your bird pointer to a good initial value (e.g., NULL) + for ( int i = 0; i < 3; i++ ) + { + bird[i] = NULL; + } +} + +/**************************************** + * GAME DESTRUCTOR + ****************************************/ +Game :: ~Game() +{ + // TODO: Check to see if there is currently a bird allocated + // and if so, delete it. + for ( int i = 0; i < 3; i++ ) + { + if (bird[i] != NULL) { + delete bird[i]; + bird[i] = NULL; + } + } +} + +/*************************************** + * GAME :: ADVANCE + * advance the game one unit of time + ***************************************/ +void Game :: advance() +{ + advanceBullets(); + advanceBird(); + + handleCollisions(); + cleanUpZombies(); +} + +/*************************************** + * GAME :: ADVANCE BULLETS + * Go through each bullet and advance it. + ***************************************/ +void Game :: advanceBullets() +{ + // Move each of the bullets forward if it is alive + for (int i = 0; i < bullets.size(); i++) + { + if (bullets[i].isAlive()) + { + // this bullet is alive, so tell it to move forward + bullets[i].advance(); + + if (!isOnScreen(bullets[i].getPoint())) + { + // the bullet has left the screen + bullets[i].kill(); + } + + } + } +} + +/************************************************************************** + * GAME :: ADVANCE BIRD + * + * 1. If there is no bird, create one with some probability + * 2. If there is a bird, and it's alive, advance it + * 3. Check if the bird has gone of the screen, and if so, "kill" it + **************************************************************************/ +void Game :: advanceBird() +{ + for ( int i = 0; i < 3; i++ ) + { + if (bird[i] == NULL) + { + // there is no bird right now, possibly create one + + // "resurrect" it will some random chance + if (random(0, 30) == 0) + { + // create a new bird + bird[i] = createBird(); + } + } + else + { + // we have a bird, make sure it's alive + if (bird[i]->isAlive()) + { + // move it forward + bird[i]->advance(); + bird[i]->applyGravity(); + // check if the bird has gone off the screen + if (!isOnScreen(bird[i]->getPoint())) + { + // We have missed the bird + bird[i]->kill(); + } + } + } + } + +} + +/************************************************************************** + * GAME :: CREATE BIRD + * Create a bird of a random type according to the rules of the game. + **************************************************************************/ +Bird* Game :: createBird() +{ + Bird* newBird = NULL; + // TODO: Fill this in + // Set random birds + int ran = random(1,4); + + if(ran == 1) + { + newBird = new StandardBird(); + } + + else if(ran == 2) + { + newBird = new ToughBird(); + } + else + { + newBird = new SacredBird(); + } + + return newBird; +} + +/************************************************************************** + * GAME :: IS ON SCREEN + * Determines if a given point is on the screen. + **************************************************************************/ +bool Game :: isOnScreen(const Point & point) +{ + return (point.getX() >= topLeft.getX() - OFF_SCREEN_BORDER_AMOUNT + && point.getX() <= bottomRight.getX() + OFF_SCREEN_BORDER_AMOUNT + && point.getY() >= bottomRight.getY() - OFF_SCREEN_BORDER_AMOUNT + && point.getY() <= topLeft.getY() + OFF_SCREEN_BORDER_AMOUNT); +} + +/************************************************************************** + * GAME :: HANDLE COLLISIONS + * Check for a collision between a bird and a bullet. + **************************************************************************/ +void Game :: handleCollisions() +{ + // now check for a hit (if it is close enough to any live bullets) + for (int i = 0; i < bullets.size(); i++) + { + if (bullets[i].isAlive()) + { + // this bullet is alive, see if its too close + + // check if the bird is at this point (in case it was hit) + for ( int j = 0; j < 3; j++ ) + { + if (bird[j] != NULL && bird[j]->isAlive()) + { + if (fabs(bullets[i].getPoint().getX() - bird[j]->getPoint().getX()) < CLOSE_ENOUGH + && fabs(bullets[i].getPoint().getY() - bird[j]->getPoint().getY()) < CLOSE_ENOUGH) + { + //we have a hit! + // hit the bird + int points = bird[j]->hit(); + score += points; + + // the bullet is dead as well + bullets[i].kill(); + } + } + } + } // if bullet is alive + + } // for bullets +} + +/************************************************************************** + * GAME :: CLEAN UP ZOMBIES + * Remove any dead objects (take bullets out of the list, deallocate bird) + **************************************************************************/ +void Game :: cleanUpZombies() +{ + // check for dead bird + for ( int i = 0; i < 3; i++ ) + { + if ( bird[i] != NULL && !bird[i]->isAlive() ) + { + delete bird[i]; + bird[i] = NULL; + } + } + + // Look for dead bullets + vector::iterator bulletIt = bullets.begin(); + while (bulletIt != bullets.end()) + { + Bullet bullet = *bulletIt; + // Asteroids Hint: + // If we had a list of pointers, we would need this line instead: + //Bullet* pBullet = *bulletIt; + + if (!bullet.isAlive()) + { + // If we had a list of pointers, we would need to delete the memory here... + + + // remove from list and advance + bulletIt = bullets.erase(bulletIt); + } + else + { + bulletIt++; // advance + } + } + +} + +/*************************************** + * GAME :: HANDLE INPUT + * accept input from the user + ***************************************/ +void Game :: handleInput(const Interface & ui) +{ + // Change the direction of the rifle + if (ui.isLeft()) + { + rifle.moveLeft(); + } + + if (ui.isRight()) + { + rifle.moveRight(); + } + + // Check for "Spacebar + if (ui.isSpace()) + { + Bullet newBullet; + newBullet.fire(rifle.getPoint(), rifle.getAngle()); + + bullets.push_back(newBullet); + } + +} + +/********************************************* + * GAME :: DRAW + * Draw everything on the screen + *********************************************/ +void Game :: draw(const Interface & ui) +{ + // draw the bird + + // TODO: Check if you have a valid bird and if it's alive + // then call it's draw method + for ( int i = 0; i < 3; i++ ) + { + if (bird[i] != NULL && bird[i]->isAlive()) + { + bird[i]->draw(); + } + } + + + // draw the rifle + rifle.draw(); + + // draw the bullets, if they are alive + for (int i = 0; i < bullets.size(); i++) + { + if (bullets[i].isAlive()) + { + bullets[i].draw(); + } + } + + // Put the score on the screen + Point scoreLocation; + scoreLocation.setX(topLeft.getX() + 5); + scoreLocation.setY(topLeft.getY() - 5); + + drawNumber(scoreLocation, score); + +} diff --git a/src/game.h b/src/game.h new file mode 100644 index 0000000..4c26bc4 --- /dev/null +++ b/src/game.h @@ -0,0 +1,103 @@ +/************************************************************* + * File: game.h + * Author: Br. Burton + * + * Description: The game of Skeet. This class holds each piece + * of the game (birds, bullets, rifle, score). It also has + * methods that make the game happen (advance, interact, etc.) + * + * Please DO NOT share this code with other students from + * other sections or other semesters. They may not receive + * the same code that you are receiving. + *************************************************************/ + +#ifndef GAME_H +#define GAME_H + +#include + +#include "uiDraw.h" +#include "uiInteract.h" +#include "point.h" +#include "velocity.h" +#include "rifle.h" + + +// TODO: include your bullet and bird classes +#include "bullet.h" +#include "bird.h" +#include "sacredBird.h" +#include "toughBird.h" +#include "standardBird.h" +#include "UFO.h" + +#define CLOSE_ENOUGH 15 + + +/***************************************** + * GAME + * The main game class containing all the state + *****************************************/ +class Game +{ +public: + /********************************************* + * Constructor + * Initializes the game + *********************************************/ + Game(Point tl, Point br); + ~Game(); + + /********************************************* + * Function: handleInput + * Description: Takes actions according to whatever + * keys the user has pressed. + *********************************************/ + void handleInput(const Interface & ui); + + /********************************************* + * Function: advance + * Description: Move everything forward one + * step in time. + *********************************************/ + void advance(); + + /********************************************* + * Function: draw + * Description: draws everything for the game. + *********************************************/ + void draw(const Interface & ui); + +private: + // The coordinates of the screen + Point topLeft; + Point bottomRight; + + int score; + + Rifle rifle; + std::vector bullets; + + // TODO: declare your bird here (e.g., "Bird * bird;") + Bird * bird[3]; + + /************************************************* + * Private methods to help with the game logic. + *************************************************/ + bool isOnScreen(const Point & point); + void advanceBullets(); + void advanceBird(); + Bird* createBird(); + + void handleCollisions(); + void cleanUpZombies(); + + /************************************************* + * Private value to check if user want to play + *************************************************/ + bool bStartGame; + + void startGame(); +}; + +#endif /* GAME_H */ diff --git a/src/makefile b/src/makefile new file mode 100644 index 0000000..16eab92 --- /dev/null +++ b/src/makefile @@ -0,0 +1,79 @@ +############################################################### +# Program: +# Project 09, Skeet +# Brother MacBeth, CS165 +# Author: +# Logan Hunt +# Summary: +# Project 09 Skeet +# Above and Beyond +# Added gravity +# Multiple Birds +############################################################### + + +LFLAGS = -lglut -lGLU -lGL + +############################################################### +# Build the main game +############################################################### +a.out: driver.o game.o uiInteract.o uiDraw.o point.o velocity.o rifle.o UFO.o bullet.o bird.o standardBird.o toughBird.o sacredBird.o + g++ driver.o game.o uiInteract.o uiDraw.o point.o velocity.o rifle.o UFO.o bullet.o bird.o standardBird.o toughBird.o sacredBird.o $(LFLAGS) + +############################################################### +# Individual files +# uiDraw.o Draw polygons on the screen and do all OpenGL graphics +# uiInteract.o Handles input events +# point.o The position on the screen +# ground.o Handles the ground / world +# game.o Handles the game interaction +############################################################### +uiDraw.o: uiDraw.cpp uiDraw.h point.h + g++ -c uiDraw.cpp + +uiInteract.o: uiInteract.cpp uiInteract.h + g++ -c uiInteract.cpp + +point.o: point.cpp point.h + g++ -c point.cpp + +game.o: game.cpp uiDraw.h uiInteract.h point.h rifle.h bullet.h bird.h UFO.h + g++ -c game.cpp + +driver.o: game.h uiInteract.h driver.cpp + g++ -c driver.cpp + +rifle.o: rifle.h point.h uiDraw.h rifle.cpp + g++ -c rifle.cpp + +####################################################################### +# ADD YOUR ADDITIONAL RULES HERE! +# +# Then, don't forget to add them to the dependecy list for a.out above. +####################################################################### +bullet.o: bullet.h bullet.cpp UFO.h + g++ -c bullet.cpp + +bird.o: bird.h bird.cpp UFO.h standardBird.h sacredBird.h toughBird.h + g++ -c bird.cpp + +UFO.o: UFO.h UFO.cpp velocity.h + g++ -c UFO.cpp velocity.h + +velocity.o: velocity.h velocity.cpp + g++ -c velocity.cpp + +toughBird.o: toughBird.h toughBird.cpp + g++ -c toughBird.cpp + +standardBird.o: standardBird.h standardBird.cpp + g++ -c standardBird.cpp + +sacredBird.o: sacredBird.h sacredBird.cpp + g++ -c sacredBird.cpp + +############################################################### +# General rules +############################################################### +clean: + rm a.out *.o diff --git a/src/point.cpp b/src/point.cpp new file mode 100644 index 0000000..4008da6 --- /dev/null +++ b/src/point.cpp @@ -0,0 +1,58 @@ + +#include "point.h" +#include + +/****************************************** + * POINT : CONSTRUCTOR WITH X,Y + * Initialize the point to the passed position + *****************************************/ +Point::Point(float x, float y) : x(0.0), y(0.0) +{ + setX(x); + setY(y); +} + +/******************************************* + * POINT : SET X + * Set the x position if the value is within range + *******************************************/ +void Point::setX(float x) +{ + this->x = x; +} + +/******************************************* + * POINT : SET Y + * Set the y position if the value is within range + *******************************************/ +void Point::setY(float y) +{ + this->y = y; +} + +/****************************************** + * POINT insertion + * Display coordinates on the screen + *****************************************/ +std::ostream & operator << (std::ostream & out, const Point & pt) +{ + out << "(" << pt.getX() << ", " << pt.getY() << ")"; + return out; +} + +/******************************************* + * POINT extraction + * Prompt for coordinates + ******************************************/ +std::istream & operator >> (std::istream & in, Point & pt) +{ + float x; + float y; + in >> x >> y; + + pt.setX(x); + pt.setY(y); + + return in; +} + diff --git a/src/point.h b/src/point.h new file mode 100644 index 0000000..545ce17 --- /dev/null +++ b/src/point.h @@ -0,0 +1,48 @@ +/*********************************************************************** + * Header File: + * Point : The representation of a position on the screen + * Author: + * Br. Helfrich + * Summary: + * Everything we need to know about a location on the screen, including + * the location and the bounds. + ************************************************************************/ + + +#ifndef POINT_H +#define POINT_H + +#include + +/********************************************* + * POINT + * A single position. + *********************************************/ +class Point +{ +public: + // constructors + Point() : x(0.0), y(0.0) {} + Point(bool check) : x(0.0), y(0.0) {} + Point(float x, float y); + + // getters + float getX() const { return x; } + float getY() const { return y; } + + // setters + void setX(float x); + void setY(float y); + void addX(float dx) { setX(getX() + dx); } + void addY(float dy) { setY(getY() + dy); } + +private: + float x; // horizontal position + float y; // vertical position +}; + +// stream I/O useful for debugging +std::ostream & operator << (std::ostream & out, const Point & pt); +std::istream & operator >> (std::istream & in, Point & pt); + +#endif // POINT_H diff --git a/src/rifle.cpp b/src/rifle.cpp new file mode 100644 index 0000000..355d42f --- /dev/null +++ b/src/rifle.cpp @@ -0,0 +1,45 @@ +/************************************************************* + * File: rifle.cpp + * Author: Br. Burton + * + * Description: Contains the function bodies for the rifle class. + * + * Please DO NOT share this code with other students from + * other sections or other semesters. They may not receive + * the same code that you are receiving. + *************************************************************/ + +#include "rifle.h" +#include "point.h" +#include "uiDraw.h" + +#include + +void Rifle :: draw() const +{ + assert(angle >= ANGLE_MIN); + assert(angle <= ANGLE_MAX); + + drawRect(point, RIFLE_WIDTH, RIFLE_HEIGHT, 90 - angle); +} + +void Rifle :: moveLeft() +{ + angle -= RIFLE_MOVE_AMOUNT; + + if (angle < ANGLE_MIN) + { + angle = ANGLE_MIN; + } +} + + +void Rifle :: moveRight() +{ + angle += RIFLE_MOVE_AMOUNT; + + if (angle > ANGLE_MAX) + { + angle = ANGLE_MAX; + } +} diff --git a/src/rifle.h b/src/rifle.h new file mode 100644 index 0000000..f095680 --- /dev/null +++ b/src/rifle.h @@ -0,0 +1,60 @@ +/************************************************************* + * File: rifle.h + * Author: Br. Burton + * + * Description: Defines a Rifle. + * + * Please DO NOT share this code with other students from + * other sections or other semesters. They may not receive + * the same code that you are receiving. + *************************************************************/ + +#ifndef RIFLE_H +#define RIFLE_H + +#include "point.h" + +#define RIFLE_WIDTH 5 +#define RIFLE_HEIGHT 40 + +#define ANGLE_MAX 90 +#define ANGLE_MIN 0 +#define ANGLE_START 45 + +#define RIFLE_MOVE_AMOUNT 3 + +class Rifle +{ +private: + Point point; + + /********************************************************** + * angle - The angle of the rifles in degrees. + * Assumes that straight right is 0 degrees and up is 90. + **********************************************************/ + float angle; + + +public: + Rifle(const Point & point) : point(point) { angle = ANGLE_START; } + + /**************** + * Basic Getters + ****************/ + float getAngle() const { return angle; } + Point getPoint() const { return point; } + + /***************** + * Drawing + *****************/ + void draw() const; + + /***************** + * Movement + *****************/ + void moveLeft(); + void moveRight(); + +}; + +#endif diff --git a/src/sacredBird.cpp b/src/sacredBird.cpp new file mode 100644 index 0000000..72e9c2c --- /dev/null +++ b/src/sacredBird.cpp @@ -0,0 +1,26 @@ +#include "sacredBird.h" +#include "uiDraw.h" +#include "UFO.h" +// SacredBird constructor +SacredBird :: SacredBird() : Bird() +{ +} + +// Draw SacredBird +void SacredBird :: draw() +{ + drawSacredBird( point , 15 ); +} + +// Apply gravity to SacredBird +void SacredBird :: applyGravity () +{ + this->velocity.addDy ( -0.1 ); +} + +// Hit SacredBird +int SacredBird :: hit() +{ + kill(); + return -10; +} diff --git a/src/sacredBird.h b/src/sacredBird.h new file mode 100644 index 0000000..67ea440 --- /dev/null +++ b/src/sacredBird.h @@ -0,0 +1,15 @@ +#ifndef SACREDBIRD_H +#define SACREDBIRD_H + +#include "bird.h" + +class SacredBird: public Bird +{ + public: + SacredBird (); + void draw(); + int hit(); + void applyGravity(); +}; + +#endif diff --git a/src/standardBird.cpp b/src/standardBird.cpp new file mode 100644 index 0000000..38f8e46 --- /dev/null +++ b/src/standardBird.cpp @@ -0,0 +1,27 @@ +#include "standardBird.h" +#include "uiDraw.h" + +// StandardBird constructor +StandardBird :: StandardBird() : Bird() +{ + +} + +// Draw StandardBird +void StandardBird :: draw() +{ + drawCircle( point , 15 ); +} + +// Apply gravity to StandardBird +void StandardBird :: applyGravity () +{ + this->velocity.addDy ( -0.1 ); +} + +// Hit StandardBird +int StandardBird :: hit() +{ + kill(); + return 1; +} diff --git a/src/standardBird.h b/src/standardBird.h new file mode 100644 index 0000000..73d87fe --- /dev/null +++ b/src/standardBird.h @@ -0,0 +1,15 @@ +#ifndef STANDARDBIRD_H +#define STANDARDBIRD_H + +#include "bird.h" + +class StandardBird: public Bird +{ + public: + StandardBird(); + void draw(); + int hit(); + void applyGravity(); +}; + +#endif diff --git a/src/toughBird.cpp b/src/toughBird.cpp new file mode 100644 index 0000000..51d5cec --- /dev/null +++ b/src/toughBird.cpp @@ -0,0 +1,41 @@ +#include "toughBird.h" +#include "bullet.h" +#include "uiDraw.h" +#include + +// ToughBird default constructor +ToughBird :: ToughBird() : Bird() +{ + health = 3; + setRandomDy( 4.5 , 6.5 ); +} + +// Hit ToughBird +int ToughBird :: hit() +{ + if ( health > 1 ) + { + health -= 1; + return 1; + } + else + { + kill(); + return 2; + } + return 0; +} + + +// Apply gravity to ToughBird +void ToughBird :: applyGravity () +{ + this->velocity.addDy ( -0.05 ); +} + + +// Draw ToughBird +void ToughBird :: draw() +{ + drawToughBird( point , 15 , health ); +} diff --git a/src/toughBird.h b/src/toughBird.h new file mode 100644 index 0000000..e5e6826 --- /dev/null +++ b/src/toughBird.h @@ -0,0 +1,17 @@ +#ifndef TOUGHBIRD_H +#define TOUGHBIRD_H + +#include "bird.h" +#include "bullet.h" +class ToughBird: public Bird +{ + public: + ToughBird (); + void draw(); + int hit(); + void applyGravity(); + private: + int health; +}; + +#endif diff --git a/src/uiDraw.cpp b/src/uiDraw.cpp new file mode 100644 index 0000000..759717c --- /dev/null +++ b/src/uiDraw.cpp @@ -0,0 +1,712 @@ +/*********************************************************************** + * Source File: + * User Interface Draw : put pixels on the screen + * Author: + * Br. Helfrich + * Summary: + * This is the code necessary to draw on the screen. We have a collection + * of procedural functions here because each draw function does not + * retain state. In other words, they are verbs (functions), not nouns + * (variables) or a mixture (objects) + ************************************************************************/ + +#include // need you ask? +#include // convert an integer into text +#include // I feel the need... the need for asserts +#include // for clock + + +#ifdef __APPLE__ +#include // Main OpenGL library +#include // Second OpenGL library +#endif // __APPLE__ + +#ifdef __linux__ +#include // Main OpenGL library +#include // Second OpenGL library +#endif // __linux__ + +#ifdef _WIN32 +#include +#include +#include // OpenGL library we copied +#define _USE_MATH_DEFINES +#include +#endif // _WIN32 + +#include "point.h" +#include "uiDraw.h" + +using namespace std; + +#define deg2rad(value) ((M_PI / 180) * (value)) + +/********************************************* + * NUMBER OUTLINES + * We are drawing the text for score and things + * like that by hand to make it look "old school." + * These are how we render each individual charactger. + * Note how -1 indicates "done". These are paired + * coordinates where the even are the x and the odd + * are the y and every 2 pairs represents a point + ********************************************/ +const char NUMBER_OUTLINES[10][20] = +{ + {0, 0, 7, 0, 7, 0, 7,10, 7,10, 0,10, 0,10, 0, 0, -1,-1, -1,-1},//0 + {7, 0, 7,10, -1,-1, -1,-1, -1,-1, -1,-1, -1,-1, -1,-1, -1,-1, -1,-1},//1 + {0, 0, 7, 0, 7, 0, 7, 5, 7, 5, 0, 5, 0, 5, 0,10, 0,10, 7,10},//2 + {0, 0, 7, 0, 7, 0, 7,10, 7,10, 0,10, 4, 5, 7, 5, -1,-1, -1,-1},//3 + {0, 0, 0, 5, 0, 5, 7, 5, 7, 0, 7,10, -1,-1, -1,-1, -1,-1, -1,-1},//4 + {7, 0, 0, 0, 0, 0, 0, 5, 0, 5, 7, 5, 7, 5, 7,10, 7,10, 0,10},//5 + {7, 0, 0, 0, 0, 0, 0,10, 0,10, 7,10, 7,10, 7, 5, 7, 5, 0, 5},//6 + {0, 0, 7, 0, 7, 0, 7,10, -1,-1, -1,-1, -1,-1, -1,-1, -1,-1, -1,-1},//7 + {0, 0, 7, 0, 0, 5, 7, 5, 0,10, 7,10, 0, 0, 0,10, 7, 0, 7,10},//8 + {0, 0, 7, 0, 7, 0, 7,10, 0, 0, 0, 5, 0, 5, 7, 5, -1,-1, -1,-1} //9 +}; + +/************************************************************************ + * DRAW DIGIT + * Draw a single digit in the old school line drawing style. The + * size of the glyph is 8x11 or x+(0..7), y+(0..10) + * INPUT topLeft The top left corner of the character + * digit The digit we are rendering: '0' .. '9' + *************************************************************************/ +void drawDigit(const Point & topLeft, char digit) +{ + // we better be only drawing digits + assert(isdigit(digit)); + if (!isdigit(digit)) + return; + + // compute the row as specified by the digit + int r = digit - '0'; + assert(r >= 0 && r <= 9); + + // go through each segment. + for (int c = 0; c < 20 && NUMBER_OUTLINES[r][c] != -1; c += 4) + { + assert(NUMBER_OUTLINES[r][c ] != -1 && + NUMBER_OUTLINES[r][c + 1] != -1 && + NUMBER_OUTLINES[r][c + 2] != -1 && + NUMBER_OUTLINES[r][c + 3] != -1); + + //Draw a line based off of the num structure for each number + Point start; + start.setX(topLeft.getX() + NUMBER_OUTLINES[r][c]); + start.setY(topLeft.getY() - NUMBER_OUTLINES[r][c + 1]); + Point end; + end.setX(topLeft.getX() + NUMBER_OUTLINES[r][c + 2]); + end.setY(topLeft.getY() - NUMBER_OUTLINES[r][c + 3]); + + drawLine(start, end); + } +} + +/************************************************************************* + * DRAW NUMBER + * Display an integer on the screen using the 7-segment method + * INPUT topLeft The top left corner of the character + * digit The digit we are rendering: '0' .. '9' + *************************************************************************/ +void drawNumber(const Point & topLeft, int number) +{ + // our cursor, if you will. It will advance as we output digits + Point point = topLeft; + + // is this negative + bool isNegative = (number < 0); + number *= (isNegative ? -1 : 1); + + // render the number as text + ostringstream sout; + sout << number; + string text = sout.str(); + + // handle the negative + if (isNegative) + { + glBegin(GL_LINES); + glVertex2f(point.getX() + 1, point.getY() - 5); + glVertex2f(point.getX() + 5, point.getY() - 5); + glEnd(); + point.addX(11); + } + + // walk through the text one digit at a time + for (const char *p = text.c_str(); *p; p++) + { + assert(isdigit(*p)); + drawDigit(point, *p); + point.addX(11); + } +} + + +/************************************************************************* + * DRAW TEXT + * Draw text using a simple bitmap font + * INPUT topLeft The top left corner of the text + * text The text to be displayed + ************************************************************************/ +void drawText(const Point & topLeft, const char * text) +{ + void *pFont = GLUT_BITMAP_HELVETICA_12; // also try _18 + + // prepare to draw the text from the top-left corner + glRasterPos2f(topLeft.getX(), topLeft.getY()); + + // loop through the text + for (const char *p = text; *p; p++) + glutBitmapCharacter(pFont, *p); +} + +/************************************************************************ + * DRAW POLYGON + * Draw a POLYGON from a given location (center) of a given size (radius). + * INPUT center Center of the polygon + * radius Size of the polygon + * points How many points will we draw it. Larger the number, + * the more line segments we will use + * rotation True circles are rotation independent. However, if you + * are drawing a 3-sided polygon (triangle), this matters! + *************************************************************************/ +void drawPolygon(const Point & center, int radius, int points, int rotation) +{ + // begin drawing + glBegin(GL_LINE_LOOP); + + //loop around a circle the given number of times drawing a line from + //one point to the next + for (double i = 0; i < 2 * M_PI; i += (2 * M_PI) / points) + { + Point temp(false /*check*/); + temp.setX(center.getX() + (radius * cos(i))); + temp.setY(center.getY() + (radius * sin(i))); + rotate(temp, center, rotation); + glVertex2f(temp.getX(), temp.getY()); + } + + // complete drawing + glEnd(); + +} + + +/************************************************************************ + * ROTATE + * Rotate a given point (point) around a given origin (center) by a given + * number of degrees (angle). + * INPUT point The point to be moved + * center The center point we will rotate around + * rotation Rotation in degrees + * OUTPUT point The new position + *************************************************************************/ +void rotate(Point & point, const Point & origin, int rotation) +{ + // because sine and cosine are expensive, we want to call them only once + double cosA = cos(deg2rad(rotation)); + double sinA = sin(deg2rad(rotation)); + + // remember our original point + Point tmp(false /*check*/); + tmp.setX(point.getX() - origin.getX()); + tmp.setY(point.getY() - origin.getY()); + + // find the new values + point.setX(static_cast (tmp.getX() * cosA - + tmp.getY() * sinA) + + origin.getX()); + point.setY(static_cast (tmp.getX() * sinA + + tmp.getY() * cosA) + + origin.getY()); +} + +/************************************************************************ + * DRAW LINE + * Draw a line on the screen from the beginning to the end. + * INPUT begin The position of the beginning of the line + * end The position of the end of the line + *************************************************************************/ +void drawLine(const Point & begin, const Point & end, + float red, float green, float blue) +{ + // Get ready... + glBegin(GL_LINES); + glColor3f(red, green, blue); + + // Draw the actual line + glVertex2f(begin.getX(), begin.getY()); + glVertex2f( end.getX(), end.getY()); + + // Complete drawing + glColor3f(1.0 /* red % */, 1.0 /* green % */, 1.0 /* blue % */); + glEnd(); +} + +/*********************************************************************** + * DRAW Lander + * Draw a moon-lander spaceship on the screen at a given point + ***********************************************************************/ +void drawLander(const Point & point) +{ + // ultra simple point + struct PT + { + int x; + int y; + } points[] = + { + {-6, 0}, {-10,0}, {-8, 0}, {-8, 3}, // left foot + {-5, 4}, {-5, 7}, {-8, 3}, {-5, 4}, // left leg + {-1, 4}, {-3, 2}, { 3, 2}, { 1, 4}, {-1, 4}, // bottom + { 5, 4}, { 5, 7}, {-5, 7}, {-3, 7}, // engine square + {-6,10}, {-6,13}, {-3,16}, { 3,16}, // left of habitat + { 6,13}, { 6,10}, { 3, 7}, { 5, 7}, // right of habitat + { 5, 4}, { 8, 3}, { 5, 7}, { 5, 4}, // right leg + { 8, 3}, { 8, 0}, {10, 0}, { 6, 0} // right foot + }; + + // draw it + glBegin(GL_LINE_STRIP); + for (int i = 0; i < sizeof(points) / sizeof(points[0]); i++) + glVertex2f(point.getX() + points[i].x, + point.getY() + points[i].y); + + // complete drawing + glEnd(); + + +} + + +/*********************************************************************** + * DRAW Lander Flame + * Draw the flames coming out of a moonlander for thrust + ***********************************************************************/ +void drawLanderFlames(const Point & point, + bool bottom, + bool left, + bool right) +{ + // simple point + struct PT + { + int x; + int y; + }; + + int iFlame = random(0, 3); // so the flame flickers + + // draw it + glBegin(GL_LINE_LOOP); + glColor3f(1.0 /* red % */, 0.0 /* green % */, 0.0 /* blue % */); + + // bottom thrust + if (bottom) + { + PT points[3][3] = + { + { {-5, -6}, { 0, -1}, { 3, -10} }, + { {-3, -6}, {-1, -2}, { 0, -15} }, + { { 2, -12}, { 1, 0}, { 6, -4} } + }; + + glVertex2f(point.getX() - 2, point.getY() + 2); + for (int i = 0; i < 3; i++) + glVertex2f(point.getX() + points[iFlame][i].x, + point.getY() + points[iFlame][i].y); + glVertex2f(point.getX() + 2, point.getY() + 2); + } + + // right thrust + if (right) + { + PT points[3][3] = + { + { {10, 14}, { 8, 12}, {12, 12} }, + { {12, 10}, { 8, 10}, {10, 8} }, + { {14, 11}, {14, 11}, {14, 11} } + }; + + glVertex2f(point.getX() + 6, point.getY() + 12); + for (int i = 0; i < 3; i++) + glVertex2f(point.getX() + points[iFlame][i].x, + point.getY() + points[iFlame][i].y); + glVertex2f(point.getX() + 6, point.getY() + 10); + } + + // left thrust + if (left) + { + PT points[3][3] = + { + { {-10, 14}, { -8, 12}, {-12, 12} }, + { {-12, 10}, { -8, 10}, {-10, 8} }, + { {-14, 11}, {-14, 11}, {-14, 11} } + }; + + glVertex2f(point.getX() - 6, point.getY() + 12); + for (int i = 0; i < 3; i++) + glVertex2f(point.getX() + points[iFlame][i].x, + point.getY() + points[iFlame][i].y); + glVertex2f(point.getX() - 6, point.getY() + 10); + } + + glColor3f(1.0 /* red % */, 1.0 /* green % */, 1.0 /* blue % */); + glEnd(); +} + + +/****************************************************************** + * RANDOM + * This function generates a random number. + * + * INPUT: min, max : The number of values (min <= num < max) + * OUTPUT : Return the integer + ****************************************************************/ +int random(int min, int max) +{ + assert(min < max); + int num = (rand() % (max - min)) + min; + assert(min <= num && num <= max); + + return num; +} + +/****************************************************************** + * RANDOM + * This function generates a random number. + * + * INPUT: min, max : The number of values (min <= num < max) + * OUTPUT : Return the double + ****************************************************************/ +double random(double min, double max) +{ + assert(min <= max); + double num = min + ((double)rand() / (double)RAND_MAX * (max - min)); + + assert(min <= num && num <= max); + + return num; +} + + +/************************************************************************ + * DRAW RECTANGLE + * Draw a rectangle on the screen centered on a given point (center) of + * a given size (width, height), and at a given orientation (rotation) + * INPUT center Center of the rectangle + * width Horizontal size + * height Vertical size + * rotation Orientation + *************************************************************************/ +void drawRect(const Point & center, int width, int height, int rotation) +{ + Point tl(false /*check*/); // top left + Point tr(false /*check*/); // top right + Point bl(false /*check*/); // bottom left + Point br(false /*check*/); // bottom right + + //Top Left point + tl.setX(center.getX() - (width / 2)); + tl.setY(center.getY() + (height / 2)); + + //Top right point + tr.setX(center.getX() + (width / 2)); + tr.setY(center.getY() + (height / 2)); + + //Bottom left point + bl.setX(center.getX() - (width / 2)); + bl.setY(center.getY() - (height / 2)); + + //Bottom right point + br.setX(center.getX() + (width / 2)); + br.setY(center.getY() - (height / 2)); + + //Rotate all points the given degrees + rotate(tl, center, rotation); + rotate(tr, center, rotation); + rotate(bl, center, rotation); + rotate(br, center, rotation); + + //Finally draw the rectangle + glBegin(GL_LINE_STRIP); + glVertex2f(tl.getX(), tl.getY()); + glVertex2f(tr.getX(), tr.getY()); + glVertex2f(br.getX(), br.getY()); + glVertex2f(bl.getX(), bl.getY()); + glVertex2f(tl.getX(), tl.getY()); + glEnd(); +} + +/************************************************************************ + * DRAW CIRCLE + * Draw a circle from a given location (center) of a given size (radius). + * INPUT center Center of the circle + * radius Size of the circle + *************************************************************************/ +void drawCircle(const Point & center, int radius) +{ + assert(radius > 1.0); + const double increment = 1.0 / (double)radius; + + // begin drawing + glBegin(GL_LINE_LOOP); + + // go around the circle + for (double radians = 0; radians < M_PI * 2.0; radians += increment) + glVertex2f(center.getX() + (radius * cos(radians)), + center.getY() + (radius * sin(radians))); + + // complete drawing + glEnd(); +} + +/************************************************************************ + * DRAW DOT + * Draw a single point on the screen, 2 pixels by 2 pixels + * INPUT point The position of the dow + *************************************************************************/ +void drawDot(const Point & point) +{ + // Get ready, get set... + glBegin(GL_POINTS); + + // Go... + glVertex2f(point.getX(), point.getY() ); + glVertex2f(point.getX() + 1, point.getY() ); + glVertex2f(point.getX() + 1, point.getY() + 1); + glVertex2f(point.getX(), point.getY() + 1); + + // Done! OK, that was a bit too dramatic + glEnd(); +} + +/************************************************************************ + * DRAW Tough Bird + * Draw a tough bird on the screen + * INPUT point The position of the sacred + * radius The size of the bird + * hits How many its remaining to kill the bird + *************************************************************************/ +void drawToughBird(const Point & center, float radius, int hits) +{ + assert(radius > 1.0); + const double increment = M_PI / 6.0; + + // begin drawing + glBegin(GL_TRIANGLES); + + // three points: center, pt1, pt2 + Point pt1(false /*check*/); + pt1.setX(center.getX() + (radius * cos(0.0))); + pt1.setY(center.getY() + (radius * sin(0.0))); + Point pt2(pt1); + + // go around the circle + for (double radians = increment; + radians <= M_PI * 2.0 + .5; + radians += increment) + { + pt2.setX(center.getX() + (radius * cos(radians))); + pt2.setY(center.getY() + (radius * sin(radians))); + + glVertex2f(center.getX(), center.getY()); + glVertex2f(pt1.getX(), pt1.getY() ); + glVertex2f(pt2.getX(), pt2.getY() ); + + pt1 = pt2; + } + + // complete drawing + glEnd(); + + // draw the score in the center + if (hits > 0 && hits < 10) + { + glColor3f(0.0 /* red % */, 0.0 /* green % */, 0.0 /* blue % */); + glRasterPos2f(center.getX() - 4, center.getY() - 3); + glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (char)(hits + '0')); + glColor3f(1.0, 1.0, 1.0); // reset to white + } +} + +/************************************************************************ + * DRAW Sacred Bird + * Draw a sacred bird on the screen + * INPUT point The position of the sacred + * radius The size of the bird + *************************************************************************/ +void drawSacredBird(const Point & center, float radius) +{ + // handle auto-rotation + static float rotation = 0.0; + rotation += 5.0; + + + // begin drawing + glBegin(GL_LINE_LOOP); + glColor3f(1.0 /* red % */, 0.0 /* green % */, 0.0 /* blue % */); + + + //loop around a circle the given number of times drawing a line from + //one point to the next + for (int i = 0; i < 5; i++) + { + Point temp(false /*check*/); + float radian = (float)i * (M_PI * 2.0) * 0.4; + temp.setX(center.getX() + (radius * cos(radian))); + temp.setY(center.getY() + (radius * sin(radian))); + rotate(temp, center, rotation); + glVertex2f(temp.getX(), temp.getY()); + } + + // complete drawing + glColor3f(1.0, 1.0, 1.0); // reset to white + glEnd(); +} + +/********************************************************************** + * DRAW SMALL ASTEROID + **********************************************************************/ +void drawSmallAsteroid( const Point & center, int rotation) +{ + // ultra simple point + struct PT + { + int x; + int y; + } points[] = + { + {-5, 9}, {4, 8}, {8, 4}, + {8, -5}, {-2, -8}, {-2, -3}, + {-8, -4}, {-8, 4}, {-5, 10} + }; + + glBegin(GL_LINE_STRIP); + for (int i = 0; i < sizeof(points)/sizeof(PT); i++) + { + Point pt(center.getX() + points[i].x, + center.getY() + points[i].y); + rotate(pt, center, rotation); + glVertex2f(pt.getX(), pt.getY()); + } + glEnd(); +} + +/********************************************************************** + * DRAW MEDIUM ASTEROID + **********************************************************************/ +void drawMediumAsteroid( const Point & center, int rotation) +{ + // ultra simple point + struct PT + { + int x; + int y; + } points[] = + { + {2, 8}, {8, 15}, {12, 8}, + {6, 2}, {12, -6}, {2, -15}, + {-6, -15}, {-14, -10}, {-15, 0}, + {-4, 15}, {2, 8} + }; + + glBegin(GL_LINE_STRIP); + for (int i = 0; i < sizeof(points)/sizeof(PT); i++) + { + Point pt(center.getX() + points[i].x, + center.getY() + points[i].y); + rotate(pt, center, rotation); + glVertex2f(pt.getX(), pt.getY()); + } + glEnd(); +} + +/********************************************************************** + * DRAW LARGE ASTEROID + **********************************************************************/ +void drawLargeAsteroid( const Point & center, int rotation) +{ + // ultra simple point + struct PT + { + int x; + int y; + } points[] = + { + {0, 12}, {8, 20}, {16, 14}, + {10, 12}, {20, 0}, {0, -20}, + {-18, -10}, {-20, -2}, {-20, 14}, + {-10, 20}, {0, 12} + }; + + glBegin(GL_LINE_STRIP); + for (int i = 0; i < sizeof(points)/sizeof(PT); i++) + { + Point pt(center.getX() + points[i].x, + center.getY() + points[i].y); + rotate(pt, center, rotation); + glVertex2f(pt.getX(), pt.getY()); + } + glEnd(); +} + + +/************************************************************************ + * DRAW Ship + * Draw a spaceship on the screen + * INPUT point The position of the ship + * angle Which direction it is ponted + *************************************************************************/ +void drawShip(const Point & center, int rotation, bool thrust) +{ + // ultra simple point + struct PT + { + int x; + int y; + }; + + // draw the ship + const PT pointsShip[] = + { // top r.wing r.engine l.engine l.wing top + {0, 6}, {6, -6}, {2, -3}, {-2, -3}, {-6, -6}, {0, 6} + }; + + glBegin(GL_LINE_STRIP); + for (int i = 0; i < sizeof(pointsShip)/sizeof(PT); i++) + { + Point pt(center.getX() + pointsShip[i].x, + center.getY() + pointsShip[i].y); + rotate(pt, center, rotation); + glVertex2f(pt.getX(), pt.getY()); + } + glEnd(); + + // draw the flame if necessary + if (thrust) + { + const PT pointsFlame[3][5] = + { + { {-2, -3}, {-2, -13}, { 0, -6}, { 2, -13}, {2, -3} }, + { {-2, -3}, {-4, -9}, {-1, -7}, { 1, -14}, {2, -3} }, + { {-2, -3}, {-1, -14}, { 1, -7}, { 4, -9}, {2, -3} } + }; + + glBegin(GL_LINE_STRIP); + glColor3f(1.0 /* red % */, 0.0 /* green % */, 0.0 /* blue % */); + int iFlame = random(0, 3); + for (int i = 0; i < 5; i++) + { + Point pt(center.getX() + pointsFlame[iFlame][i].x, + center.getY() + pointsFlame[iFlame][i].y); + rotate(pt, center, rotation); + glVertex2f(pt.getX(), pt.getY()); + } + glColor3f(1.0, 1.0, 1.0); // reset to white + glEnd(); + } +} + + diff --git a/src/uiDraw.h b/src/uiDraw.h new file mode 100644 index 0000000..c282a3b --- /dev/null +++ b/src/uiDraw.h @@ -0,0 +1,135 @@ +/*********************************************************************** + * Header File: + * User Interface Draw : put pixels on the screen + * Author: + * Br. Helfrich + * Summary: + * This is the code necessary to draw on the screen. We have a collection + * of procedural functions here because each draw function does not + * retain state. In other words, they are verbs (functions), not nouns + * (variables) or a mixture (objects) + ************************************************************************/ + +#ifndef UI_DRAW_H +#define UI_DRAW_H + +#include // To display text on the screen +#include // for M_PI, sin() and cos() +#include "point.h" // Where things are drawn +using std::string; + +/************************************************************************ + * DRAW DIGIT + * Draw a single digit in the old school line drawing style. The + * size of the glyph is 8x11 or x+(0..7), y+(0..10) + *************************************************************************/ +void drawDigit(const Point & topLeft, char digit); + +/************************************************************************* + * DRAW NUMBER + * Display an integer on the screen using the 7-segment method + *************************************************************************/ +void drawNumber(const Point & topLeft, int number); + +/************************************************************************* + * DRAW TEXT + * Draw text using a simple bitmap font + ************************************************************************/ +void drawText(const Point & topLeft, const char * text); + +/************************************************************************ + * ROTATE + * Rotate a given point (point) around a given origin (center) by a given + * number of degrees (angle). + *************************************************************************/ +void rotate(Point & point, const Point & origin, int rotation = 0); + +/************************************************************************ + * DRAW RECTANGLE + * Draw a rectangle on the screen centered on a given point (center) of + * a given size (width, height), and at a given orientation (rotation) + * measured in degrees (0 - 360) + *************************************************************************/ +void drawRect(const Point & center, int width, int height, int rotation); + +/************************************************************************ + * DRAW CIRCLE + * Draw a circle from a given location (center) of a given size (radius). + *************************************************************************/ +void drawCircle(const Point & center, int radius); + +/************************************************************************ + * DRAW POLYGON + * Draw a polygon from a given location (center) of a given size (radius). + *************************************************************************/ +void drawPolygon(const Point & center, + int radius = 20, + int points = 4, + int rotation = 0); + +/************************************************************************ + * DRAW LINE + * Draw a line on the screen from the beginning to the end. + *************************************************************************/ +void drawLine(const Point & begin, const Point & end, + float red = 1.0, float green = 1.0, float blue = 1.0); + + +/*********************************************************************** + * DRAW Lander + * Draw a moon-lander spaceship on the screen at a given point + ***********************************************************************/ +void drawLander(const Point & point); + +/*********************************************************************** + * DRAW Lander Flame + * Draw the flames coming out of a moonlander for thrust + ***********************************************************************/ +void drawLanderFlames(const Point & point, + bool bottom, + bool left, + bool right); + +/************************************************************************ + * DRAW DOT + * Draw a single point on the screen, 2 pixels by 2 pixels + *************************************************************************/ +void drawDot(const Point & point); + +/************************************************************************ + * DRAW Sacred Bird + * Draw the bird on the screen + *************************************************************************/ +void drawSacredBird(const Point & center, float radius); + +/************************************************************************ + * DRAW Tough Bird + * Draw a tough bird on the screen + *************************************************************************/ +void drawToughBird(const Point & center, float radius, int hits); + +/************************************************************************ + * DRAW Ship + * Draw the spaceship on the screen + *************************************************************************/ +void drawShip(const Point & point, int rotation, bool thrust = false); + +/********************************************************************** + * DRAW * ASTEROID + **********************************************************************/ +void drawSmallAsteroid( const Point & point, int rotation); +void drawMediumAsteroid(const Point & point, int rotation); +void drawLargeAsteroid( const Point & point, int rotation); + +/****************************************************************** + * RANDOM + * This function generates a random number. The user specifies + * The parameters + * INPUT: min, max : The number of values (min <= num <= max) + * OUTPUT : Return the integer + ****************************************************************/ +int random(int min, int max); +double random(double min, double max); + + +#endif // UI_DRAW_H diff --git a/src/uiInteract.cpp b/src/uiInteract.cpp new file mode 100644 index 0000000..7a0d504 --- /dev/null +++ b/src/uiInteract.cpp @@ -0,0 +1,331 @@ +/*********************************************************************** + * Source File: + * UI INTERACT + * Author: + * Br. Helfrich + * Description: + * Implement the interfaces specified in uiInterface.h. This handles + * all the interfaces and events necessary to work with OpenGL. Your + * program will interface with this thorough the callback function + * pointer towards the bottom of the file. + ************************************************************************/ + +#include // need you ask? +#include // convert an integer into text +#include // I feel the need... the need for asserts +#include // for clock +#include // for rand() + + +#ifdef __APPLE__ +#include // Main OpenGL library +#include // Second OpenGL library +#endif // __APPLE__ + +#ifdef __linux__ +#include // Main OpenGL library +#include // Second OpenGL library +#endif // __linux__ + +#ifdef _WIN32 +#include +#include +#include // OpenGL library we copied +#include // for ::Sleep(); +#include + +#define _USE_MATH_DEFINES +#include +#endif // _WIN32 + +#include "uiInteract.h" +#include "point.h" + +using namespace std; + + +/********************************************************************* + * SLEEP + * Pause for a while. We want to put the program to sleep until it + * is time to draw again. Note that this requires us to tell the OS + * that we are idle. the nanosleep function performs this task for us + * INPUT: msSleep: sleep time in milliseconds + *********************************************************************/ +void sleep(unsigned long msSleep) +{ + // Windows handles sleep one way +#ifdef _WIN32 + ::Sleep(msSleep + 35); + + // Unix-based operating systems (OS-X, Linux) do it another +#else // LINUX, XCODE + timespec req = {}; + time_t sec = (int)(msSleep / 1000); + msSleep -= (sec * 1000); + + req.tv_sec = sec; + req.tv_nsec = msSleep * 1000000L; + + while (nanosleep(&req, &req) == -1) + ; +#endif // LINUX, XCODE + return; +} + +/************************************************************************ + * DRAW CALLBACK + * This is the main callback from OpenGL. It gets called constantly by + * the graphics engine to refresh and draw the window. Here we will + * clear the background buffer, draw on it, and send it to the forefront + * when the appropriate time period has passsed. + * + * Note: This and all other callbacks can't be member functions, they must + * have global scope for OpenGL to see them. + *************************************************************************/ +void drawCallback() +{ + // even though this is a local variable, all the members are static + Interface ui; + // Prepare the background buffer for drawing + glClear(GL_COLOR_BUFFER_BIT); //clear the screen + glColor3f(1,1,1); + + //calls the client's display function + assert(ui.callBack != NULL); + ui.callBack(&ui, ui.p); + + //loop until the timer runs out + if (!ui.isTimeToDraw()) + sleep((unsigned long)((ui.getNextTick() - clock()) / 1000)); + + // from this point, set the next draw time + ui.setNextDrawTime(); + + // bring forth the background buffer + glutSwapBuffers(); + + // clear the space at the end + ui.keyEvent(); +} + +/************************************************************************ + * KEY DOWN CALLBACK + * When a key on the keyboard has been pressed, we need to pass that + * on to the client. Currently, we are only registering the arrow keys + * INPUT key: the key we pressed according to the GLUT_KEY_ prefix + * x y: the position in the window, which we ignore + *************************************************************************/ +void keyDownCallback(int key, int x, int y) +{ + // Even though this is a local variable, all the members are static + // so we are actually getting the same version as in the constructor. + Interface ui; + ui.keyEvent(key, true /*fDown*/); +} + +/************************************************************************ + * KEY UP CALLBACK + * When the user has released the key, we need to reset the pressed flag + * INPUT key: the key we pressed according to the GLUT_KEY_ prefix + * x y: the position in the window, which we ignore + *************************************************************************/ +void keyUpCallback(int key, int x, int y) +{ + // Even though this is a local variable, all the members are static + // so we are actually getting the same version as in the constructor. + Interface ui; + ui.keyEvent(key, false /*fDown*/); +} + +/*************************************************************** + * KEYBOARD CALLBACK + * Generic callback to a regular ascii keyboard event, such as + * the space bar or the letter 'q' + ***************************************************************/ +void keyboardCallback(unsigned char key, int x, int y) +{ + // Even though this is a local variable, all the members are static + // so we are actually getting the same version as in the constructor. + Interface ui; + ui.keyEvent(key, true /*fDown*/); +} + +/*************************************************************** + * INTERFACE : KEY EVENT + * Either set the up or down event for a given key + * INPUT key which key is pressed + * fDown down or brown + ****************************************************************/ +void Interface::keyEvent(int key, bool fDown) +{ + switch(key) + { + case GLUT_KEY_DOWN: + isDownPress = fDown; + break; + case GLUT_KEY_UP: + isUpPress = fDown; + break; + case GLUT_KEY_RIGHT: + isRightPress = fDown; + break; + case GLUT_KEY_LEFT: + isLeftPress = fDown; + break; + case GLUT_KEY_F1: + isYPress = fDown; + break; + case GLUT_KEY_HOME: + case ' ': + isSpacePress = fDown; + break; + } +} +/*************************************************************** + * INTERFACE : KEY EVENT + * Either set the up or down event for a given key + * INPUT key which key is pressed + * fDown down or brown + ****************************************************************/ +void Interface::keyEvent() +{ + if (isDownPress) + isDownPress++; + if (isUpPress) + isUpPress++; + if (isLeftPress) + isLeftPress++; + if (isRightPress) + isRightPress++; + isYPress = false; + isSpacePress = false; +} + + +/************************************************************************ + * INTEFACE : IS TIME TO DRAW + * Have we waited long enough to draw swap the background buffer with + * the foreground buffer? + *************************************************************************/ +bool Interface::isTimeToDraw() +{ + return ((unsigned int)clock() >= nextTick); +} + +/************************************************************************ + * INTERFACE : SET NEXT DRAW TIME + * What time should we draw the buffer again? This is a function of + * the current time and the frames per second. + *************************************************************************/ +void Interface::setNextDrawTime() +{ + nextTick = clock() + static_cast (timePeriod * CLOCKS_PER_SEC); +} + +/************************************************************************ + * INTERFACE : SET FRAMES PER SECOND + * The frames per second dictates the speed of the game. The more frames + * per second, the quicker the game will appear to the user. We will default + * to 30 frames/second but the client can set this at will. + * INPUT value The number of frames per second. 30 is default + *************************************************************************/ +void Interface::setFramesPerSecond(double value) +{ + timePeriod = (1 / value); +} + +/*************************************************** + * STATICS + * All the static member variables need to be initialized + * Somewhere globally. This is a good spot + **************************************************/ +int Interface::isDownPress = 0; +int Interface::isUpPress = 0; +int Interface::isLeftPress = 0; +int Interface::isRightPress = 0; +bool Interface::isYPress = false; +bool Interface::isSpacePress = false; +bool Interface::initialized = false; +double Interface::timePeriod = 1.0 / 30; // default to 30 frames/second +unsigned int Interface::nextTick = 0; // redraw now please +void * Interface::p = NULL; +void (*Interface::callBack)(const Interface *, void *) = NULL; + + +/************************************************************************ + * INTERFACE : DESTRUCTOR + * Nothing here! + ***********************************************************************/ +Interface::~Interface() +{ +} + + +/************************************************************************ + * INTEFACE : INITIALIZE + * Initialize our drawing window. This will set the size and position, + * get ready for drawing, set up the colors, and everything else ready to + * draw the window. All these are part of initializing Open GL. + * INPUT argc: Count of command-line arguments from main + * argv: The actual command-line parameters + * title: The text for the titlebar of the window + *************************************************************************/ +void Interface::initialize(int argc, char ** argv, const char * title, Point topLeft, Point bottomRight) +{ + if (initialized) + return; + + // set up the random number generator + srand((unsigned int)time(NULL)); + + // create the window + glutInit(&argc, argv); + Point point; + glutInitWindowSize( // size of the window + (int)(bottomRight.getX() - topLeft.getX()), + (int)(topLeft.getY() - bottomRight.getY())); + + glutInitWindowPosition( 10, 10); // initial position + glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); // double buffering + glutCreateWindow(title); // text on titlebar + glutIgnoreKeyRepeat(true); + + // set up the drawing style: B/W and 2D + glClearColor(0, 0, 0, 0); // Black is the background color + gluOrtho2D((int)topLeft.getX(), (int)bottomRight.getX(), + (int)bottomRight.getY(), (int)topLeft.getY()); // 2D environment + + // register the callbacks so OpenGL knows how to call us + glutDisplayFunc( drawCallback ); + glutIdleFunc( drawCallback ); + glutKeyboardFunc( keyboardCallback); + glutSpecialFunc( keyDownCallback ); + glutSpecialUpFunc( keyUpCallback ); + initialized = true; + + // done + return; +} + +/************************************************************************ + * INTERFACE : RUN + * Start the main graphics loop and play the game + * INPUT callBack: Callback function. Every time we are beginning + * to draw a new frame, we first callback to the client + * to see if he wants to do anything, such as move + * the game pieces or respond to input + * p: Void point to whatever the caller wants. You + * will need to cast this back to your own data + * type before using it. + *************************************************************************/ +void Interface::run(void (*callBack)(const Interface *, void *), void *p) +{ + // setup the callbacks + this->p = p; + this->callBack = callBack; + + glutMainLoop(); + + return; +} + diff --git a/src/uiInteract.h b/src/uiInteract.h new file mode 100644 index 0000000..3a2f00c --- /dev/null +++ b/src/uiInteract.h @@ -0,0 +1,133 @@ +/********************************************* + * Header file: + * UI INTERFACE + * Author: + * Br. Helfrich + * Summary: + * This module will create an OpenGL window, + * enter the OpenGL main loop, and accept events. + * The main methods are: + * 1. Constructors - Create the window + * 2. run() - Run the main loop + * 3. callback - Specified in Run, this user-provided + * function will get called with every frame + * 4. isDown() - Is a given key pressed on this loop? + **********************************************/ + +#ifndef UI_INTERFACE_H +#define UI_INTERFACE_H + + #include "point.h" + +/******************************************** + * INTERFACE + * All the data necessary to keep our graphics + * state in memory + ********************************************/ +class Interface +{ +public: + // Default constructor useful for setting up the random variables + // or for opening the file for output + Interface() { initialize(0, 0x0000, "Window", Point(-50, 50), Point(50, -50)); }; + + // Constructor if you want to set up the window with anything but + // the default parameters + Interface(int argc, char ** argv, const char * title, Point topLeft, Point bottomRight) + { + initialize(argc, argv, title, topLeft, bottomRight); + } + + // Destructor, incase any housecleaning needs to occr + ~Interface(); + + // This will set the game in motion + void run(void (*callBack)(const Interface *, void *), void *p); + + // Is it time to redraw the screen + bool isTimeToDraw(); + + // Set the next draw time based on current time and time period + void setNextDrawTime(); + + // Retrieve the next tick time... the time of the next draw. + unsigned int getNextTick() { return nextTick; }; + + // How many frames per second are we configured for? + void setFramesPerSecond(double value); + + // Key event indicating a key has been pressed or not. The callbacks + // should be the only onces to call this + void keyEvent(int key, bool fDown); + void keyEvent(); + + // Current frame rate + double frameRate() const { return timePeriod; }; + + // Get various key events + int isDown() const { return isDownPress; }; + int isUp() const { return isUpPress; }; + int isLeft() const { return isLeftPress; }; + int isRight() const { return isRightPress; }; + bool isSpace() const { return isSpacePress; }; + bool isY() const { return isYPress; }; + + static void *p; // for client + static void (*callBack)(const Interface *, void *); + +private: + void initialize(int argc, char ** argv, const char * title, Point topLeft, Point bottomRight); + + static bool initialized; // only run the constructor once! + static double timePeriod; // interval between frame draws + static unsigned int nextTick; // time (from clock()) of our next draw + + static int isDownPress; // is the down arrow currently pressed? + static int isUpPress; // " up " + static int isLeftPress; // " left " + static int isRightPress; // " right " + static bool isSpacePress; // " space " + static bool isYPress; +}; + + + +/************************************************************************ + * DRAW CALLBACK + * This is the main callback from OpenGL. It gets called constantly by + * the graphics engine to refresh and draw the window. Here we will + * clear the background buffer, draw on it, and send it to the forefront + * when the appropriate time period has passsed. + * + * Note: This and all other callbacks can't be member functions, they must + * have global scope for OpenGL to see them. + *************************************************************************/ +void drawCallback(); + +/************************************************************************ + * KEY DOWN CALLBACK + * When a key on the keyboard has been pressed, we need to pass that + * on to the client. Currnetly, we are only registering the arrow keys + *************************************************************************/ +void keyDownCallback(int key, int x, int y); + +/************************************************************************ + * KEY UP CALLBACK + * When the user has released the key, we need to reset the pressed flag + *************************************************************************/ +void keyUpCallback(int key, int x, int y); + +/*************************************************************** + * KEYBOARD CALLBACK + * Generic callback to a regular ascii keyboard event, such as + * the space bar or the letter 'q' + ***************************************************************/ +void keyboardCallback(unsigned char key, int x, int y); + +/************************************************************************ + * RUN + * Set the game in action. We will get control back in our drawCallback + *************************************************************************/ +void run(); + +#endif // UI_INTERFACE_H diff --git a/src/velocity.cpp b/src/velocity.cpp new file mode 100644 index 0000000..ce739e3 --- /dev/null +++ b/src/velocity.cpp @@ -0,0 +1,58 @@ +#include "velocity.h" + +Velocity :: Velocity () +{ + setDx ( 0.0 ); + setDy ( 0.0 ); +} + +// Velocity constructor +Velocity :: Velocity ( float dx , float dy ) +{ + setDx ( dx ); + setDy ( dy ); +} + +// Get Velocity dx +float Velocity :: getDx() const +{ + return dx; +} + +// Get Velocity dy +float Velocity :: getDy() const +{ + return dy; +} + +// Set Velocity dx +void Velocity :: setDx( float dx ) +{ + this->dx = dx; +} + +// Set Velocity dy +void Velocity :: setDy( float dy ) +{ + this->dy = dy; +} + +// Add dy Velocity +void Velocity :: addDy ( const float dy ) +{ + this->dy += dy; +} + +// Add dx Velocity +void Velocity :: addDx ( const float dx ) +{ + this->dx += dx; +} + +// Update a point +Point Velocity :: updatePoint ( Point &point ) +{ + point.addX ( dx ); + point.addY ( dy ); + return point; +} diff --git a/src/velocity.h b/src/velocity.h new file mode 100644 index 0000000..11c41cb --- /dev/null +++ b/src/velocity.h @@ -0,0 +1,23 @@ +#ifndef VELOCITY_H +#define VELOCITY_H + +#include "point.h" + +class Velocity +{ + public: + Velocity(); + Velocity( float dx , float dy ); + float getDx() const; + float getDy() const; + void addDy( const float dy ); + void addDx( const float dx ); + void setDx( float dx ); + void setDy( float dy ); + Point updatePoint ( Point &point ); + private: + float dx; + float dy; +}; + +#endif