猪猪虾 发表于 2023-5-3 21:37:28

为什么按键控制飞机移动无效,只有在程序点击运行的时候,我按下按键,可以运动一下

动这一下之后,后面按键就无效了
我测试了,第一下那个dx,dy是传进去了的,应该是后面的按键就没传进去

#pragma once
#include<graphics.h>
#include<cstring>
#include<vector>
//#include<MyPlane.h> 如果这里这么用,会发现 当前.h文件和MyPlane.h文件的彼此头文件相互包含,会报错
class MyPlane;//告诉编译器,需要这个类,其他功能结构都没变
using namespace std;

class GameMain
{
public:
        //构造函数用于初始化参数,游戏界面设置

        GameMain();

        //注意,你需要在GameMain类的析构函数中删除MyPlane
   //类的实例*以避免内存泄漏。在GameMain类中添加一个析构函数,并在其中删除MP :GameMain.h文件
        ~GameMain();// 添加析构函数
        //游戏界面初始化
        void init();
        void paly(); // 开始游戏
        int* getBgSize();

        int rows;
        int cols;

private:
        void keyEvent();//按键控制
        void updateWindow();//渲染界面

private:
        bool update;

        // 添加这一行,这样其他地方调用这个类的时候,就不用每次都申明,不同地方申明,还是不同的对象,无法
        //实现同时操作一辆飞机
        MyPlane *MP;

        //背景图像参数
        IMAGE imgBg;//背景图片

        //创建一个动态数组bullets,里面的元素都是一个个Bullet对象
        //std::vector<Bullet> bullets;// 添加子弹容器
};

#include "GameMain.h"
#include "MyPlane.h"
#include "Bullet.h"
#include<stdlib.h>
#include <time.h>
#include<graphics.h>
#include <conio.h>
#include"iostream"
#include"string"
#include "fstream"
//音效
#include<mmsystem.h>
#pragma comment(lib,"winmm.lib")
#pragma comment(lib,"WINMM.LIB")

using namespace std;

GameMain::GameMain()
{
        rows = 438;
        cols = 675;
        MP = new MyPlane(this);// 在创建 MyPlane 实例时传递 GameMain 类的指针
        // 为 MyPlane 类对象的指针 MP 分配内存空间
        //MP = new MyPlane();
        //将游戏界面的宽度指定成背景图片的显示宽度

}

//析构函数主要作用就是释放资源, 避免内存泄漏
GameMain::~GameMain()
{
        delete MP;// 删除 MyPlane 实例
}

void GameMain::init()
{
        //播放背景音乐
        mciSendString("play E:/res/bg.mp3 repeat", 0, 0, 0);

        //创建游戏窗口
        *initgraph(rows, cols);

        //加载背景图片
        loadimage(&imgBg, "E:/Leecode_April/plane/image/background.png");

        update = true;
}

void GameMain::paly()
{
        init();

        update = true;
        while (1)
        {
                BeginBatchDraw();

                //接收用户的输入
                keyEvent();
                if (update == true) {
                        //更新游戏画面
                        updateWindow();
                }
               
                system("pause");
                EndBatchDraw();
        }
}

int* GameMain::getBgSize()
{
        int num[] = { rows ,cols };
        int* ptr = new int;
        for (int i = 0; i < 2; i++) {
                ptr = num;
        }
        return ptr;
}


void GameMain::keyEvent()
{
        unsigned char ch;
        int dx = 0;
        int dy = 0;

        //判断当前有没有按键输入,如果他没有按键输入,程序正常执行
        if (_kbhit()) {
                ch = _getch();

                //按下字母,返回的就是字母,按下的是方向键
                //上,先后返回: 224 72下:224 80   左:75 224,75右:224 77
                if (ch == 224) {
                        ch = _getch();
                        switch (ch) {
                        case 72:
                                dy = -MP->pace;
                                break;
                        case 80:
                                dy = MP->pace;
                                break;
                        case 75:
                                dx = -MP->pace;
                                break;
                        case 77:
                                dx = MP->pace;
                                break;
                        default:
                                break;
                        }
                }
        }
        if (dx != 0 || dy != 0)//左右移动
        {
//                MyPlane MP;
                MP->Move(dx,dy);
        //        MP->Move(-20,- 20);
                update = true;
        }
}

void GameMain::updateWindow()
{
        putimage(0, 0, &imgBg);
        BeginBatchDraw();

        //绘制我方飞机
        //MyPlane MP;
        IMAGE TEMP_my;
        TEMP_my = MP->getImage_Myplane();
        putimage(MP->My_current_posiX, MP->My_current_posiY, &TEMP_my);

        //绘制子弹
        //Bullet BT;
        //IMAGE TEMP_BT;
        //TEMP_BT = BT.getImage_Bullet();
        //putimage(MP->My_current_posiX, MP->My_current_posiY, &TEMP_BT);
        //for (Bullet& bullet : bullets) {
        //        bullet.update();// 更新子弹位置
        //        IMAGE TEMP_BT;
        //        TEMP_BT = bullet.getImage_Bullet();
        //        putimage(bullet.getPosX(), bullet.getPosY(), &TEMP_BT);
        //}

        EndBatchDraw();
}



#pragma once
#include<graphics.h>
#include<cstring>
#include<vector>
//#include "GameMain.h"
using namespace std;
class GameMain;

class MyPlane
{
public:
        MyPlane(GameMain* gm);//MyPlane类的构造函数中使用了 GameMain 类的指针GM 。但是,你没有初始化这个指针
        //static IMAGE getImages();    //私有成员可以在public里面,通过函数来间接访问和修改
        void Move(int dx, int dy);
        static IMAGE getImage_Myplane();

