2017-02-19 133 views
-1

最近,我開始製作Pong遊戲,因爲我跟隨的教程告訴我現在我可以製作簡單的遊戲。乒乓球碰撞問題

我想Pong並不像我想的那麼簡單。

首先,這裏的代碼:

#include "MainWindow.h" 
#include "Game.h" 
#include <ctime> 
#include <iostream> 
#include <cstdlib> 
using namespace std; 




Game::Game(MainWindow& wnd) 
    : 
    wnd(wnd), 
    gfx(wnd) 
{ 
} 

void Game::Go() 
{ 
    gfx.BeginFrame(); 
    UpdateModel(); 
    ComposeFrame(); 
    gfx.EndFrame(); 
} 

void Game::UpdateModel() 
{ 
    ///Moves player paddles 
    MovePaddle(); 
    ///Checks if player paddles are inside the given parameters. 
    LeftPlayerY = WallInsideBorder(LeftPlayerY); 
    RightPlayerY = WallInsideBorder(RightPlayerY); 
    PongBallPhysics(); 
    IsGoal(); 

} 

void Game::ComposeFrame() 
{ 

    DrawBall(BallX, BallY, BallRed, BallGreen, BallBlue); 
    DrawWall(LeftPlayerX, LeftPlayerY); 
    DrawWall(RightPlayerX, RightPlayerY); 
    DrawThePixelatedWall(); 
    DrawScoreboard(); 

} 

