Balls collision simulation - problem

Hi ! :) I'm new to C++ and need to somehow manage balls collision simulation for
my classes. If there was similar topic then I'm sorry I didnt find it.


So here is my code and what I find problematic is the void Runrandom function
in Universe class. Im really struggling to somehow combine balls movement, class plotter and collision detection. Can someone help me? Please :)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
  #include <iostream>
#include <cmath>
#include <vector>
#include <ctime>
#include<iomanip>

using namespace std;

class Ball
{
	double mass=1, radius=0.2;

	public:

		double Getmass(){ return mass;}
		double Getradius(){ return radius;}

		double vx, vy, vz;
		double posx, posy, posz;

		Ball(){}

		void Randomize_parameters();
		void set_starting_parameters(double, double, double, double, double, double);


		void Print();
		double Distance(const Ball &B);
};

                void Ball::Print()
                {	cout<<" "<<endl;
                        cout<<"Position x: "<<posx<<endl;
                        //cout<<"Position y: "<<posy<<endl;
                        //cout<<"Position z: "<<posz<<endl;
			cout<<" "<<endl;
                        cout<<"Velocity vx: "<<vx<<endl;
                        //cout<<"Velocity vy: "<<vy<<endl;
                        //cout<<"Velocity vz: "<<vz<<endl;
			cout<<" "<<endl;
                }

		double Ball::Distance(const Ball &B)
		{
			return sqrt(pow(posx-B.posx,2) + pow(posy-B.posy,2) + pow(posy-B.posy,2));
		}

		void Ball::set_starting_parameters(double x, double y, double z, double Vx, double Vy, double Vz)
		{
			posx=x;
			posy=y;
			posz=z;
			vx=Vx;
			vy=Vy;
			vz=Vz;
		}


		void Ball::Randomize_parameters()
		{
			double a,b,c,d,e,f;
                	a=rand()%10+rand()/(RAND_MAX +1.);
                	b=rand()%10+rand()/(RAND_MAX +1.);
                	c=rand()%10+rand()/(RAND_MAX +1.);
                	posx=a;
                	posy=b;
                	posz=c;

			d=rand()%2-rand()/(RAND_MAX +1.);
                        e=rand()%2-rand()/(RAND_MAX +1.);
                        f=rand()%2-rand()/(RAND_MAX +1.);
                        vx=d;
                        vy=e;
                        vz=f;
		}


class Movement
{
	double time=100., interval=1;

	public:

		Ball a;
		int box=10;
		vector<int> index;

		Movement(Ball A): a(A){}
		bool collision=false;
		//vector<double> vector_x, vector_y, vector_z;
		void MoveBall(Ball &a)
		{
				a.posx+=a.vx*interval;
				a.posy+=a.vy*interval;
				a.posz+=a.vz*interval;

				//vector_x.push_back(a.posx);
				//vector_y.push_back(a.posy);
				//vector_z.push_back(a.posz);

				if(a.posx>=box && a.vx>0){a.vx*=-1.;}
				if(a.posy>=box && a.vy>0){a.vy*=-1.;}
				if(a.posz>=box && a.vz>0){a.vz*=-1.;}

				if(a.posx<=0 && a.vx<0){a.vx*=-1.;}
                                if(a.posy<=0 && a.vy<0){a.vy*=-1.;}
                                if(a.posz<=0 && a.vz<0){a.vz*=-1.;}

		}

		void Collision(const Movement &A);

		void check()
		{
			for(int i=0;i<time;i+=10)
			{
				cout<<"Ball posottion: : "<<a.posx<<", ball velocity: "<<a.vx<<endl;
			}
		}




};

	void Movement::Collision(const Movement &A)
	{
		for(int i=0;i<=time-1;i++)
		{
			if(abs(a.posx-A.a.posx)<=0.01) //to be added later && abs(a.posy-A.a.posy)<=0.01 && abs(a.posz-A.a.posz)<=0.01)
			{

				if(a.vx<0 && A.a.vx>0)
				{
				index.push_back(i);
				collision=true;
				}

				else if(a.vx>0 && A.a.vx<0)
				{
				index.push_back(i);
                                collision=true;
				}

				else { collision=false;}
				//cout<<"Collision"<<endl; cout<<"Index: "<<i<<"Pos 1: "<<vector_x.at(i)<<", pos 2: "<<A.vector_x.at(i)<<endl;}
		}}
	}

//class Plotter
//{

          //I will add plotter later
//};



class Universe
{

        public:
        vector<Ball> Balls;

	int N;

        Universe(vector<Ball> balls, int n): Balls(balls), N(n){}
	vector<Movement> moves;
	vector<double> now_x, now_y;

