2017-02-19 126 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