-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBall.cpp
More file actions
executable file
·182 lines (141 loc) · 7.35 KB
/
Ball.cpp
File metadata and controls
executable file
·182 lines (141 loc) · 7.35 KB
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
//Hi David
//Headers to include
#include "Ball.h"
#include <iostream>
Ball::Ball(SDL_Renderer* renderer, UserInterface* uiInstanceSet)
{
rendererInstance = renderer;
speed = START_SPEED;
position.x = SCREEN_WIDTH / 2 - size / 2;
position.y = SCREEN_HEIGHT / 2 - size / 2;
velocity.x = -1;
velocity.y = -1;
ballRect.x = (int)position.x; ballRect.y = (int)position.y;
ballRect.w = ballRect.h = size;
ballTexture = SDL_CreateTextureFromSurface(rendererInstance, ballTempSurface);
if (!ballTexture) std::cerr << "couldn't load ball texture";
SDL_FreeSurface(ballTempSurface);
uiInstance = uiInstanceSet;
}
void Ball::Update(Paddle *leftPaddle, Paddle *rightPaddle, float frameSpeed)
{
//Y vel is subtracted because position is from top right, and positive moving up is more common and makes more sense
position.y -= (velocity.y * speed) * frameSpeed; position.x += (velocity.x * speed) * frameSpeed;
//std::cout << Game::frameSpeed << std::endl;
CheckForGoal();
if (position.y < 0)
{
velocity.y = -velocity.y; //Flips the balls y velocity if it's off screen
position.y = 0;
ballSounds = Mix_LoadWAV(WALL_BOUNCE_SOUND_DIRECTORY);
Mix_PlayChannel(-1, ballSounds, 0);
}
else if (position.y + size > SCREEN_HEIGHT)
{
velocity.y = -velocity.y;
position.y = SCREEN_HEIGHT - size;
ballSounds = Mix_LoadWAV(WALL_BOUNCE_SOUND_DIRECTORY);
Mix_PlayChannel(-1, ballSounds, 0);
}
HandleCollision(leftPaddle); HandleCollision(rightPaddle);
ballRect.x = (int)position.x; ballRect.y = (int)position.y;
}
void Ball::Reset()
{
speed = START_SPEED;
position.x = SCREEN_WIDTH / 2 - size / 2;
position.y = SCREEN_HEIGHT / 2 - size / 2;
velocity.x = ((rand() % 2) * 2) - 1; //Randomly choses the velocity of the ball to go to each 4 corners
velocity.y = ((rand() % 2) * 2) - 1;
ballRect.x = (int)position.x; ballRect.y = (int)position.y;
}
void Ball::HandleCollision(Paddle* paddleInstance)
{
//If the ball hits the left or right of the paddles
if (
position.x + size >= paddleInstance->GetRect()->x && //Left of paddle Right of ball
position.x <= paddleInstance->GetRect()->x + paddleInstance->GetRect()->w && //Right of paddle Left of ball
position.y + size >= paddleInstance->GetRect()->y && //Top of paddle Bottom of ball
position.y <= paddleInstance->GetRect()->y + paddleInstance->GetRect()->h //Bottom of paddle Top of ball
)
{
calculateVelocity(paddleInstance);
ballSounds = Mix_LoadWAV(PADDLE_BOUNCE_SOUND_DIRECTORY);
Mix_PlayChannel(-1, ballSounds, 0);
if (speed < MAX_SPEED)
{
speed += SPEED_INCREMENT;
}
}
}
void Ball::calculateVelocity(Paddle* paddleInstance)
{
//This checks which paddle paddleInstance is, and then checks if the ball is to left of the left paddle or to the right of the right paddle, and near the top and bottom.
//This is done because the top left of the ball can be outside of the range of the left or right paddle, but the ball could've still hit the top or bottom of those paddles
//The offset check prevents the ball detecting a top or bottom hit if it hits the top or bottom of the sides
if (((!paddleInstance->GetIsRightPaddle() && position.x < paddleInstance->GetRect()->x + paddleInstance->GetRect()->w - TOP_BOTTOM_OFFSET_CHECK) || (paddleInstance->GetIsRightPaddle() && position.x + size > paddleInstance->GetRect()->x + TOP_BOTTOM_OFFSET_CHECK)) &&
(position.y + size <= paddleInstance->GetRect()->y + TOP_BOTTOM_OFFSET_CHECK || position.y >= paddleInstance->GetRect()->y + paddleInstance->GetRect()->h - TOP_BOTTOM_OFFSET_CHECK))
{
if (position.y < paddleInstance->GetRect()->y + (paddleInstance->GetRect()->h / 2))
{
position.y = paddleInstance->GetRect()->y - size;
velocity.y = 1;
//Velocity is set based on where the ball hit instead of being reversed since if the paddle moves up towards the ball the ball hits it multiple times, and it could end up being reversed twice and go the wrong way
//This makes sure that regardless of how many times the ball hits the paddle, it always moves the right direction for where the ball hit the paddle
}
else
{
position.y = paddleInstance->GetRect()->y + paddleInstance->GetRect()->h;
velocity.y = -1;
}
}
else
{
if (paddleInstance->GetIsRightPaddle())
{
position.x = paddleInstance->GetRect()->x - size;
}
else
{
position.x = paddleInstance->GetRect()->x + paddleInstance->GetRect()->w;
}
}
velocity.x = paddleInstance->GetIsRightPaddle() ? -1 : 1;
//velocity.y = velocity.y < 0 ? -1 : 1;
applyEdgeVelocityMultiplier(paddleInstance);
}
void Ball::applyEdgeVelocityMultiplier(Paddle* paddleInstance)
{
float yPosDifference = position.y + (size / 2);
yPosDifference = InverseLerp(paddleInstance->GetRect()->y, paddleInstance->GetRect()->y + paddleInstance->GetRect()->h, yPosDifference);
yPosDifference = (yPosDifference * 2) - 1; //Done as the top needs to have a positive multiplier and the bottom needs a negative multiplier, with the middle of the paddle being 0. This changes it from 0 - 1 to -1 - 1
yPosDifference = -yPosDifference; //Done since the top is -1, but the top needs to add positive velocity, so the number is reversed
float maxPossibleRand = (MAX_RANDOMNESS - MIN_RANDOMNESS) * std::abs(yPosDifference); //Calculates the max possible random number that can be generated at the position on the paddle the ball hit
maxPossibleRand += MIN_RANDOMNESS;
float chosenRandomAddition = rand() % (int)(maxPossibleRand * 2000); //Generates a random number from -maxpossiblerand to maxpossiblerand
chosenRandomAddition /= 1000; //Multiplies by 2000 since the numbers are decimal and modulo can't be used on decimals, and the number needs to be multiplied by 2 to get positive and negative values
chosenRandomAddition -= maxPossibleRand;
float setVelocityY = velocity.y + ((yPosDifference * MAX_EDGE_VELOCITY) + chosenRandomAddition); //Calculates the velocity the paddle should add based on where the ball hit it and adds the random addition onto it, as well as the existing y velocity
//Clamps the velocity to the max that can be set from hitting the paddle once, so that the velocity doesn't keep adding every time the ball hits the same part of the paddle
setVelocityY = setVelocityY > MAX_EDGE_VELOCITY + maxPossibleRand + 1 ? MAX_EDGE_VELOCITY + maxPossibleRand + 1 : setVelocityY < -MAX_EDGE_VELOCITY - maxPossibleRand - 1 ? -MAX_EDGE_VELOCITY - maxPossibleRand - 1 : setVelocityY;
velocity.y = setVelocityY;
velocity.x = velocity.x > 0 ? 1.5 - (std::abs(setVelocityY) / 2) : -(1.5 - (std::abs(setVelocityY) / 2)); //Changes the x value so that the ball mostly keeps the same speed, so the ball doesn't seem slower when going directly left or right compared to up or down
//velocity.x = velocity.x > 0 ? (1 - std::abs(velocity.y)) : -(1 - std::abs(velocity.y));s
}
void Ball::CheckForGoal()
{
if (position.x + size < 0) //Left goal
{
uiInstance->GivePoint(true);
ballSounds = Mix_LoadWAV(SCORE_GOAL_SOUND_DIRECTORY);
Mix_PlayChannel(-1, ballSounds, 0);
Reset();
}
else if (position.x > SCREEN_WIDTH) //Right goal
{
uiInstance->GivePoint(false);
ballSounds = Mix_LoadWAV(SCORE_GOAL_SOUND_DIRECTORY);
Mix_PlayChannel(-1, ballSounds, 0);
Reset();
}
}