鱼C论坛

 找回密码
 立即注册
查看: 1308|回复: 5

绘制子弹崩溃

[复制链接]
发表于 2023-5-4 18:50:53 | 显示全部楼层 |阅读模式

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

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

x
本帖最后由 猪猪虾 于 2023-5-4 18:52 编辑

(我感觉在出连续剧 ,一天更新一点。。。)
同样的方法,绘制飞机可以,绘制子弹就不行了
我先尝试简单的绘制一个子弹,只不过在绘制子弹的时候,子弹的位置是要用到飞机类,也就是要用到飞机的位置,所以在子弹类里面调用了飞机的位置,绘制飞机的位置在 GameMain。cpp的upwindow函数里面
捕获.PNG
  1. #pragma once
  2. #include<graphics.h>
  3. #include<cstring>
  4. #include<vector>

  5. using namespace std;
  6. class GameMain;
  7. class MyPlane;

  8. class Bullet
  9. {
  10. public:
  11.         Bullet(GameMain* gm, MyPlane* mp);  //  Bullet  类的构造函数中使用了 GameMain 类的指针  GM 。但是,你没有初始化这个指针
  12.         static IMAGE getImage_Bullet();
  13.         void Move();

  14.         int Bullte_current_posiX;
  15.         int Bullte_current_posiY;
  16.         int width;
  17.         int height;
  18.         int Bullet_pace;
  19.         bool BT_IsAlive;
  20. private:
  21.         static IMAGE imgBullet;  //static 成员变量属于类,不属于某个具体的对象,即使创建多个对象,也只为 static 成员变量分配一份内存,所有对象使用的都是这份内存中的数据。
  22.         GameMain* GM;
  23.         MyPlane* MP;
  24. };
复制代码


  1. #pragma once
  2. #include<graphics.h>
  3. #include<cstring>
  4. #include<vector>

  5. #include "Bullet.h"
  6. #include "GameMain.h"
  7. #include "MyPlane.h"

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

  10. Bullet::Bullet(GameMain* gm,MyPlane* mp):GM(gm),MP(mp)
  11. {
  12.         width = 5;
  13.         height = 10;
  14.         Bullet_pace = 20;
  15.         BT_IsAlive = true;

  16.         loadimage(&imgBullet, "E:/2022上/Leecode_April/plane/image/bullet1.png");

  17.         //初始化飞机的位置在图像的正下方的中心
  18.         Bullte_current_posiX = MP->My_current_posiX ;
  19.         Bullte_current_posiY = MP->My_current_posiY - MP->height;
  20. }


  21. IMAGE Bullet::getImage_Bullet()
  22. {
  23.         return imgBullet;
  24. }

  25. void Bullet::Move()
  26. {
  27.         Bullte_current_posiY -= Bullet_pace;
  28.         if (Bullte_current_posiY < 0) { BT_IsAlive = false; }
  29. }


