Vector 使我的程序崩溃
Vector is crashing my program
我的 SFML 游戏出现严重问题。
我整天都在努力寻找解决方案,尝试了不同的方法,但到目前为止对我没有任何帮助。
这些是我的 .h 文件:
Bullet.h
#pragma once
#include <SFML\Graphics.hpp>
#include <iostream>
#include <vector>
class Bullet
{
friend class Player;
friend class Game;
float width;
float height;
float x;
float y;
std::vector<Bullet*> projectiles;
sf::RectangleShape bullet;
void draw_projectiles(sf::RenderWindow &window);
void make_projectiles();
public:
void check();
Bullet();
~Bullet();
};
Game.h
#pragma once
#include <SFML\Graphics.hpp>
#include "Player.h"
#include "Bullet.h"
#include <vector>
//#include "Enemy.h"
class Game
{
friend class Player;
sf::RenderWindow* window;
sf::Event* evnt;
Player* player;
Bullet* bullet;
public:
void Loop();
void game_func();
Game();
~Game();
};
Player.h
#pragma once
#include <SFML\Graphics.hpp>
#include <iostream>
#include "Game.h"
#include "Bullet.h"
class Player
{
sf::RectangleShape player;
Bullet* bullet;
int ammo;
float width;
float height;
int x;
int y;
float vel;
public:
void draw(sf::RenderWindow &window);
void move(sf::Event &evnt, sf::RenderWindow &window);
Player();
~Player();
};
这里有cpp文件
Bullet.cpp
#include "Bullet.h"
void Bullet::check()
{
x = bullet.getPosition().x;
y = bullet.getPosition().y;
}
void Bullet::draw_projectiles(sf::RenderWindow &window)
{
for (int i = 0; i < 10; i++)
{
window.draw(projectiles[i]->bullet);
}
}
void Bullet::make_projectiles()
{
projectiles.push_back(new Bullet());
}
Bullet::Bullet()
{
std::cout << "zostal utworzony nowy obiekt" << std::endl;
width = 50;
height = 50;
bullet = sf::RectangleShape(sf::Vector2f(width, height));
bullet.setFillColor(sf::Color::Yellow);
bullet.setPosition(0, 0);
x = bullet.getPosition().x;
y = bullet.getPosition().y;
}
Bullet::~Bullet(){}
Game.cpp
#include "Game.h"
Game::Game()
{
window= new sf::RenderWindow(sf::VideoMode(1280, 720), "SFML Game",
sf::Style::Close);
player = new Player();
}
Game::~Game(){}
void Game::Loop()
{
while (window->isOpen())
{
sf::Event evnt;
while (window->pollEvent(evnt))
{
//events
if (evnt.type==sf::Event::Closed)
window->close();
player->move(evnt, *window);
window->clear();
player->draw(*window);
window->display();
bullet->draw_projectiles(*window);
}
}
}
void Game::game_func()
{
Game::Loop();
}
Player.cpp
#include "Player.h"
void Player::draw(sf::RenderWindow &window)
{
window.draw(player);
}
void Player::move(sf::Event &evnt, sf::RenderWindow &window)
{
x = player.getPosition().x;
y = player.getPosition().y;
float width = window.getSize().x;
float height = window.getSize().y;
Bullet obj;
if (evnt.type == sf::Event::KeyPressed)
{
//movement
if (evnt.key.code == sf::Keyboard::Key::W)
{
if (y <= 0)
{
return;
}
player.move(0, -1 * vel);
}
if (evnt.key.code == sf::Keyboard::Key::S)
{
if (y >= height - Player::height)
{
return;
}
player.move(0, 1 * vel);
}
if (evnt.key.code == sf::Keyboard::Key::A)
{
if (x <= 0)
{
return;
}
player.move(-1 * vel, 0);
}
if (evnt.key.code == sf::Keyboard::D)
{
if(x>width-Player::width)
{
return;
}
player.move(1 * vel, 0);
}
if (evnt.key.code == sf::Keyboard::Space)
{
obj.make_projectiles();
}
}
}
Player::Player()
{
width = 100;
height = 100;
vel = 10;
player = sf::RectangleShape(sf::Vector2f(width, height));
player.setFillColor(sf::Color::Red);
player.setPosition(sf::Vector2f(15, 20));
}
Player::~Player(){}
和main.cpp
#include <SFML/Graphics.hpp>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
#include "Game.h"
int main()
{
Game gme;
gme.game_func();
return 0;
}
我尝试了很多不同的东西,但无法弄清楚为什么它不起作用。我 运行 在 Visual Studio 15。
所以这是我得到的错误:
Exception thrown: read access violation.
std::_Vector_alloc<std::_Vec_base_types<Bullet *,std::allocator<Bullet *> >
>::_Mylast(...) returned 0x18.
我知道代码并不完美而且有点混乱,但我只是一个初学者,正在尝试学习新东西。
我将不胜感激任何帮助!
我相信您正试图访问十个射弹:
for (int i = 0; i < 10; i++)
{
window.draw(projectiles[i]->bullet);
}
但是你一次只能添加一个:
projectiles.push_back(new Bullet());
我在最后一段回答了你的问题,你可以跳到那一段,但我建议你看一下所有这些。首先,您应该了解基本游戏在代码中应该是什么样子。
游戏逻辑
您可以将游戏逻辑分为 2 个主要函数。初始化和循环。
初始化
在初始化函数中,您基本上将游戏所需的所有内容加载到 运行(这仅适用于小型游戏,因为在内存中加载数十个 sprite 可能不是大型游戏的最佳解决方案一个。随着时间的推移,你会找出加载和释放资源的正确时间)。
循环
这称为主循环或游戏循环。这个循环应该执行 3 个主要函数。 处理用户输入、更新世界并渲染世界。这个循环应该在游戏 运行ning 时执行(即当 window 打开时)
所以你的 main 在伪 C++ 中应该看起来像这样:
Init();
while (window.isOpen())
{
HandleEvents(window); //user input
Update(elapsedTime);
Render(window);
}
我将解释这些函数的作用、参数的含义以及这些函数如何映射到您的代码。请记住,每个功能都有一个特定的任务,而且仅此而已。当我在屏幕上绘制精灵时,我不会检查用户是否按下了按钮。
用户输入
从按下按钮和鼠标点击到按下退出按钮和调整 window 大小的一切都称为 用户输入 。用户的操作会生成所谓的 事件 ,我们会在每个循环开始时处理这些事件。现在此事件是 window 特定的(如果 window 最小化或未聚焦,您将无法控制播放器)。这意味着 window 会生成事件(如果我在技术上对这个事件有误,请纠正我)。这就是为什么在处理事件时需要传递 window 的原因。
事件
在处理事件之前,您需要了解 sf::Event 是如何制作的(请参阅 sfml
页面上的更多信息)。长话短说 sf::Event 是一个联合(一次只有一个字段有效)。也就是说,如果您在 window.pollEvent()
return 编辑 sf::Event::JoystickEvent
时尝试访问 event.key
,您将得到未定义的行为(我过着幸福的生活,但不知道联合是什么,从未使用过它们,可能永远也不会,但它们是一个非常有趣的概念,至少值得一读)。好的,通过调用 window.pollEvent()
并向其传递一个 sf::Event 实例来创建事件对象。此函数将从队列中为您提供事件,直到没有更多事件要提供为止,此时它 return 为 false。考虑到这一点,您的事件处理代码将类似于:
sf::Event ev;
while (window.pollEvent(ev))
{
switch (ev.type)
{
//code for each type needed by your application
}
}
请记住,关键事件不处理实时输入(sf::Keyboard::isKeyPressed
处理)。这意味着如果你想让你的角色在你按住一个按钮时移动,通过事件处理它会导致延迟,这可以用打字的方式最好地解释(当你按住 'a' 例如第一个字符被立即写入,其余输入在注册前延迟一秒)。这是一种解释它的方式,但可能不是最技术性的(我在这里寻求一点帮助:))。无论如何,这个问题可以通过使用 sf::Keyboard 的静态方法或在你的 Player class 中保留一个 bool
来解决 KeyPressed
和 [=24] =](将根据该布尔值处理更新)。
世界更新
这是您的逻辑代码(尽管玩家移动也可以在事件部分处理,因为它基于事件部分)。在这里你更新你的实体(根据他的 AI 将敌人移动一个方块),在地图上移动太阳等。请记住,这与绘图部分无关,在本节中你只改变你的状态对象。在您的游戏中,这意味着,在您通过用户触发的事件发射射弹后,您在每一帧移动射弹。此代码通常需要某种帧计数方法。
帧数
一帧是循环的迭代,你可以说游戏在每一帧更新和绘制自己。框架是一个非常重要的概念,因为它们会引起一些问题。如果游戏每帧更新自己,这意味着弹丸在移动的每一帧,这意味着他的移动取决于您的电脑可以达到的 FPS 运行。这是一个问题,因为虽然您的游戏可能 运行 在您的电脑上以稳定的 60 FPS 速率运行,但在我的游戏上它可能 运行 为 53 或其他随机值。这意味着我电脑上的射弹会移动得更慢,我们不希望这样。
帧独立运动
这可以通过计算帧数来实现。一种方法是计算自上一帧以来经过的秒数,考虑到这一点,您可以获得实体在该特定帧中需要移动的 space 量。例如,您想以 100 像素/秒的速度移动您的射弹。如果你有 2FPS,这意味着在 2 帧中它需要移动 100px,所以每帧移动 100 / 2
px。所以公式就是finalDistance / framerate
。有更多的方法可以做到这一点,但在我看来,这是一开始最容易理解的。那么这在 SFML 中是如何实现的呢?您基本上会保留一个时钟,在每次更新结束时重新启动。 getElapsedTime
并重新启动,但是重新启动 return 和 elapsedTime
所以最好调用一次,因为一个一个地调用它们可能会导致不同的时间和不同步。
sf::Clock clock;
while (window.isOpen())
{
HandleEvents(window);
Update(clock.restart());
Render(window);
}
并且您只需使用 move(vector * clock.getElapsedTime().asSeconds())
移动您的实体,因为 sf::Vector
为浮点数(asSeconds()
的 return 类型)超载了 operator*
。
渲染
渲染部分可能会很复杂,但是sfml
就可以了"simple and fast"。基本上它是这样工作的:清除屏幕,绘制实体,显示屏幕。更具技术性的答案如下:window 包含 2 个缓冲区,一个可见,一个隐藏。可见的是您在屏幕上看到的那个。当您调用 clear()
时,您基本上清除了隐藏的,draw()
也在隐藏的 window 上绘制,最后 display()
交换缓冲区。
这意味着除非您调用 window.display()
,否则您将看不到任何结果,如果您在绘图前不调用 clear()
,您将获得 window xp 体验。所以 Render 函数可能看起来像这样:
window.clear();
window.draw(player); //or player.draw(window) based on your implementation
//other draws
window.display();
你的问题
您的代码中发生的事情是您尝试访问不存在的内容。您一次添加一个抛射物,但每帧绘制 10 个。
解决方法
记录您的对象。由于您使用的是已经提供的矢量,因此您 std::vector::size
return 正是您所期望的,因此您的代码将变成如下内容:
for (int i = 0; i < yourProjectiles.size(); i++)
{
window.draw(yourProjectiles[i]->bullet);
}
或者你可以使用迭代器(查找它们):
for (auto it = yourProjectiles.begin(); it != yourProjectiles.end(); ++it)
{
window.draw(it->bullet);
}
内存管理
您没有释放内存。您必须研究动态内存分配。基本原则是对于每个新的都应该有一个删除。大部分时间应该在 class 的析构函数中处理释放部分。我想有人可能会建议使用智能指针(std::shared_ptr
)来管理你的记忆,但我不能推荐你这样做,因为你才刚刚开始。智能指针是一个您应该牢记的概念,但是在您开始时最好面对手动内存管理的困难(直到您习惯它)。
代码整理
一个class应该只用于一个目的。当您创建一个名为 Bullet 的 class 时,预计此 Bullet 将代表您游戏中的一个弹丸,但是当您的 Bullet 制造 "projectiles" 并存储弹丸时,它就变成了一个超自然实体。你的子弹 atm 持有指向其他子弹实例的指针,这些指针持有指向其他子弹实例的指针。这完全是一团糟。除非您想创建某种图形或树,否则您没有任何理由存储相同 class 实例的指针。
朋友太多
如果每个 class 都是每个 class 的朋友,那么您创建私有字段的原因是什么?朋友是一个非常强大的概念,应该小心使用,只有在你没有其他选择的情况下。我避免使用此关键字的唯一原因是它造成的混乱。它产生与 public 属性相同的效果。当一切都可以从任何地方访问时,一切都可以从任何地方被摧毁。当您创建一小组操作您的属性的方法时,您就会知道问题出在哪里。
结论
我可能建议多研究一下 C++,然后调试您的游戏,或者从头开始重新创建它。虽然我知道尝试新事物的感觉,但您应该始终小心,不要搬起石头砸自己的腿,并且在遇到此类错误时不要害怕回到基础。您在管理内存时遇到问题?阅读有关动态内存分配的更多信息,使用它做一些示例应用程序。除此之外,我注意到您仍处于开始使用 classes 的阶段。我会说熟能生巧。看看其他人的代码,甚至像 sfml 这样的第 3 方库也可能会给你一些关于好的 class 实践的提示。好处是不需要看那些库的源代码,你只需要使用它们的接口。如果你喜欢它,那就意味着它写得很好,你可以借鉴那种风格的一部分并在你的 classes 中实现。最后我要说的是,如果您有任何其他问题,我非常高兴并渴望通过电子邮件为您提供帮助。
我的 SFML 游戏出现严重问题。 我整天都在努力寻找解决方案,尝试了不同的方法,但到目前为止对我没有任何帮助。 这些是我的 .h 文件: Bullet.h
#pragma once
#include <SFML\Graphics.hpp>
#include <iostream>
#include <vector>
class Bullet
{
friend class Player;
friend class Game;
float width;
float height;
float x;
float y;
std::vector<Bullet*> projectiles;
sf::RectangleShape bullet;
void draw_projectiles(sf::RenderWindow &window);
void make_projectiles();
public:
void check();
Bullet();
~Bullet();
};
Game.h
#pragma once
#include <SFML\Graphics.hpp>
#include "Player.h"
#include "Bullet.h"
#include <vector>
//#include "Enemy.h"
class Game
{
friend class Player;
sf::RenderWindow* window;
sf::Event* evnt;
Player* player;
Bullet* bullet;
public:
void Loop();
void game_func();
Game();
~Game();
};
Player.h
#pragma once
#include <SFML\Graphics.hpp>
#include <iostream>
#include "Game.h"
#include "Bullet.h"
class Player
{
sf::RectangleShape player;
Bullet* bullet;
int ammo;
float width;
float height;
int x;
int y;
float vel;
public:
void draw(sf::RenderWindow &window);
void move(sf::Event &evnt, sf::RenderWindow &window);
Player();
~Player();
};
这里有cpp文件 Bullet.cpp
#include "Bullet.h"
void Bullet::check()
{
x = bullet.getPosition().x;
y = bullet.getPosition().y;
}
void Bullet::draw_projectiles(sf::RenderWindow &window)
{
for (int i = 0; i < 10; i++)
{
window.draw(projectiles[i]->bullet);
}
}
void Bullet::make_projectiles()
{
projectiles.push_back(new Bullet());
}
Bullet::Bullet()
{
std::cout << "zostal utworzony nowy obiekt" << std::endl;
width = 50;
height = 50;
bullet = sf::RectangleShape(sf::Vector2f(width, height));
bullet.setFillColor(sf::Color::Yellow);
bullet.setPosition(0, 0);
x = bullet.getPosition().x;
y = bullet.getPosition().y;
}
Bullet::~Bullet(){}
Game.cpp
#include "Game.h"
Game::Game()
{
window= new sf::RenderWindow(sf::VideoMode(1280, 720), "SFML Game",
sf::Style::Close);
player = new Player();
}
Game::~Game(){}
void Game::Loop()
{
while (window->isOpen())
{
sf::Event evnt;
while (window->pollEvent(evnt))
{
//events
if (evnt.type==sf::Event::Closed)
window->close();
player->move(evnt, *window);
window->clear();
player->draw(*window);
window->display();
bullet->draw_projectiles(*window);
}
}
}
void Game::game_func()
{
Game::Loop();
}
Player.cpp
#include "Player.h"
void Player::draw(sf::RenderWindow &window)
{
window.draw(player);
}
void Player::move(sf::Event &evnt, sf::RenderWindow &window)
{
x = player.getPosition().x;
y = player.getPosition().y;
float width = window.getSize().x;
float height = window.getSize().y;
Bullet obj;
if (evnt.type == sf::Event::KeyPressed)
{
//movement
if (evnt.key.code == sf::Keyboard::Key::W)
{
if (y <= 0)
{
return;
}
player.move(0, -1 * vel);
}
if (evnt.key.code == sf::Keyboard::Key::S)
{
if (y >= height - Player::height)
{
return;
}
player.move(0, 1 * vel);
}
if (evnt.key.code == sf::Keyboard::Key::A)
{
if (x <= 0)
{
return;
}
player.move(-1 * vel, 0);
}
if (evnt.key.code == sf::Keyboard::D)
{
if(x>width-Player::width)
{
return;
}
player.move(1 * vel, 0);
}
if (evnt.key.code == sf::Keyboard::Space)
{
obj.make_projectiles();
}
}
}
Player::Player()
{
width = 100;
height = 100;
vel = 10;
player = sf::RectangleShape(sf::Vector2f(width, height));
player.setFillColor(sf::Color::Red);
player.setPosition(sf::Vector2f(15, 20));
}
Player::~Player(){}
和main.cpp
#include <SFML/Graphics.hpp>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
#include "Game.h"
int main()
{
Game gme;
gme.game_func();
return 0;
}
我尝试了很多不同的东西,但无法弄清楚为什么它不起作用。我 运行 在 Visual Studio 15。 所以这是我得到的错误:
Exception thrown: read access violation.
std::_Vector_alloc<std::_Vec_base_types<Bullet *,std::allocator<Bullet *> >
>::_Mylast(...) returned 0x18.
我知道代码并不完美而且有点混乱,但我只是一个初学者,正在尝试学习新东西。 我将不胜感激任何帮助!
我相信您正试图访问十个射弹:
for (int i = 0; i < 10; i++)
{
window.draw(projectiles[i]->bullet);
}
但是你一次只能添加一个:
projectiles.push_back(new Bullet());
我在最后一段回答了你的问题,你可以跳到那一段,但我建议你看一下所有这些。首先,您应该了解基本游戏在代码中应该是什么样子。
游戏逻辑
您可以将游戏逻辑分为 2 个主要函数。初始化和循环。
初始化
在初始化函数中,您基本上将游戏所需的所有内容加载到 运行(这仅适用于小型游戏,因为在内存中加载数十个 sprite 可能不是大型游戏的最佳解决方案一个。随着时间的推移,你会找出加载和释放资源的正确时间)。
循环
这称为主循环或游戏循环。这个循环应该执行 3 个主要函数。 处理用户输入、更新世界并渲染世界。这个循环应该在游戏 运行ning 时执行(即当 window 打开时)
所以你的 main 在伪 C++ 中应该看起来像这样:
Init();
while (window.isOpen())
{
HandleEvents(window); //user input
Update(elapsedTime);
Render(window);
}
我将解释这些函数的作用、参数的含义以及这些函数如何映射到您的代码。请记住,每个功能都有一个特定的任务,而且仅此而已。当我在屏幕上绘制精灵时,我不会检查用户是否按下了按钮。
用户输入
从按下按钮和鼠标点击到按下退出按钮和调整 window 大小的一切都称为 用户输入 。用户的操作会生成所谓的 事件 ,我们会在每个循环开始时处理这些事件。现在此事件是 window 特定的(如果 window 最小化或未聚焦,您将无法控制播放器)。这意味着 window 会生成事件(如果我在技术上对这个事件有误,请纠正我)。这就是为什么在处理事件时需要传递 window 的原因。
事件
在处理事件之前,您需要了解 sf::Event 是如何制作的(请参阅 sfml
页面上的更多信息)。长话短说 sf::Event 是一个联合(一次只有一个字段有效)。也就是说,如果您在 window.pollEvent()
return 编辑 sf::Event::JoystickEvent
时尝试访问 event.key
,您将得到未定义的行为(我过着幸福的生活,但不知道联合是什么,从未使用过它们,可能永远也不会,但它们是一个非常有趣的概念,至少值得一读)。好的,通过调用 window.pollEvent()
并向其传递一个 sf::Event 实例来创建事件对象。此函数将从队列中为您提供事件,直到没有更多事件要提供为止,此时它 return 为 false。考虑到这一点,您的事件处理代码将类似于:
sf::Event ev;
while (window.pollEvent(ev))
{
switch (ev.type)
{
//code for each type needed by your application
}
}
请记住,关键事件不处理实时输入(sf::Keyboard::isKeyPressed
处理)。这意味着如果你想让你的角色在你按住一个按钮时移动,通过事件处理它会导致延迟,这可以用打字的方式最好地解释(当你按住 'a' 例如第一个字符被立即写入,其余输入在注册前延迟一秒)。这是一种解释它的方式,但可能不是最技术性的(我在这里寻求一点帮助:))。无论如何,这个问题可以通过使用 sf::Keyboard 的静态方法或在你的 Player class 中保留一个 bool
来解决 KeyPressed
和 [=24] =](将根据该布尔值处理更新)。
世界更新
这是您的逻辑代码(尽管玩家移动也可以在事件部分处理,因为它基于事件部分)。在这里你更新你的实体(根据他的 AI 将敌人移动一个方块),在地图上移动太阳等。请记住,这与绘图部分无关,在本节中你只改变你的状态对象。在您的游戏中,这意味着,在您通过用户触发的事件发射射弹后,您在每一帧移动射弹。此代码通常需要某种帧计数方法。
帧数
一帧是循环的迭代,你可以说游戏在每一帧更新和绘制自己。框架是一个非常重要的概念,因为它们会引起一些问题。如果游戏每帧更新自己,这意味着弹丸在移动的每一帧,这意味着他的移动取决于您的电脑可以达到的 FPS 运行。这是一个问题,因为虽然您的游戏可能 运行 在您的电脑上以稳定的 60 FPS 速率运行,但在我的游戏上它可能 运行 为 53 或其他随机值。这意味着我电脑上的射弹会移动得更慢,我们不希望这样。
帧独立运动
这可以通过计算帧数来实现。一种方法是计算自上一帧以来经过的秒数,考虑到这一点,您可以获得实体在该特定帧中需要移动的 space 量。例如,您想以 100 像素/秒的速度移动您的射弹。如果你有 2FPS,这意味着在 2 帧中它需要移动 100px,所以每帧移动 100 / 2
px。所以公式就是finalDistance / framerate
。有更多的方法可以做到这一点,但在我看来,这是一开始最容易理解的。那么这在 SFML 中是如何实现的呢?您基本上会保留一个时钟,在每次更新结束时重新启动。 getElapsedTime
并重新启动,但是重新启动 return 和 elapsedTime
所以最好调用一次,因为一个一个地调用它们可能会导致不同的时间和不同步。
sf::Clock clock;
while (window.isOpen())
{
HandleEvents(window);
Update(clock.restart());
Render(window);
}
并且您只需使用 move(vector * clock.getElapsedTime().asSeconds())
移动您的实体,因为 sf::Vector
为浮点数(asSeconds()
的 return 类型)超载了 operator*
。
渲染
渲染部分可能会很复杂,但是sfml
就可以了"simple and fast"。基本上它是这样工作的:清除屏幕,绘制实体,显示屏幕。更具技术性的答案如下:window 包含 2 个缓冲区,一个可见,一个隐藏。可见的是您在屏幕上看到的那个。当您调用 clear()
时,您基本上清除了隐藏的,draw()
也在隐藏的 window 上绘制,最后 display()
交换缓冲区。
这意味着除非您调用 window.display()
,否则您将看不到任何结果,如果您在绘图前不调用 clear()
,您将获得 window xp 体验。所以 Render 函数可能看起来像这样:
window.clear();
window.draw(player); //or player.draw(window) based on your implementation
//other draws
window.display();
你的问题
您的代码中发生的事情是您尝试访问不存在的内容。您一次添加一个抛射物,但每帧绘制 10 个。
解决方法
记录您的对象。由于您使用的是已经提供的矢量,因此您 std::vector::size
return 正是您所期望的,因此您的代码将变成如下内容:
for (int i = 0; i < yourProjectiles.size(); i++)
{
window.draw(yourProjectiles[i]->bullet);
}
或者你可以使用迭代器(查找它们):
for (auto it = yourProjectiles.begin(); it != yourProjectiles.end(); ++it)
{
window.draw(it->bullet);
}
内存管理
您没有释放内存。您必须研究动态内存分配。基本原则是对于每个新的都应该有一个删除。大部分时间应该在 class 的析构函数中处理释放部分。我想有人可能会建议使用智能指针(std::shared_ptr
)来管理你的记忆,但我不能推荐你这样做,因为你才刚刚开始。智能指针是一个您应该牢记的概念,但是在您开始时最好面对手动内存管理的困难(直到您习惯它)。
代码整理
一个class应该只用于一个目的。当您创建一个名为 Bullet 的 class 时,预计此 Bullet 将代表您游戏中的一个弹丸,但是当您的 Bullet 制造 "projectiles" 并存储弹丸时,它就变成了一个超自然实体。你的子弹 atm 持有指向其他子弹实例的指针,这些指针持有指向其他子弹实例的指针。这完全是一团糟。除非您想创建某种图形或树,否则您没有任何理由存储相同 class 实例的指针。
朋友太多
如果每个 class 都是每个 class 的朋友,那么您创建私有字段的原因是什么?朋友是一个非常强大的概念,应该小心使用,只有在你没有其他选择的情况下。我避免使用此关键字的唯一原因是它造成的混乱。它产生与 public 属性相同的效果。当一切都可以从任何地方访问时,一切都可以从任何地方被摧毁。当您创建一小组操作您的属性的方法时,您就会知道问题出在哪里。
结论
我可能建议多研究一下 C++,然后调试您的游戏,或者从头开始重新创建它。虽然我知道尝试新事物的感觉,但您应该始终小心,不要搬起石头砸自己的腿,并且在遇到此类错误时不要害怕回到基础。您在管理内存时遇到问题?阅读有关动态内存分配的更多信息,使用它做一些示例应用程序。除此之外,我注意到您仍处于开始使用 classes 的阶段。我会说熟能生巧。看看其他人的代码,甚至像 sfml 这样的第 3 方库也可能会给你一些关于好的 class 实践的提示。好处是不需要看那些库的源代码,你只需要使用它们的接口。如果你喜欢它,那就意味着它写得很好,你可以借鉴那种风格的一部分并在你的 classes 中实现。最后我要说的是,如果您有任何其他问题,我非常高兴并渴望通过电子邮件为您提供帮助。