How do I create a vector which stores all the instances of a class? Then how do I iterate over them and call one of their member functions?
Here's a condensed example of what I've been trying to do.
#include <vector>
struct Entity{
Entity::Draw(){
// do drawing things
}
};
static std::vector<Entity> entities;
Entity player;
Entity enemy;
void renderEntities() {
for (std::vector<Entity>::iterator iter = entities.begin();
iter < entities.end();
iter++) {
iter->Draw; // Error in the example. I'm using Draw(); in the actual code.
}
But renderEntities() isn't doing anything. The Draw member function works, if I use e.g. player->Draw. I'm either screwing up the vector or the iterator or both and I can't figure out how to fix it. I've tried using references and pointers, which I assume is the thing to do, but whenever I try that I get errors that I haven't been able to fix.
UPDATE: I appreciate all the help, I'm learning a lot. However my render_entities function still isn't doing anything. Here's all the code.
Any function call that starts with terminal_ is from the BearLibTerminal library.
main.cpp
#include <BLT/BearLibTerminal.h>
#include <iostream>
#include <string.h>
#include <vector>
#include "entity.h"
const int WindowSizeX{50};
const int WindowSizeY{20};
const std::string Title{"BLT Test"};
const std::string Font{"../res/SourceCodePro-Regular.ttf"};
const int FontSize{24};
bool quit_game{false};
static Entity player;
static Entity enemy;
void initialize();
void handle_input(int key, Entity &entity);
void draw_player(int x, int y, const char *symbol);
void render_entities();
void clear_entities();
int main() {
initialize();
while (!quit_game) {
terminal_refresh();
int key{terminal_read()};
if (key != TK_CLOSE) {
handle_input(key, player);
}
else {
quit_game = true;
break;
}
clear_entities();
}
terminal_close();
return 0;
}
void initialize() {
terminal_open();
std::string size{"size=" + std::to_string(WindowSizeX) + "x" +
std::to_string(WindowSizeY)};
std::string title{"title='" + Title + "'"};
std::string window{"window: " + size + "," + title};
std::string fontSize{"size=" + std::to_string(FontSize)};
std::string font{"font: " + Font + ", " + fontSize};
std::string concatWndFnt{window + "; " + font};
const char *setWndFnt{concatWndFnt.c_str()};
terminal_set(setWndFnt);
terminal_clear();
player.x = 0;
player.y = 0;
player.layer = 0;
player.symbol = "P";
player.color = "green";
enemy.x = 10;
enemy.y = 10;
enemy.layer = 0;
enemy.symbol = "N";
enemy.color = "red";
}
void handle_input(int key, Entity &entity) {
int dx{0};
int dy{0};
switch (key) {
case TK_LEFT:
case TK_H:
dx = -1;
dy = 0;
break;
case TK_RIGHT:
case TK_L:
dx = 1;
dy = 0;
break;
case TK_UP:
case TK_K:
dx = 0;
dy = -1;
break;
case TK_DOWN:
case TK_J:
dy = 1;
dx = 0;
break;
case TK_Y:
dx = -1;
dy = -1;
break;
case TK_U:
dx = 1;
dy = -1;
break;
case TK_B:
dx = -1;
dy = 1;
break;
case TK_N:
dx = 1;
dy = 1;
break;
case TK_ESCAPE:
quit_game = true;
break;
}
player.Move(dx, dy);
if (player.x > WindowSizeX - 1) {
player.x = WindowSizeX - 1;
}
else if (player.x < 0) {
player.x = 0;
}
if (player.y > WindowSizeY - 1) {
player.y = WindowSizeY - 1;
}
else if (player.y < 0) {
player.y = 0;
}
player.Draw(); // This works.
enemy.Draw(); // So do this.
entity.Draw(); // This draws only player.
render_entities(); // This doesn't do anything.
// Player X and Y are printed out correctly, Entities is always 0.
std::cout << "Player X: " << player.x << std::endl;
std::cout << "Player Y: " << player.y << std::endl;
std::cout << "Entities: " << entities.size() << std::endl;
}
void render_entities() {
for (auto entity : entities) {
entity->Draw();
}
}
void clear_entities() {
for (auto entity : entities) {
entity->Clear();
}
}
entity.h
#ifndef ENTITY_H_
#define ENTITY_H_
struct Entity {
int x;
int y;
int layer;
const char *symbol;
const char *color;
Entity();
~Entity();
void Move(int dx, int dy);
void Draw();
void Clear();
};
static std::vector<Entity *> entities;
#endif /* ENTITY_H_ */
entity.cpp
#include <BLT/BearLibTerminal.h>
#include <vector>
#include <algorithm>
#include "entity.h"
Entity::Entity() {
entities.push_back(this);
}
// Entity(const Entity &) : Entity() {}
// I get an "expected unqualified-id" when I uncomment this. Why?
Entity::~Entity() {
auto iter = std::find(entities.begin(), entities.end(), this);
if (iter != entities.end())
entities.erase(iter);
}
void Entity::Move(int dx, int dy) {
this->x += dx;
this->y += dy;
}
void Entity::Draw() {
terminal_layer(this->layer);
terminal_color(color_from_name(this->color));
terminal_print(this->x, this->y, this->symbol);
}
void Entity::Clear() {
terminal_layer(this->layer);
terminal_print(this->x, this->y, " ");
}
In main.cpp, at the bottom of handle_input() you will see...
player.Draw(); // This works.
enemy.Draw(); // So do this.
entity.Draw(); // This draws only player.
render_entities(); // This doesn't do anything.
// Player X and Y are printed out correctly, Entities is always 0.
std::cout << "Player X: " << player.x << std::endl;
std::cout << "Player Y: " << player.y << std::endl;
std::cout << "Entities: " << entities.size() << std::endl;
renderEntities()does not do anything because you didn't add anyEntityobjects to thevector. When you declare yourplayerandenemyobjects, they are just hanging around in memory, they are not automatically added to thevector. You need to add them explicitly, such as by callingentities.push_back().I would suggest using the
Entityconstructor and destructor to update thevectorautomatically, instead of you having to remember to do it manually. That way, everyEntityobject is accounted for byrenderEntities(), eg:Live Demo
UPDATE: after seeing your full code, I can see that you are still making some mistakes.
In
main.cpp, there is noentityvariable in scope ofhandle_input(), so callingentity.Draw()should not compile.The really big mistake is in
entity.h, though. DO NOT declare yourentitiesvariable asstaticin that file! This causes every.cppwhich#include's yourentity.hfile to get its own copy of the variable. This means thatmain.cppandentity.cppare operating on separatestd::vectorobjects! That is why you seeentitiesis always empty inmain.cpp- theEntityobjects are never being added to thestd::vectorthat exists inmain.cpp, only to thestd::vectorthat exists inentities.cpp.You need to move the actual
std::vectorvariable intoentity.cpp(withoutstatic), and then declare the variable asexterninentity.hso that all of your.cppfiles can access and share that single variable.Try this instead:
entity.h
entity.cpp