Help in create ball movement

Hello guys, i need a help in creating ball movement. like Pong or BreakOut ball if he hits an object it will calulate the angel and by that will change his movement direction.
i tried look on google and tried build 1 by myself and i did use directions
if the ball hits the wall (for example) it is chekc the direction the ball came from and redirect it to a specific direction no calculation made.
please help me where to start this task :)
thanks alot , sean

the code i made so far:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
	if (this->direction == 1) {
		this->_ball.move(- this->ballSpeed, - this->ballSpeed);
		this->_hitBox.move(-this->ballSpeed, -this->ballSpeed);
	}
	else if (this->direction == 2) {
		this->_ball.move(this->ballSpeed, this->ballSpeed);
		this->_hitBox.move(this->ballSpeed, this->ballSpeed);
	}
	else if (this->direction == 3) {
		this->_ball.move(- this->ballSpeed, this->ballSpeed);
		this->_hitBox.move(-this->ballSpeed, this->ballSpeed);
	}
	else if (this->direction == 4) {
		this->_ball.move(this->ballSpeed,- this->ballSpeed);
		this->_hitBox.move(this->ballSpeed, -this->ballSpeed);
	}
My guess would be something like

1
2
3
4
5
6
7
8
9

direction.x=3;
direction.y=4;

If (collision) {
direction.x = -direction.x;  //if it hits a wall.  Return from other player would be  different 

}


obviously x,y in relation to origin would be the angle
Last edited on

got this working pretty good. Its basically full on pong with computer opponent. I'm honestly shocked that i was able to make this using the console. Only works in i64 debug for whatever reason. I also have to paste it in 2 parts of the same cpp bc it wont let me do it in one post. I'd also like to add that this is tied to the resolution of my laptop. It should adjust to other resolutions but if the display looks all crazy thats probably why. I didn't spend alot of time on that aspect but theres alot of math based off of the resolution and theres no guarantee it will translate over.

my resolution is... 1365 x 767 ? weird laptop resolution. whatever that translates into. thats just what the mouse position tool says is max x and y....

edit!! Snip

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
#include <Windows.h>
#include <iostream>
#include <time.h>
#include "wtypes.h"


using namespace std;

HWND WindowHwND = NULL;

struct game {
	int gameX, gameY;
	HANDLE handle1, handle2, handle3, handle4, handle5, handle6;
	HWND WindowHwnd;
	game()
		: gameX(), gameY(), handle1(), handle2(), handle3(), handle4(), handle5(), WindowHwnd(), handle6() {}

	struct player {
		int score, playerN, difficulty, reactiontime;
		player()
			: score(), playerN(), difficulty(), reactiontime() {}

		struct paddle {
			int posX, size, speed, posY;
			paddle()
				:posX(), size(), speed(), posY() {}
		};
		paddle pad;
	};

	player player1;
	player player2;

	void monitor_player_input() {
		std::string in;

		if (GetKeyState(VK_RIGHT) < 0) {
			if (this->player1.pad.posX < (this->gameX - (this->player1.pad.size / 2)) - 2) {
				this->player1.pad.posX++;
			}
		}

		else if (GetKeyState(VK_LEFT) < 0) {
			if (this->player1.pad.posX > (2 + (this->player1.pad.size / 2))) {
				this->player1.pad.posX--;
			}

		}
		else if (GetKeyState(VK_ESCAPE) < 0) {
			std::cout << "PAUSED.....for a list of commands type enter help" << std::endl;
			std::cin >> in;
			if (in == "help") {
				//do stuff 
			}

		}
	}

	void window_managment() {

		RECT desktop;

		this->WindowHwnd = FindWindow("ConsoleWindowClass", NULL);


		if (this->WindowHwnd) {
			ShowWindow(this->WindowHwnd, SW_SHOWMAXIMIZED);
			Sleep(250);
			GetWindowRect(this->WindowHwnd, &desktop);
			this->gameX = desktop.right - 100;
			this->gameY = desktop.bottom - 100;
		}
		else { std::cout << "error window_management()"; std::cin; }

	}

};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

struct ball : game {

	int angleX, angleY, speed, posX, posY;
	bool reset;
	ball()
		: angleX(), angleY(), speed(), posX(), posY(), reset() {}

