I'm pretty new to C++ and just getting started with pointers and such. I'm making a simple game with SFML. I've made a vector "drawList" to store all the shapes in the game that will be rendered on screen. If I add the shapes to the vector before the main loop starts it works fine, however when I add objects at runtime I get an Access violation error on the following code:
for (size_t i = 0; i < drawList.size(); i++){
window.draw(*drawList[i]);
}
I think that the *drawlist[i] is an invalid pointer, however attempts to fix the issue so far have been unsuccessfull. The drawList vector and the method to add objects to it are setup like this in a header:
extern std::vector<const sf::Drawable*> drawList;
struct Globals {
void AddDrawable(const sf::Drawable &drawable);
};
and like this in the associated cpp:
std::vector<const sf::Drawable*> drawList;
void Globals::AddDrawable(const sf::Drawable & drawable){
drawList.push_back(&drawable);
}
I then try to add a shape to the vector in the constructor of a newly instatiated projectile class by calling the "AddDrawable" method and giving it the following method as parameter:
sf::RectangleShape& GetShape() { return shape; };
I feel like there is something really obvious going wrong with the references and pointers of things but so far I've not been able to figure it out. If anyone could suggest me ways to adress this issue it would be greatly appriciated. Thanks in advance!
EDIT:
I'll try to give some more context on Cris Luengo's suggestion, I have a main.cpp containing the main while loop. Before that while loop is initiated I instantiate a Player and a Projectile class. Inside the while loop I check if there is anything to update and draw in a forloop like so:
int main() {
Projectile bullet = Projectile(WINDOW_WIDTH /2.f, WINDOW_HEIGHT /2.f, 0.05f, 0.05f);
Player player = Player(WINDOW_WIDTH / 2.f, WINDOW_HEIGHT / 1.2f);
while (true) {
window.clear(Color::Black);
if (Keyboard::isKeyPressed(Keyboard::Key::Escape)) break;
for (size_t i = 0; i < updateList.size(); i++){
updateList[i]();
window.draw(*drawList.at(i));
}
window.display();
The updateList and drawList are both vectors that get filled from the constructors of the Player and the Projectile classes like so (This is identical for both the player and the projectile constructor respectively):
Projectile::Projectile(float mX, float mY, float velX, float velY){
velocity = sf::Vector2f(velX, velY);
GetShape().setPosition(mX, mY);
//other shape stuff
Globals globals;
updateIndex = globals.AddToUpdateList([this]() {Update(); });
globals.AddDrawable(GetShape());
}
As shown earlier, the GetShape() method is setup in the Player and Projectile headers like like this:
sf::RectangleShape& GetShape() { return shape; };
As it stands right now, this code works when I instantiate the objects to be added to the drawList before the while loop starts. If I read new data to it at runtime, when it is also being read, the program throws an access violation error in the forloop when the drawList is being accessed.
I use the same code when adding things to the drawList at runtime. I simply instantiate a new Projectile on a button press. The idea is that the constructor of the instantiated class adds the needed data to the lists (The updateList works fine)
Thank you in advance
Related
I am fairly new to SFML and am trying to make a scrolling plane game that shoots out a bullet whenever I press the spacebar. I've gotten all of the movement working, but I'm trying to figure out how to put the bullets into another class file so that I can have a whole set of them later on (I.E. create.bullet(), create.missle(), etc.). Here is the code that I have now.
void create::bullet(int xPos, int yPos)
{
sf::Texture bulletTexture;
if(!bulletTexture.loadFromFile("bullet.png"))
cout << "There was an error loading the bullet texture file." << endl;
sf::Sprite bulletSprite;
bulletSprite.setTexture(bulletTexture);
bulletSprite.setPosition(xPos, yPos);
window.draw(bulletSprite);
}
I have the sf::RenderWindow instance called window in the main class, but I apparently can't reference it directly from another class. I haven't been able to implement velocity yet either, but I should be able to do that. Another thing that I need help with however, is getting it so that there is no limit on the number of bullets that can be fired. It seems like if I just have this function run whenever spacebar is pressed, it will just reset the sprite to the new position and get rid of the old one. Thanks for the help!
First of all, loading textures from files is slow. You should do it once when the program or level starts, and store the texture somewhere.
Instead of a Create class, make a Bullet class. Then, you can have a vector of bullets (or pointers/smart pointers to them). Each time you want a new bullet, you just push_back() it to the vector. If a bullet needs to be destroyed you erase() it. Then, for the game itself, you need to call Move() for every bullet and then Draw() for every bullet in the vector. Once you have that done, you can add the collision detection and so on.
You also have a choice - each bullet can have its own sf::sprite and modify it, or you can have one sf::sprite for each game sprite and reposition it for every bullet.
Personally, I'm using the second approach. My Bullet class looks like this:
Bullet::Bullet(std::string ntype, double nx, double ny, double nvx, double nvy):
type(ntype), x(nx), y(ny), vx(nvx), vy(nvy)
{
angle=atan2(vy, vx)*(180/M_PI);
}
void Bullet::Move()
{
x+=vx;
y+=vy;
};
void Bullet::Draw()
{
DrawSprite(type, x, y, angle+90);
};
In the separate .cpp file, I have a string ordered map of sf::sprites. My draw function looks like this:
void DrawSprite(std::string type, float x, float y, float angle)
{
sf::Sprite temp=sprites[type];
temp.setRotation(angle);
temp.setPosition(x, y);
window.draw(temp);
}
First of all let me prefix this question with the following points:
1) I have searched Stackexchange for this issue, most of the code presented was difficult enough for me to follow in order to warrant Asking a new Question/Opening a new Thread about this. The closest i could find was this Creating multiple class objects with the same name? c++ and unfortunately this is way past my scope of understanding
2) http://www.cplusplus.com/doc/tutorial/classes/ has not really discussed this or i have missed it.
Now that this is out of the way:
Rectangle Class code:
class Rectangle {
private:
int lineNumber;
float valueMax;
float valueMin;
public:
Rectangle(SCStudyInterfaceRef sc, int lineNumber, float valueMax, float valueMin);
int getLineNumber(); // member function of class
float getValueMax(); // member function of class Rectangle
float getValueMin(); // member function of class Rectangle
};
Rectangle::Rectangle(SCStudyInterfaceRef sc, int lineNumber0, float value1, float value2) {
lineNumber = lineNumber0;
int value2_greater_than_value1 = sc.FormattedEvaluate(value2, sc.BaseGraphValueFormat, GREATER_OPERATOR, value1, sc.BaseGraphValueFormat);
if (value2_greater_than_value1 == 1) {
valueMax = value2;
valueMin = value1;
} else {
valueMax = value1;
valueMin = value2;
}
}
int Rectangle::getLineNumber() {
return lineNumber;
}
float Rectangle::getValueMax() {
return valueMax;
}
float Rectangle::getValueMin() {
return valueMin;
}
And here is the more important part, this code is running pretty much in a loop and will repeat everytime a certain event triggers it:
bool xxx = Conditions here
if (xxx) {
// Draw new rectangle using plattforms code
code here
// Save rectangle information in the list:
Rectangle rect(sc, linenumbr + indexvalue, high, low);
(*p_LowRectanglesList).push_back(rect);
}
bool yyy = conditions here
if (Short) {
// Draw new rectangle using plattforms code
code here
// Save rectangle information in the list:
Rectangle rect(sc, linenumber + indexvalue, high, low);
(*p_HighRectanglesList).push_back(rect);
}
So the question is the following:
Since this is looped everytime an event triggers the second part of the code is going to be run, the bool condition is going to be checked, if its true its going to use plattform integrated code to draw a rectangle. Once it has drawn it this information is going to be passed to a new rectangle object/instance based on the Rectangle Class in the first part of the code using the: Rectangle rect(sc, linenumber + indexvalue, high, low); part and then save that information in a list which is in a different part of the code for now and irrelevant.
What exactly happens when there is a new Bool = True condition and the code gets executed after it has already been executed? Will the old rectangle object be simply replaced with a new rectangle object with the same name and using the new parameters (since they change on every instance due to the way the code is written)? Or are there now two objects of the Rectangle Class using the same name "rect" ?
It's technically speaking not even that important to me since the information of the parameters should be pushed into a list anyways using the (*p_HighRectanglesList).push_back(rect); part of the code
So TL;DR:
Does "rect" get destroyed/overwritten or are there now potentially limitless amounts of Rectangle Objects/Instances called "rect" floating around?
My Apologies for the wall of text but being a complete noob i thought it would be best to outline my thought process so that it will be easier for you to correct me on where I'm wrong.
Kind regards,
Orbital
Yes, rect is destroyed and recreated every loop. In C++, the scope of any variable declared in a block (in this case an if() statement) is limited to that block. Every time your program iterates, you get a new rect, and the old rect is gone.
To add, whenever you call NEW, you are basically allocating memory and creating Rectangle objects. NEW will allocate address to each instance. The pointer *rect will be pointing to the current memory address, and when you call rect with NEW again, now rect will be pointing to the new memory address the previous address becomes a NULL reference. However in C++ you have to worry about memory leaks unlike Java where you have a garbage collector.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I'm creating a 2D game using the Qt Framework. Although I do have some experience in some other languages, C++ is a kind of new language for me.
My first question is about the monsters. How should I initialize(and store them) ? Every level of my game has a different number of mobs. At this moment I initialize them in this way:
Monster *mobs;
mobs = new Monster[mobsQuantity];
But I am not sure this is the best way to do it. Also, every second, every mob positioned on the map must move by 1 position. This is the function that should move the mobs.
void MainWindow::moveMobs(){
int random[mobsQuantity]; // Different random position move for each monster.
for(int a = 0; a < mobsQuantity; a++){
random[a] = qrand() % 5; // Initialize the moves
}
for(int a = 0; a < mobsQuantity; a++){
int x = mobs[a].x();
int y = mobs[a].y(); // Take the position for each different mob
switch(random[a]){
case NORTH:
// Collision detection and movement
break;
case SOUTH:
// Collision detection and movement
break;
case WEST:
// Collision detection and movement
break;
case EAST:
// Collision detection and movement
break;
}
}
}
Is there any better way to do this?
My 2nd problem is passing the Monster class to a function. Monster is derived from QGraphicsItem. I have a function in the Main Window which sets the right position for each mob and then add it to the QGraphicsScene. My code looks like this:
void MainWindow::createMobs(){
for(int a = 0; a < mobsQuantity; a++){
mobs[a].setPos(/* X pos */ , /* Y pos */);
scene->addItem(mobs[a]);
}
}
The error comes from adding the item to the scene. How should I properly pass an element of a dinamically allocated array as a pointer ?
error: no matching function for call to 'QGraphicsScene::addItem(Monster&)'
I tried adding it like this:
scene->addItem(&mobs[a]);
But my program crashes.
Thanks for everyone who will try to help me.
#Austin is right in that using a vector or list would be much better for you to use than a plain array, though I'd use a QVector rather than std::vector if you're using Qt. Both work, but that's my preference.
Also, games in C++ often use an architecture of objects updating themselves in an update loop. So you'd have a main game loop that just calls an update function for the Monsters. Something like this skeleton code: -
class Monster : public QGraphicsObject // note QGraphicsObject instead of Item so we have signals and slots too!
{
void Update()
{
// move the monster according to rules
// check for colliding objects
}
};
Then in your main game loop
QList<QMonster*> pMonsterList = GetMonsters(); // from CLevel shown by #Austin
QMonster* pMonster;
foreach(pMonster, monsterList)
{
pMonster->Update();
}
Now, if you create a base class, let's call it GameObject which is derived from QGraphicsObject you can then have all moveable objects run with the same architecture.
class GameObject : public QGraphicsObject
{
virtual void Update() = 0; // move object
};
class Monster : public GameObject
{
void Update();
};
So you'd now just update all objects from the level with something like this: -
CLevel::Update()
{
QList<GameObject*> gameObjectList = GetGameObjects();
GameObject* pGameObj;
foreach(pGameObj, gameObjectList)
{
pGameObj->Update();
}
}
Seems like using std::vector<Monster*> or qvector<Monster*> is the best bet. Example:
//header example for CLevel
class CLevel:
CLevel();
std::vector<Monster*> *GetMonsters() {return &mMonsterVector;}
void CreateMonsters(int NumberOfMonsters);
private:
std::vector<Monster*> mMonsterVector;
};
//cpp file
void CLevel::CreateMonsters(int NumberOfMonsters){
//make this a method in the level class
for(int i = 0; i < NumberOfMonsters; i++){
Monster *newMob = new Monster;
//Fill in the monster properties
newMob->FillProperties();
//end monster properties
mMonsterVector.push_back(newMob);
}
}
For the 2nd question, it is hard to diagnose without seeing all the code, but if the code is crashing after passing a pointer (which &array[a] is), then the pointer doesn't exist or hasn't been initialized or has been de-initialized. Perhaps the array was allocated in a function that has been de-allocated after the function is called since the compiler cleaned it up.
I am doing an assignment for the university course and me and my partner have a problem. Program we are making is a game.
We have several classes, which all inherit from the base class, called Creature. These are all enemies player needs to deal with and they all run their own AIs. There are 4 different types of child classes, all within namespace Creature(Including parent, Creature), with one class having special functions that only it needs. This class is called Bunny.
Now, my job is to call AI functions as needed. Problem is, I do not always know what class I am calling out, as such, when I ask the game board to tell me what Creature I get.
All enemies are saved as pointers like so, in game board squares:
struct Square
{
// Pointers to Morso class, where the enemy is saved
Creature::Creature* creature;
//Undeeded stuff removed
};
Now, this is all and fine until we need to access to special functions. Pupu will multiply if certain conditions are filled. As such, with in Pupu there are few functions I need to call to make sure it carries out it's act correctly.
However, here comes the problem.
I call our board class to give me the creature that is in the coordinates I give to it.
void GameEngine::GameEngine::runAI()
{
Creature::Creature* creature= NULL;
for(unsigned int y = 0; y < dimY; y++)
{
for(unsigned int x = 0; x < dimX; x++)
{
Coordinate target;
target.setX(x);
target.setY(y);
creature= board_->returnCreature(target);
//If there is a creature in the target, run its AI
if(creature!= NULL)
{
//If it is, check special procedures
if(creature->returnType() == "bunny")
{
bunnyReproduce(creature);
}
creature->ai();
}
}//for x
}//for y
}
Now, :
void GameEngine::GameEngine::bunnyReproduce(Ccreature::Creature* creature)
{
//Checks that it really is a bunny
if( creature->returnType() != "bunny"){ return; }
//Check is there another bunny near
creature->checkForMate();
}
The problem is, creature, at this point, can't call for checkForMate, which is public member of Bunny, but not Creature. Do we need to make virtual function into Creature?
I tried making checkForMate into Creature::Bunny, but since the original value I try to give to it is Creature class, I can't do so. Do we need to to create an empty virtual function in Creature class and then override it it Bunnyclass?
I am running Qt Creator 2.7.0, with QT 5.0.2.
You should add virtual function reproduce to Creature class and implement it in Bunny or any other creature you may later add to the game. So that any creature will reproduce itself in it's own way. You don't even need to check creature type in this case. Since if you have some non reproducible creatures, you may just implement reproduce as empty method that will do nothing.
Ideally, your engine shouldn't need to care at all what kind of creature it's working with.
If you want the bunny to reproduce on each ai() step, why not do it in the bunny's ai()?
After all, shouldn't it be the bunny's responsibility to decide when to reproduce, rather than some almighty external Engine?
void Creature::Bunny::ai()
{
if (niceMateNearby())
reproduce();
else
eatCarrotsAndJumpAround();
}
I am making a snake game. I have two classes, snake and food. When I call snake->move() it needs to check that there are no collisions and for this purpose it needs to know what food's position is and therefore requires a pointer to food. food has a function that moves it to a new random position, move->setNewPosition(), which needs to know the position of snake so that it doesn't collide with the snake when it moves. For this purpose, it requires a pointer to snake.
Therefore, for both classes, I would need to supply a pointer to the other class which must be initialised. But to initialise the other class I need to initialise the other class and so on. Is there any way to initialise two classes, that require pointers to each other, at the same time?
If not, what would be a better way of structuring my program that would allow me to check the coordinates of the other class?
If i don't misunderstand you, create init function that call before game loop starts:
void initSnake()
{
auto snake = new Snake();
auto food = new Food();
snake->setFood(food);
food->setSnake(snake);
}
They just need the facility to find the location of other snakes and food items when their movement functions are invoked. There's no need to know of their existence at initialisation time!
You can therefore have a collection of snakes and a collection of food items, and pass a reference to those collections to any newly created snakes and food items. Just create those collections first.
You could do this via another class, perhaps, which could also act as a factory.
class GameManager;
class Snake
{
friend class GameManager;
public:
int getX() { return _x; }
int getY() { return _y; }
void setPosition(int x, y) { /* ... */ }
private:
Snake(GameManager* manager, int x, int y) : _manager(manager), _x(x), _y(y) {}
GameManager* _manager;
int _x, _y;
};
class GameManager
{
public:
const std::vector<Snake*>& Snakes() { return _snakes; }
Snake* SpawnSnake(int x, int y)
{
Snake* newSnake = new Snake(this, x, y);
snakes.push_back(newSnake);
return snake;
}
private:
std::vector<Snake*> _snakes;
};
(Just an example. Code not tested to see if it actually compiles. E&OE)
The GameManager ensures that all created snakes are found in the snakes vector because the Snake constructor is private. Each snake can call _manager.Snakes() to get a vector containing all the other snakes in the game which it can then query individually for their positions. This is easily generalised to support food items as well.
This has the small advantage over the "construct-initialise" pattern suggested in other answers in that it ensures that when you get a new Snake object it is actually ready for use... this example isn't quite RAII, but it would require a minimum of effort to make it reasonably exception-safe.
You can define one base class for them, which has these methods:
virtual void setPosition(const int x, const int y)
virtual void getPosition(int &x, int &y) const
Snake should use them too, just override them if you need to. Now both classes can call each other's setPosition and getPosition directly if you give the other object as a parameter with type Base.
An other way would be; In your main()-function, or wherever you define your snake:
int main()
{
Snake* s = new Snake;
Food* f = new Food;
Snake->setLocation(0,0); // Wherever you want the snake to start from
}
And whenever you create a new food, give it snake's location: f->setRandomLocation(snake->getLocation()) where the parameter would be coordinates where NOT to place it.
One alternative would be to have a Manager class which both of them send their requests to, which would make more sense (but doesn't solve your particular problem).
Nevertheless, if you have class A and class B, and each one needs the other, you can do the following:
A *a = new A;
B *b = new B;
// check a and b to make sure they are not NULL
a->set_b(b);
b->set_a(a);
Mmn, not sure how your game works but I assume there would be a lot of food objects?
Maybe an idea would be to create a Collision class that accepts a Snake player and stores all the Food players in the game.
So the Collision constructor might look like this
Collison(Snake &snake, Vector<Food*> &foods)
{
}
The Collision class would also have an collision update to loop that you call somewhere in your code.. This loop would check if the snake object collides with a food object.. and you can do whatever you want.. remove the food from the foods vector change the food position, whatever.
collison.UpdateCollisions() ;
I would suggest breaking the cyclic dependency, instead of hammering it in: make both moving functions take the environment (i.e. a list of things it can collide with) as a parameter.