///Draws the Pongball 
void Game::DrawBall(int BallX, int BallY, int BallRed, int BallGreen, int BallBlue) 
{ 
    ///Middle layer of pixels 
    gfx.PutPixel(BallX, BallY, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX + 1, BallY, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX + 2, BallY, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX + 3, BallY, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX - 1, BallY, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX - 2, BallY, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX - 3, BallY, BallRed, BallGreen, BallBlue); 
    ///Layer of Pixels above middle layer 
    gfx.PutPixel(BallX - 3, BallY - 1, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX - 2, BallY - 1, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX - 1, BallY - 1, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX, BallY - 1, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX + 1, BallY - 1, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX + 2, BallY - 1, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX + 3, BallY - 1, BallRed, BallGreen, BallBlue); 
    ///Layer of Pixels beneath top layer 
    gfx.PutPixel(BallX - 2, BallY - 2, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX - 1, BallY - 2, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX, BallY - 2, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX + 1, BallY - 2, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX + 2, BallY - 2, BallRed, BallGreen, BallBlue); 
    ///Top Layer 
    gfx.PutPixel(BallX - 1, BallY - 3, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX, BallY - 3, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX + 1, BallY - 3, BallRed, BallGreen, BallBlue); 
    ///Layer beneath middle layer 
    gfx.PutPixel(BallX - 3, BallY + 1, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX - 2, BallY + 1, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX - 1, BallY + 1, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX, BallY + 1, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX + 1, BallY + 1, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX + 2, BallY + 1, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX + 3, BallY + 1, BallRed, BallGreen, BallBlue); 
    ///Layer above bottom layer 
    gfx.PutPixel(BallX - 2, BallY + 2, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX - 1, BallY + 2, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX, BallY + 2, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX + 1, BallY + 2, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX + 2, BallY + 2, BallRed, BallGreen, BallBlue); 
    ///Bottom layer 
    gfx.PutPixel(BallX - 1, BallY + 3, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX, BallY + 3, BallRed, BallGreen, BallBlue); 
    gfx.PutPixel(BallX + 1, BallY + 3, BallRed, BallGreen, BallBlue); 



} 
///Draws the walls for the players (100 pixels tall) 
void Game::DrawWall(int XCoordinate, int YCoordinate) 
{ 
    if (XCoordinate == LeftPlayerX) 
    { 
     for (int i = -50; i <= 50; ++i) 
     { 
      gfx.PutPixel(XCoordinate, YCoordinate + i, 255, 255, 255); 
      gfx.PutPixel(XCoordinate - 1, YCoordinate + i, 255, 255, 255); 
      gfx.PutPixel(XCoordinate - 2, YCoordinate + i, 255, 255, 255); 
      gfx.PutPixel(XCoordinate - 3, YCoordinate + i, 255, 255, 255); 
     } 
    } 

    if (XCoordinate == RightPlayerX) 
    { 
     for (int i = -50; i <= 50; ++i) 
     { 
      gfx.PutPixel(XCoordinate, YCoordinate + i, 255, 255, 255); 
      gfx.PutPixel(XCoordinate + 1, YCoordinate + i, 255, 255, 255); 
      gfx.PutPixel(XCoordinate + 2, YCoordinate + i, 255, 255, 255); 
      gfx.PutPixel(XCoordinate + 3, YCoordinate + i, 255, 255, 255); 
     } 
    } 
} 
///Draws the boundary between the player fields 
void Game::DrawThePixelatedWall() 
{ 
    for (int i = 0; i <= 597; i = i + 3) 
    { 
     gfx.PutPixel(399, i, 255, 255, 255); 
    } 
} 
///Draws the scoreboard. 
void Game::DrawScoreboard() 
{ 
    switch (LeftPlayerScore) { 
    case 0: 
     for (int i = 6; i <= 50; ++i) 
     { 
      gfx.PutPixel(320 + 6, i, 255, 255, 255); 
      gfx.PutPixel(320 + 5, i, 255, 255, 255); 
      gfx.PutPixel(320 - 5, i, 255, 255, 255); 
      gfx.PutPixel(320 - 6, i, 255, 255, 255); 
      gfx.PutPixel(320 + 7, i, 255, 255, 255); 
      gfx.PutPixel(320 - 7, i, 255, 255, 255); 
     } 
     for (int i = -4; i <= 6; ++i) 
     { 
      gfx.PutPixel(320 + i, 6, 255, 255, 255); 
      gfx.PutPixel(320 + i, 7, 255, 255, 255); 
      gfx.PutPixel(320 + i, 8, 255, 255, 255); 
      gfx.PutPixel(320 + i, 50, 255, 255, 255); 
      gfx.PutPixel(320 + i, 49, 255, 255, 255); 
      gfx.PutPixel(320 + i, 48, 255, 255, 255); 
     } 


     break; 

    case 1: 
     for (int i = 6; i <= 50; ++i) 
     { 
      gfx.PutPixel(320, i, 255, 255, 255); 
      gfx.PutPixel(320 + 1, i, 255, 255, 255); 
      gfx.PutPixel(320 - 1, i, 255, 255, 255); 
     } 
     break; 

    case 2: 
     break; 

    case 3: 
     break; 

    case 4: 
     break; 

    case 5: 
     break; 

    case 6: 
     break; 

    case 7: 
     break; 

    case 8: 
     for (int i = 6; i <= 50; ++i) 
     { 
      gfx.PutPixel(320 + 6, i, 255, 255, 255); 
      gfx.PutPixel(320 + 5, i, 255, 255, 255); 
      gfx.PutPixel(320 - 5, i, 255, 255, 255); 
      gfx.PutPixel(320 - 6, i, 255, 255, 255); 
      gfx.PutPixel(320 + 7, i, 255, 255, 255); 
      gfx.PutPixel(320 - 7, i, 255, 255, 255); 
     } 
     for (int i = -4; i <= 6; ++i) 
     { 
      gfx.PutPixel(320 + i, 6, 255, 255, 255); 
      gfx.PutPixel(320 + i, 7, 255, 255, 255); 
      gfx.PutPixel(320 + i, 8, 255, 255, 255); 
      gfx.PutPixel(320 + i, 50, 255, 255, 255); 
      gfx.PutPixel(320 + i, 49, 255, 255, 255); 
      gfx.PutPixel(320 + i, 48, 255, 255, 255); 
      gfx.PutPixel(320 + i, 27, 255, 255, 255); 
      gfx.PutPixel(320 + i, 28, 255, 255, 255); 
     } 

     break; 

    case 9: 
     break; 

    case 10: 
     break; 

    } 
    switch (RightPlayerScore) { 
    case 0: 
     for (int i = 6; i <= 50; ++i) 
     { 
      gfx.PutPixel(478 + 6, i, 255, 255, 255); 
      gfx.PutPixel(478 + 5, i, 255, 255, 255); 
      gfx.PutPixel(478 - 5, i, 255, 255, 255); 
      gfx.PutPixel(478 - 6, i, 255, 255, 255); 
      gfx.PutPixel(478 + 7, i, 255, 255, 255); 
      gfx.PutPixel(478 - 7, i, 255, 255, 255); 
     } 
     for (int i = -4; i <= 6; ++i) 
     { 
      gfx.PutPixel(478 + i, 6, 255, 255, 255); 
      gfx.PutPixel(478 + i, 7, 255, 255, 255); 
      gfx.PutPixel(478 + i, 8, 255, 255, 255); 
      gfx.PutPixel(478 + i, 50, 255, 255, 255); 
      gfx.PutPixel(478 + i, 49, 255, 255, 255); 
      gfx.PutPixel(478 + i, 48, 255, 255, 255); 
     } 
     break; 

    case 1: 
     for (int i = 6; i <= 50; ++i) 
     { 
      gfx.PutPixel(478, i, 255, 255, 255); 
      gfx.PutPixel(478 + 1, i, 255, 255, 255); 
      gfx.PutPixel(478 - 1, i, 255, 255, 255); 
     } 
     break; 

    case 2: 
     break; 

    case 3: 
     break; 

    case 4: 
     break; 

    case 5: 
     break; 

    case 6: 
     break; 

    case 7: 
     break; 

    case 8: 
     break; 

    case 9: 
     break; 

    case 10: 
     break; 

    } 
} 
///Checks if Walls are inside 
int Game::WallInsideBorder(int YCoordinate) 
{ 
    if (YCoordinate + 50 >= gfx.ScreenHeight) 
    { 
     return gfx.ScreenHeight - 51; 
    } 
    if (YCoordinate - 50 < 0) 
    { 
     return 51; 
    } 
    return YCoordinate; 
} 
///Pong Ball physics :D 
void Game::PongBallPhysics() 
{ 
    BallX = BallX + BallVX; 
    BallY = BallY + BallVY; 
    ///Sets initial VX and VY 
    if (FirstTime) 
    { 
     srand(time(NULL)); 
     BallY = rand() % 599; 
     BallVX = rand() % 4 + 1; 
     srand(time(NULL)); 
     BallVY = rand() % 4 + 1; 
     FirstTime = false; 
    } 
    /// Touching top or bottom? 
    if (BallY - 3 < 0) 
    { 
     DoBounceCalculation(); 
     BallY = 3; 
    } 
    if (BallY + 3 > 599) 
    { 
     DoBounceCalculation(); 
     BallY = 595; 
    } 
    ///Touching a wall? 
    /// ERROR, BallVX goes PAST LeftPlayerX/RightPlayerX! 
    IsTouchingWall(); 

} 
///Makes the angle be the same as when it hit the wall/boundary.Looked at and is working 
void Game::DoBounceCalculation() 
{ 
    BallVY = -BallVY; 
} 
///Swaps two variables, looked at and should be working 
void Game::Swap(int &x, int &y) 
{ 
    int SwapVariable = x; 
    x = y; 
    y = SwapVariable; 
} 
///Checks if ball is in opponent's goal, looked at and is working 
void Game::IsGoal() 
{ 
    if (BallX - 3 <= 0) 
    { 
     RightPlayerScore++; 
     BallX = 399; 
     FirstTime = true; 
    } 
    if (BallX + 3 >= gfx.ScreenWidth) 
    { 
     LeftPlayerScore++; 
     BallX = 399; 
     FirstTime = true; 
    } 
} 
///Moves player walls, looked at and is working 
void Game::MovePaddle() 
{ 
    if (wnd.kbd.KeyIsPressed(0x57)) 
    { 
     LeftPlayerY = LeftPlayerY - 3; 
    } 
    if (wnd.kbd.KeyIsPressed(0x53)) 
    { 
     LeftPlayerY = LeftPlayerY + 3; 
    } 
    if (wnd.kbd.KeyIsPressed(0x49)) 
    { 
     RightPlayerY = RightPlayerY - 3; 
    } 
    if (wnd.kbd.KeyIsPressed(0x4B)) 
    { 
     RightPlayerY = RightPlayerY + 3; 
    } 
} 
///Checks if Ball is touching Player paddles and changes velocity accordingly, this is bwoke man, check it 
void Game::IsTouchingWall() 
{ 
    // if-statement that checks if the ball is gonna hit the paddle in the next frame. 
    // The problem is, that VX or VY skip the pixels between (when they're set to anything higher than 1) 
    // So that they jump other the paddle. 
} 