	void start() {

		this->window_managment();
		srand(time(0));
		this->reset = false;

		// pick positive or negative
		int rando = rand() % 2; //1 is positive 0 is negative

		if (rando) { this->angleX = rand() % 20; }
		else { this->angleX = -(rand() % 20); }

		rando = rand() % 2;

		if (rando) { this->angleY = rand() % 20; }
		else { this->angleY = -(rand() % 20); }
		this->gameX = (this->gameX - 100) / 7;
		this->gameY = (this->gameY - 100) / 13;

		this->speed = 250;
		this->posX = this->gameX / 2;
		this->posY = this->gameY / 2;

		this->player1.pad.posY = this->gameY - 3;
		this->player1.pad.posX = this->gameX / 2;
		this->player1.pad.size = 14;
		this->player1.pad.speed = 2;

		this->player2.pad.posY = 1;
		this->player2.pad.posX = this->gameX / 2;

		this->player2.difficulty = 1;
		this->player2.reactiontime = 75;
		this->player2.pad.size = 14;
		this->player2.pad.speed = 1;

	}

	void move() {
		if (this->angleX > 0) { this->posX++; }
		else { this->posX--; }

		if (this->angleY > 0) { this->posY++; }
		else { this->posY--; }
		Sleep(this->speed);
	}

	void monitor_collision_walls() {

		if (this->posX < 3) { this->angleX = -(this->angleX); this->speed = this->speed - 20; Sleep(500); }
		else if (this->posY > this->gameY + 10) { score(100); }  //score
		else if (this->posY < -10) { score(0); }   //score
		else if (this->posX > (this->gameX - 3)) { this->angleX = (-this->angleX); this->speed = this->speed - 20; Sleep(500); }
	}

	void score(int a) {
		if (a == 100) { this->player2.score++; }
		else { this->player1.score++; }
		this->restart();
	}

	void monitor_collision_paddles() {
		if (this->posX > (this->player1.pad.posX - (this->player1.pad.size / 2) - 5) && this->posX < (this->player1.pad.posX + (this->player1.pad.size / 2)) + 1) {
			if (this->posY <= this->player1.pad.posY && this->posY >= this->player1.pad.posY - 2) {
				//this->angleX = -(this->angleX);
				this->angleY = -(this->angleY);
				this->speed -= 10;
				Sleep(500);
			}
		}
	}

	void monitor_collision_paddles2() {

				if (this->posX > (this->player2.pad.posX - (this->player2.pad.size * .5) - 5)) {
					if (this->posX < (this->player2.pad.posX + ((this->player2.pad.size * .5)) + 2)) {
						if (this->posY < 4) {
							this->angleY = (-this->angleY);
							this->speed -= 10;
							Sleep(500);
						}
					}
				}

	}

	void restart() {

		this->posX = this->gameX / 2;
		this->posY = this->gameY / 2;
		this->speed = 250;
		
		this->player2.pad.posX = (this->gameX * .5);


		int rando = rand() % 2;

		if (rando) { this->angleX = rand() % 20; }
		else { this->angleX = -(rand() % 20); }

		rando = rand() % 2;

		if (rando) { this->angleY = rand() % 20; }
		else { this->angleY = -(rand() % 20); }

	}


Last edited on
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

	void AI() {


		if (this->angleY < 0) {
			Sleep(this->player2.reactiontime);
			if (this->posX > this->player2.pad.posX && this->gameX > this->player2.pad.posX + (this->player2.pad.size / 2) + 2) { this->player2.pad.posX++; }
			else if (0 < this->player2.pad.posX - (this->player2.pad.size / 2) - 2) { this->player2.pad.posX--; }
		}

	}

