鱼C论坛

 找回密码
 立即注册
查看: 1559|回复: 7

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

[复制链接]
发表于 2023-5-3 21:37:28 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
动这一下之后,后面按键就无效了
我测试了,第一下那个dx,dy是传进去了的,应该是后面的按键就没传进去
1.PNG
  1. #pragma once
  2. #include<graphics.h>
  3. #include<cstring>
  4. #include<vector>
  5. //#include<MyPlane.h> 如果这里这么用,会发现 当前.h文件和MyPlane.h文件的彼此头文件相互包含,会报错
  6. class MyPlane;  //告诉编译器,需要这个类,其他功能结构都没变
  7. using namespace std;

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

  12.         GameMain();

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

  20.         int rows;
  21.         int cols;

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

  25. private:
  26.         bool update;

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

  30.         //背景图像参数
  31.         IMAGE imgBg;  //背景图片

  32.         //创建一个动态数组bullets,里面的元素都是一个个Bullet对象
  33.         //std::vector<Bullet> bullets;  // 添加子弹容器
  34. };
复制代码
  1. #include "GameMain.h"
  2. #include "MyPlane.h"
  3. #include "Bullet.h"
  4. #include<stdlib.h>
  5. #include <time.h>
  6. #include<graphics.h>
  7. #include <conio.h>
  8. #include"iostream"
  9. #include"string"
  10. #include "fstream"
  11. //音效
  12. #include<mmsystem.h>
  13. #pragma comment(lib,"winmm.lib")
  14. #pragma comment(lib,"WINMM.LIB")

  15. using namespace std;

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

  24. }

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

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

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

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

  38.         update = true;
  39. }

  40. void GameMain::paly()
  41. {
  42.         init();

  43.         update = true;
  44.         while (1)
  45.         {
  46.                 BeginBatchDraw();

  47.                 //接收用户的输入
  48.                 keyEvent();
  49.                 if (update == true) {
  50.                         //更新游戏画面
  51.                         updateWindow();
  52.                 }
  53.                
  54.                 system("pause");
  55.                 EndBatchDraw();
  56.         }
  57. }

  58. int* GameMain::getBgSize()
  59. {
  60.         int num[] = { rows ,cols };
  61.         int* ptr = new int[2];
  62.         for (int i = 0; i < 2; i++) {
  63.                 ptr[i] = num[i];
  64.         }
  65.         return ptr;
  66. }


  67. void GameMain::keyEvent()
  68. {
  69.         unsigned char ch;
  70.         int dx = 0;
  71.         int dy = 0;

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

  75.                 //按下字母,返回的就是字母,按下的是方向键
  76.                 //上,先后返回: 224 72  下:224 80   左:75 224,75  右:224 77
  77.                 if (ch == 224) {
  78.                         ch = _getch();
  79.                         switch (ch) {
  80.                         case 72:
  81.                                 dy = -MP->pace;
  82.                                 break;
  83.                         case 80:
  84.                                 dy = MP->pace;
  85.                                 break;
  86.                         case 75:
  87.                                 dx = -MP->pace;
  88.                                 break;
  89.                         case 77:
  90.                                 dx = MP->pace;
  91.                                 break;
  92.                         default:
  93.                                 break;
  94.                         }
  95.                 }
  96.         }
  97.         if (dx != 0 || dy != 0)  //左右移动
  98.         {
  99. //                MyPlane MP;
  100.                 MP->Move(dx,dy);
  101.         //        MP->Move(-20,- 20);
  102.                 update = true;
  103.         }
  104. }

  105. void GameMain::updateWindow()
  106. {
  107.         putimage(0, 0, &imgBg);
  108.         BeginBatchDraw();

  109.         //绘制我方飞机
  110.         //MyPlane MP;
  111.         IMAGE TEMP_my;
  112.         TEMP_my = MP->getImage_Myplane();
  113.         putimage(MP->My_current_posiX, MP->My_current_posiY, &TEMP_my);

  114.         //绘制子弹
  115.         //Bullet BT;
  116.         //IMAGE TEMP_BT;
  117.         //TEMP_BT = BT.getImage_Bullet();
  118.         //putimage(MP->My_current_posiX, MP->My_current_posiY, &TEMP_BT);
  119.         //for (Bullet& bullet : bullets) {
  120.         //        bullet.update();  // 更新子弹位置
  121.         //        IMAGE TEMP_BT;
  122.         //        TEMP_BT = bullet.getImage_Bullet();
  123.         //        putimage(bullet.getPosX(), bullet.getPosY(), &TEMP_BT);
  124.         //}

  125.         EndBatchDraw();
  126. }

