Jump to content
  • Advertisement
Sign in to follow this  
Meshboy

Sphere sliding walls.

This topic is 3665 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am thinking of going back to basics. I need tactics for letting a sphere slide along "lines" the lines can be connected to other lines both obtuse and the other way around (convex and convace). i want to slide against a plane/line (not really a plane but a line that goes from v1-v2). My problem is not to find if sphere hits the line or not, the problem is sliding at the end of the line releasing player and also check for slide directions in concave and convex corners. Help me with the best math for this taks! is there anyone that has a demo or source for this kind of stuff? i want all angels for my "lines" not just a gridsystem with only 90 degrees.

Share this post


Link to post
Share on other sites
Advertisement
this is what I would try first




#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 player
Vector P;
float r;
Vector MousePos(-1, -1);

// the segments
enum { 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;
}



1) find closest point on segment to sphere centre.
2) if point not in sphere, no collision.
3) move sphere position away from point so that they are at distance 'r' from each other.

Share this post


Link to post
Share on other sites
tnx for code, my problem is really "move sphere away" and how to get the directions to slide to? by using X strategy.

Share this post


Link to post
Share on other sites
the collision vector (aka mtd here) gives you effectively a collision plane.

From there on, you can reflect the velocity on the collison plane (v -= (1 + cor) * (v . n)) * n).

but just pushing the player away will make him slide.

the code is just this part :


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

for(int i = 0; i < segmentCount; i ++)
{
Vector collVector;
if(CircleSegmentCollide(P, r, segments[0], segments[1], collVector))
{
P += collVector;
}
}

Share this post


Link to post
Share on other sites
Can you help me explain this one a little bit more deep?

"reflect the velocity on the collison plane (v -= (1 + cor) * (v . n)) * n)."

i also use closestPointOnLine but when i set my "slide-vector" i use the closestPointOnLine and then another closestPointOnLine based from the endPoint where the player would want to go, but this gives me errors on the edges.

If you are right infront a convex corner, do you take the plane that has the lovest DotPorduct? (the plane the player is NOT facing at most in sync sorta speak)

Can i setup lots of plane without having to implement other checks or algebra?

Share this post


Link to post
Share on other sites
I dont really understand what you mean. If you can post a drawing, that would help.

[Edited by - oliii on June 12, 2008 10:57:55 AM]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!