复制代码
  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> 如果这里这么用,会发现 当前.h文件和MyPlane.h文件的彼此头文件相互包含,会报错
  6. class MyPlane;  //告诉编译器,需要这个类,其他功能结构都没变
  7. class Bullet;
  8. using namespace std;

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

  13.         GameMain();

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

  21.         int rows;
  22.         int cols;

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

  26. private:
  27.         bool update;

  28.         // 添加这一行,这样其他地方调用这个类的时候,就不用每次都申明,不同地方申明,还是不同的对象,无法
  29.         //实现同时操作一辆飞机
  30.         MyPlane *MP;
  31.         Bullet *BT;
  32.         //背景图像参数
  33.         IMAGE imgBg;  //背景图片

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



  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.         update = true;
  19.         rows = 438;
  20.         cols = 675;
  21.         MP = new MyPlane(this);  // 在创建 MyPlane 实例时传递 GameMain 类的指针
  22.         BT = new Bullet(this, MP);
  23.         // 为 MyPlane 类对象的指针 MP 分配内存空间
  24.         //MP = new MyPlane();
  25.         //将游戏界面的宽度指定成背景图片的显示宽度

  26. }

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

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

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

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

  41.        
  42. }

  43. void GameMain::paly()
  44. {
  45.         init();

  46.         update = true;
  47.         while (1)
  48.         {
  49.                 //BeginBatchDraw();

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

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


  70. void GameMain::keyEvent()
  71. {
  72.         unsigned char ch;
  73.         int dx = 0;
  74.         int dy = 0;

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

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

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

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

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

  127.    //绘制子弹
  128.         IMAGE TEMP_BT;
  129.         TEMP_BT = BT->getImage_Bullet();
  130.         putimage(BT->Bullte_current_posiX, BT->Bullte_current_posiY, &TEMP_BT);

  131.         EndBatchDraw();
  132. }

复制代码


小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2023-5-4 19:03:33 | 显示全部楼层
在子弹类里面调用了飞机的位置,可能是因为未正确初始化 MyPlane 对象,导致子弹无法获取到正确的飞机位置。建议将 MyPlane 对象的初始化代码移动到 GameMain 类的构造函数中,并在 Bullet 类中传入 GameMain 对象和 MyPlane 对象的引用,以便子弹类能够正确获取飞机位置并进行绘制。同时,也需要在 GameMain::updateWindow() 中根据子弹对象的当前位置来更新子弹的绘制位置。以下是示例代码:


  1. // GameMain.h

  2. class GameMain
  3. {
  4. public:
  5.     GameMain();
  6.     ~GameMain();

  7.     // ...

  8. private:
  9.     MyPlane MP;
  10.     Bullet BT;

  11.     // ...
  12. };

  13. // Bullet.h

  14. #include "GameMain.h"
  15. #include "MyPlane.h"

  16. class Bullet {
  17. public:
  18.     Bullet(GameMain& game, MyPlane& plane);
  19.     ~Bullet();

  20.     void update();
  21.     IMAGE getImage_Bullet();

  22. private:
  23.     GameMain& m_game; // 引用 GameMain 对象
  24.     MyPlane& m_plane; // 引用 MyPlane 对象

  25.     int Bullte_width=8;
  26.     int Bullte_height=24;
  27.     int Bullte_current_posiX;
  28.     int Bullte_current_posiY;
  29.     IMAGE img_DM_bullet;
  30. };

  31. // Bullet.cpp

  32. Bullet::Bullet(GameMain& game, MyPlane& plane)
  33.     : m_game(game), m_plane(plane)
  34. {
  35.     Bullte_current_posiX = m_plane.My_current_posiX + m_plane.width / 2 - Bullte_width / 2;
  36.     Bullte_current_posiY = m_plane.My_current_posiY - Bullte_height;
  37.     loadimage(&img_DM_bullet, "E:/cpp_proj/plane/image/bullet.png");
  38. }

  39. void Bullet::update()
  40. {
  41.     Bullte_current_posiY -= 10; // 子弹向上移动
  42.     if (Bullte_current_posiY < 0) // 当子弹飞出屏幕时,重置子弹位置
  43.     {
  44.         Bullte_current_posiX = m_plane.My_current_posiX + m_plane.width / 2 - Bullte_width
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-4 19:45:02 | 显示全部楼层
sfqxx 发表于 2023-5-4 19:03
在子弹类里面调用了飞机的位置,可能是因为未正确初始化 MyPlane 对象,导致子弹无法获取到正确的飞机位置 ...

在class GameMain.h里面定义   这种MyPlane MP而不是这种 MyPlane *MP;我这边会显示使用没有定义的class,我一开始就想不用指针的形式,后来没办法才用的指针
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-5-4 19:49:24 | 显示全部楼层
猪猪虾 发表于 2023-5-4 19:45
在class GameMain.h里面定义   这种MyPlane MP而不是这种 MyPlane *MP;我这边会显示使用没有定义的class ...

然后呢
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-5-4 20:19:38 | 显示全部楼层
看起来你的代码想要实现一个飞机发射子弹的游戏。你可以成功地绘制飞机,但在绘制子弹时出现了问题。这是因为你在子弹类中使用了飞机的位置来初始化子弹的位置。在你的GameMain类中,你已经创建了一个MyPlane实例(MP)和一个Bullet实例(BT)。

要解决这个问题:

首先,在GameMain类中,添加一个表示子弹列表的向量成员:
  1. vector<Bullet*> bullets;
复制代码


接着,在 keyEvent 函数中,当按下空格键时创建新的Bullet实例并添加到子弹列表中:

  1. if (_kbhit()) {
  2.     ch = _getch();
  3.     // 添加以下代码来处理空格键按下
  4.     if (ch == 32) {
  5.         Bullet* newBullet = new Bullet(this, MP);
  6.         bullets.push_back(newBullet);
  7.     } else if (ch == 224) {
  8.     ...
  9. }
复制代码


为了避免内存泄漏,记得在GameMain的析构函数删除bullets向量中所有创建的Bullet实例:

  1. GameMain::~GameMain() {
  2.     delete MP;

  3.     for (Bullet* bullet : bullets){
  4.         delete bullet;
  5.     }
  6. }
复制代码


最后,在 updateWindow 函数中,遍历bullets向量中的每一个bullet,并更新它们的位置,然后绘制它们:

  1. for (Bullet* bullet : bullets) {
  2.     bullet->Move();
  3.     IMAGE TEMP_BT;
  4.     TEMP_BT = bullet->getImage_Bullet();
  5.     putimage(bullet->Bullte_current_posiX, bullet->Bullte_current_posiY, &TEMP_BT);
  6. }
复制代码


现在,当你按下空格键时,子弹应该会从飞机的位置创建并向上移动。请注意,上述更改可能无法解决所有问题,你可能需要调整一些其他部分以确保游戏按预期工作。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-5 16:12:36 | 显示全部楼层
本帖最后由 猪猪虾 于 2023-5-5 16:15 编辑
isdkz 发表于 2023-5-4 20:19
看起来你的代码想要实现一个飞机发射子弹的游戏。你可以成功地绘制飞机,但在绘制子弹时出现了问题。这是因 ...


这是因为你在子弹类中使用了飞机的位置来初始化子弹的位置。这个理论上也没啥毛病吧,问题的本质是啥呢,我断点进入子弹的构造函数,子弹的位置是被赋予了的,一直执行到绘图的时候才崩溃

您提供的修改是绘图方式的不同,我那个可能就一次只绘制了一颗子弹
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-6-10 09:44

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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