Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Nothing is drawn (inheriting from Drawable)  (Read 1615 times)

0 Members and 2 Guests are viewing this topic.

mentor

  • Newbie
  • *
  • Posts: 31
    • View Profile
Nothing is drawn (inheriting from Drawable)
« on: April 10, 2015, 01:35:26 am »
Hello,

I'm starting this little project and I started with writing a Room class. Room is a single board that we see in the game, like a street, a lab room. Room consists of layers. This should allow me to do some nice work with z order. I don't know how many layers each room will have - one could have only 2 layers, second 5 layers and third 3 layers. So creating a simple array with a constant number of elements wouldn't do the trick, it would be useless consuming too much memory. Therefore I thought about vector. But personally I don't really like vector, it also can consume much memory. I decided to create my own easy template class for some dynamic array. I did that and I think it works okay right now (although there are some things that I could improve, but that's not a matter of my problem). Once I created my dynamic array class I, of course, began writing Room class. I started with a constructor, deconstructor and a method for adding layers. I've done drawing by making Room class inherit from Drawable (so in the game loop I can do something like this: window.draw(myroom)). I overrode draw method correctly, I think... And so, I created a Room object and I added one layer to it, pressed F7, then F5 and... Nothing is drawn. There's only a white sprite in the place where my background should be visible. This white sprite's position is the same as the position given in the parameter in the add layer function, so I think it kinda works... Something there works, but something doesn't. And I have no idea what doesn't. Here's the complete code I have (it's not long):

DArray.h
Code: [Select]
#ifndef DARRAY_H
#define DARRAY_H

#include <iostream>

using namespace std;

template<class Foo>
class DArray {
private:
struct node {
Foo data;
node* ptr;

node(Foo d) {
data = d;
ptr = NULL;
}
};
node* first;
int counter;

public:
DArray();
~DArray();
void push(Foo d);
Foo pop();
int size() const;
bool empty();
Foo& operator[](int i) const;
};

template<class Foo>
DArray<Foo>::DArray() {
first = NULL;
counter = 0;
}

template<class Foo>
DArray<Foo>::~DArray() {
while (!empty())
pop();
}

template<class Foo>
void DArray<Foo>::push(Foo d) {
if (empty()) {
first = new node(d);
}
else {
node* tmp = first;
while (tmp->ptr != NULL)
tmp = tmp->ptr;
tmp->ptr = new node(d);
}
counter++;
}

template<class Foo>
Foo DArray<Foo>::pop() {
if (!empty()) {
Foo d;
node* tmp;
tmp = first;
first = first->ptr;
d = tmp->data;
delete tmp;
return d;
}
}

template<class Foo>
int DArray<Foo>::size() const {
return counter;
}

template<class Foo>
bool DArray<Foo>::empty() {
if (first == NULL)
return true;
else
return false;
}

template<class Foo>
Foo& DArray<Foo>::operator[](int i) const {
node* tmp = first;

for (int j = 1; j < i+1; j++) {
tmp = tmp->ptr;
}

return tmp->data;
}

#endif

Room.h
Code: [Select]
#ifndef ROOM_H
#define ROOM_H

#include <SFML\Graphics.hpp>
#include "DArray.h"

using namespace sf;
using namespace std;

struct Layer {
Texture tex;
Sprite spr;
//id, name

Layer() { }

Layer(const string path, Vector2f pos) {
tex.loadFromFile(path);
spr.setTexture(tex);
spr.setPosition(pos);
}
};

class Room : public Drawable {
private:
DArray<Layer> layers;
//int id;
//string name;

virtual void draw(RenderTarget& target, RenderStates states) const {
for (int i = 0; i < layers.size(); i++) {
target.draw(layers[i].spr, states);
}
}

public:
Room();
~Room();
void AddLayer(const string path, Vector2f pos);
//void RemoveLayer();
//show layers' names
};

#endif

Room.cpp
Code: [Select]
#include "Room.h"

Room::Room() {

}

Room::~Room() {

}