	void print() {

		std::cout << "               PLAYER 1 SCORE: " << this->player1.score << ' ';
		

		for (int i = 20; i < this->gameX - 50; i++) { std::cout << ' '; }

		std::cout << "PLAYER 2 SCORE: " << this->player2.score << "\n";

		for (int i = 0; i < this->gameX; i++) { std::cout << "_"; }
		std::cout << '\n';

		//good to here............................

		for (int y = 0; y < this->gameY; y++) {
			for (int x = 0; x < this->gameX; x++) {

				if (x == this->posX && y == this->posY) { std::cout << '0'; } //this deals with the ball

				else if (x == this->player1.pad.posX - (this->player1.pad.size / 2) && y == (this->player1.pad.posY - 1)) { //this deals with player1 pad

					int cc_x = x;

					for (int u = 0; u < 2; u++, y++) {

						if (u == 0) {

							for (int i = 0; i < this->player1.pad.size - 1; i++, cc_x++) { std::cout << "_"; } //starts the pad

							for (; cc_x < this->gameX; cc_x++) {   //finishes first line of the pad
								if (cc_x == this->gameX - 1) { std::cout << "|" << "\n"; }
								else { std::cout << ' '; }
							}

						}

						else if (u > 0) {

							cc_x = 0;
							for (int i = 0; i < x; i++) {   //starts second line

								if (i == 0) { std::cout << "|"; }
								else if (i > 0) {
									std::cout << ' ';
								}
							}
							// from zer to x....


							for (int i = 0; i < (this->gameX - cc_x - 1); i++, x++) {

								if (i == 0) { std::cout << '|'; }

								else if (i > 0 && i < this->player1.pad.size - 1) {

									std::cout << "_";
								}
								else if (i == this->player1.pad.size) { std::cout << '|'; }

								else if (i > this->player1.pad.size && x < this->gameX) { std::cout << " "; }

								else if (x == this->gameX) { std::cout << "|" << "\n"; }
							}
						}
					}
				}

				else if (x == this->player2.pad.posX - (this->player2.pad.size / 2) && y == (this->player2.pad.posY - 1)) { //this deals with player2 pad

					int cc_x = x;

					for (int u = 0; u < 2; u++, y++) {

						if (u == 0) {

							for (int i = 0; i < this->player2.pad.size - 1; i++, cc_x++) { std::cout << "_"; } //starts the pad

							for (; cc_x < this->gameX; cc_x++) {   //finishes first line of the pad
								if (cc_x == this->gameX - 1) { std::cout << "|" << "\n"; }
								else { std::cout << ' '; }
							}

						}

						else if (u > 0) {

							cc_x = 0;
							for (int i = 0; i < x; i++) {   //starts second line

								if (i == 0) { std::cout << "|"; }
								else if (i > 0) {
									std::cout << ' ';
								}
							}
							// from zer to x....


							for (int i = 0; i < (this->gameX - cc_x - 1); i++, x++) {

								if (i == 0) { std::cout << '|'; }

								else if (i > 0 && i < this->player2.pad.size - 1) {

									std::cout << "_";
								}
								else if (i == this->player2.pad.size) { std::cout << '|'; }

								else if (i > this->player2.pad.size && x < this->gameX) { std::cout << " "; }

								else if (x == this->gameX) { std::cout << "|" << "\n"; }
							}
						}
					}
				}


				else if (x == 0) { std::cout << '|'; }

				else if (x == this->gameX - 1) { std::cout << '|' << "\n"; }

				else if (y + 1 == this->gameY && x > 0 && x < this->gameX - 2) { std::cout << '_'; }

				else { std::cout << ' '; }
			}
		}

	}




};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

void ThreadMove(ball b) {
	Sleep(1000);

	while (b.reset == false) {
		b.move();

	}
}

void ThreadCollisionWalls(ball b) {
	while (b.reset == false) {
		b.monitor_collision_walls();
		Sleep(10);
	}
}

void ThreadCollisionPaddles(ball b) {
	while (b.reset == false) {
		b.monitor_collision_paddles();
		Sleep(10);
	}
}

void ThreadPlayerInput(ball b) {
	while (b.reset == false) {
		b.monitor_player_input();
		Sleep(40);
	}

}

void ThreadAI(ball b) {
	while (b.reset == false) {
		b.AI();
		Sleep(10);
	}

}

