J'ai fait un jeu pour une présentation en anglais (je sais bien?) Et j'ai eu quelques problèmes étranges récemment.Comportement incohérent entre 2 joueurs du jeu
A ce stade, il y a deux cases pour les joueurs qui peuvent tirer des balles. Lorsque les balles touchent le bord de l'écran ou la bordure centrale, elles doivent disparaître et éventuellement être réutilisées plus tard. Le problème est, tout d'abord, quand l'un ou l'autre joueur tire vers le haut ou vers le bas, les balles disparaissent dans le haut/bas/milieu de l'écran comme ils sont supposés le faire. Si le joueur 2 tire quelques balles sur le côté, dès que l'un d'entre eux touche, ils semblent tous disparaître (seulement les balles du joueur 2) et je dois attendre quelques secondes avant de recommencer à tirer. Le problème principal cependant, c'est que même lorsque j'utilise exactement le même code modifié pour le joueur 1 au lieu du joueur 2, quand le premier coup du joueur 1 pour frapper le côté de l'écran arrive, il sépare le programme.
La chose vraiment étrange est que, à un moment donné, cela est arrivé, et sans rien changer, je l'ai couru à nouveau et tout a parfaitement fonctionné. Cela peut avoir à voir avec l'ordre des balles entre les joueurs 1 et 2, ou même où je tire en premier. J'ai essayé de le recréer, mais aucun résultat pour l'instant. Juste une note avant d'essayer de compiler le code, j'ai utilisé un emballage que j'ai fait pour rendre la fenêtre avec facilité. J'ai noté ce qui se passe dans les coulisses avec /// commentaires cependant, donc l'ajout de cette information dans la méthode que vous utilisez pour faire vos fenêtres fonctionnera aussi bien.
Problématiques sont répertoriés près du fond:
///Works best on 1280x1024 resolution
///1 vs 1 splitscreen game that involves flying around and shooting things
///angles start at 0 facing upwards and increase clockwise
#include <window.h> //incomplete wrapper, but works perfectly for quick, easy window creation
#define _USE_MATH_DEFINES //for M_PI
#include <cmath> //for M_PI
#include <iostream> //used for debugging
using std::cout; //output
struct Actions //actions a player can take
{
bool up; //if player is moving in these 4 directions, they will be true
bool left;
bool down;
bool right;
bool shoot; //if player is shooting, this will be true
};
struct Player //a player
{
Player() {};
void fire(); //fire a bullet
void checkActions (HWND); //check what actions player is taking
double x; //position (centre of square)
double y;
double angle; //angle (might add diagonals so...)
int pnum; //player number (0 or 1)
COLORREF colour; //player's colour
Actions action; //player's actions
};
struct Bullet //a bullet
{
double x; //position (centre of square)
double y;
Player owner; //owner of bullet
int index; //bullet's index in array
double angle; //bullet's angle
};
Player *p = new Player[2]; //2 players
Bullet **bullet; //2d array of bullets
int bcount[2] = {0}; //number of bullets for each player
int btime [2] = {0}; //timer for bullets
const double PLSIZE = 10; //player size = 20x20 square (10 from centre outwards)
const double BSIZE = 2; //bullet size = 4x4 square
const double SPEED = 1; //player's moving speed is 1
const int BDELAY = 100; //delay between bullets is 100ms
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); //window procedure
void OnPaint (HDC, HWND); //painting function
void moveBullets (HWND); //calculates bullet positions
void deleteBullet (int, int); //"deletes" a bullet
int main() //main function
{
//hide(console()); //hides console window (currently showing for debugging)
bullet = new Bullet*[2]; //create bullet array of 1000/player (I'll size down the 1000 later)
bullet[0] = new Bullet[1000];
bullet[1] = new Bullet[1000];
p[0].x = 630; //player 1's position
p[0].y = 250;
p[0].colour = RGB(255,0,0); //player 1 is red
p[0].pnum = 0; //player 1's number is 0
p[0].angle = 0; //face upwards
p[0].action = {0}; //player 1 is doing nothing
p[1].x = 630; //player 2's position
p[1].y = 750;
p[1].colour = RGB(0,0,255); //player 2 is blue
p[1].pnum = 1; //player 2's number is 1
p[1].angle = 0; //face upwards
p[1].action = {0}; //player 2 is doing nothing
Window window; //create window object (part of wrapper, sets default values for class and window)
///background = (HBRUSH)COLOR_WINDOW
///class name = "Default Wrapper Class"
///hInstance = GetModuleHandle (NULL)
///all others are standard default or 0
window.createClass(WndProc); //create class using earlier-mentioned window procedure
window.setStyle(WS_OVERLAPPEDWINDOW | WS_MAXIMIZE); //set window style to overlapped and maximized
window.setTitle (L"Word Blaster"); //set window title to "Word Blaster" (it's an English project, shush)
///x/y/width/height = CW_USEDEFAULT
///class name = other class name
///hInstance = GetModuleHandle (NULL)
///all others are standard default or 0
HWND hwnd = window.createWindow(); //create window
MSG msg; //message loop
while(GetMessage(&msg,0,0,0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) //window proc
{
HDC hdc; //hdc for painting
PAINTSTRUCT ps; //paintstruct for painting
bool ret = false; //return value (you'll see later)
switch(msg)
{
case WM_CREATE: //currently not in use
break;
case WM_KEYDOWN: //check for pressed keys
switch (wParam) //keycode
{
case 0x57: //'w'
p[0].action.up = true; //player 1 wants to move up (couldn't just change position here or no diagonal movement)
break;
case 0x41: //'a', left
p[0].action.left = true;
break;
case 0x53: //'s', down
p[0].action.down = true;
break;
case 0x44: //'d', right
p[0].action.right = true;
break;
case 0x20: // space, shoot
p[0].action.shoot = true;
break;
case VK_UP: //up arrow, player 2 up
p[1].action.up = true;
break;
case VK_LEFT: //left arrow
p[1].action.left = true;
break;
case VK_DOWN: //down arrow
p[1].action.down = true;
break;
case VK_RIGHT: //right arrow
p[1].action.right = true;
break;
case VK_RETURN: //either enter key, p2 shoot
p[1].action.shoot = true;
break;
}
break;
case WM_KEYUP: //check for unpressed keys
switch (wParam)
{
case 0x57: //'w', player 1 should stop moving up
p[0].action.up = false;
break;
case 0x41: //all same order as above
p[0].action.left = false;
break;
case 0x53:
p[0].action.down = false;
break;
case 0x44:
p[0].action.right = false;
break;
case 0x20: // space
p[0].action.shoot = false;
break;
case VK_UP:
p[1].action.up = false;
break;
case VK_LEFT:
p[1].action.left = false;
break;
case VK_DOWN:
p[1].action.down = false;
break;
case VK_RIGHT:
p[1].action.right = false;
break;
case VK_RETURN:
p[1].action.shoot = false;
break;
}
break;
case WM_PAINT: //draw on screen
hdc = BeginPaint (hwnd, &ps); //prepare window for drawing
OnPaint (hdc,hwnd); //draw
EndPaint (hwnd, &ps); //finish drawing
break;
case WM_CLOSE: //if ready to close
show(console()); //show console window in case it doesn't close
end(); //close console window (PostMessage (GetConsoleWindow(),WM_CLOSE,0,0))
DestroyWindow(hwnd); //close main window
break;
case WM_DESTROY: //window is closing
PostQuitMessage(0); //post WM_QUIT to end (probably won't get here since console closes earlier)
break;
case WM_ERASEBKGND: //if background is going to be erased, don't let it (causes flicker)
ret = true; //hold that thought for a bit
break;
}
p[0].checkActions(hwnd); //check player 1's actions
p[1].checkActions(hwnd); //check player 2's actions
moveBullets (hwnd); //move any bullets
InvalidateRect (hwnd,NULL,true); //update window
Sleep (1); //delay a bit
if (!ret) return DefWindowProc(hwnd, msg, wParam, lParam); //if WM_ERASEBKGND wasn't called, take default action
}
void Player::fire() //fire a bullet
{
bullet [pnum][bcount[pnum]].x = x; //bullet starts in player's centre
bullet [pnum][bcount[pnum]].y = y;
bullet [pnum][bcount[pnum]].owner = *this; //owner of bullet is the object calling this function
bullet [pnum][bcount[pnum]].index = bcount[pnum]; //index of bullet is the number of bullets for player
bullet [pnum][bcount[pnum]].angle = angle; //angle of bullet is player's angle
while (
(bullet[pnum][bcount[pnum]].x - BSIZE < x + PLSIZE && bullet[pnum][bcount[pnum]].x - BSIZE > x - PLSIZE //left side of bullet inside player OR
|| bullet[pnum][bcount[pnum]].x + BSIZE < x + PLSIZE && bullet[pnum][bcount[pnum]].x + BSIZE > x - PLSIZE) //right side in player --- AND ---
&& (bullet[pnum][bcount[pnum]].y - BSIZE < y + PLSIZE && bullet[pnum][bcount[pnum]].y - BSIZE > y - PLSIZE //top in player OR
|| bullet[pnum][bcount[pnum]].y + BSIZE < y + PLSIZE && bullet[pnum][bcount[pnum]].y + BSIZE > y - PLSIZE) //bottom in player
)
{
bullet[pnum][bcount[pnum]].x += sin (bullet[pnum][bcount[pnum]].angle * M_PI/180); //start moving bullet until it's out
bullet[pnum][bcount[pnum]].y -= cos (bullet[pnum][bcount[pnum]].angle * M_PI/180);
}
btime [pnum] = GetTickCount(); //set up bullet delay for that player
++bcount[pnum]; //increase number of bullets for that player
}
void Player::checkActions (HWND hwnd) //check player's actions
{
RECT r;
GetClientRect (hwnd, &r); //get canvas space
if (action.up) //if moving up
{
y -= SPEED; //change y position
angle = 0; //change angle
if (pnum == 0) //if player 1
{
if (y - PLSIZE < 1) y = PLSIZE + 1; //check top of screen boundary
}
else //if player 2
{
if (y - PLSIZE < r.bottom/2 + 5) y = r.bottom/2 + 5 + PLSIZE; //check middle boundary
}
}
if (action.left) //if moving left
{
x -= SPEED; //change x position
angle = 270; //change angle
if (x - PLSIZE < 1) x = PLSIZE + 1; //check left of screen boundary
}
if (action.down) //down is opposite of up
{
y += SPEED;
angle = 180;
if (pnum == 0)
{
if (y + PLSIZE > r.bottom/2 - 5) y = r.bottom/2 - 5 - PLSIZE;
}
else
{
if (y + PLSIZE > r.bottom) y = r.bottom - PLSIZE;
}
}
if (action.right) //right is opposite of left
{
x += SPEED;
angle = 90;
if (x + PLSIZE > r.right) x = r.right - PLSIZE;
}
if (action.shoot && GetTickCount() - btime [pnum] > BDELAY) fire(); //if player wants to shoot and enough time has passed, fire bullet
}
void OnPaint (HDC hdc, HWND hwnd) //draw stuff
{
RECT r;
GetClientRect (hwnd, &r); //get canvas area
HDC buffer = CreateCompatibleDC (hdc); //create buffer DC
HBITMAP bitmap = CreateCompatibleBitmap (hdc,r.right,r.bottom); //create buffer bitmap
HBITMAP oldBM = (HBITMAP)SelectObject (buffer, bitmap); //create another bitmap
HBRUSH player1brush = CreateSolidBrush(p[0].colour); //player 1's brush
HBRUSH player2brush = CreateSolidBrush(p[1].colour); //player 2's brush
HBRUSH blackBrush = CreateSolidBrush (RGB(0,0,0)); //black brush
HPEN /*player1*/pen = CreatePen (PS_NULL,1,RGB(255,0,0)); //don't need pen
BitBlt(buffer,0,0,r.right,r.bottom,NULL,0,0,WHITENESS); //erase bitmap background
SelectObject(buffer,pen); //select pen (since I need one to do anything)
SelectObject (buffer, blackBrush); //select black brush
Rectangle (buffer, 0, r.bottom/2 - 5, r.right, r.bottom/2 + 5); //draw middle line
// MoveTo() //these comments are because I was about to change the graphics to ships
SelectObject (buffer,player1brush); //select player 1's brush
Rectangle (buffer,p[0].x-PLSIZE,p[0].y-PLSIZE,p[0].x+PLSIZE,p[0].y+PLSIZE); //draw player 1
SelectObject (buffer,player2brush); //do the same for p2
Rectangle (buffer,p[1].x-PLSIZE,p[1].y-PLSIZE,p[1].x+PLSIZE,p[1].y+PLSIZE);
if (bcount[0] > 0) //if p1 has a bullet
{
SelectObject (buffer, blackBrush); //select black brush
for (int i = 0; i < bcount[0]; ++i) //draw bullet(s)
{
Ellipse (buffer, bullet [0][i].x - BSIZE, bullet [0][i].y - BSIZE, bullet [0][i].x + BSIZE, bullet [0][i].y + BSIZE);
}
}
if (bcount[1] > 0) //same goes for p2
{
SelectObject (buffer, blackBrush);
for (int i = 0; i < bcount[1]; ++i)
{
Ellipse (buffer, bullet [1][i].x - BSIZE, bullet [1][i].y - BSIZE, bullet [1][i].x + BSIZE, bullet [1][i].y + BSIZE);
}
}
BitBlt(hdc, 0,0, r.right , r.bottom, buffer, 0,0, SRCCOPY); //copy buffer bitmap to window
DeleteObject (player1brush); //delete stuff
DeleteObject (player2brush);
DeleteObject (pen);
SelectObject (buffer, oldBM);
DeleteObject (bitmap);
DeleteDC(buffer);
}
void moveBullets (HWND hwnd) //move the bullets ***PROBLEM AREA***
{
RECT r;
GetClientRect (hwnd, &r); //get canvas area
if (bcount[0] > 0) //if p1 has bullet(s)
{
for (int i = 0; i < bcount[0]; ++i) //go through p1's bullets
{
///DOESN'T WORK
bullet [0][i].x += sin (bullet [0][i].angle * M_PI/180); //move the bullet horizontally
if (bullet [0][i].x - BSIZE < 1 || bullet [0][i].x + BSIZE > r.right) //if out of bounds
{
deleteBullet (0, bullet [0][i].index); //delete the bullet
--i; //if bullet [2] was deleted, bullet [2] will now be the old bullet [3] so recheck this one next time
}
///WORKS PERFECTLY
bullet [0][i].y -= cos (bullet [0][i].angle * M_PI/180); //do same for y, including middle border
if (bullet [0][i].y - BSIZE < 1 || bullet [0][i].y + BSIZE > r.bottom/2 - 5)
{
deleteBullet (0, bullet [0][i].index);
--i;
}
}
}
if (bcount[1] > 0) //exact same thing (I checked a LOT) for p2
{
for (int i = 0; i < bcount[1]; ++i)
{
///WORKS PERFECTLY (at least in the p1 sense, there is a slight problem)
bullet [1][i].x += sin (bullet [1][i].angle * M_PI/180);
if (bullet [1][i].x - BSIZE < 1 || bullet [1][i].x + BSIZE > r.right)
{
deleteBullet (1, bullet [1][i].index);
--i;
}
///WORKS PERFECTLY
bullet [1][i].y -= cos (bullet [1][i].angle * M_PI/180);
if (bullet [1][i].y - BSIZE < r.bottom/2 + 5 || bullet [1][i].y + BSIZE > r.bottom)
{
deleteBullet (1, bullet [1][i].index);
--i;
}
}
}
}
void deleteBullet (int player, int index) //delete bullet ***PROBLEM AREA***
{
if (index != bcount [player] - 1) //if it isn't the last bullet
{
for (int j = index; j < bcount[player] - 1; ++j) //go from here to the end of the current bullets - 1
{
bullet [player][j] = bullet [player][j+1]; //copy the next bullet into this spot
--bullet [player][j].index; //change the index of the bullet since it was moved back one
}
}
--bcount [player]; //lessen the bullet count, this is all that's needed if it's the last bullet
}
Toute aide avec ledit problème ou quelque chose d'autre que vous avis serait grandement apprécié.
EDIT: une chose que j'ai oublié de demander était s'il y avait une meilleure façon de faire continuellement des choses comme déplacer des balles par exemple que de mettre tout ce qui est en dehors du commutateur dans la fenêtre et le DefWindowProc
après.
#include pas trouvé .. si pas grand, poster aussi trop .. Et je vous suggère de le renommer en my_window.h –
Kashyap
aussi comment avez-vous débogué ce code sans un seul printf ou cout ?! – Kashyap
Un simple conteneur (pour les balles) et un objet pour les joueurs vous épargneraient beaucoup de problèmes. J'ai vraiment été là avant, essayant juste de faire quelque chose et de copier le code, mais quand quelque chose ne fonctionne pas, ça peut être exaspérant! Droite? :) – user