commit 7a60ab9f178dd813c876fcf8e25c947f9a9a5e06 Author: Simponic Date: Tue Jun 30 20:04:55 2020 -0600 Updated indentation 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