another example, just using a circle / segment collision check.
#include <windows.h>#include <winuser.h>#include <gl\glut.h>#include <math.h>#include <stdio.h>#include <stdlib.h>int sgn(double a) { return (a>0); }double clamp(double x, double min, double max) { return (x < min)? min : (x > max)? max : x; }double frand(double x) { return (rand() / (double) RAND_MAX) * x; }double Pi() { static const double _Pi = atan(1.0) * 4.0; return _Pi; }struct Vector{ double x, y; Vector() {} Vector(double _x, double _y) : x(_x) , y(_y) {} Vector& operator +=(const Vector& V) { x += V.x; y += V.y; return *this; } Vector& operator -=(const Vector& V) { x -= V.x; y -= V.y; return *this; } Vector& operator *=(double k) { x *= k ; y *= k ; return *this; } Vector& operator /=(double k) { x /= k ; y /= k ; return *this; } Vector operator + (const Vector& V) const { return Vector(x + V.x, y + V.y); } Vector operator - (const Vector& V) const { return Vector(x - V.x, y - V.y); } Vector operator * (double k) const { return Vector(x * k, y * k); } Vector operator / (double k) const { return Vector(x / k, y / k); } double operator * (const Vector& V) const { return x * V.x + y * V.y; } double operator ^ (const Vector& V) const { return x * V.y - y * V.x; } double Length() const { return sqrt(x*x + y*y); } double Normalise() { double l = Length(); x /= l; y /= l; return l; } Vector Scale (const Vector& xScale) const { return Vector(x * xScale.x, y * xScale.y); } Vector InvScale(const Vector& xScale) const { return Vector(x / xScale.x, y / xScale.y); } Vector Rotate(const Vector& C, double a) const { double px = (x - C.x) * cos(a) - (y - C.y) * sin(a) + C.x; double py = (x - C.x) * sin(a) + (y - C.y) * cos(a) + C.y; return Vector(px, py); } Vector& Randomise(const Vector& Min, const Vector& Max) { x = Min.x + frand(Max.x - Min.x); y = Min.y + frand(Max.y - Min.y); return *this; }};struct CColour{ double r; double g; double b; double a; CColour(double R, double G, double B, double A) { r = R; g = G; b = B; a = A; } void Render() const { glColor4f(r, g, b, a); }};void RenderPoint(const Vector& P, CColour col, double radius){ col.Render(); glBegin(GL_POINTS); glPointSize(radius); glVertex2f(P.x, P.y); glEnd();}void RenderSegment(const Vector& P, const Vector& Q, CColour col, double radius){ col.Render(); glBegin(GL_LINES); glLineWidth(radius); glVertex2f(P.x, P.y); glVertex2f(Q.x, Q.y); glEnd();}void RenderArrow(const Vector& P, const Vector& D, CColour col, double radius){ col.Render(); glLineWidth(radius); float angle = atan2(D.y, D.x); glPushMatrix(); glTranslatef(P.x, P.y, 0.0f); glScalef(D.Length(), D.Length(), 1.0f); glRotatef(angle * 180.0f / Pi(), 0, 0, 1); glBegin(GL_LINES); glVertex2f(0, 0); glVertex2f(1, 0); glVertex2f(1, 0); glVertex2f(0.9, -0.05); glVertex2f(1, 0); glVertex2f(0.9, +0.05); glEnd(); glPopMatrix();}void RenderCircle(const Vector& P, float r, CColour col, double radius){ col.Render(); glLineWidth(radius); glBegin(GL_LINE_LOOP); int steps = 16; double angle = 0.0; for(int i = 0; i < steps; i ++, angle += (2.0 * Pi()) / (double) steps) { Vector D(cos(angle) * r, sin(angle) * r); glVertex2f(P.x + D.x, P.y + D.y); } glVertex2f(P.x + r, P.y); glEnd();}bool CircleSegmentCollide(Vector& P, float r, const Vector& A, const Vector& B, Vector& collVector){ Vector AP = P - A; // distance vector Vector AB = B - A; // segment vector // compute closest point on line (A, B) to P double u = (AP * AB) / (AB * AB); // clamp to segment [A, B] range u = (u < 0.0f)? 0.0f : (u > 1.0f)? 1.0f : u; // closest point on segment [A, B] to P Vector C = A + AB * u; // cehck if point inside circle Vector CP = P - C; double l2 = CP * CP; // nope, no collision if (l2 > r * r) return false; // compute penetration vector double l = sqrt(l2); collVector = CP * (r - l) / l; return true;}int screen_width = 640;int screen_height = 480;// the playerVector P;float r;Vector MousePos(-1, -1);// the segmentsenum { MAX_SEGMENTS = 1000 };int segmentCount = 0;Vector segments[MAX_SEGMENTS][2];//-------------------------------------------------------------------------------------------------//// OPENGL Functions////-------------------------------------------------------------------------------------------------void init(){ // randomise player pos. r = frand(10) + 10; P.Randomise(Vector(0, 0), Vector(screen_width, screen_height)); // add screen boundaries segmentCount = 0; segments[0][0] = Vector(0, 0); segments[0][1] = Vector(screen_width, 0); segments[1][0] = Vector(screen_width, 0); segments[1][1] = Vector(screen_width, screen_height); segments[2][0] = Vector(screen_width, screen_height); segments[2][1] = Vector(0, screen_height); segments[3][0] = Vector(0, screen_height); segments[3][1] = Vector(0, 0); segmentCount = 4; // add random segments segmentCount += rand() % 20; for(int i = 0; i < segmentCount; i ++) { Vector C; Vector D; C.Randomise(Vector(0, 0), Vector(screen_width, screen_height)); D.Randomise(Vector(-100, -100), Vector(100, 100)); segments[0] = C; segments[1] = C + D; }}void display(void){ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glViewport( 0, 0, screen_width, screen_height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, screen_width, screen_height, 0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); Vector Displacement = MousePos - P; double d = Displacement.Length(); if(d > 3.0) Displacement *= 3.0f / d; P += Displacement; for(int i = 0; i < segmentCount; i ++) { Vector Coll; if(CircleSegmentCollide(P, r, segments[0], segments[1], Coll)) { P += Coll; } } for(int i = 0; i < segmentCount; i ++) { RenderPoint(segments[0], CColour(1, 0, 0, 1), 5); RenderPoint(segments[1], CColour(1, 0, 0, 1), 5); RenderSegment(segments[0], segments[1], CColour(1, 1.0, 0.5, 1), 3); } RenderPoint(P, CColour(1, 0, 0, 1), 5); RenderPoint(MousePos, CColour(1, 0, 0, 1), 5); RenderCircle(P, r, CColour(1, 1.0, 1.0, 1), 2); RenderArrow(P, MousePos-P, CColour(1, 0.2, 0.2, 1), 1); glutSwapBuffers();}void reshape(int w,int h){ screen_width = w; screen_height = h;}void ticker(int i){ display(); glutTimerFunc(4, ticker, 0);}void keyboard(unsigned char key, int x, int y){ if(key == 27) { exit(0); } if(key == ' ') { init(); }}void mouse(int x, int y){ MousePos.x = x; MousePos.y = y;}int main(int argc,char **argv){ glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH); glutInitWindowSize(screen_width, screen_height); glutInitWindowPosition(100,100); glutCreateWindow("verlet"); glutDisplayFunc(display); glutReshapeFunc(reshape); glutPassiveMotionFunc(mouse); glutKeyboardFunc(keyboard); glutTimerFunc(33, ticker, 0); glClearColor(0.0f,0.0f,0.3f,0.1f); glPointSize(8); glEnable(GL_POINT_SMOOTH); glEnable(GL_LINE_SMOOTH); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); init(); glutMainLoop(); return 0;}