From 7a60ab9f178dd813c876fcf8e25c947f9a9a5e06 Mon Sep 17 00:00:00 2001 From: Simponic Date: Tue, 30 Jun 2020 20:04:55 -0600 Subject: [PATCH] Updated indentation --- LICENSE | 21 ++ README.md | 2 + bullet.cpp | 29 ++ bullet.h | 24 ++ driver.cpp | 45 +++ flyingObject.cpp | 20 ++ flyingObject.h | 28 ++ game.cpp | 278 ++++++++++++++++++ game.h | 53 ++++ makefile | 71 +++++ point.cpp | 77 +++++ point.h | 49 ++++ rocks.cpp | 63 +++++ rocks.h | 84 ++++++ ship.cpp | 36 +++ ship.h | 32 +++ uiDraw.cpp | 714 +++++++++++++++++++++++++++++++++++++++++++++++ uiDraw.h | 135 +++++++++ uiInteract.cpp | 326 ++++++++++++++++++++++ uiInteract.h | 131 +++++++++ velocity.cpp | 59 ++++ velocity.h | 23 ++ 22 files changed, 2300 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 bullet.cpp create mode 100644 bullet.h create mode 100644 driver.cpp create mode 100644 flyingObject.cpp create mode 100644 flyingObject.h create mode 100644 game.cpp create mode 100644 game.h create mode 100644 makefile create mode 100644 point.cpp create mode 100644 point.h create mode 100644 rocks.cpp create mode 100644 rocks.h create mode 100644 ship.cpp create mode 100644 ship.h create mode 100644 uiDraw.cpp create mode 100644 uiDraw.h create mode 100644 uiInteract.cpp create mode 100644 uiInteract.h create mode 100644 velocity.cpp create mode 100644 velocity.h diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bc341d0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Logan Hunt + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9653d82 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Asteroids-CPP +The game asteroids in c++ using the simplified drawing library provided by my school. diff --git a/bullet.cpp b/bullet.cpp new file mode 100644 index 0000000..69fb603 --- /dev/null +++ b/bullet.cpp @@ -0,0 +1,29 @@ +#include "bullet.h" +#include "ship.h" +#include + +#define M_PI 3.14159265 + +// Bullet non-default constructor +Bullet :: Bullet( const Point &point ) : FlyingObject() , framesAlive( 0 ) +{ + setPoint ( point ); +} + +// Fire Bullet +void Bullet :: fire ( const Velocity &vel , const float angle ) +{ + velocity.setDx ( BULLET_SPEED * ( -cos ( M_PI / 180 * angle ) ) ); + velocity.setDy ( BULLET_SPEED * ( sin ( M_PI / 180 * angle ) ) ); +} + +// Advance Bullet +void Bullet :: advance () +{ + framesAlive++; + if ( framesAlive >= 40 ) + { + kill(); + } + FlyingObject :: advance(); +} diff --git a/bullet.h b/bullet.h new file mode 100644 index 0000000..3392ee4 --- /dev/null +++ b/bullet.h @@ -0,0 +1,24 @@ +#ifndef bullet_h +#define bullet_h + +#define BULLET_SPEED 10 +#define BULLET_LIFE 40 + +#include "point.h" +#include "velocity.h" +#include "flyingObject.h" + +class Bullet : public FlyingObject +{ +private: + int framesAlive; + +public: + Bullet( const Point &point ); + int getFramesAlive() const { return framesAlive; }; + void fire( const Velocity &velocity , const float angle ); + void advance(); +}; + + +#endif /* bullet_h */ diff --git a/driver.cpp b/driver.cpp new file mode 100644 index 0000000..5e1b9a5 --- /dev/null +++ b/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->draw(*pUI); + pGame->handleInput(*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, "Asteroids", topLeft, bottomRight); + Game game(topLeft, bottomRight); + ui.run(callBack, &game); + + return 0; +} diff --git a/flyingObject.cpp b/flyingObject.cpp new file mode 100644 index 0000000..149e3f5 --- /dev/null +++ b/flyingObject.cpp @@ -0,0 +1,20 @@ +#include "flyingObject.h" +#include + +// Advance flyingobjects +void FlyingObject::advance() +{ + point.addX( getVelocity().getDx() ); + point.addY( getVelocity().getDy() ); + + if ( point.getX() > 200 ) + point.setX( -200 ); + else if ( point.getX() < -200 ) + point.setX( 200 ); + + if ( point.getY() > 200 ) + point.setY( -200 ); + else if ( point.getY() < -200 ) + point.setY( 200 ); + +} diff --git a/flyingObject.h b/flyingObject.h new file mode 100644 index 0000000..2e77e5e --- /dev/null +++ b/flyingObject.h @@ -0,0 +1,28 @@ +#ifndef flyingObject_h +#define flyingObject_h + +#include "point.h" +#include "velocity.h" +#include "uiDraw.h" + +class FlyingObject +{ +protected: + Point point; + Velocity velocity + bool alive; +public: + FlyingObject() : point( Point() ) , velocity( Velocity() ) , alive( true ) {} + Point getPoint() const { return this->point; } + void setPoint( const Point &point ) { this->point = point; } + Velocity getVelocity() const { return this->velocity; } + void setVelocity( const Velocity &velocity) { this->velocity = velocity; } + bool isAlive() { return this->alive; } + void kill() { alive = false; }; + virtual void draw() { drawDot( point ); }; + virtual void advance(); +}; + + + +#endif /* flyingObject_h */ diff --git a/game.cpp b/game.cpp new file mode 100644 index 0000000..a2aa491 --- /dev/null +++ b/game.cpp @@ -0,0 +1,278 @@ +/********************************************************************* + * File: game.cpp + * Description: Contains the implementaiton of the game class + * methods. + * + *********************************************************************/ + +#include "game.h" +#include "uiDraw.h" +#include "bullet.h" +// These are needed for the getClosestDistance function... +#include +#include +#include +#define CLOSE_ENOUGH 15 +using namespace std; + +// Game non-default constructor +Game :: Game ( const Point &tl , const Point &br ) : topLeft ( tl ) , bottomRight ( br ) +{ + rocks = createRocks(); + ship = new Ship ( Point() ); +} + +// Create rocks for the game +vector Game :: createRocks() +{ + vector initRocks; + for ( int i = 0; i < random ( 5 , 8 ); i++ ) + { + Point rockPoint = Point ( random( -190 , 190 ) , random ( -190 , 190 ) ); + Velocity velocity; + velocity.setDx ( random ( -3.0 , 3.0 ) ); + velocity.setDy ( random ( -2.0 , 2.0 ) ); + // Make sure spawn is safe on start by calculating if + // The rock is on a trajectory to the ship + float m = velocity.getDy() / velocity.getDx(); + + if ( fabs ( rockPoint.getY() - m * rockPoint.getX() ) >= 50 ) + { + switch ( random( 1 , 5 ) ) { + case 1: + case 2: + case 3: + initRocks.push_back ( new BigRock ( rockPoint , velocity ) ); + break; + case 4: + initRocks.push_back ( new MediumRock ( rockPoint , velocity ) ); + break; + case 5: + initRocks.push_back ( new SmallRock ( rockPoint , velocity ) ); + break; + default: + break; + } + } + } + return initRocks; +} + +// Get closest distance between two flying objects +float Game :: getClosestDistance(const FlyingObject &obj1, const FlyingObject &obj2) const +{ + // find the maximum distance traveled + float dMax = max(abs(obj1.getVelocity().getDx()), abs(obj1.getVelocity().getDy())); + dMax = max(dMax, abs(obj2.getVelocity().getDx())); + dMax = max(dMax, abs(obj2.getVelocity().getDy())); + dMax = max(dMax, 0.1f); // when dx and dy are 0.0. Go through the loop once. + + float distMin = std::numeric_limits::max(); + for (float i = 0.0; i <= dMax; i++) + { + Point point1(obj1.getPoint().getX() + (obj1.getVelocity().getDx() * i / dMax), + obj1.getPoint().getY() + (obj1.getVelocity().getDy() * i / dMax)); + Point point2(obj2.getPoint().getX() + (obj2.getVelocity().getDx() * i / dMax), + obj2.getPoint().getY() + (obj2.getVelocity().getDy() * i / dMax)); + + float xDiff = point1.getX() - point2.getX(); + float yDiff = point1.getY() - point2.getY(); + + float distSquared = (xDiff * xDiff) +(yDiff * yDiff); + + distMin = min(distMin, distSquared); + } + + return sqrt(distMin); +} + +// Advance everything in the game +void Game :: advance() +{ + cleanUpZombies(); + advanceShip(); + advanceBullets(); + advanceAsteroids(); + + handleCollisions(); +} + +// Advance all asteroids in game +void Game :: advanceAsteroids() +{ + for ( int i = 0; i < rocks.size(); i++ ) + { + rocks[i]->advance(); + } +} + +// Advance all the bullets +void Game :: advanceBullets() +{ + for ( int i = 0; i < bullets.size(); i++ ) + { + bullets[i]->advance(); + } +} + +// Advance the ship +void Game :: advanceShip() +{ + if ( ship->isAlive() && ship->getFuel() >= 0 ) + { + ship->advance(); + } +} + +// Clean up memory +void Game :: cleanUpZombies() +{ + for ( int i = 0; i < bullets.size(); i++ ) + { + if ( !bullets[i]->isAlive() ) + { + delete bullets[i]; + bullets[i] = NULL; + bullets.erase( bullets.begin() + i ); + } + } + for ( int i = 0; i < rocks.size(); i++ ) + { + if ( !rocks[i]->isAlive() ) + { + delete rocks[i]; + rocks[i] = NULL; + rocks.erase( rocks.begin() + i ); + } + } +} + +// Handle all collisions +void Game :: handleCollisions() +{ + // Handle bullet collisions + for ( int i = 0; i < rocks.size(); i++ ) + { + Rock * rock = rocks[i]; + if ( rock->isAlive() ) + { + for ( int j = 0; j < bullets.size(); j++ ) + { + Bullet * bullet = bullets[j]; + if ( bullet->isAlive() ) + { + float allowedRange = rock->getSize() + CLOSE_ENOUGH; + if ( fabs( getClosestDistance( *bullet , *rock ) ) < allowedRange + || bullet->getPoint().inRange( rock->getPoint() , allowedRange ) ) + { + vector newRocks = rock->destroy(); + for ( int i = 0; i < newRocks.size(); i++ ) + { + rocks.push_back ( newRocks[i] ); + } + rock->kill(); + bullet->kill(); + } + } + } + } + } + + // Handle ship collisions + for ( int i = 0; i < rocks.size(); i++ ) + { + Rock * rock = rocks[i]; + if ( rock->isAlive() && ship->isAlive() ) + { + float allowedRange = rock->getSize() + CLOSE_ENOUGH; + if ( fabs( getClosestDistance( *ship , *rock ) ) < allowedRange + || ship->getPoint().inRange( rock->getPoint() , allowedRange ) ) + { + vector newRocks = rock->destroy(); + for ( int i = 0; i < newRocks.size(); i++ ) + { + rocks.push_back ( newRocks[i] ); + } + rock->kill(); + ship->kill(); + } + } + } + cleanUpZombies(); +} + +// Draw everything +void Game :: draw ( const Interface &ui ) +{ + drawRocks(); + drawShip(); + drawBullets(); + drawNumber ( Point ( -170 , 170 ) , (int) ship->getFuel() ); + drawText ( Point ( -170 , 180 ) , "FUEL:" ); +} + +// Draw rocks +void Game :: drawRocks() +{ + for ( int i = 0; i < rocks.size(); i++ ) + { + rocks[i]->draw(); + } +} + +// Draw ship +void Game :: drawShip() +{ + if ( ship->isAlive() ) + { + ship->draw(); + } +} + +// Draw bullets +void Game :: drawBullets() +{ + for ( int i = 0; i < bullets.size(); i++ ) + { + bullets[i]->draw(); + } +} + +// Handle in-game input +void Game::handleInput(const Interface & ui) +{ + if ( ship->isAlive() ) + { + if ( ui.isUp() ) + { + ship->setThrusting ( true ); + ship->thrust( true ); + } + if ( ui.isDown() ) + { + ship->setThrusting ( true ); + ship->thrust( false ); + } + if ( ui.isLeft() ) + { + ship->setThrusting ( true ); + ship->rotate( true ); + } + if ( ui.isRight() ) + { + ship->setThrusting ( true ); + ship->rotate( false ); + } + if ( ui.isSpace() ) + { + Bullet * newBullet = new Bullet( ship->getPoint() ); + newBullet->fire( ship->getVelocity(), ship->getAngle() ); + bullets.push_back( newBullet ); + } + if ( !ui.isRight() && !ui.isUp() && !ui.isDown() && !ui.isLeft() ) + { + ship->setThrusting ( false ); + } + } + +} diff --git a/game.h b/game.h new file mode 100644 index 0000000..d64efc6 --- /dev/null +++ b/game.h @@ -0,0 +1,53 @@ +/********************************************************************* + * File: game.h + * Description: Defines the game class for Asteroids + * + *********************************************************************/ + +#ifndef GAME_H +#define GAME_H + +#include +#include "bullet.h" +#include "ship.h" +#include "rocks.h" +#include "uiDraw.h" +#include "uiInteract.h" + +#define CLOSE_ENOUGH 15 + +using namespace std; + +class Game +{ +private: + Point topLeft; + Point bottomRight; + vector rocks; + vector bullets; + Ship* ship; + + float getClosestDistance( const FlyingObject &obj1 , const FlyingObject &obj2 ) const; + + vector createRocks(); + + void advanceBullets(); + void advanceAsteroids(); + void advanceShip(); + + void cleanUpZombies(); + + void handleCollisions(); + + void drawBullets(); + void drawRocks(); + void drawShip(); +public: + Game ( const Point &tl , const Point &br ); + void handleInput ( const Interface &ui ); + void draw ( const Interface &ui ); + void advance(); +}; + + +#endif /* GAME_H */ diff --git a/makefile b/makefile new file mode 100644 index 0000000..22b20f7 --- /dev/null +++ b/makefile @@ -0,0 +1,71 @@ +# Author: +# Logan Hunt +# Summary: +# Play the game asteroids +# Above and Beyond +# Changed colors +# Added fuel +# rotation: -1 units/frame +# movement: -3 units/frame +# Made sure that initially, trajectories of rocks will +# not hit ship +# There's a chance of medium asteroids spawning at the start +# The initial amount of large rocks is random +############################################################### + + +LFLAGS = -lglut -lGLU -lGL + +############################################################### +# Build the main game +############################################################### +a.out: driver.o game.o uiInteract.o uiDraw.o point.o velocity.o flyingObject.o ship.o bullet.o rocks.o + g++ driver.o game.o uiInteract.o uiDraw.o point.o velocity.o flyingObject.o ship.o bullet.o rocks.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 +# game.o Handles the game interaction +# velocity.o Velocity (speed and direction) +# flyingObject.o Base class for all flying objects +# ship.o The player's ship +# bullet.o The bullets fired from the ship +# rocks.o Contains all of the Rock classes +############################################################### +uiDraw.o: uiDraw.cpp uiDraw.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 + +driver.o: driver.cpp game.h + g++ -c driver.cpp + +game.o: game.cpp game.h uiDraw.h uiInteract.h point.h velocity.h flyingObject.h bullet.h rocks.h ship.h + g++ -c game.cpp + +velocity.o: velocity.cpp velocity.h point.h + g++ -c velocity.cpp + +flyingObject.o: flyingObject.cpp flyingObject.h point.h velocity.h uiDraw.h + g++ -c flyingObject.cpp + +ship.o: ship.cpp ship.h flyingObject.h point.h velocity.h uiDraw.h + g++ -c ship.cpp + +bullet.o: bullet.cpp bullet.h flyingObject.h point.h velocity.h uiDraw.h + g++ -c bullet.cpp + +rocks.o: rocks.cpp rocks.h flyingObject.h point.h velocity.h uiDraw.h + g++ -c rocks.cpp + +############################################################### +# General rules +############################################################### +clean: + rm a.out *.o diff --git a/point.cpp b/point.cpp new file mode 100644 index 0000000..cad96e4 --- /dev/null +++ b/point.cpp @@ -0,0 +1,77 @@ +/*********************************************************************** + * Source 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. + ************************************************************************/ + +#include "point.h" +#include +#include "uiDraw.h" +using namespace std; +/****************************************** + * 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; +} + +bool Point::inRange( const Point &p, const float range ) +{ + if ( ( fabs( getX() - p.getX() ) < range) && + ( fabs( getY() - p.getY() ) < range ) ) + { + return true; + } + return false; +} diff --git a/point.h b/point.h new file mode 100644 index 0000000..7f0715f --- /dev/null +++ b/point.h @@ -0,0 +1,49 @@ +/*********************************************************************** + * 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); } + + bool inRange ( const Point &p , const float range ); +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/rocks.cpp b/rocks.cpp new file mode 100644 index 0000000..7c3c13e --- /dev/null +++ b/rocks.cpp @@ -0,0 +1,63 @@ +#include "rocks.h" +#include "uiDraw.h" +#include +#define M_PI 3.14159265 + +// Destroy Big Rock and return vector of new *rocks +vector BigRock :: destroy() +{ + vector rocks; + Velocity rockVel = this->velocity; + Point rockPoint = this->point; + + rockVel.addDy ( 1 ); + rocks.push_back ( new MediumRock ( rockPoint , rockVel ) ); + + rockVel.addDy ( -2 ); // Original rockvel dy - 1 + rocks.push_back ( new MediumRock ( rockPoint , rockVel ) ); + + rockVel.addDy ( 1 ); // Original rockvel dy + rockVel.addDx ( (float) random ( 1.0 , 3.0 ) ); + rocks.push_back ( new SmallRock ( rockPoint , rockVel ) ); + + return rocks; +} + +// Draw big rock +void BigRock :: draw() +{ + drawLargeAsteroid ( this->point , this->angle ); +} + +// Destroy Medium Rock and return vector of new *rocks +vector MediumRock :: destroy() +{ + vector rocks; + Velocity rockVel = this->velocity; + Point rockPoint = this->point; + + rockVel.addDx ( 3 ); + rocks.push_back ( new SmallRock ( rockPoint , rockVel ) ); + rockVel.addDx ( -6 ); + rocks.push_back ( new SmallRock ( rockPoint , rockVel ) ); + + return rocks; +} + +// Draw Medium Rock +void MediumRock :: draw() +{ + drawMediumAsteroid ( this->point , this->angle ); +} + +// Destroy Small Rock and return an empty *rock vector +vector SmallRock :: destroy() +{ + return vector(); +} + +// Draw small rock +void SmallRock :: draw() +{ + drawSmallAsteroid ( this->point , this->angle ); +} diff --git a/rocks.h b/rocks.h new file mode 100644 index 0000000..ae12e2b --- /dev/null +++ b/rocks.h @@ -0,0 +1,84 @@ +#ifndef rocks_h +#define rocks_h + +#define BIG_ROCK_SIZE 16 +#define MEDIUM_ROCK_SIZE 8 +#define SMALL_ROCK_SIZE 4 + +#define BIG_ROCK_SPIN 2 +#define MEDIUM_ROCK_SPIN 5 +#define SMALL_ROCK_SPIN 10 + +#include "flyingObject.h" +#include + +using namespace std; + +class Rock : public FlyingObject +{ +protected: + int rotationDegPerFrame; + int size; + float angle; +public: + Rock() : FlyingObject() , rotationDegPerFrame ( 0 ) , size ( 1 ) , angle ( 0 ) {} + Rock ( int degPerFrame , int size , float angle ) : rotationDegPerFrame ( degPerFrame ) , size ( size ) , angle ( angle ) {} + + int getRotationDegPerFrame() { return rotationDegPerFrame; } + int getSize () { return size; } + float getAngle() { return angle; } + + void setAngle ( const float angle ) { this->angle = angle; } + void setRotationDegPerFrame ( const int degPerFrame ) { this->rotationDegPerFrame = degPerFrame; } + void setSize ( const int size ) { this->size = size; } + void advance() { this->angle += rotationDegPerFrame; FlyingObject::advance(); } + virtual void draw() {}; + virtual vector destroy() = 0; +}; + +class BigRock : public Rock +{ +public: + BigRock ( const Point &point , const Velocity &velocity ) + { + setPoint ( point ); + setAngle ( 0 ); + setSize ( BIG_ROCK_SIZE ); + setRotationDegPerFrame ( BIG_ROCK_SPIN ); + setAngle ( random ( 0 , 360 ) ); + setVelocity ( velocity ); + } + + vector destroy(); + void draw(); +}; + +class MediumRock : public Rock +{ +public: + MediumRock ( const Point &point , const Velocity &vel ) { + this->point = point; + this->velocity = vel; + setAngle ( 0 ); + setRotationDegPerFrame ( MEDIUM_ROCK_SPIN ); + setSize ( MEDIUM_ROCK_SIZE ); + } + vector destroy(); + void draw(); +}; + +class SmallRock : public Rock +{ +public: + SmallRock( const Point &point , const Velocity &vel ) { + this->point = point; + this->velocity = vel; + setAngle ( 0 ); + setRotationDegPerFrame ( SMALL_ROCK_SPIN ); + setSize ( SMALL_ROCK_SIZE ); + } + vector destroy(); + void draw(); +}; + +#endif /* rocks_h */ diff --git a/ship.cpp b/ship.cpp new file mode 100644 index 0000000..2eaa852 --- /dev/null +++ b/ship.cpp @@ -0,0 +1,36 @@ +#include "ship.h" +#include "bullet.h" + +#include + +#define M_PI 3.14159265 +// Put your ship methods here + +// Apply thrust to ship +void Ship :: thrust ( const bool isUp ) +{ + float thrust = THRUST_AMOUNT * ( isUp ? 1 : -1 ); + fuel -= 3; + if ( fuel >= 0 ) + { + velocity.addDx ( thrust * ( -cos ( M_PI / 180 * angle ) ) ); + velocity.addDy ( thrust * ( sin ( M_PI / 180 * angle ) ) ); + } + else + { + fuel = 0; // In the case of negative fuel + } +} + +// Rotate ship +void Ship :: rotate ( const bool isRight ) +{ + angle += ROTATE_AMOUNT * ( isRight ? -1 : 1 ); + fuel -= 1; +} + +// Draw ship +void Ship :: draw ( ) const +{ + drawShip ( getPoint() , -(angle - 90) , isThrusting ); +} diff --git a/ship.h b/ship.h new file mode 100644 index 0000000..46b6817 --- /dev/null +++ b/ship.h @@ -0,0 +1,32 @@ +#ifndef ship_h +#define ship_h + +#define SHIP_SIZE 10 +#define ROTATE_AMOUNT 6 +#define THRUST_AMOUNT 0.5 + +#include "flyingObject.h" +#include "uiDraw.h" +#include "uiInteract.h" + +using namespace std; + +class Ship : public FlyingObject +{ +private: + float angle; + bool isThrusting; + int fuel; +public: + Ship( const Point &point ) : FlyingObject() , fuel ( 1000 ) , angle ( 90.0 ) , isThrusting( false ) { setPoint ( point ); } + float getAngle() const { return this->angle; } + float getFuel() { return this->fuel; } + void setFuel ( const int fuel ) { this->fuel - fuel; } + void thrust( const bool isUp ); + void rotate( const bool isRight ); + bool getIsThrusting() { return isThrusting; } + void setThrusting( const bool isThrusting ) { this->isThrusting = isThrusting; } + void draw() const; +}; + +#endif /* ship_h */ diff --git a/uiDraw.cpp b/uiDraw.cpp new file mode 100644 index 0000000..6d36f24 --- /dev/null +++ b/uiDraw.cpp @@ -0,0 +1,714 @@ +/*********************************************************************** + * 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); + glColor3f(1.0 /* red % */, 0.0/* green % */, 1.0/* blue % */); + 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); + glColor3f(1.0 /* red % */, 0.0/* green % */, 1.0/* blue % */); + 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); + glColor3f(1.0 /* red % */, 0.0/* green % */, 0.0/* blue % */); + 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); + glColor3f(0.0 /* red % */, 0.0/* green % */, 1.0/* blue % */); + 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/uiDraw.h b/uiDraw.h new file mode 100644 index 0000000..caa0fb5 --- /dev/null +++ b/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); + +/********************************************************************** + * 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/uiInteract.cpp b/uiInteract.cpp new file mode 100644 index 0000000..1e89833 --- /dev/null +++ b/uiInteract.cpp @@ -0,0 +1,326 @@ +/*********************************************************************** + * 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_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++; + 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::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/uiInteract.h b/uiInteract.h new file mode 100644 index 0000000..d7bfe6b --- /dev/null +++ b/uiInteract.h @@ -0,0 +1,131 @@ +/********************************************* + * 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; }; + + 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 " +}; + + + +/************************************************************************ + * 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/velocity.cpp b/velocity.cpp new file mode 100644 index 0000000..ceca109 --- /dev/null +++ b/velocity.cpp @@ -0,0 +1,59 @@ +#include "velocity.h" + +// Default velocity constructor +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/velocity.h b/velocity.h new file mode 100644 index 0000000..11c41cb --- /dev/null +++ b/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