W
wired
Hi,
I've just taught myself C++, so I haven't learnt much about style or
the like from any single source, and I'm quite styleless as a result.
But at the same time, I really want nice code and I go to great
lengths to restructure my code just to look concise and make it more
manageable.
When I say this, I'm also referring to the way I write my functions.
It seems to me sometimes that I shouldn't have many void functions
accepting addresses and changing their values for example, but rather
a double function that returns the calculated value. i.e.
void Change(Type& variable);
should be replaced with
Type Change(Type variable);
I just don't know what's better code (in terms of speed, style, etc.).
I'm moving into a more mature phase of my program, and before I
continue I would like jsut a final verdict on my code. I'm looking for
comments about whether my functions should be more simple (i.e. too
much happens in each), whether I should rather return value instead of
alter through references passed, whether my general style is
inelegant. I'm also concerned about my class structures. But I'll show
you _some_ code and let you decide.
Please note that I'm not asking you to go through the actual logic of
all this code, but rather just calls to functions, classes and the
like.
Thanks.
Davin.
//---------------------
//Globals.cpp - just some global variables needed by most functions
#include <vector>
#include "GLFiles.h"
#include "Derived.h"
using std::vector;
//quadratic to draw cylinders, spheres etc.
GLUquadricObj *quadratic;
//window dimensions
int WIDTH = 1024;
int HEIGHT = 768;
//table dimensions
float length = 25.15f; // 251.5cm
float width = 13.84f;
float height = 8.13f;
float goal = 4.0f;
float rest = 1.5f; // width between esdge and tabletop
// Misc
int step = 150; // number of steps the collision detection will
deconstruct each translation into in checking for a collision
Mallet* Mallet1;
Mallet* Mallet2;
vector <Puck*> Pucks;
double friction = 0.985;
int mouse_sens = 4; // 4-10, 10-least sensitive
//---------------------
//Abstract.h - two abstract classes, some derived classes will be
inherited from both
#ifndef Abstract_Classes
#define Abstract_Classes
#include "Globals.h"
using namespace std;
class Movable;
class Drawable;
void AddDraw(Drawable* draw);
void AddMove(Movable* move);
extern double friction;
class Drawable
{
public:
Drawable() {
AddDraw(this);
}
virtual void Draw() = 0;
};
class Movable
{
public:
Movable(double x1, double y1, double r, Controller cont) {
AddMove(this);
control = cont;
x = x1;
y = y1;
x_change = 0.0;
y_change = 0.0;
radius = r;
}
double next_x() { return x + friction * x_change; }
double next_y() { return y + friction * y_change; }
double change_x() { return x_change; }
double change_y() { return y_change; }
double now_x() { return x; }
double now_y() { return y; }
double get_radius() { return radius; }
double get_mass() { return mass; }
Controller controller() { return control; }
friend void Collide();
friend void HitTable(Movable* obj, double change);
void Replace(); // reset its position (after a goal for example) and
velocity
virtual void Move() = 0;
protected:
Controller control;
double radius;
double mass; //used as a comparison between inherited types (as well
as the physics)
double x;
double y;
double x_change;
double y_change;
};
#endif
//------------------
//Derived.h - two derived classes
#ifndef Derived_Classes
#define Derived_Classes
#include "Abstract.h"
class Mallet: public Drawable, public Movable
{
public:
Mallet(double x, double y, Controller cont): Movable(x,y, 0.76, cont)
{
mass = 3; // 3kg
}
void Draw();
void Move();
};
class Puck: public Drawable, public Movable
{
public:
Puck(double x, double y): Movable(x,y, 0.7, physics) {
mass = 0.03; // 30g
}
void Draw();
void Move();
};
#endif
//----------------
//Derived.cpp - the functions for Derived.h
#include <vector>
#include <cmath>
#include "GLFiles.h"
#include "Derived.h"
#include "GeoMotion.h"
using namespace std;
//MalletXXX works when a mallet isnt hitting a XXX
void MalletWall(GeoMotion& coords); // if the object has hit a wall,
it returns the appropriate variable, else it returns the same variable
value
void MalletSquash(GeoMotion& coords, Mallet* mal); // has it hit a
squashes puck against the wall (for example)?
void MalletBound(GeoMotion& coords, Mallet* mal); // if its in your
half - y includes the position + change + radius
GeoMotion MouseCont(Mallet* mal); // mouse control
GeoMotion AICont(Mallet* mal); // AI control
bool Over(double coord, double fixed);
extern GLUquadricObj *quadratic;
extern vector<Drawable *> DrawList;
extern vector<Movable *> MoveList;
extern float length;
extern float width;
extern float rest;
extern int step; // to disect the mallets movement if its going into
another object that is unmovable
extern vector<Puck*> Pucks;
extern double friction;
extern int mouse_sens;
extern int WIDTH;
extern int HEIGHT;
void Puck:
raw() {
glPushMatrix();
glColor3f(0.0f, 0.0f, 0.0f);
glTranslatef(x, 0.0f, y);
glRotatef(90, 1.0f, 0.0f, 0.0f);
gluCylinder(quadratic, radius, radius,0.1f,32,32); // main outside
gluDisk(quadratic,0.0f, radius,32,32); // disc covering top
gluCylinder(quadratic, 0.2, 0.2,0.11f,32,32); // nice looking ring in
the middle
glPopMatrix();
return;
}
void Puck::Move() {
x_change *= friction;
y_change *= friction;
x += x_change;
y += y_change;
return;
}
void Mallet:
raw() {
double OuterHeight = 0.25; // outer mallet height
double WallDown = 0.1; // how far down the base of the handle is from
the outer height
double WallIn = 0.1; // how far in the outer wall comes
double HHeight = 0.4; // handle heigth
double HWidth = 0.6;
glPushMatrix();
glColor3f(0.0f, 0.0f, 0.0f);
glTranslatef(x, 0.0f, y);
glRotatef(-90, 1.0f, 0.0f, 0.0f);
gluCylinder(quadratic, radius, radius, OuterHeight ,32,32); //
outside wall
glTranslatef(0.0f, 0.0f, OuterHeight);
gluDisk(quadratic, radius-WallIn, radius,32,32); // top of the wall
glTranslatef(0.0f, 0.0f, -WallDown); // has been rotated, so z axis
is where y used to be, and -
gluCylinder(quadratic, HWidth/2 , radius-WallIn, WallDown,32,32); //
connection from handle to top of wall
gluCylinder(quadratic, HWidth/2 , HWidth/2, HHeight ,32,32); //
handle
glTranslatef(0.0f, 0.0f, HHeight);
gluSphere(quadratic, HWidth/2 ,32,32); // handle nob
glPopMatrix();
return;
}
void Mallet::Move() {
GeoMotion coords(this);
if (control == mouse)
coords = MouseCont(this);
else if (control == AI)
coords = AICont(this);
x = coords.x;
y = coords.y;
x_change = coords.x_change;
y_change = coords.y_change;
return;
}
GeoMotion MouseCont(Mallet* mal) {
GeoMotion coords(mal);
POINT mouse;
GetCursorPos(&mouse); // from windows.h
double tmpX = mouse.x - WIDTH/2; // centre screen gives large
coordinates, but coordinates in the centre should be 0,0 - without
this, centre coords will be like 512,384
double tmpY = mouse.y - HEIGHT/2;
coords.x_change = (tmpX / WIDTH * width)/mouse_sens; // get it as a
fraction of the screen, then make that fraction relative to the table
dimension, then divide by the sensitivity
coords.y_change = (tmpY / HEIGHT * length)/mouse_sens;
//continually send the coords to a function and have values updated
MalletWall(coords); // if its hitting a wall, return the change that
it should have to go max without hittin, else return current change
MalletBound(coords, mal);
MalletSquash(coords, mal);
coords.x = coords.x + coords.x_change; // make the x position its
curretn position plus its newly calculated change
coords.y = coords.y + coords.y_change;
SetCursorPos(WIDTH/2, HEIGHT/2);
return coords;
}
GeoMotion AICont(Mallet* mal) {
GeoMotion coords(mal);
coords.x_change = Pucks[0]->now_x() - coords.x;
coords.y_change=0;
MalletBound(coords,mal);
coords.x += coords.x_change;
coords.y += coords.y_change;
return coords;
}
void MalletBound(GeoMotion& coords, Mallet* mal) { // bound to own
half
double littlebit = 0.3;
double bound = mal->controller() == mouse? 0 + Pucks[0]->get_radius()
+littlebit : 0 - Pucks[0]->get_radius() -littlebit; // boundary,
furthest forward it can go. 0 is halfway
if (mal->controller() == mouse &&
coords.y+coords.y_change-coords.radius <= bound)
coords.y_change = bound - (coords.y-coords.radius);
else if ( mal->controller() != mouse && mal->controller() != physics
&& coords.y+coords.y_change+coords.radius >= bound)
coords.y_change = bound - (coords.y+coords.radius); // make distance
to be just touching
return;
}
void MalletSquash(GeoMotion& coords, Mallet* mal) {
for (int i=0; i<MoveList.size(); ++i) // if its being squashed
against a wall..
{
if (MoveList != mal && MoveList->controller() == physics) //
if its not the same address (in which case of course they will collide
and this will return false) and if its changeable on collision, like a
puck
if (sqrt( pow(coords.x+coords.x_change-MoveList->next_x(), 2.0)
+ pow(coords.y+coords.y_change-MoveList->next_y(), 2.0) ) <
coords.radius+MoveList->get_radius()) // if (using distance
formula) its not hittign the object, if it is, their distance b/w
radii will be less than sum of radii
if ( Over(coords.x+coords.x_change, width/2-rest
-2*MoveList->get_radius()-coords.radius) == true ||
Over(coords.y+coords.y_change, length/2-rest
-2*MoveList->get_radius()-coords.radius) == true)
for (int j=0; j<=step; ++j)
if (sqrt( pow(coords.x+ j*coords.x_change/step
-MoveList->next_x(), 2.0) + pow(coords.y+ j*coords.y_change/step
-MoveList->next_y(), 2.0) ) <
coords.radius+MoveList->get_radius())
{
coords.x_change = (j-1)*coords.x_change/step; // take the one
right before collision, otherwise the object will bounce back INSIDE
the mallet
coords.y_change = (j-1)*coords.y_change/step;
}
}
return;
}
void MalletWall(GeoMotion& coords) {
if (coords.x+coords.x_change + coords.radius > width/2-rest) // if
its going over the side wall
coords.x_change = width/2-rest -coords.radius - coords.x;
else if (coords.x+coords.x_change - coords.radius < -width/2+rest)
coords.x_change = -width/2+rest + coords.radius - coords.x; // make
it go right up to the wall
if (coords.y+coords.y_change + coords.radius > length/2-rest) // if
its going over the front/back wall
coords.y_change = length/2-rest -coords.radius - coords.y;
else if (coords.y+coords.y_change - coords.radius < -length/2+rest)
coords.y_change = -length/2+rest + coords.radius - coords.y; // make
it go right up to the wall
return;
}
void Movable::Replace() {
x_change = 0;
y_change = 0;
x = 0;
if (y<0) // if it needs to be reset on the other side
y = -length/4;
else
y = length/4;
double inity = y;
bool overlap;
do {
overlap = false;
for (int i=0; i< MoveList.size(); ++i)
if (MoveList != this && sqrt( pow(y - MoveList->y, 2.0) +
pow(x - MoveList->x, 2.0) ) < radius + MoveList->get_radius())
{
overlap = true;
x >= 0? x=-x-radius/2 : x=-x; // if its on the right, switch it to
the left, if its on the left sidemove it one object diameter across
and retry
if (x < -width/2+rest + radius) // dont keep replacing it, so
check its not off the edge, but make sure you dont place it too close,
at least a radius away
{
x = 0;
y = y >= inity? y - 2*(y-inity) -radius/2 : y + 2*(inity-y); //
switch sides each time, done by subtracting from y twice its distance
from length/4 (starting point) thereby reflecting it by this point
if (y < radius || y > -radius)
{
y=inity;
overlap = false; // we have placed it everywhere in the whole
half and nothing works, pretend there nothing wrong and set it in a
goal position to redo this procedure next iteration
}
}
break;
}
} while (overlap == true);
return;
}
void AddDraw(Drawable* draw) {
DrawList.push_back(draw);
return;
}
void AddMove(Movable* move) {
MoveList.push_back(move);
return;
}
//----------------
//DrawMotion.cpp - handles functions like drawing each frame,
collision detection, and how objects should reflect (both speed and
direction)
#include <vector>
#include <cmath>
#include "Derived.h"
#include "GLFiles.h"
using namespace std;
void SetupObj();
bool LoadPucks(int pucks);
bool LoadMallets();
void ReplacePucks();
void CloseGL();
void DrawObj();
bool Over(double coord, double fixed);
int CircleCol(Movable* obj1, Movable* obj2);
int FixedCol(Movable* obj, double x, double y);
double GoalCoord(double coord, double fixed);
void HitTable(Movable* obj, double change);
double NewVel(double vel1, double vel2, double m1, double m2);
void Collide();
void Reset();
void NextFrame();
extern Mallet* Mallet1;
extern Mallet* Mallet2;
extern vector<Puck*> Pucks;
extern float length;
extern float width;
extern float height;
extern float rest;
extern float goal;
extern int step;
vector<Drawable *> DrawList;
vector<Movable *> MoveList;
void SetupObj() {
ShowCursor(false);
if (LoadPucks(1) != true || LoadMallets() != true) // LoadPucks first
because mallet AI is used to check where the puck is and it will move
the puck first this way, and the AI can check
exit(-1);
ReplacePucks();
return;
}
bool LoadPucks(int pucks) {
Puck* tmpPuck;
for (int i=0; i<pucks; ++i)
{
try {
tmpPuck = new Puck(0,5);
Pucks.push_back(tmpPuck);
}
catch(std::bad_alloc nomem)
{
return false;
}
}
return true;
}
bool LoadMallets() {
try {
Mallet* Mallet1 = new Mallet(0,6, mouse);
Mallet* Mallet2 = new Mallet(0,1, AI);
}
catch(std::bad_alloc nomem)
{
return false;
}
return true;
}
void ReplacePucks() {
for (int i=0; i<Pucks.size(); ++i)
Pucks[0]->Replace();
return;
}
void CloseGL() {
ShowCursor(true);
delete Mallet1;
delete Mallet2;
for (int i=0; i<Pucks.size(); ++i)
delete Pucks;
return;
}
void DrawObj() {
for (int i=0; i < DrawList.size(); ++i)
DrawList->Draw();
return;
}
bool Over(double coord, double fixed) { // has coord gone beyond fixed
in both positive and negative dimensions
if (coord > fixed || coord < -fixed)
return true;
return false;
}
int CircleCol(Movable* obj1, Movable* obj2) { // returns 0 if there no
collision, else it returns the step of the process where the collision
was
double xdist1 = obj1->now_x(); // its distance in the x direction
after any given number of steps through the process of deconstruction
double ydist1 = obj1->now_y();
double xdist2 = obj2->now_x();
double ydist2 = obj2->now_y();
double tmpX1 = obj1->change_x();
double tmpY1 = obj1->change_y();
double tmpX2 = obj2->change_x();
double tmpY2 = obj2->change_y();
for (int i=1; i<=step; ++i)
{
if (Over(xdist1 +tmpX1/step, width/2-rest -obj1->get_radius()) ==
true) // if any of the NEXT distances (thats why one step has been
added) are beyond a boundary, change the direction
tmpX1 *= -1;
if (Over(ydist1 +tmpY1/step, length/2-rest -obj1->get_radius()) ==
true && (xdist1+tmpX1/step >= goal/2 || xdist1+tmpX1/step <= -goal/2)
)
tmpY1 *= -1;
if (Over(xdist2 +tmpX2/step, width/2-rest -obj2->get_radius()) ==
true && (xdist2+tmpX2/step >= goal/2 || xdist2+tmpX2/step <= -goal/2)
)
tmpX2 *= -1;
if (Over(ydist2 +tmpY2/step, length/2-rest -obj2->get_radius()) ==
true)
tmpY2 *= -1;
// check this FIRST because the first step could step over a
boundary first and this needs to check it before ?dist is set to set
the correct direction of tmp?
xdist1 = obj1->now_x() + i * (tmpX1/step); // where it is + i
fractions of the change, i.e. more of the fraction
ydist1 = obj1->now_y() + i * (tmpY1/step);
xdist2 = obj2->now_x() + i * (tmpX2/step);
ydist2 = obj2->now_y() + i * (tmpY2/step);
if ( sqrt( pow(xdist1 - xdist2, 2.0) + pow(ydist1 - ydist2, 2.0) ) <
obj1->get_radius()+obj2->get_radius() ) // distance between radii <
the sum of the radii
return i;
}
return 0;
}
int FixedCol(Movable* obj, double x, double y) { // returns 0 if there
no collision, else it returns the step of the process where the
collision was
double xdist = obj->now_x(); // its distance in the x direction after
any given number of steps through the process of deconstruction
double ydist = obj->now_y();
double tmpX = obj->change_x();
double tmpY = obj->change_y();
for (int i=1; i<=step; ++i)
{
if (Over(xdist +tmpX/step, width/2-rest -obj->get_radius()) == true)
// if any of the NEXT distances (thats why one step has been added)
are beyond a boundary, change the direction
tmpX *= -1;
if (Over(ydist +tmpY/step, length/2-rest -obj->get_radius()) == true
&& (xdist+tmpX/step >= goal/2 || xdist+tmpX/step <= -goal/2) )
tmpY *= -1;
// check this FIRST because the first step could step over a
boundary first and this needs to check it before ?dist is set to set
the correct direction of tmp?
xdist = obj->now_x() + i * (tmpX/step); // where it is + i fractions
of the change, i.e. more of the fraction
ydist = obj->now_y() + i * (tmpY/step);
if ( sqrt( pow(xdist - x, 2.0) + pow(ydist - y, 2.0) ) <
obj->get_radius() ) // distance between radii < the sum of the radii
return i;
}
return 0;
}
double GoalCoord(double coord, double fixed) {
if (coord > 0)
return fixed;
else
return -fixed;
}
double NewVel(double vel1, double vel2, double m1, double m2) {
return vel1 * (m1-m2) / (m1+m2) + vel2 * 2 * m2 / (m1+m2);
}
void HitTable(Movable* obj, double change) {
if (Over(obj->next_y(), length/2-rest) && obj->next_x() <=
goal/2-obj->get_radius() && obj->next_x() >=
-goal/2+obj->get_radius()) // GOAL !! only reset its position when its
beyond saving
{
obj->Replace();
return; // no need to continue
}
if ( Over(obj->next_x(), width/2-rest - obj->radius) ) // If its hit
the side walls
obj->x_change *= -change;
if ( Over(obj->next_y(), length/2-rest - obj->radius) ) // possibly
hit the front/back wall
{
if ( obj->next_x() >= goal/2 || obj->next_x() <= -goal/2 ) //
hitting the actual wall
obj->y_change *= -change;
else // hitting the corner or its a goal
{
double gx = GoalCoord(obj->next_x(), goal/2); // goal x
double gy = GoalCoord(obj->next_y(), length/2-rest); // goal y
if ( int stepped = FixedCol(obj, gx, gy) ) // hits the corner of
the goal because its distance from it is less than its radius
{
double xdist = obj->x + stepped * obj->x_change/step;
double ydist = obj->y + stepped * obj->y_change/step;
double x = ( -obj->y_change - xdist*(ydist-gy)/(xdist-gx) +
(xdist+obj->x_change)*(gx-xdist)/(ydist-gy) ) / (
(gx-xdist)/(ydist-gy) - (ydist-gy)/(xdist-gx) ); // effect of the
corner (vector)
double y = ydist + x*(ydist-gy)/(xdist-gx) -
xdist*(ydist-gy)/(xdist-gx); // y effect
double invx = (xdist+obj->x_change) - x; // inverse
(perpendicular) velocities calculated before points are made relative
- otherwise the geometry is broken
double invy = (ydist+obj->y_change) - y;
x -= xdist;
y -= ydist;
obj->x_change = invx + change * -x; // corner just reverses the
motion (very solid)
obj->y_change = invy + change * -y;
}
}
}
return;
}
void Collide() {
double energy = 0.9; // _energy_ is multiplied by the velocities
after a collision compensating for energy loss to sound, heat etc.
int stepped;
for (int a=0; a < MoveList.size(); ++a)
for (int b=a+1; b < MoveList.size(); ++b) // only go through the
ones you havent already, because the first went through all, the
second need only go from the 3RD onwards
{
if ( stepped = CircleCol(MoveList[a], MoveList) )
{
double x1; // x velocity contributed via centre of mass, i.e. the
vector that contributes to the change, this is the x coordinate
double y1;
double x2;
double y2;
double invx1; // x velocity NOT contributed via centre of mass,
i.e. the vector that compliments x1 making up the velocity
double invy1;
double invx2;
double invy2;
double xdist1 = MoveList[a]->x +
stepped*MoveList[a]->x_change/step;
double ydist1 = MoveList[a]->y +
stepped*MoveList[a]->y_change/step;
double xdist2 = MoveList->x +
stepped*MoveList->x_change/step;
double ydist2 = MoveList->y +
stepped*MoveList->y_change/step;
if (xdist1 == xdist2) // prevent division by 0
{
x1 = 0;
y1 = MoveList[a]->y_change;
invx1 = 0;
invy1 = 0;
x2 = 0;
y2 = MoveList->y_change;
invx2 = 0;
invy2 = 0;
}
else if (ydist1 == ydist2)
{
x1 = MoveList[a]->x_change;
y1 = 0;
invx1 = 0;
invy1 = 0;
x2 = MoveList->x_change;
y2 = 0;
invx2 = 0;
invy2 = 0;
}
else
{
x1 = ( (xdist1 +
MoveList[a]->x_change)*((xdist1-xdist2)/(ydist2-ydist1)) -
MoveList[a]->y_change - xdist1*((ydist2-ydist1)/(xdist2-xdist1)) ) / (
(xdist1-xdist2)/(ydist2-ydist1) - (ydist2-ydist1)/(xdist2-xdist1) );
y1 = (x1*(ydist2-ydist1)/(xdist2-xdist1)) - xdist1 *
(ydist2-ydist1)/(xdist2-xdist1) + ydist1;
invx1 = (xdist1+MoveList[a]->x_change) - x1;
invy1 = (ydist1+MoveList[a]->y_change) - y1;
x2 = ( (xdist2 +
MoveList->x_change)*((xdist2-xdist1)/(ydist1-ydist2)) -
MoveList->y_change - xdist2*((ydist1-ydist2)/(xdist1-xdist2)) ) / (
(xdist2-xdist1)/(ydist1-ydist2) - (ydist1-ydist2)/(xdist1-xdist2) );
y2 = (x2*(ydist1-ydist2)/(xdist1-xdist2)) - xdist2 *
(ydist1-ydist2)/(xdist1-xdist2) + ydist2;
invx2 = (xdist2+MoveList->x_change) - x2;
invy2 = (ydist2+MoveList->y_change) - y2;
x1 -= xdist1; // its co-ordinates are only relative to its
position, lets give them an absolute value by making them be the
amount of change, making where they were useless
y1 -= ydist1;
x2 -= xdist2;
y2 -= ydist2;
}
if (MoveList[a]->controller() == physics) // only change its
velocity if its an object thats manipulated like that
{
MoveList[a]->x_change = invx1 + energy * NewVel(x1,x2,
MoveList[a]->get_mass(), MoveList->get_mass()); // we want to take
its initial velocity and change it (according to the masses) by the
impact of the 2nd object
MoveList[a]->y_change = invy1 + energy * NewVel(y1,y2,
MoveList[a]->get_mass(), MoveList->get_mass());
HitTable(MoveList[a], 0); // if the object has been hit by
another object and hits the wall as well, its going to be in a fast
rebound for many iterations, but physically, the mallet would absorb
the energy, thus passing 0.0 so the velocity is nothing
}
if (MoveList->controller() == physics)
{
MoveList->x_change = invx2 + energy * NewVel(x2,x1,
MoveList->get_mass(), MoveList[a]->get_mass());
MoveList->y_change = invy2 + energy * NewVel(y2,y1,
MoveList->get_mass(), MoveList[a]->get_mass());
HitTable(MoveList, 0);
}
}
}
for (int i=0; i<MoveList.size(); ++i)
if (MoveList->controller() == physics)
HitTable(MoveList, energy);
return;
}
void Reset() {
double leeway = 0.02; // amount that the reset function allows the
puck to be away from the wall, this converts to 0.5cm
for (int i=0; i < MoveList.size(); ++i)
if (MoveList->controller() == physics) // a puck
if ( Over( MoveList->next_x(), width/2-rest -
MoveList->get_radius() - leeway ))
if ( Over( MoveList->next_y(), length/2-rest -
MoveList->get_radius() - leeway )) // only check your side, cant
reset on the other side
if ( sqrt( pow(MoveList->change_x(), 2.0) +
pow(MoveList->change_y(), 2.0) ) < leeway) // if total velocity is
almost nothing
MoveList->Replace();
return;
}
void NextFrame() {
Reset();
Collide();
for (int i=0; i < MoveList.size(); ++i)
MoveList->Move();
return;
}
I've just taught myself C++, so I haven't learnt much about style or
the like from any single source, and I'm quite styleless as a result.
But at the same time, I really want nice code and I go to great
lengths to restructure my code just to look concise and make it more
manageable.
When I say this, I'm also referring to the way I write my functions.
It seems to me sometimes that I shouldn't have many void functions
accepting addresses and changing their values for example, but rather
a double function that returns the calculated value. i.e.
void Change(Type& variable);
should be replaced with
Type Change(Type variable);
I just don't know what's better code (in terms of speed, style, etc.).
I'm moving into a more mature phase of my program, and before I
continue I would like jsut a final verdict on my code. I'm looking for
comments about whether my functions should be more simple (i.e. too
much happens in each), whether I should rather return value instead of
alter through references passed, whether my general style is
inelegant. I'm also concerned about my class structures. But I'll show
you _some_ code and let you decide.
Please note that I'm not asking you to go through the actual logic of
all this code, but rather just calls to functions, classes and the
like.
Thanks.
Davin.
//---------------------
//Globals.cpp - just some global variables needed by most functions
#include <vector>
#include "GLFiles.h"
#include "Derived.h"
using std::vector;
//quadratic to draw cylinders, spheres etc.
GLUquadricObj *quadratic;
//window dimensions
int WIDTH = 1024;
int HEIGHT = 768;
//table dimensions
float length = 25.15f; // 251.5cm
float width = 13.84f;
float height = 8.13f;
float goal = 4.0f;
float rest = 1.5f; // width between esdge and tabletop
// Misc
int step = 150; // number of steps the collision detection will
deconstruct each translation into in checking for a collision
Mallet* Mallet1;
Mallet* Mallet2;
vector <Puck*> Pucks;
double friction = 0.985;
int mouse_sens = 4; // 4-10, 10-least sensitive
//---------------------
//Abstract.h - two abstract classes, some derived classes will be
inherited from both
#ifndef Abstract_Classes
#define Abstract_Classes
#include "Globals.h"
using namespace std;
class Movable;
class Drawable;
void AddDraw(Drawable* draw);
void AddMove(Movable* move);
extern double friction;
class Drawable
{
public:
Drawable() {
AddDraw(this);
}
virtual void Draw() = 0;
};
class Movable
{
public:
Movable(double x1, double y1, double r, Controller cont) {
AddMove(this);
control = cont;
x = x1;
y = y1;
x_change = 0.0;
y_change = 0.0;
radius = r;
}
double next_x() { return x + friction * x_change; }
double next_y() { return y + friction * y_change; }
double change_x() { return x_change; }
double change_y() { return y_change; }
double now_x() { return x; }
double now_y() { return y; }
double get_radius() { return radius; }
double get_mass() { return mass; }
Controller controller() { return control; }
friend void Collide();
friend void HitTable(Movable* obj, double change);
void Replace(); // reset its position (after a goal for example) and
velocity
virtual void Move() = 0;
protected:
Controller control;
double radius;
double mass; //used as a comparison between inherited types (as well
as the physics)
double x;
double y;
double x_change;
double y_change;
};
#endif
//------------------
//Derived.h - two derived classes
#ifndef Derived_Classes
#define Derived_Classes
#include "Abstract.h"
class Mallet: public Drawable, public Movable
{
public:
Mallet(double x, double y, Controller cont): Movable(x,y, 0.76, cont)
{
mass = 3; // 3kg
}
void Draw();
void Move();
};
class Puck: public Drawable, public Movable
{
public:
Puck(double x, double y): Movable(x,y, 0.7, physics) {
mass = 0.03; // 30g
}
void Draw();
void Move();
};
#endif
//----------------
//Derived.cpp - the functions for Derived.h
#include <vector>
#include <cmath>
#include "GLFiles.h"
#include "Derived.h"
#include "GeoMotion.h"
using namespace std;
//MalletXXX works when a mallet isnt hitting a XXX
void MalletWall(GeoMotion& coords); // if the object has hit a wall,
it returns the appropriate variable, else it returns the same variable
value
void MalletSquash(GeoMotion& coords, Mallet* mal); // has it hit a
squashes puck against the wall (for example)?
void MalletBound(GeoMotion& coords, Mallet* mal); // if its in your
half - y includes the position + change + radius
GeoMotion MouseCont(Mallet* mal); // mouse control
GeoMotion AICont(Mallet* mal); // AI control
bool Over(double coord, double fixed);
extern GLUquadricObj *quadratic;
extern vector<Drawable *> DrawList;
extern vector<Movable *> MoveList;
extern float length;
extern float width;
extern float rest;
extern int step; // to disect the mallets movement if its going into
another object that is unmovable
extern vector<Puck*> Pucks;
extern double friction;
extern int mouse_sens;
extern int WIDTH;
extern int HEIGHT;
void Puck:
glPushMatrix();
glColor3f(0.0f, 0.0f, 0.0f);
glTranslatef(x, 0.0f, y);
glRotatef(90, 1.0f, 0.0f, 0.0f);
gluCylinder(quadratic, radius, radius,0.1f,32,32); // main outside
gluDisk(quadratic,0.0f, radius,32,32); // disc covering top
gluCylinder(quadratic, 0.2, 0.2,0.11f,32,32); // nice looking ring in
the middle
glPopMatrix();
return;
}
void Puck::Move() {
x_change *= friction;
y_change *= friction;
x += x_change;
y += y_change;
return;
}
void Mallet:
double OuterHeight = 0.25; // outer mallet height
double WallDown = 0.1; // how far down the base of the handle is from
the outer height
double WallIn = 0.1; // how far in the outer wall comes
double HHeight = 0.4; // handle heigth
double HWidth = 0.6;
glPushMatrix();
glColor3f(0.0f, 0.0f, 0.0f);
glTranslatef(x, 0.0f, y);
glRotatef(-90, 1.0f, 0.0f, 0.0f);
gluCylinder(quadratic, radius, radius, OuterHeight ,32,32); //
outside wall
glTranslatef(0.0f, 0.0f, OuterHeight);
gluDisk(quadratic, radius-WallIn, radius,32,32); // top of the wall
glTranslatef(0.0f, 0.0f, -WallDown); // has been rotated, so z axis
is where y used to be, and -
gluCylinder(quadratic, HWidth/2 , radius-WallIn, WallDown,32,32); //
connection from handle to top of wall
gluCylinder(quadratic, HWidth/2 , HWidth/2, HHeight ,32,32); //
handle
glTranslatef(0.0f, 0.0f, HHeight);
gluSphere(quadratic, HWidth/2 ,32,32); // handle nob
glPopMatrix();
return;
}
void Mallet::Move() {
GeoMotion coords(this);
if (control == mouse)
coords = MouseCont(this);
else if (control == AI)
coords = AICont(this);
x = coords.x;
y = coords.y;
x_change = coords.x_change;
y_change = coords.y_change;
return;
}
GeoMotion MouseCont(Mallet* mal) {
GeoMotion coords(mal);
POINT mouse;
GetCursorPos(&mouse); // from windows.h
double tmpX = mouse.x - WIDTH/2; // centre screen gives large
coordinates, but coordinates in the centre should be 0,0 - without
this, centre coords will be like 512,384
double tmpY = mouse.y - HEIGHT/2;
coords.x_change = (tmpX / WIDTH * width)/mouse_sens; // get it as a
fraction of the screen, then make that fraction relative to the table
dimension, then divide by the sensitivity
coords.y_change = (tmpY / HEIGHT * length)/mouse_sens;
//continually send the coords to a function and have values updated
MalletWall(coords); // if its hitting a wall, return the change that
it should have to go max without hittin, else return current change
MalletBound(coords, mal);
MalletSquash(coords, mal);
coords.x = coords.x + coords.x_change; // make the x position its
curretn position plus its newly calculated change
coords.y = coords.y + coords.y_change;
SetCursorPos(WIDTH/2, HEIGHT/2);
return coords;
}
GeoMotion AICont(Mallet* mal) {
GeoMotion coords(mal);
coords.x_change = Pucks[0]->now_x() - coords.x;
coords.y_change=0;
MalletBound(coords,mal);
coords.x += coords.x_change;
coords.y += coords.y_change;
return coords;
}
void MalletBound(GeoMotion& coords, Mallet* mal) { // bound to own
half
double littlebit = 0.3;
double bound = mal->controller() == mouse? 0 + Pucks[0]->get_radius()
+littlebit : 0 - Pucks[0]->get_radius() -littlebit; // boundary,
furthest forward it can go. 0 is halfway
if (mal->controller() == mouse &&
coords.y+coords.y_change-coords.radius <= bound)
coords.y_change = bound - (coords.y-coords.radius);
else if ( mal->controller() != mouse && mal->controller() != physics
&& coords.y+coords.y_change+coords.radius >= bound)
coords.y_change = bound - (coords.y+coords.radius); // make distance
to be just touching
return;
}
void MalletSquash(GeoMotion& coords, Mallet* mal) {
for (int i=0; i<MoveList.size(); ++i) // if its being squashed
against a wall..
{
if (MoveList != mal && MoveList->controller() == physics) //
if its not the same address (in which case of course they will collide
and this will return false) and if its changeable on collision, like a
puck
if (sqrt( pow(coords.x+coords.x_change-MoveList->next_x(), 2.0)
+ pow(coords.y+coords.y_change-MoveList->next_y(), 2.0) ) <
coords.radius+MoveList->get_radius()) // if (using distance
formula) its not hittign the object, if it is, their distance b/w
radii will be less than sum of radii
if ( Over(coords.x+coords.x_change, width/2-rest
-2*MoveList->get_radius()-coords.radius) == true ||
Over(coords.y+coords.y_change, length/2-rest
-2*MoveList->get_radius()-coords.radius) == true)
for (int j=0; j<=step; ++j)
if (sqrt( pow(coords.x+ j*coords.x_change/step
-MoveList->next_x(), 2.0) + pow(coords.y+ j*coords.y_change/step
-MoveList->next_y(), 2.0) ) <
coords.radius+MoveList->get_radius())
{
coords.x_change = (j-1)*coords.x_change/step; // take the one
right before collision, otherwise the object will bounce back INSIDE
the mallet
coords.y_change = (j-1)*coords.y_change/step;
}
}
return;
}
void MalletWall(GeoMotion& coords) {
if (coords.x+coords.x_change + coords.radius > width/2-rest) // if
its going over the side wall
coords.x_change = width/2-rest -coords.radius - coords.x;
else if (coords.x+coords.x_change - coords.radius < -width/2+rest)
coords.x_change = -width/2+rest + coords.radius - coords.x; // make
it go right up to the wall
if (coords.y+coords.y_change + coords.radius > length/2-rest) // if
its going over the front/back wall
coords.y_change = length/2-rest -coords.radius - coords.y;
else if (coords.y+coords.y_change - coords.radius < -length/2+rest)
coords.y_change = -length/2+rest + coords.radius - coords.y; // make
it go right up to the wall
return;
}
void Movable::Replace() {
x_change = 0;
y_change = 0;
x = 0;
if (y<0) // if it needs to be reset on the other side
y = -length/4;
else
y = length/4;
double inity = y;
bool overlap;
do {
overlap = false;
for (int i=0; i< MoveList.size(); ++i)
if (MoveList != this && sqrt( pow(y - MoveList->y, 2.0) +
pow(x - MoveList->x, 2.0) ) < radius + MoveList->get_radius())
{
overlap = true;
x >= 0? x=-x-radius/2 : x=-x; // if its on the right, switch it to
the left, if its on the left sidemove it one object diameter across
and retry
if (x < -width/2+rest + radius) // dont keep replacing it, so
check its not off the edge, but make sure you dont place it too close,
at least a radius away
{
x = 0;
y = y >= inity? y - 2*(y-inity) -radius/2 : y + 2*(inity-y); //
switch sides each time, done by subtracting from y twice its distance
from length/4 (starting point) thereby reflecting it by this point
if (y < radius || y > -radius)
{
y=inity;
overlap = false; // we have placed it everywhere in the whole
half and nothing works, pretend there nothing wrong and set it in a
goal position to redo this procedure next iteration
}
}
break;
}
} while (overlap == true);
return;
}
void AddDraw(Drawable* draw) {
DrawList.push_back(draw);
return;
}
void AddMove(Movable* move) {
MoveList.push_back(move);
return;
}
//----------------
//DrawMotion.cpp - handles functions like drawing each frame,
collision detection, and how objects should reflect (both speed and
direction)
#include <vector>
#include <cmath>
#include "Derived.h"
#include "GLFiles.h"
using namespace std;
void SetupObj();
bool LoadPucks(int pucks);
bool LoadMallets();
void ReplacePucks();
void CloseGL();
void DrawObj();
bool Over(double coord, double fixed);
int CircleCol(Movable* obj1, Movable* obj2);
int FixedCol(Movable* obj, double x, double y);
double GoalCoord(double coord, double fixed);
void HitTable(Movable* obj, double change);
double NewVel(double vel1, double vel2, double m1, double m2);
void Collide();
void Reset();
void NextFrame();
extern Mallet* Mallet1;
extern Mallet* Mallet2;
extern vector<Puck*> Pucks;
extern float length;
extern float width;
extern float height;
extern float rest;
extern float goal;
extern int step;
vector<Drawable *> DrawList;
vector<Movable *> MoveList;
void SetupObj() {
ShowCursor(false);
if (LoadPucks(1) != true || LoadMallets() != true) // LoadPucks first
because mallet AI is used to check where the puck is and it will move
the puck first this way, and the AI can check
exit(-1);
ReplacePucks();
return;
}
bool LoadPucks(int pucks) {
Puck* tmpPuck;
for (int i=0; i<pucks; ++i)
{
try {
tmpPuck = new Puck(0,5);
Pucks.push_back(tmpPuck);
}
catch(std::bad_alloc nomem)
{
return false;
}
}
return true;
}
bool LoadMallets() {
try {
Mallet* Mallet1 = new Mallet(0,6, mouse);
Mallet* Mallet2 = new Mallet(0,1, AI);
}
catch(std::bad_alloc nomem)
{
return false;
}
return true;
}
void ReplacePucks() {
for (int i=0; i<Pucks.size(); ++i)
Pucks[0]->Replace();
return;
}
void CloseGL() {
ShowCursor(true);
delete Mallet1;
delete Mallet2;
for (int i=0; i<Pucks.size(); ++i)
delete Pucks;
return;
}
void DrawObj() {
for (int i=0; i < DrawList.size(); ++i)
DrawList->Draw();
return;
}
bool Over(double coord, double fixed) { // has coord gone beyond fixed
in both positive and negative dimensions
if (coord > fixed || coord < -fixed)
return true;
return false;
}
int CircleCol(Movable* obj1, Movable* obj2) { // returns 0 if there no
collision, else it returns the step of the process where the collision
was
double xdist1 = obj1->now_x(); // its distance in the x direction
after any given number of steps through the process of deconstruction
double ydist1 = obj1->now_y();
double xdist2 = obj2->now_x();
double ydist2 = obj2->now_y();
double tmpX1 = obj1->change_x();
double tmpY1 = obj1->change_y();
double tmpX2 = obj2->change_x();
double tmpY2 = obj2->change_y();
for (int i=1; i<=step; ++i)
{
if (Over(xdist1 +tmpX1/step, width/2-rest -obj1->get_radius()) ==
true) // if any of the NEXT distances (thats why one step has been
added) are beyond a boundary, change the direction
tmpX1 *= -1;
if (Over(ydist1 +tmpY1/step, length/2-rest -obj1->get_radius()) ==
true && (xdist1+tmpX1/step >= goal/2 || xdist1+tmpX1/step <= -goal/2)
)
tmpY1 *= -1;
if (Over(xdist2 +tmpX2/step, width/2-rest -obj2->get_radius()) ==
true && (xdist2+tmpX2/step >= goal/2 || xdist2+tmpX2/step <= -goal/2)
)
tmpX2 *= -1;
if (Over(ydist2 +tmpY2/step, length/2-rest -obj2->get_radius()) ==
true)
tmpY2 *= -1;
// check this FIRST because the first step could step over a
boundary first and this needs to check it before ?dist is set to set
the correct direction of tmp?
xdist1 = obj1->now_x() + i * (tmpX1/step); // where it is + i
fractions of the change, i.e. more of the fraction
ydist1 = obj1->now_y() + i * (tmpY1/step);
xdist2 = obj2->now_x() + i * (tmpX2/step);
ydist2 = obj2->now_y() + i * (tmpY2/step);
if ( sqrt( pow(xdist1 - xdist2, 2.0) + pow(ydist1 - ydist2, 2.0) ) <
obj1->get_radius()+obj2->get_radius() ) // distance between radii <
the sum of the radii
return i;
}
return 0;
}
int FixedCol(Movable* obj, double x, double y) { // returns 0 if there
no collision, else it returns the step of the process where the
collision was
double xdist = obj->now_x(); // its distance in the x direction after
any given number of steps through the process of deconstruction
double ydist = obj->now_y();
double tmpX = obj->change_x();
double tmpY = obj->change_y();
for (int i=1; i<=step; ++i)
{
if (Over(xdist +tmpX/step, width/2-rest -obj->get_radius()) == true)
// if any of the NEXT distances (thats why one step has been added)
are beyond a boundary, change the direction
tmpX *= -1;
if (Over(ydist +tmpY/step, length/2-rest -obj->get_radius()) == true
&& (xdist+tmpX/step >= goal/2 || xdist+tmpX/step <= -goal/2) )
tmpY *= -1;
// check this FIRST because the first step could step over a
boundary first and this needs to check it before ?dist is set to set
the correct direction of tmp?
xdist = obj->now_x() + i * (tmpX/step); // where it is + i fractions
of the change, i.e. more of the fraction
ydist = obj->now_y() + i * (tmpY/step);
if ( sqrt( pow(xdist - x, 2.0) + pow(ydist - y, 2.0) ) <
obj->get_radius() ) // distance between radii < the sum of the radii
return i;
}
return 0;
}
double GoalCoord(double coord, double fixed) {
if (coord > 0)
return fixed;
else
return -fixed;
}
double NewVel(double vel1, double vel2, double m1, double m2) {
return vel1 * (m1-m2) / (m1+m2) + vel2 * 2 * m2 / (m1+m2);
}
void HitTable(Movable* obj, double change) {
if (Over(obj->next_y(), length/2-rest) && obj->next_x() <=
goal/2-obj->get_radius() && obj->next_x() >=
-goal/2+obj->get_radius()) // GOAL !! only reset its position when its
beyond saving
{
obj->Replace();
return; // no need to continue
}
if ( Over(obj->next_x(), width/2-rest - obj->radius) ) // If its hit
the side walls
obj->x_change *= -change;
if ( Over(obj->next_y(), length/2-rest - obj->radius) ) // possibly
hit the front/back wall
{
if ( obj->next_x() >= goal/2 || obj->next_x() <= -goal/2 ) //
hitting the actual wall
obj->y_change *= -change;
else // hitting the corner or its a goal
{
double gx = GoalCoord(obj->next_x(), goal/2); // goal x
double gy = GoalCoord(obj->next_y(), length/2-rest); // goal y
if ( int stepped = FixedCol(obj, gx, gy) ) // hits the corner of
the goal because its distance from it is less than its radius
{
double xdist = obj->x + stepped * obj->x_change/step;
double ydist = obj->y + stepped * obj->y_change/step;
double x = ( -obj->y_change - xdist*(ydist-gy)/(xdist-gx) +
(xdist+obj->x_change)*(gx-xdist)/(ydist-gy) ) / (
(gx-xdist)/(ydist-gy) - (ydist-gy)/(xdist-gx) ); // effect of the
corner (vector)
double y = ydist + x*(ydist-gy)/(xdist-gx) -
xdist*(ydist-gy)/(xdist-gx); // y effect
double invx = (xdist+obj->x_change) - x; // inverse
(perpendicular) velocities calculated before points are made relative
- otherwise the geometry is broken
double invy = (ydist+obj->y_change) - y;
x -= xdist;
y -= ydist;
obj->x_change = invx + change * -x; // corner just reverses the
motion (very solid)
obj->y_change = invy + change * -y;
}
}
}
return;
}
void Collide() {
double energy = 0.9; // _energy_ is multiplied by the velocities
after a collision compensating for energy loss to sound, heat etc.
int stepped;
for (int a=0; a < MoveList.size(); ++a)
for (int b=a+1; b < MoveList.size(); ++b) // only go through the
ones you havent already, because the first went through all, the
second need only go from the 3RD onwards
{
if ( stepped = CircleCol(MoveList[a], MoveList) )
{
double x1; // x velocity contributed via centre of mass, i.e. the
vector that contributes to the change, this is the x coordinate
double y1;
double x2;
double y2;
double invx1; // x velocity NOT contributed via centre of mass,
i.e. the vector that compliments x1 making up the velocity
double invy1;
double invx2;
double invy2;
double xdist1 = MoveList[a]->x +
stepped*MoveList[a]->x_change/step;
double ydist1 = MoveList[a]->y +
stepped*MoveList[a]->y_change/step;
double xdist2 = MoveList->x +
stepped*MoveList->x_change/step;
double ydist2 = MoveList->y +
stepped*MoveList->y_change/step;
if (xdist1 == xdist2) // prevent division by 0
{
x1 = 0;
y1 = MoveList[a]->y_change;
invx1 = 0;
invy1 = 0;
x2 = 0;
y2 = MoveList->y_change;
invx2 = 0;
invy2 = 0;
}
else if (ydist1 == ydist2)
{
x1 = MoveList[a]->x_change;
y1 = 0;
invx1 = 0;
invy1 = 0;
x2 = MoveList->x_change;
y2 = 0;
invx2 = 0;
invy2 = 0;
}
else
{
x1 = ( (xdist1 +
MoveList[a]->x_change)*((xdist1-xdist2)/(ydist2-ydist1)) -
MoveList[a]->y_change - xdist1*((ydist2-ydist1)/(xdist2-xdist1)) ) / (
(xdist1-xdist2)/(ydist2-ydist1) - (ydist2-ydist1)/(xdist2-xdist1) );
y1 = (x1*(ydist2-ydist1)/(xdist2-xdist1)) - xdist1 *
(ydist2-ydist1)/(xdist2-xdist1) + ydist1;
invx1 = (xdist1+MoveList[a]->x_change) - x1;
invy1 = (ydist1+MoveList[a]->y_change) - y1;
x2 = ( (xdist2 +
MoveList->x_change)*((xdist2-xdist1)/(ydist1-ydist2)) -
MoveList->y_change - xdist2*((ydist1-ydist2)/(xdist1-xdist2)) ) / (
(xdist2-xdist1)/(ydist1-ydist2) - (ydist1-ydist2)/(xdist1-xdist2) );
y2 = (x2*(ydist1-ydist2)/(xdist1-xdist2)) - xdist2 *
(ydist1-ydist2)/(xdist1-xdist2) + ydist2;
invx2 = (xdist2+MoveList->x_change) - x2;
invy2 = (ydist2+MoveList->y_change) - y2;
x1 -= xdist1; // its co-ordinates are only relative to its
position, lets give them an absolute value by making them be the
amount of change, making where they were useless
y1 -= ydist1;
x2 -= xdist2;
y2 -= ydist2;
}
if (MoveList[a]->controller() == physics) // only change its
velocity if its an object thats manipulated like that
{
MoveList[a]->x_change = invx1 + energy * NewVel(x1,x2,
MoveList[a]->get_mass(), MoveList->get_mass()); // we want to take
its initial velocity and change it (according to the masses) by the
impact of the 2nd object
MoveList[a]->y_change = invy1 + energy * NewVel(y1,y2,
MoveList[a]->get_mass(), MoveList->get_mass());
HitTable(MoveList[a], 0); // if the object has been hit by
another object and hits the wall as well, its going to be in a fast
rebound for many iterations, but physically, the mallet would absorb
the energy, thus passing 0.0 so the velocity is nothing
}
if (MoveList->controller() == physics)
{
MoveList->x_change = invx2 + energy * NewVel(x2,x1,
MoveList->get_mass(), MoveList[a]->get_mass());
MoveList->y_change = invy2 + energy * NewVel(y2,y1,
MoveList->get_mass(), MoveList[a]->get_mass());
HitTable(MoveList, 0);
}
}
}
for (int i=0; i<MoveList.size(); ++i)
if (MoveList->controller() == physics)
HitTable(MoveList, energy);
return;
}
void Reset() {
double leeway = 0.02; // amount that the reset function allows the
puck to be away from the wall, this converts to 0.5cm
for (int i=0; i < MoveList.size(); ++i)
if (MoveList->controller() == physics) // a puck
if ( Over( MoveList->next_x(), width/2-rest -
MoveList->get_radius() - leeway ))
if ( Over( MoveList->next_y(), length/2-rest -
MoveList->get_radius() - leeway )) // only check your side, cant
reset on the other side
if ( sqrt( pow(MoveList->change_x(), 2.0) +
pow(MoveList->change_y(), 2.0) ) < leeway) // if total velocity is
almost nothing
MoveList->Replace();
return;
}
void NextFrame() {
Reset();
Collide();
for (int i=0; i < MoveList.size(); ++i)
MoveList->Move();
return;
}