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?
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
[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
Vielen Dank! Ich war auch zu diesem Schluss gekommen, als ich deinen Beitrag gesehen habe, wusste aber nicht, wie ich das berechnen sollte. – Zedtho