2017-02-19 3 views
-1

Vor kurzem habe ich begonnen, das Pong-Spiel zu machen, weil das Tutorial, dem ich folge, mir sagte, dass ich jetzt einfache Spiele machen kann.Pong Ball Kollisionsprobleme

Ich denke Pong ist nicht so einfach wie ich dachte.

Zunächst einmal ist hier der Code:

#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. 
} 

Und hier ist die Header-Datei, wenn Sie interessiert sind.

#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; 

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

Wenn Sie nicht vertraut mit dem Pong-Spiel sind here klicken. Im Grunde, in Pong, versuchen Sie den Pongball an den Spielern vorbei zu paddeln und müssen Ihre Seite des Feldes verteidigen. Du "verteidigst", indem du dein Paddel in die Richtung des Pongballs bewegst, der es in zufälliger Richtung zurück auf deinen Gegner schießt.

Das Problem, mit dem ich momentan konfrontiert bin, ist, dass ich nicht die Hitbox der Pongball Hitbox der Spieler schlagen kann. Dies liegt daran, dass sich der Pongball durch Hinzufügen der "Beschleuniger" zu den Koordinaten bewegt.

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

Das bedeutet, es kann über die Hitboxen der Paddles überspringen, nicht mit dem Paddel kollidieren. Dieser Ansatz war sowieso falsch, da die Pongball-Richtung durch die Beschleunigung in verschiedene Richtungen auch den Pongball schneller macht.

Ich sollte hinzufügen, dass die Funktion gfx.PutPixel() wurde mir durch das Tutorial gegeben, und es funktioniert wie folgt: gfx.PutPixel (XCoordinate, YCoordinate, Rotwert, Grünwert, Blau Wert); Die Draw-Funktionen verursachen meines Wissens nach keine Probleme, also solltest du sie wahrscheinlich überspringen.

Meine Frage an euch ist: Wie soll ich erkennen, dass der Pongball mit dem Paddel kollidieren würde?

Antwort

2

Collision detection in Spielen im Allgemeinen ist keine so triviale Aufgabe. Aber für einen einfachsten Fall in Pong, wo man Größen von Paddeln und Ball ignorieren kann, ist es ausreichend, Kugelflugbahn mit Paddel zu schneiden. Mit anderen Worten, Sie können zwei Liniensegmente nehmen: zuerst von der Position des Balls im vorherigen Rahmen zur aktuellen Ballposition und dann von einem Ende des Paddels zum anderen und den Ball abprallen, wenn sie sich schneiden.

+0

Das klingt extrem dumm von mir, aber wie würde ich berechnen, wenn die beiden Linien schneiden? Und hätte ich nicht das Problem, dass der Ball ein gutes Stück vom eigentlichen Paddel wegspringt? Sehr interessant aber! – Zedtho

+0

[Hier] (http://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/) ist ein Beispiel. Für das Ballprellen können Sie den Ball am Schnittpunkt platzieren (Clipping eliminieren) und den Geschwindigkeitsvektor reflektieren/skalieren. Wenigstens einige grundlegende Geometrie/Lineare Algebra ist jedoch für GameDev essentiell. [Es gibt einige gute Bücher] (https://www.amazon.com/exec/obidos/ASIN/1482250926) für nicht mathematisch versierte. – w1ck3dg0ph3r

+0

Vielen Dank! Ich war auch zu diesem Schluss gekommen, als ich deinen Beitrag gesehen habe, wusste aber nicht, wie ich das berechnen sollte. – Zedtho