# Sphere sliding walls.

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

## 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 on other sites
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 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;}

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

1. 1
Rutin
70
2. 2
3. 3
4. 4
5. 5

• 21
• 10
• 33
• 20
• 9
• ### Forum Statistics

• Total Topics
633430
• Total Posts
3011825
• ### Who's Online (See full list)

There are no registered users currently online

×