2011-09-22 8 views
1

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.

+0

#include pas trouvé .. si pas grand, poster aussi trop .. Et je vous suggère de le renommer en my_window.h – Kashyap

+0

aussi comment avez-vous débogué ce code sans un seul printf ou cout ?! – Kashyap

+0

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

Répondre

0

Il semble que deleteBullet peut être appelé deux fois sur le même i à l'intérieur de la boucle for (i=0...) dans moveBullets. Je pense que cela pourrait arriver si la balle se déplace en diagonale. Cependant, je ne suis pas sûr que ce soit la cause du problème.

Première question en anglais que j'ai vu sur stackoverflow!

+0

J'ai regardé la fonction, et bien que ce ne soit certainement pas un mouvement en diagonale (comme il n'y a pas de mouvement de diagonale pour le moment), vous obtenez un point valide en considérant la décrémentation. Je reviendrai à vous à ce sujet. – chris

+0

Ok, après un tout petit peu de tests après avoir mis x et y dans des boucles séparées, ça semble fonctionner. En effet, supprimer une balle dans la partie x n'interférerait pas avec la partie y plus tard maintenant. Je vais ajouter et tester pendant le week-end donc si je ne vois plus aucune trace de l'un ou l'autre problème d'ici demain, je marquerai ceci comme étant répondu. Le vrai kicker est que cet ordinateur est 100x plus lent que celui que je vais présenter sur>.> – chris

Questions connexes