-
Notifications
You must be signed in to change notification settings - Fork 0
/
Ball.cs
190 lines (164 loc) · 5.9 KB
/
Ball.cs
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
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
public class Ball
{
//Starting position of the ball.
double PositionX = 45;
double PositionY = 190;
//Size of the ball (diameter).
static int Size = 7;
//Speed in pixels/sec.
double Speed = 2;
//Angle of the ball.
double Theta = -Math.PI/4;
//The maximum angle a ball can riccochet off the paddle.
//Unimplemented.
double MaxReflect = Math.PI;
//The total points.
public static int Points = 0;
//Pause the ball after death.
bool Paused = true;
//Time in seconds to hold the ball in place after death.
double PauseTimer = 3;
//The game over condition.
public static bool Dead = false;
//Number of balls remaining.
public static int BallsLeft;
public static readonly int BallsLeftStart = 2;
//For those times when the ball is not doing much.
double DontBeMadTimer;
readonly double DontBeMadTimerDefault = 10;
//The balls' texture.
Texture2D BallTexture;
public Ball()
{
DontBeMadTimer = DontBeMadTimerDefault;
BallTexture = Utils.TextureLoader("ball.png");
}
public void Draw(AD2SpriteBatch sb)
{
sb.DrawTexture(BallTexture, (int)PositionX, (int)PositionY);
if (DontBeMadTimer < 0)
Utils.DefaultFont.Draw(sb, "ENJOY THE MUSIC", 40, 212, Color.White, 2, true);
}
public void Update(InGame world, int ms)
{
if (!Paused)
{
//Break movements into small steps for edge collision.
int steps = (int)Speed + 1;
DontBeMadTimer -= (double)ms / 1000;
for (int step = 0; step != steps; step++)
{
//Move the ball based on the angle.
PositionX += (Math.Cos(Theta) * Speed) / steps;
PositionY += (Math.Sin(Theta) * Speed) / steps;
//check for collision with the world.
if (WorldCollide(world))
return;
//check for collision with the paddle.
PaddleCollide(world);
//Check for collision with bricks.
BounceBallOffBricks(world);
}
}else //If the ball is being held after death,
{
//roll the Pause Timer.
PauseTimer -= (double)ms/1000;
//Has the Pause Timer expired?
if (PauseTimer <= 0)
//The ball is released.
Paused = false;
}
}
bool WorldCollide(InGame world)
{
//check for vertical world collision
if ((PositionX <= 0) || (PositionX + Size >= Breakout.StageWidth))
//Hit a side! Reflect the x direction of the ball.
FlipThetaX();
//check for horizontal world collision
if (PositionY <= 0)
//Hit the top! Reflect the y direction of the ball.
FlipThetaY();
else if (PositionY > Breakout.BaseHeight)
//if the ball is off the borrom, then it dies.
BallOut(world);
return PositionY > Breakout.BaseHeight;
}
void FlipThetaX()
{
//Reflect the X direction of the ball.
Theta = -(Theta + -(Math.PI / 2)) + (Math.PI / 2);
}
void FlipThetaY()
{
//Reflect the Y direction of the ball.
Theta = -(Theta);
}
void BounceBallOffBricks(InGame world)
{
foreach (Brick br in world.Bricks)
{
//See if the ball is touching any of the bricks.
if ((br.BrickLive) && InGame.Collide((int)PositionX, (int)PositionY, Size, Size, br.PositionX, br.PositionY, br.Width, br.Height))
{
//Now check if the collision is on the top or bottom,
if ((TopCollide(br)) || BottomCollide(br))
//If so, then reflect the Y direction of the ball.
FlipThetaY();
//Otherwise, it can be assumed it hit on one of the sides,
else
//and we can reflect the X direction.
FlipThetaX();
//Get points
switch (br.BrickType)
{
case ("normal"):
Points++;
break;
case ("blue"):
Points += 2;
break;
}
//Kill the brick.
br.BrickLive = false;
//Play the hit sound.
SoundManager.Play("hit.wav");
//Reset the fun stuff.
DontBeMadTimer = DontBeMadTimerDefault;
//It is assumed you can only hit one brick at a time.
//This SHOULD be looked into, but I probably won't.
return;
}
}
}
void PaddleCollide(InGame world)
{
if (InGame.Collide((int)PositionX, (int)PositionY + Size - 1, Size, 1, (int)world.Player.PositionX, world.Player.PositionY, world.Player.Width, 1) && Math.Sin(Theta) > 0)
{
Theta = (((PositionX + (Size / 2) + -world.Player.PositionX) / (world.Player.Width)) + -1) * MaxReflect;
DontBeMadTimer = DontBeMadTimerDefault;
}
}
bool TopCollide(Brick br)
{
return Math.Sin(Theta) > 0 && InGame.Collide((int)PositionX, (int)PositionY + Size +- 1, Size, 1, br.PositionX, br.PositionY, br.Width, 1);
}
bool BottomCollide(Brick br)
{
return Math.Sin(Theta) < 0 && InGame.Collide((int)PositionX, (int)PositionY, Size, 1, br.PositionX, br.PositionY + br.Height +- 1, br.Width, 1);
}
void BallOut(InGame world)
{
if (BallsLeft > 0)
//Number of balls avaliable is lessened
BallsLeft--;
else
Dead = true;
//Game Over!
//Remove a ball from the list
world.OutOfBounds.AddLast(this);
}
}