        int My_current_posiX;
        int My_current_posiY;
        int width;
        int height;
        int pace;   //每次按键飞机移动的距离
private:
        static IMAGE imgMyplane;
        GameMain *GM;
};


#pragma once
#include<graphics.h>
#include<cstring>
#include<vector>
#include "MyPlane.h"
#include "GameMain.h"

using namespace std;
//静态成员,需要在类外进行声明
IMAGE MyPlane::imgMyplane;// 这一行为 imgMyplane 分配内存空间

//`MyPlane` 类在头文件 `MyPlane.h` 中声明,而 `imgMyplane` 的定义位于与类实现相关联的源文件
//`MyPlane.cpp` 中。这样,您就解决了 `LNK2001` 错误。
//如果您将所有代码放在同一个文件中,那么只需在类定义之后添加 `IMAGE MyPlane::imgMyplane; ` 这一行即可。
//IMAGE MyPlane::imgMyplane;// 这一行为 imgMyplane 分配内存空间


MyPlane::MyPlane(GameMain* gm):GM(gm)
{
        width = 100;
        height = 125;
        pace = 20;
        loadimage(&imgMyplane, "E:/Leecode_April/plane/image/me1.png");

        //初始化飞机的位置在图像的正下方的中心
       
        My_current_posiX = GM->rows / 2 - width / 2;
        My_current_posiY = GM->cols - height;
}

IMAGE MyPlane::getImage_Myplane()
{
        return imgMyplane;
}

void MyPlane::Move(int dx, int dy)
{
       
        My_current_posiX += dx;
        My_current_posiY += dy;

        //判断是否超出了边界,还要考虑飞机本身的宽度
        if (My_current_posiX > (GM->rows - width / 2) || My_current_posiX < width / 2)
        {
                My_current_posiX -= dx;
        }

        if (My_current_posiX > (GM->cols - height / 2) || My_current_posiX < height / 2)
        {
                My_current_posiY -= dy;
        }

}

isdkz 发表于 2023-5-3 21:39:08

本帖最后由 isdkz 于 2023-5-3 21:41 编辑

首先,从你的代码中,我发现了一个问题。在GameMain::paly()函数中,你在游戏主循环的每一次迭代后都有一个system("pause");调用。这会导致游戏在每一帧之后都暂停并等待用户按下回车键。这可能是你遇到的按键无效问题的原因之一。要解决此问题,请删除system("pause");这一行。

另外,在GameMain::keyEvent()函数中,你需要在_kbhit()调用之前先调用_flushall() ,以确保在_kbhit()调用之前清除任何缓冲的输入。这是一个解决方案:

void GameMain::keyEvent()
{
    _flushall();// 添加此行以清除缓冲的输入
    unsigned char ch;
    int dx = 0;
    int dy = 0;

    //判断当前有没有按键输入,如果他没有按键输入,程序正常执行
    if (_kbhit()) {
      ch = _getch();

      //按下字母,返回的就是字母,按下的是方向键
      //上,先后返回: 224 72下:224 80   左:75 224,75右:224 77
      if (ch == 224) {
            ch = _getch();
            switch (ch) {
            case 72:
                dy = -MP->pace;
                break;
            case 80:
                dy = MP->pace;
                break;
            case 75:
                dx = -MP->pace;
                break;
            case 77:
                dx = MP->pace;
                break;
            default:
                break;
            }
      }
    }
    if (dx != 0 || dy != 0)//左右移动
    {
      MP->Move(dx,dy);
      update = true;
    }
}


在做了这些更改之后,按键控制应该可以正常工作。希望这可以解决你的问题!

猪猪虾 发表于 2023-5-3 21:42:38

isdkz 发表于 2023-5-3 21:39
首先,从你的代码中,我发现了一个问题。在GameMain::paly()函数中,你在游戏主循环的每一次迭代后都有 ...

还是动不了诶

猪猪虾 发表于 2023-5-3 21:52:39

isdkz 发表于 2023-5-3 21:39
首先,从你的代码中,我发现了一个问题。在GameMain::paly()函数中,你在游戏主循环的每一次迭代后都有 ...

https://blog.csdn.net/weixin_43528481/article/details/130252992?spm=1001.2014.3001.5502
我是仿照这个俄罗斯方块写的,虽然不是一个游戏,但是思路差不多

isdkz 发表于 2023-5-3 22:05:44

猪猪虾 发表于 2023-5-3 21:42
还是动不了诶

system("pause"); 删了吗?

猪猪虾 发表于 2023-5-3 22:13:08

isdkz 发表于 2023-5-3 22:05
system("pause"); 删了吗?

删了,还是不行

isdkz 发表于 2023-5-3 22:45:18

猪猪虾 发表于 2023-5-3 22:13
删了,还是不行

在 GameMain::paly() 函数的 while (1) 循环中,删除 BeginBatchDraw(); 和 EndBatchDraw(); 函数调用。这些函数实际上是用于双缓冲技术,用于防止屏幕闪烁,但在这种情况下,它们可能会干扰按键事件的处理。将 GameMain::paly() 函数修改为:

void GameMain::paly()
{
    init();

    update = true;
    while (1)
    {
      //接收用户的输入
      keyEvent();
      if (update == true) {
            //更新游戏画面
            updateWindow();
      }
    }
}

猪猪虾 发表于 2023-5-4 15:44:03

isdkz 发表于 2023-5-3 22:45
在 GameMain::paly() 函数的 while (1) 循环中,删除 BeginBatchDraw(); 和 EndBatchDraw(); 函数调用。 ...

删掉确实可以了,但是频闪{:5_104:}
页: [1]
查看完整版本: 为什么按键控制飞机移动无效,只有在程序点击运行的时候,我按下按键,可以运动一下