Updated indentation

This commit is contained in:
Simponic 2020-06-30 20:04:55 -06:00
commit 7a60ab9f17
22 changed files with 2300 additions and 0 deletions

21
LICENSE Normal file
View File

@ -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.

2
README.md Normal file
View File

@ -0,0 +1,2 @@
# Asteroids-CPP
The game asteroids in c++ using the simplified drawing library provided by my school.

29
bullet.cpp Normal file
View File

@ -0,0 +1,29 @@
#include "bullet.h"
#include "ship.h"
#include <cmath>
#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();
}

24
bullet.h Normal file
View File

@ -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 */

45
driver.cpp Normal file
View File

@ -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;
}

20
flyingObject.cpp Normal file
View File

@ -0,0 +1,20 @@
#include "flyingObject.h"
#include <iostream>
// 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 );
}

28
flyingObject.h Normal file
View File

@ -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 */

278
game.cpp Normal file
View File

@ -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 <limits>
#include <iostream>
#include <algorithm>
#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<Rock *> Game :: createRocks()
{
vector<Rock *> 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<float>::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<Rock *> 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<Rock *> 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 );
}
}
}

53
game.h Normal file
View File

@ -0,0 +1,53 @@
/*********************************************************************
* File: game.h
* Description: Defines the game class for Asteroids
*
*********************************************************************/
#ifndef GAME_H
#define GAME_H
#include <vector>
#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<Rock *> rocks;
vector<Bullet *> bullets;
Ship* ship;
float getClosestDistance( const FlyingObject &obj1 , const FlyingObject &obj2 ) const;
vector<Rock *> 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 */

71
makefile Normal file
View File

@ -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

77
point.cpp Normal file
View File

@ -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 <cassert>
#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;
}

49
point.h Normal file
View File

@ -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 <iostream>
/*********************************************
* 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

63
rocks.cpp Normal file
View File

@ -0,0 +1,63 @@
#include "rocks.h"
#include "uiDraw.h"
#include <cmath>
#define M_PI 3.14159265
// Destroy Big Rock and return vector of new *rocks
vector<Rock *> BigRock :: destroy()
{
vector<Rock *> 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<Rock *> MediumRock :: destroy()
{
vector<Rock *> 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<Rock *> SmallRock :: destroy()
{
return vector<Rock *>();
}
// Draw small rock
void SmallRock :: draw()
{
drawSmallAsteroid ( this->point , this->angle );
}

84
rocks.h Normal file
View File

@ -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 <vector>
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<Rock *> 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<Rock *> 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<Rock *> 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<Rock *> destroy();
void draw();
};
#endif /* rocks_h */

36
ship.cpp Normal file
View File

@ -0,0 +1,36 @@
#include "ship.h"
#include "bullet.h"
#include <cmath>
#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 );
}

32
ship.h Normal file
View File

@ -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 */

714
uiDraw.cpp Normal file
View File

@ -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 <string> // need you ask?
#include <sstream> // convert an integer into text
#include <cassert> // I feel the need... the need for asserts
#include <time.h> // for clock
#ifdef __APPLE__
#include <openGL/gl.h> // Main OpenGL library
#include <GLUT/glut.h> // Second OpenGL library
#endif // __APPLE__
#ifdef __linux__
#include <GL/gl.h> // Main OpenGL library
#include <GL/glut.h> // Second OpenGL library
#endif // __linux__
#ifdef _WIN32
#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h> // OpenGL library we copied
#define _USE_MATH_DEFINES
#include <math.h>
#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<int> (tmp.getX() * cosA -
tmp.getY() * sinA) +
origin.getX());
point.setY(static_cast<int> (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> : 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> : 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();
}
}

135
uiDraw.h Normal file
View File

@ -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 <string> // To display text on the screen
#include <cmath> // 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> : Return the integer
****************************************************************/
int random(int min, int max);
double random(double min, double max);
#endif // UI_DRAW_H

326
uiInteract.cpp Normal file
View File

@ -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 <string> // need you ask?
#include <sstream> // convert an integer into text
#include <cassert> // I feel the need... the need for asserts
#include <time.h> // for clock
#include <cstdlib> // for rand()
#ifdef __APPLE__
#include <openGL/gl.h> // Main OpenGL library
#include <GLUT/glut.h> // Second OpenGL library
#endif // __APPLE__
#ifdef __linux__
#include <GL/gl.h> // Main OpenGL library
#include <GL/glut.h> // Second OpenGL library
#endif // __linux__
#ifdef _WIN32
#include <stdio.h>
#include <stdlib.h>
#include <Gl/glut.h> // OpenGL library we copied
#include <ctime> // for ::Sleep();
#include <Windows.h>
#define _USE_MATH_DEFINES
#include <math.h>
#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<int> (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;
}

131
uiInteract.h Normal file
View File

@ -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

59
velocity.cpp Normal file
View File

@ -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;
}

23
velocity.h Normal file
View File

@ -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