而這裏的頭文件,如果你有興趣。

#pragma once 

#include "Keyboard.h" 
#include "Mouse.h" 
#include "Graphics.h" 

class Game 
{ 
public: 
    Game(class MainWindow& wnd); 
    Game(const Game&) = delete; 
    Game& operator=(const Game&) = delete; 
    void Go(); 
private: 
    void ComposeFrame(); 
    void UpdateModel(); 
    /********************************/ 
    /* User Functions    */ 
    void DrawBall(int BallX, int BallY, int BallRed, int BallGreen, int BallBlue); 
    void DrawWall(int XCoordinate, int YCoordinate); 
    void DrawThePixelatedWall(); 
    void DrawScoreboard(); 
    int WallInsideBorder(int YCoordinate); 
    void PongBallPhysics(); 
    void DoBounceCalculation(); 
    void Swap(int& x, int& y); 
    void IsGoal(); 
    void MovePaddle(); 
    void IsTouchingWall(); 

    /********************************/ 
private: 
    MainWindow& wnd; 
    Graphics gfx; 
    /********************************/ 
    /* User Variables    */ 
    int BallVX = 0; 
    int BallVY = 0; 
    int BallX = 399; 
    int BallY = 0; 
    int BallRed = 255; 
    int BallGreen = 255; 
    int BallBlue = 255; 
    const int LeftPlayerX = 100; 
    int LeftPlayerY = 299; 
    const int RightPlayerX = 700; 
    int RightPlayerY = 299; 
    int LeftPlayerScore = 0; 
    int RightPlayerScore = 0; 
    bool FirstTime = true; 