void Room::AddLayer(const string path, Vector2f pos) {
layers.push(Layer(path, pos));
}

GameApp.h
Code: [Select]
#ifndef GAMEAPP_H
#define GAMEAPP_H

#include <SFML\Graphics.hpp>
#include <iostream>
#include "Room.h"

using namespace sf;
using namespace std;

class GameApp {
private:
RenderWindow win;
bool fullscreen;
Event evt;
double dt, dwticks, dwnewticks;
Clock main_clock;

public:
GameApp();
~GameApp();
void Run();
//void ToggleFullscreen();
};

#endif

GameApp.cpp
Code: [Select]
#include "GameApp.h"

GameApp::GameApp() {
fullscreen = false;
dt = dwticks = dwnewticks = 0.f;

win.create(VideoMode(800, 600), "PNC", fullscreen ? Style::Fullscreen : Style::Default);
win.setFramerateLimit(60);
win.setVerticalSyncEnabled(true);
win.setMouseCursorVisible(true);
}

GameApp::~GameApp() {

}

void GameApp::Run() {
main_clock.restart();
dwticks = main_clock.getElapsedTime().asMilliseconds();

Room str;
str.AddLayer("data/rooms/str/gfx/bgr.jpg", Vector2f(0, 50));

while (win.isOpen()) {
if (win.pollEvent(evt)) {
if (Keyboard::isKeyPressed(Keyboard::Key::Escape) ||
evt.type == Event::Closed) {
win.close();
}
}
else {
dwnewticks = main_clock.getElapsedTime().asMilliseconds();
dt = dwnewticks > dwticks ? (dwnewticks - dwticks) / 4000.f : 0.f;
dwticks = dwnewticks;

win.clear(Color(0, 0, 0));
win.draw(str);
win.display();
}
}
}

main.cpp
Code: [Select]
#include "GameApp.h"

int main() {
GameApp game;

game.Run();

return 0;
}

When I replaced the const string path parameter in Layer constructor with Texture& t (and also did the same changes in add layer method) and then in the Run() method in GameApp class I created a texture:

Code: [Select]
Texture t;
t.loadFromFile("data/rooms/str/gfx/bgr.jpg");

and passed it to the parameter as this:

Code: [Select]
Room str;
str.AddLayer(t, Vector2f(0, 50));

it did the trick. Background shows correctly that way. But I want it to work also with that string parameter.

I'd be forever ashamed if I did something really stupid.

zsbzsb

  • Hero Member
  • *****
  • Posts: 1409
  • Active Maintainer of CSFML/SFML.NET
    • View Profile
    • My little corner...
    • Email
Re: Nothing is drawn (inheriting from Drawable)
« Reply #1 on: April 10, 2015, 01:46:36 am »
Your problem is because you copy your "layer" when adding it to your "room". This then results in the texture owned by "layer" being copied and but the sprite still points at the old texture that is now no longer exists.

This is a common mistake. When you set the texture of a sprite, all it does internally is store a pointer to the texture instance. Therefore, if the texture is destroyed or moves elsewhere in memory, the sprite ends up with an invalid texture pointer.

By the way, why are you basically implementing your own vector class? The std::vector<T> class is more than suitable for what you are doing here, it will probably even be faster. The way you are doing it is almost like a vector combined with a linked list, yet at the same time not. It really doesn't make much sense.
« Last Edit: April 10, 2015, 02:18:05 am by zsbzsb »
Motion / MotionNET - Complete video / audio playback for SFML / SFML.NET

NetEXT - An SFML.NET Extension Library based on Thor

mentor

  • Newbie
  • *
  • Posts: 31
    • View Profile
Re: Nothing is drawn (inheriting from Drawable)
« Reply #2 on: April 10, 2015, 02:03:05 am »
Thanks, I fixed that and now it works! I'm glad and ashamed at the same time that I did a common mistake.

Quote from: zsbzsb
why are you basically implementing your own vector class?

Actually I'd like to check by myself if my own class will work faster than vector. At least writing this kind of vector class is a good practice.