复制代码

  1. #pragma once
  2. #include<graphics.h>
  3. #include<cstring>
  4. #include<vector>
  5. //#include "GameMain.h"
  6. using namespace std;
  7. class GameMain;

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

  15.         int My_current_posiX;
  16.         int My_current_posiY;
  17.         int width;
  18.         int height;
  19.         int pace;   //每次按键飞机移动的距离
  20. private:
  21.         static IMAGE imgMyplane;
  22.         GameMain *GM;
  23. };
复制代码

  1. #pragma once
  2. #include<graphics.h>
  3. #include<cstring>
  4. #include<vector>
  5. #include "MyPlane.h"
  6. #include "GameMain.h"

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

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


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

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

  25. IMAGE MyPlane::getImage_Myplane()
  26. {
  27.         return imgMyplane;
  28. }

  29. void MyPlane::Move(int dx, int dy)
  30. {
  31.        
  32.         My_current_posiX += dx;
  33.         My_current_posiY += dy;

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

  39.         if (My_current_posiX > (GM->cols - height / 2) || My_current_posiX < height / 2)
  40.         {
  41.                 My_current_posiY -= dy;
  42.         }

  43. }
复制代码
最佳答案
2023-5-3 22:45:18

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

  1. void GameMain::paly()
  2. {
  3.     init();

  4.     update = true;
  5.     while (1)
  6.     {
  7.         //接收用户的输入
  8.         keyEvent();
  9.         if (update == true) {
  10.             //更新游戏画面
  11.             updateWindow();
  12.         }
  13.     }
  14. }
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2023-5-3 21:39:08 | 显示全部楼层
本帖最后由 isdkz 于 2023-5-3 21:41 编辑

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

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

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

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

  10.         //按下字母,返回的就是字母,按下的是方向键
  11.         //上,先后返回: 224 72  下:224 80   左:75 224,75  右:224 77
  12.         if (ch == 224) {
  13.             ch = _getch();
  14.             switch (ch) {
  15.             case 72:
  16.                 dy = -MP->pace;
  17.                 break;
  18.             case 80:
  19.                 dy = MP->pace;
  20.                 break;
  21.             case 75:
  22.                 dx = -MP->pace;
  23.                 break;
  24.             case 77:
  25.                 dx = MP->pace;
  26.                 break;
  27.             default:
  28.                 break;
  29.             }
  30.         }
  31.     }
  32.     if (dx != 0 || dy != 0)  //左右移动
  33.     {
  34.         MP->Move(dx,dy);
  35.         update = true;
  36.     }
  37. }
复制代码


在做了这些更改之后,按键控制应该可以正常工作。希望这可以解决你的问题!
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

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

还是动不了诶
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 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
我是仿照这个俄罗斯方块写的,虽然不是一个游戏,但是思路差不多
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-5-3 22:05:44 | 显示全部楼层

system("pause"); 删了吗?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-3 22:13:08 | 显示全部楼层
isdkz 发表于 2023-5-3 22:05
system("pause"); 删了吗?

删了,还是不行
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-5-3 22:45:18 | 显示全部楼层    本楼为最佳答案   

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

  1. void GameMain::paly()
  2. {
  3.     init();

  4.     update = true;
  5.     while (1)
  6.     {
  7.         //接收用户的输入
  8.         keyEvent();
  9.         if (update == true) {
  10.             //更新游戏画面
  11.             updateWindow();
  12.         }
  13.     }
  14. }
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-4 15:44:03 | 显示全部楼层
isdkz 发表于 2023-5-3 22:45
在 GameMain::paly() 函数的 while (1) 循环中,删除 BeginBatchDraw(); 和 EndBatchDraw(); 函数调用。 ...

删掉确实可以了,但是频闪
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-6-10 16:14

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表