    /********************************/ 
}; 

如果您不熟悉乒乓遊戲,請點擊here。 基本上,在Pong,你嘗試讓球員通過球員槳,並需要保衛你的領域。你通過在Pongball中移動你的槳來「防守」,Pongball會隨機向你的對手發射。

我現在面臨的問題是我無法讓Pongball的hitbox撞擊到玩家的hitboxes。這是因爲Pongball通過將「加速器」添加到座標而移動。

BallX = BallX + BallVX; BallY = BallY + BallVY;

這意味着它可以跳過槳的撞擊盒,不會碰撞槳。無論如何,這種做法是錯誤的,因爲通過加速進入不同方向來改變乒乓球的方向也會使乒乓球變得更快。我應該補充說gfx.PutPixel()函數是由教程給我的,它的工作原理是這樣的:gfx.PutPixel(XCoordinate,YCoordinate,Red Value,Green Value,Blue Value); ,就我所知,Draw函數並沒有引起任何問題,所以你應該跳過它們。

我對你們的問題是: 我應該如何檢測到Pongball將與槳碰撞?

回答

2

Collision detection在一般的遊戲中並不是這麼平凡的任務。但是對於乒乓球中最簡單的情況,您可以忽略槳和球的大小,用球拍將球軌跡交叉就足夠了。換句話說,你可以採取兩條線段:首先從前一幀的球位置到當前的球位置,然後從球拍的一端到另一端,如果它們相交,則彈起球。

+0

這聽起來很愚蠢,但如果兩條線相交會如何計算?並且我不會得到球會從實際槳葉上彈開一點點的問題嗎?雖然很有趣! – Zedtho

+0

[這裏](http://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/)就是一個例子。對於彈跳,您可以將球放在交叉點(消除裁剪)並反射/縮放速度矢量。儘管至少有一些基本的幾何/線性代數對於gamedev是必不可少的。 [有一些好書](https://www.amazon.com/exec/obidos/ASIN/1482250926)不懂數學。 – w1ck3dg0ph3r

+0

非常感謝!當我看到你的帖子時,我也得出了這個結論,但不知道如何計算。 – Zedtho