鱼C论坛

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

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

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

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

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

x
动这一下之后,后面按键就无效了
我测试了,第一下那个dx,dy是传进去了的,应该是后面的按键就没传进去
1.PNG
#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[2];
        for (int i = 0; i < 2; i++) {
                ptr[i] = num[i];
        }
        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;
        }

}
最佳答案
2023-5-3 22:45:18

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

    update = true;
    while (1)
    {
        //接收用户的输入
        keyEvent();
        if (update == true) {
            //更新游戏画面
            updateWindow();
        }
    }
}
想知道小甲鱼最近在做啥?请访问 -> 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()  调用之前清除任何缓冲的输入。这是一个解决方案:
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;
    }
}

在做了这些更改之后,按键控制应该可以正常工作。希望这可以解决你的问题!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

还是动不了诶
想知道小甲鱼最近在做啥?请访问 -> 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
我是仿照这个俄罗斯方块写的,虽然不是一个游戏,但是思路差不多
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

system("pause"); 删了吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

删了,还是不行
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

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

    update = true;
    while (1)
    {
        //接收用户的输入
        keyEvent();
        if (update == true) {
            //更新游戏画面
            updateWindow();
        }
    }
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

删掉确实可以了,但是频闪
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-9-27 23:45

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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