        void Runrandom(vector<Ball> &Balls, int &N)
        {
	        for(int i=0;i<=N-1;i++)
        	{
               		Balls.at(i).Randomize_parameters();
                	//Balls.at(i).Print();
			Movement M(Balls.at(i));
                        moves.push_back(M);
		}


			for(int k=1;k<=10;k++)
                	{
				for(int i=0;i<=N-1;i++)
				{
                                   for(int j=0;j<=N-1;j++)
				        {
				         if(j!=i) 
                                        {moves.at(i).Collision(moves.at(j));}
				        

                       if(moves.at(i).collision==true)
                       {   
                               cout<<"Collision"<<endl;
                               Balls.at(i).vx*=-1; Balls.at(j).vx*=-1;
                        }}
				moves.at(i).MoveBall(Balls.at(i));
				now_x.push_back(Balls.at(i).posx);
				now_y.push_back(Balls.at(i).posy);
                                cout<<"Ball: "<<i<<endl;
                                Balls.at(i).Print();
				}
			}


		vector<double> now_x2, now_y2;

			for(int k=1;k<=10;k+=1)
                        {
				now_x2.push_back(now_x.at(k));
				now_y2.push_back(now_y.at(k));
			}
	}



        void Runtest()
        {
        	Ball A, B;
		A.set_starting_parameters(0,5,0,1,0,0);
        	B.set_starting_parameters(10,5,0,-1,0,0);
		vector<double> vec_xa, vec_ya, vec_xb, vec_yb;

		for(double i=1;i<=40;i+=0.5)
		{
			Movement MA(A);
                	Movement MB(B);


			MA.Collision(MB);

                        if(MA.collision==true)
                        {   
                                cout<<"Collision"<<endl;
                                A.vx*=-1; B.vx*=-1;
                        }


			MA.MoveBall(A);
			MB.MoveBall(B);

			vec_xa.push_back(A.posx);
			vec_xb.push_back(B.posx);

			vec_ya.push_back(A.posy);
			vec_yb.push_back(B.posy);
			
			cout<<"Ball 1: "<<endl;
			A.Print();
			cout<<"Ball 2: "<<endl;
			B.Print();
		}

        }


};


int main()
{

	srand(time(0));
        cout<<setprecision(2)<<fixed;

	int n=3;

	vector<Ball> balls;

	for(int i=1;i<=n;i++)
	{
		Ball A;
		balls.push_back(A);
	}

	Universe U(balls,n);
	//U.Runrandom(balls,n);
	U.Runtest();

return 0;
}
Last edited on
Hello yumi518,

After all that code you left out the header file "matplotlibcpp.h". With out it the code is full of errors and I can not test it.

Please post that file so the program can compile and run.

Andy
Hello Handy Andy,

Thank you for your reply. Unfortunately the header file "matplotlibcpp.h" is already installed on my PC and I cant find it so I just removed all the elements that need it and I will add them later. Now it should run smoothly :) When you run U.Runtest(); in the main() the balls are clearly colliding and changing directions but I cant get the same result for U.Runrandom(balls,n) :(

The idea of the simulation is to make an animation of n balls in a box using python. The balls are supposed to bounce from the walls and from each other.
Last edited on
@yumi518,
your code doesn't compile. Click the button to the right and try it in cpp.sh.

Have a look at it in your post above. It is not very intelligible. Please go back and fix that. I strongly suggest that you use spaces rather than tabs, as the latter often appears different in different environments.

Please remove all unnecessary stuff and make sure that the indentation shows correctly.

"It doesn't give the same result" is not a helpful description of the problem as (a) it doesn't run as it stands and (b) you are dealing with random numbers.
Hi Yumi518!

Try to use one of two 2D collision detection.
The first is based on rectangle shape bounding boxes:
1
2
3
4
5
6
if (ball1.x < ball2.x + ball2.width &&
   ball1.x + ball1.width > ball2.x &&
   ball1.y < ball2.y + ball2.height &&
   ball1.height + ball1.y > ball2.y) {
    // collision detected!
}

and the second is the circle collision: this algorithm works by taking the centre points of the two circles and ensuring the distance between the centre points are less than the two radii added together.
Just take a ball (ball1) and test the collision with all other balls with a FOR loop (it gives the values of ball2).
Hi Tomi!

Yes, it worked perfectly! Thank you so much. I didn't think I will ever get it to work properly :)
ASIDE

If you are going on to extend your program, you should consider refactoring it by converting associated variables into classes. In particular:

double vx, vy, vz; --> Velocity v;

double posx, posy, posz; --> Position pos;


And get the classes Velocity and Position to do their own work!

Andy
^^ in 3-d programs you typically need an XYZHPR for objects (3-d coordinate and 3-d orientation angles), as well as as velocity. What you are seeing here is that a ball does not really have a front/back/left/right that is noteworthy so you can ignore the HPR, but if it were a car, it could be important that it was moving to the left but the front of the car is to the right (its going in reverse) or that its moving to the left and facing to the right (its sliding down an icy hill?) and so on.
Hi,

You could also add to the modelling by adding more realistic physics like momentum, friction and energy. But this adds a few extra functions to affect energy etc.
Topic archived. No new replies allowed.