- Player vs Player – ја започнува играта во режим на 2 играчи
- Player vs Computer – ја започнува играта против компјутер, во еден од избраните режими “Easy”, “Medium”, “Hard”
- Options – го отвора менито за опции
- Exit – ја затвора апликацијата
Слика 1. Почетно мени
Со одбирање на „Player vs Player“ се отвора прозорецот за играње. Пред да започне играта на екранот се претставени контролите. Играчот 1 ја контролира левата лопатка. Со кликање на копчето W, лопатката се поместува нагоре, а со кликање на S надолу. Играчот 2 ја контролира левата лопатка со стрелките за нагоре и надолу, соодветно. Играта се започнува со кликање на Space копчето, и со истото копче може да се паузира во било кој момент. Со кликање на Esc се затвора прозорецот. Со кликање и влечење на било кој дел од прозорецот, тој може да се поместува по десктопот.Слика 2. Поле за играње - Контроли
Слика 3. Поле за играње
Играчот треба да освои 11 поени за да победи, а по победата се појавува MessageBox кој му честита на победникот, и од каде може да се започне реванш.
Слика 4. Прозорец кој се појавува по победа
Со одбирање „Player vs Computer“ се отвора мало мени каде се понудени 3 нивоа на тежини: „Easy“, „Medium“, и „Hard“. Менито може да се види на сликата бр 5.Слика 5. Мени за избор на тежина
По одбирање на тежината ни се отвора истиот прозорец како кога избравме „Player vs Player“, но сега играчот може да ја контролира само левата лопатка, и се прикажани контролите само за левата лопатка.
Слика 6. Поле за играње против компјутер
Доколку избереме „Options“ ни се појавува мени, каде може да селектираме дали сакаме Powerups во играта. Менито може да се види на слика 7.Слика 7. Опции
Доколку се вклучат, се појавуваат по одреден период некаде на полето на играње и можат да бидат добри или штетни за играчот кој ги погодил. Постојат 4 различни Powerups:-
EnlargePaddle – ја зголемува должината на лопатката на играчот кој го погодил овој Powerup. -
ShrinkPaddle – ја намалува должината на лопатката на играчот кој го погодил.
-
EnlargeOpposition – ја зголемува должината на лопатката на противникот.
-
ShrinkOpposition – ја намалува должината на лопатката на противникот.
Движењето на топчето на претставено со 2 вектори SpeedX и SpeedY. При креирање на топчето и двата вектори имаат вредност 5. Доколку е првата рунда векторот SpeedX се множи со случајна вредност (1 или -1) за да добие случајна насока лево или десно.
При креирање на нова рунда, новокреираното топче добива како аргумент дали треба да оди лево или десно, и согласно тоа SpeedX се множи со соодветната вредност (-1 за лево, 1 за десно).
При судир со горниот и долниот ѕид, SpeedY се множи со -1, што ја променува неговата вертикална насока.
Кодот со кој е опишано движењето може да се види подолу.
За одбивање од лопатките се користи посложен алгоритам.
За поинтересно играње, топчето се одбива различно зависно од делот на лопатката од кој се одбива. За разлика од оригиналната игра во која топчето може да има само 8 насоки, во оваа верзија нема такво ограничување. Пресметување на агол на одбивање Како што е претходно споменато движењето на топчето е опишано со двете променливи SpeedX и SpeedY. Со помош на функцијата CheckCollisionWithPlayer дознаваме дали некој играч се има судрено со топчето. Функцијата враќа 1 за левата лопатка, 2 за десната, а 0 доколку нема судир. Функцијата го пресметува тоа соодветно координатите на секој играч, и координатите на топчето функцијата може да се види подолу.
public int CheckCollisionWithPlayer(Player Player_1, Player Player_2)
{
if((this.CenterCoordinates.X-Radius < Player_1.Coordinates.X + Player.Width)
&& ((this.CenterCoordinates.Y + Radius > Player_1.Coordinates.Y)
&& (this.CenterCoordinates.Y - Radius < Player_1.Coordinates.Y + Player_1.Height)))
{
return 1;
}
if ((this.CenterCoordinates.X+Radius > Player_2.Coordinates.X)
&& ((this.CenterCoordinates.Y + Radius > Player_2.Coordinates.Y)
&& (this.CenterCoordinates.Y - Radius < Player_2.Coordinates.Y + Player_1.Height)))
{
return 2;
}
return 0;
}
Откако ќе добиеме дали некој играч е во судир со топчето ја собираме вкупната брзина т.е. апсолутните вредностите на SpeedX и SpeedY во нова променлива TotalSpeed. Оваа променлива ја инкрементираме, што дава ефект на забрзување на топчето со секој удар. Потоа ја пресметуваме релативната положба на топчето во однос на центарот на лопатката со која се има судрено. Со променливата relativeY ја добиваме вредноста на X координатата во однос на лопатката а со функцијата Math.Abs(relativeY - (PlayerHeight/2)) ја добиваме оддалеченоста од центарот. Оддалеченоста од центарот ја делиме со половина од должината на лопатката, што ни ја дава процентуалната оддалеченост од центарот, која тежи кон нула кога е поблиску кон центарот. Оваа вредност ја користиме како тежински фактор за SpeedY. За да не добиеме целосно хоризонтално движење на топчето, што ќе ја заглави играта во место оваа вредност ја множиме со 0.7. Вредноста на SpeedY ја добиваме множејќи ја вкупната брзина со новодобиената тежина. Вредноста на SpeedX ја добиваме одземајќи ја SpeedY од вкупната брзина. На крајот ја корегираме насоката доколку играчот 2 го има удрено топчето го SpeedX го множиме со -1, и доколку топчето е удрено со горната половина на лопатката SpeedY се множи по -1. Целиот код може да се види подолу.
public void Move(Player Player_1, Player Player_2, int Form_Width, int Form_Height)
{
CenterCoordinates = new Point(CenterCoordinates.X + SpeedX, CenterCoordinates.Y + SpeedY);
CheckCollision(Player_1, Player_2, Form_Width, Form_Height);
}
public void CheckCollision(Player Player_1, Player Player_2, int Form_Width, int Form_Height)
{
//collision with top wall
if (this.CenterCoordinates.Y <= 0 && SpeedY < 0)
{
SpeedY *= -1;
}
//collision with bottom wall
if (this.CenterCoordinates.Y > Form_Height - Radius && SpeedY > 0)
{
SpeedY *= -1;
}
//collision with player paddles
int PlayerCollided = CheckCollisionWithPlayer(Player_1, Player_2);
if (PlayerCollided > 0)
{
//change speedY depending on area of paddle hit
int TotalSpeed = Math.Abs(SpeedX) + Math.Abs(SpeedY);
TotalSpeed++;
//get what player was in contact with the ball
int PlayerY = Player_1.Coordinates.Y;
if(PlayerCollided == 2) PlayerY = Player_2.Coordinates.Y;
//get position of ball relative to the hit player
int relativeY = this.CenterCoordinates.Y - PlayerY;
//calculate the speed vectors
double Yweight = Math.Abs(relativeY - 60) / 60.0;
SpeedY = (int) (TotalSpeed * Yweight * 0.7);
SpeedX = TotalSpeed - SpeedY;
//correct direction
if(PlayerCollided == 2 ) SpeedX *= -1;
if (relativeY < 60) SpeedY *= -1;
}
}
public void AIMovement(Ball MovingBall, int FormWidth, int FormHeight)
{
if(Name != "Player1" && Name !="Player2")
{
int XThreshold = 0;
if(Name == "Easy") XThreshold = FormWidth - (FormWidth / 3);
if(MovingBall.SpeedX > 0 && MovingBall.CenterCoordinates.X > XThreshold)
{
Point PointToHit = new Point(Coordinates.X, Coordinates.Y + Height / 2);
int Y = MovingBall.CenterCoordinates.Y;
if (PointToHit.Y > Y && Math.Abs(PointToHit.Y - Y) > 10)
{
MoveUp();
}
else if (PointToHit.Y < Y && Math.Abs(PointToHit.Y - Y) > 10)
{
MoveDown();
}
}
if(Name == "Hard" && MovingBall.SpeedX < 0)
{
Point PointToHit = new Point(Coordinates.X, Coordinates.Y + Height / 2);
int Y = FormHeight/2;
if (PointToHit.Y > Y)
{
MoveUp();
}
else if (PointToHit.Y < Y)
{
MoveDown();
}
}
}
}








![Одбивање на топче]](https://github.com/Polclard/Pong-Project/raw/master/README-resources/Rebound-Direction.png)