void ThreadCollisionPaddles2(ball b) {
	while (b.reset == false) {
		b.monitor_collision_paddles2();
		Sleep(10);
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

int main() {

	ball _ball;

	_ball.start();
	_ball.handle4 = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)ThreadPlayerInput, &_ball, 0, 0);
	_ball.handle5 = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)ThreadAI, &_ball, 0, 0);
	_ball.handle2 = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)ThreadCollisionWalls, &_ball, 0, 0);
	_ball.handle3 = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)ThreadCollisionPaddles, &_ball, 0, 0);
	_ball.handle1 = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)ThreadMove, &_ball, 0, 0);
	_ball.handle6 = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)ThreadCollisionPaddles2, &_ball, 0, 0);

	if (!_ball.handle1) {
		std::cout << "error thread failed" << "\n";
		std::cin;
	}
	if (!_ball.handle2) {
		std::cout << "error thread failed" << "\n";
		std::cin;
	}
	if (!_ball.handle3) {
		std::cout << "error thread failed" << "\n";
		std::cin;
	}
	if (!_ball.handle4) {
		std::cout << "error thread failed" << "\n";
		std::cin;
	}
	if (!_ball.handle5) {
		std::cout << "error thread failed" << "\n";
		std::cin;
	}
	if (!_ball.handle6) {
		std::cout << "error thread failed" << "\n";
		std::cin;
	}


	COORD coord{ 0,0 };
	CONSOLE_CURSOR_INFO cursor;
	cursor.bVisible = FALSE;
	cursor.dwSize = 100;
	HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorInfo(console, &cursor);


	while (1) {

		_ball.print();
		Sleep(10);

		SetConsoleCursorPosition(console, coord);
	}
}
Last edited on
Hey,
Im sorry guys u didnt understand me.
lets say the ball hits direct in the paddle in 90º it should return to same direction it came from.
if the ball hits the paddle in 30º it should redirect the ball to 150º and so on.
how can i calculate the degree the ball hits the paddle.
For those who didnt understand me ill add a draw:
https://sketch.io/render/sk-ea8ed8f426f5c70386a64a7eb5f13906.jpeg
Thanks for the helpers.

edit:
example for a game with same ball activity:
https://www.coolmathgames.com/0-brick-breaker
Last edited on
https://youtu.be/RWyY3n9nTf8


dude... i've been trying to think of a way to describe it in the simplest terms. theres just a ton of stuff involved. I didn't put it all in the above program but the general groundwork is there.

basically different stuff needs to happen depending on which axis is collided. and like what kinda system your using.

like lets say for instance you have an angle x = -2, y = 3. the ball is traveling SE towards the max y collision object.. say it lives at maxY = 100. so imagine -2 is the point of origin and the ball passed through y=3. So the x is actually incrementing up and so is y. So movement per step would be ball_posX += 2/3; posY +=1. I was saving the angle in my program as anglex = to the inverse of the actual because it corresponds to the direction. hence the original angle x was actuall - 2 i save it as 2 bc thats the direction the ball is traveling and it doesn't matter when it comes to the fraction to figure out the difference in the resulting position. I didn't go this far into it but regardless it doesn't matter and it makes it easier. bc if the ball is traveling twards the right the x angle would be positive and you {pos_x+= whatevs} it acually simplifies the movement calculation bc if its negative and you need to decrement adding a negative subtracts anyways. So it makes it easier to keep track of. That and say were traveling towards max y collision object maxY=100. Once that collision happens the x direction stays positive. but becomes = to whatever postive angle_y was. angle_y then becomes inverted old value of x.

So the ball would still be traveling right but now up and the angle is opposite. So at the next movement calculation. Movement per step would be posX+=1 posY+=2/3 or posX +=(1)^step posY+=(angle_y/angle_x)^step. To determine which coord is getting incremented at what rate you can just check which unsigned u_angleX or u_angleY is bigger. it forms a recognizable pattern. whichever is smaller gets (angle_y/angle_x)^step. At least i believe. My brain is shot at this point. You should run that program i wrote its pretty cool. works really well. I worked hard on that thing.

I actually sat down with pen and paper and checked this stuff.

Now if the ball collides with a somethin on the y axis. in that case the whole thing changes. angle_y remains pos or neg depending on what it is at collision, but = value of x, angle x = inverted old angle y... its inverted because it changes the x direction.

this is how i would do it someone elses solution maybe more sophistication but i actually think this is probably the simplest method i can think of.
Last edited on
Topic archived. No new replies allowed.