Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/151.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 游戏中两名玩家之间行为不一致_C++_Winapi_Window_Gdi - Fatal编程技术网

C++ 游戏中两名玩家之间行为不一致

C++ 游戏中两名玩家之间行为不一致,c++,winapi,window,gdi,C++,Winapi,Window,Gdi,我一直在为一个英语演讲做游戏(我知道是吧?),最近我遇到了一些奇怪的问题 在这个阶段,有两个方块供玩家发射子弹。当子弹击中屏幕侧面或中间边框时,它们应该消失,并可能在以后重新使用 问题是,首先,当任何一个玩家向上或向下射击时,子弹都会像预期的那样消失在屏幕的上/下/中间。如果玩家2向侧面射出几颗子弹,一旦有一颗击中,它们似乎都消失了(只有玩家2的子弹),我必须等待几秒钟,然后它才能再次开始射击 不过,主要的问题是,即使我使用了为播放器1而不是播放器2修改的完全相同的代码,当播放器1第一次击中屏幕

我一直在为一个英语演讲做游戏(我知道是吧?),最近我遇到了一些奇怪的问题

在这个阶段,有两个方块供玩家发射子弹。当子弹击中屏幕侧面或中间边框时,它们应该消失,并可能在以后重新使用

问题是,首先,当任何一个玩家向上或向下射击时,子弹都会像预期的那样消失在屏幕的上/下/中间。如果玩家2向侧面射出几颗子弹,一旦有一颗击中,它们似乎都消失了(只有玩家2的子弹),我必须等待几秒钟,然后它才能再次开始射击

不过,主要的问题是,即使我使用了为播放器1而不是播放器2修改的完全相同的代码,当播放器1第一次击中屏幕一侧时,它也会导致程序出错

真正奇怪的是,在某一点上,这种情况发生了,没有任何改变,我再次运行了它,一切都很好。这可能与玩家1和玩家2之间的子弹顺序有关,甚至与我第一次射击的位置有关。我尝试过重新创建它,但还没有结果

在您尝试编译代码之前,请注意,我使用了我制作的包装器来轻松创建窗口。不过,我用///注释记下了幕后发生的事情,因此将这些信息添加到您使用的任何方法中,使您的窗口也能正常工作

底部附近列出了问题区域:

///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
}
///在分辨率为1280x1024时效果最佳
///1对1分屏游戏,包括飞行和射击
///角度从0开始朝上,并顺时针增加
#include//包装不完整,但非常适合快速、轻松地创建窗口
#定义(使用)数学(定义)//
#包括//用于M_PI
#include//用于调试
使用std::cout//输出
结构动作//玩家可以采取的动作
{
bool up;//如果玩家朝这4个方向移动,它们将是真的
布尔左;
下钻;
布尔右派;
bool shot;//如果玩家正在射击,这将是真的
};
struct Player//a Player
{
Player(){};
void fire();//发射子弹
无效检查动作(HWND);//检查玩家正在采取的动作
双x;//位置(正方形中心)
双y;
双角度;//角度(可能会添加对角线…)
int pnum;//播放器编号(0或1)
COLORREF COLOR;//玩家的颜色
动作动作;//玩家的动作
};
结构子弹//子弹
{
双x;//位置(正方形中心)
双y;
玩家所有者;//子弹的所有者
int index;//数组中的项目符号索引
双角度;//子弹的角度
};
玩家*p=新玩家[2]//2名球员
子弹**子弹//二维子弹阵列
int bcount[2]={0}//每个玩家的子弹数
int btime[2]={0}//子弹计时器
常数双PLSIZE=10//播放器尺寸=20x20平方(从中心向外10)
常数双BSIZE=2//子弹尺寸=4x4平方英寸
恒双速=1//玩家移动速度为1
常数int BDELAY=100//子弹之间的延迟为100毫秒
LRESULT回调WndProc(HWND、UINT、WPARAM、LPARAM)//窗口程序
油漆上的空隙(HDC、HWND)//绘画功能
无效子弹(HWND)//计算子弹位置
无效删除项目符号(int,int)//“删除”一个项目符号
int main()//主函数
{
//隐藏(console());//隐藏控制台窗口(当前显示用于调试)
bullet=new bullet*[2];//创建1000个/玩家的子弹阵列(我稍后会缩小1000个)
项目符号[0]=新项目符号[1000];
项目符号[1]=新项目符号[1000];
p[0].x=630;//玩家1的位置
p[0].y=250;
p[0].color=RGB(255,0,0);//播放器1为红色
p[0].pnum=0;//玩家1的号码是0
p[0]。角度=0;//面朝上
p[0]。操作={0};//玩家1什么也没做
p[1].x=630;//玩家2的位置
p[1].y=750;
p[1].color=RGB(0,0255);//播放器2是蓝色的
p[1].pnum=1;//玩家2的号码是1
p[1]。角度=0;//面朝上
p[1]。操作={0};//玩家2什么也没做
Window;//创建窗口对象(包装的一部分,为类和窗口设置默认值)
///背景=(HBRUSH)颜色窗口
///class name=“默认包装器类”
///hInstance=GetModuleHandle(NULL)
///所有其他都是标准默认值或0
createClass(WndProc);//使用前面提到的窗口过程创建类
setStyle(WS|u OVERLAPPEDWINDOW | WS_MAXIMIZE);//将窗口样式设置为重叠并最大化
window.setTitle(L“Word Blaster”);//将窗口标题设置为“Word Blaster”(这是一个英语项目,嘘)
///x/y/宽度/高度=顺时针使用默认值
///类名=其他类名
///hInstance=GetModuleHandle(NULL)
///所有其他都是标准默认值或0
HWND HWND=window.createWindow();//创建窗口
MSG;//消息循环
while(GetMessage(&msg,0,0,0)>0)
{
翻译信息(&msg);
发送消息(&msg);
}
返回msg.wParam;
}
LRESULT回调WndProc(HWND HWND,UINT msg,WPARAM WPARAM,LPARAM LPARAM)//窗口过程
{
HDC HDC;//用于绘画的HDC
PAINTSTRUCT ps;//用于绘制的PAINTSTRUCT
bool ret=false;//返回值(稍后将看到)
开关(msg)
{
案例WM_CREATE://当前未使用
打破
case WM_KEYDOWN://检查按键是否按下
开关(wParam)//keycode
{
案例0x57://“w”
p[0].action.up=true;//玩家1想要向上移动(不能在这里改变位置或没有对角线移动)
打破
案例0x41://“a”,左侧
p[0]。action.left=true;
打破
案例0x53://“s”,向下
p[0]。action.down=true;
打破
案例0x44://“d”,对吗
p[0]。action.right=true;