绘制子弹崩溃
本帖最后由 猪猪虾 于 2023-5-4 18:52 编辑(我感觉在出连续剧{:5_104:} ,一天更新一点。。。)
同样的方法,绘制飞机可以,绘制子弹就不行了
我先尝试简单的绘制一个子弹,只不过在绘制子弹的时候,子弹的位置是要用到飞机类,也就是要用到飞机的位置,所以在子弹类里面调用了飞机的位置,绘制飞机的位置在 GameMain。cpp的upwindow函数里面
#pragma once
#include<graphics.h>
#include<cstring>
#include<vector>
using namespace std;
class GameMain;
class MyPlane;
class Bullet
{
public:
Bullet(GameMain* gm, MyPlane* mp);//Bullet类的构造函数中使用了 GameMain 类的指针GM 。但是,你没有初始化这个指针
static IMAGE getImage_Bullet();
void Move();
int Bullte_current_posiX;
int Bullte_current_posiY;
int width;
int height;
int Bullet_pace;
bool BT_IsAlive;
private:
static IMAGE imgBullet;//static 成员变量属于类,不属于某个具体的对象,即使创建多个对象,也只为 static 成员变量分配一份内存,所有对象使用的都是这份内存中的数据。
GameMain* GM;
MyPlane* MP;
};
#pragma once
#include<graphics.h>
#include<cstring>
#include<vector>
#include "Bullet.h"
#include "GameMain.h"
#include "MyPlane.h"
//静态成员,需要在类外进行声明
IMAGE Bullet::imgBullet;// 这一行为 imgMyplane 分配内存空间
Bullet::Bullet(GameMain* gm,MyPlane* mp):GM(gm),MP(mp)
{
width = 5;
height = 10;
Bullet_pace = 20;
BT_IsAlive = true;
loadimage(&imgBullet, "E:/2022上/Leecode_April/plane/image/bullet1.png");
//初始化飞机的位置在图像的正下方的中心
Bullte_current_posiX = MP->My_current_posiX ;
Bullte_current_posiY = MP->My_current_posiY - MP->height;
}
IMAGE Bullet::getImage_Bullet()
{
return imgBullet;
}
void Bullet::Move()
{
Bullte_current_posiY -= Bullet_pace;
if (Bullte_current_posiY < 0) { BT_IsAlive = false; }
}
#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> 如果这里这么用,会发现 当前.h文件和MyPlane.h文件的彼此头文件相互包含,会报错
class MyPlane;//告诉编译器,需要这个类,其他功能结构都没变
class Bullet;
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;
Bullet *BT;
//背景图像参数
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()
{
update = true;
rows = 438;
cols = 675;
MP = new MyPlane(this);// 在创建 MyPlane 实例时传递 GameMain 类的指针
BT = new Bullet(this, MP);
// 为 MyPlane 类对象的指针 MP 分配内存空间
//MP = new MyPlane();
//将游戏界面的宽度指定成背景图片的显示宽度
}
//析构函数主要作用就是释放资源, 避免内存泄漏
GameMain::~GameMain()
{
delete MP;// 删除 MyPlane 实例
delete BT;
}
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");
}
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);
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);
//}
//绘制子弹
IMAGE TEMP_BT;
TEMP_BT = BT->getImage_Bullet();
putimage(BT->Bullte_current_posiX, BT->Bullte_current_posiY, &TEMP_BT);
EndBatchDraw();
}
在子弹类里面调用了飞机的位置,可能是因为未正确初始化 MyPlane 对象,导致子弹无法获取到正确的飞机位置。建议将 MyPlane 对象的初始化代码移动到 GameMain 类的构造函数中,并在 Bullet 类中传入 GameMain 对象和 MyPlane 对象的引用,以便子弹类能够正确获取飞机位置并进行绘制。同时,也需要在 GameMain::updateWindow() 中根据子弹对象的当前位置来更新子弹的绘制位置。以下是示例代码:
// GameMain.h
class GameMain
{
public:
GameMain();
~GameMain();
// ...
private:
MyPlane MP;
Bullet BT;
// ...
};
// Bullet.h
#include "GameMain.h"
#include "MyPlane.h"
class Bullet {
public:
Bullet(GameMain& game, MyPlane& plane);
~Bullet();
void update();
IMAGE getImage_Bullet();
private:
GameMain& m_game; // 引用 GameMain 对象
MyPlane& m_plane; // 引用 MyPlane 对象
int Bullte_width=8;
int Bullte_height=24;
int Bullte_current_posiX;
int Bullte_current_posiY;
IMAGE img_DM_bullet;
};
// Bullet.cpp
Bullet::Bullet(GameMain& game, MyPlane& plane)
: m_game(game), m_plane(plane)
{
Bullte_current_posiX = m_plane.My_current_posiX + m_plane.width / 2 - Bullte_width / 2;
Bullte_current_posiY = m_plane.My_current_posiY - Bullte_height;
loadimage(&img_DM_bullet, "E:/cpp_proj/plane/image/bullet.png");
}
void Bullet::update()
{
Bullte_current_posiY -= 10; // 子弹向上移动
if (Bullte_current_posiY < 0) // 当子弹飞出屏幕时,重置子弹位置
{
Bullte_current_posiX = m_plane.My_current_posiX + m_plane.width / 2 - Bullte_width sfqxx 发表于 2023-5-4 19:03
在子弹类里面调用了飞机的位置,可能是因为未正确初始化 MyPlane 对象,导致子弹无法获取到正确的飞机位置 ...
在class GameMain.h里面定义 这种MyPlane MP而不是这种 MyPlane *MP;我这边会显示使用没有定义的class,我一开始就想不用指针的形式,后来没办法才用的指针 猪猪虾 发表于 2023-5-4 19:45
在class GameMain.h里面定义 这种MyPlane MP而不是这种 MyPlane *MP;我这边会显示使用没有定义的class ...
然后呢 看起来你的代码想要实现一个飞机发射子弹的游戏。你可以成功地绘制飞机,但在绘制子弹时出现了问题。这是因为你在子弹类中使用了飞机的位置来初始化子弹的位置。在你的GameMain类中,你已经创建了一个MyPlane实例(MP)和一个Bullet实例(BT)。
要解决这个问题:
首先,在GameMain类中,添加一个表示子弹列表的向量成员:
vector<Bullet*> bullets;
接着,在 keyEvent 函数中,当按下空格键时创建新的Bullet实例并添加到子弹列表中:
if (_kbhit()) {
ch = _getch();
// 添加以下代码来处理空格键按下
if (ch == 32) {
Bullet* newBullet = new Bullet(this, MP);
bullets.push_back(newBullet);
} else if (ch == 224) {
...
}
为了避免内存泄漏,记得在GameMain的析构函数删除bullets向量中所有创建的Bullet实例:
GameMain::~GameMain() {
delete MP;
for (Bullet* bullet : bullets){
delete bullet;
}
}
最后,在 updateWindow 函数中,遍历bullets向量中的每一个bullet,并更新它们的位置,然后绘制它们:
for (Bullet* bullet : bullets) {
bullet->Move();
IMAGE TEMP_BT;
TEMP_BT = bullet->getImage_Bullet();
putimage(bullet->Bullte_current_posiX, bullet->Bullte_current_posiY, &TEMP_BT);
}
现在,当你按下空格键时,子弹应该会从飞机的位置创建并向上移动。请注意,上述更改可能无法解决所有问题,你可能需要调整一些其他部分以确保游戏按预期工作。 本帖最后由 猪猪虾 于 2023-5-5 16:15 编辑
isdkz 发表于 2023-5-4 20:19
看起来你的代码想要实现一个飞机发射子弹的游戏。你可以成功地绘制飞机,但在绘制子弹时出现了问题。这是因 ...
这是因为你在子弹类中使用了飞机的位置来初始化子弹的位置。这个理论上也没啥毛病吧,问题的本质是啥呢,我断点进入子弹的构造函数,子弹的位置是被赋予了的,一直执行到绘图的时候才崩溃
您提供的修改是绘图方式的不同,我那个可能就一次只绘制了一颗子弹
页:
[1]