A little confusion with rendering a sprite!

Started by
4 comments, last by ThePointingMan 11 years, 2 months ago

Alright, So I thought to myself Boy wouldn't it be great if all of the objects stored a pointer to the sprite that I'd like to have them render with? Sounds fantastic to me!

Thus I made this little file looking something like this


//Spritelist.h
#pragma once
#include "Sprite.h"
namespace SpriteList
{
	static Sprite Player1("Rainbow.bmp",64,64,4,4);
}

And then Within the Object class I have there is a Sprite pointer pointing to said static variable. Wow great!

But then onto my Render Method Something appears to be askew!?


//Within some direct3d file
void Direct3D::render_frame(vector<Object> *Objects)
{
	d3ddev->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,40,0100),1.0f,0);
	d3ddev->BeginScene();
	d3dspt->Begin(NULL);
	for(vector<Object>::iterator index = Objects->begin();index != Objects->end();index++)
	{
		//does not pass, however if the line fallowing labeled "WiggityWack"it passes then the second time this //function goes by (I assume) it does pass
		if(index->sprite==&Player1)
		{
			index->sprite->frameStore++;
		}
                //"WiggityWack" index->sprite = &Player1;      <- also if the equivilent of this line is //place in the code that calls this render function the top if statement still willl not pass.
		//does pass
		if(index->sprite->cols==Player1.cols)
		{
			index->sprite->frameStore++;
		}
		//index->sprite=&Player1;
                
                //does not render anything
                DrawSprite(index->sprite,1, 64, 64 , 1.0f);
                //Does render something! Wow thats great!
		DrawSprite(&Player1,1, 64, 64 , 1.0f);
	}
	d3dspt->End();
	d3ddev->EndScene();
	d3ddev->Present(NULL,NULL,NULL,NULL);
}

I've done a lot of random tests and I've cut down the problem to the objects within the vector's sprite member simply isn't pointing to that static Sprite called Player1. Static variables have been something I've tried to avoid as I've heard people like to avoid them, so now that I am using one I'm wandering if perhaps I've misinterpretted their use and that's related to why this does not work. Would anyone be able to clarify on this?

I'll post my Object class just in case you see anything stupid there that i totally passed, but i believe there is nothing wrong here.


//Object.h
struct Object
{
public:
	//constructor and deconstructodon Awww yeah!
	Object(/*HWND *hwnd,*/Sprite *_sprite ,int _x, int _y);
	~Object();
	
	// I forget what these are called, uuuuh like... variables inside a class, it's somethin stupid.
	//HWND hwnd;
	Sprite * sprite;
	unsigned int frame;
	int x, y;
	
	//methods
	void update(/*inputdata*/);
};

//Object.cpp
Object::Object(Sprite *_sprite ,int _x, int _y) :sprite(_sprite), x(_x), y(_y),frame(0)
{
}
Object::~Object()
{
}
void Object::update(/*inputdata*/)
{
}

Advertisement
Static in this context means one copy per translation unit. Every cpp file will have its own copy of that sprite.

Assuming you want to use a global (and you should revisit that decision at some point), declare it as extern in the header and define it in one cpp file only.

I am aware that keeping this in global space is to be avoided, I'm just not sure how one would go about doing this without doing so. I would like to be able to have something like this for the constructor of the child class of an object


//PlayerSpt Sprite("File",blabla variables n crap)
//Player class, child of Object class
Player(x,y):Object(&Player,x,y)

But it needs to be accesible to my method that loads in all of the graphics. Does anyone have some advice on how I might do this, is there some other method people would advise for doing this or am I just dreaming and will have to use one of the other idea's I've come up with such as using an intager instead of a sprite pointer and making the sprite only accesible to the d3ddevise and using the intager to pick which sprite is being used.

You could do this plenty of ways but your idea about using an integer instead of a pointer is sensible. I'd suggest looking into that more. Using an integer or a handle or really any mechanism for keeping a 'name' to your referenced object would be better than keeping a pointer directly all the time. And as you've already guessed you can start limiting how much of your code needs to know specifics like what a Sprite is.

What happens if/when your game grows to sufficient size that having all images loaded into statics becomes too much? Typically at this point you might want to look into smarter resource management. You need to implement a better means for obtaining resources (textures, sounds, geometry, etc...) on demand, without requiring them to be in memory all the time. This way, you can load only the resources you need for a particular level or portion of your game, unloading them when they are no longer needed and loading others in their place.

One method for resource management I have seen and used is to implement a pattern where a resource container maintains the resources and hands out shared_ptrs to them upon request. The way this work is that internally, the container implements a map keyed with a string (the name of the resource to load) and with weak_ptr to resource as the value. When a resource is requested, it checks the map first to see if the resource exists in the map (ie, it has been loaded at one point). This check merely indexes the map to see if there is an entry for the resource. If there is an entry, then it next checks the weak_ptr to see if it is valid. If it is not valid, that means the shared_ptrs that the weak_ptr shares with all went out of scope or were otherwise released, and so the resource was unloaded. If the resource is unloaded, or was never loaded to start, then the resource is loaded from file and a weak_ptr to it is stored in the map. Then a shared_ptr is constructed from this weak_ptr and returned for your object to use.

The beauty of this system is that your object doesn't need to explicitly release the resource; it merely has to reset() the shared_ptr, or just let the shared_ptr be deleted when the object is deleted in order for it to go away. A very quick sample implementation:
// spritemanager.h
#include <map>
#include <string>
#include <memory>
#include "Sprite.h"

class SpriteManager
{
	public:
	SpriteManager();
	~SpriteManager();
	
	std::shared_ptr<Sprite> getSprite(std::string name, int w, int h, int unknown1, int unknown2);
	
	private:
	std::map<std::string, std::weak_ptr<Sprite> > sprites_;
};


// spritemanager.cpp
#include "spritemanager.h"

SpriteManager::SpriteManager(){}
SpriteManager::~SpriteManager(){}

std::shared_ptr<Sprite> getSprite(std::string name, int w, int h, int unknown1, int unknown2)
{
	auto iter=sprites_.find(name);
	if(iter==sprites_.end() || (*iter).second.expired())
	{
		auto sprite=std::make_shared<Sprite>(name,w,h,unknown1,unknown2);
		sprites_[name]=std::weak_ptr<Sprite>(sprite);
		return sprite;
	}
	else
	{
		return std::shared_ptr<Sprite>((*iter).second);
	}
}


// Object.h
struct Object
{
public:
	//constructor and deconstructodon Awww yeah!
	Object(/*HWND *hwnd,*/ std::shared_ptr<Sprite> _sprite ,int _x, int _y);
	~Object();
	
	// I forget what these are called, uuuuh like... variables inside a class, it's somethin stupid.
	//HWND hwnd;
	std::shared_ptr<Sprite> sprite;
	unsigned int frame;
	int x, y;
	
	//methods
	void update(/*inputdata*/);
};



//Object.cpp
Object::Object(std::shared_ptr<Sprite> _sprite ,int _x, int _y) :sprite(_sprite), x(_x), y(_y),frame(0)
{
}
Object::~Object()
{
}
void Object::update(/*inputdata*/)
{
}
Then, you would instance SpriteManager and use it to obtain sprites:
smgr=SpriteManager();

Object player(smgr.getSprite("Rainbow.bmp", 64, 64, 4, 4), 10, 10);
At this point, player would have a pointer to the Rainbow.bmp sprite resource. Whenever player is deleted, the stored shared_ptr will be deleted, and the resource dropped. If other objects hold shared_ptrs to the resource, it will not be deleted. But as soon as all shared_ptrs to the resource are deleted, then the resource itself will be deleted and the weak_ptr stored inside SpriteManager will be invalidated. The next time the resource is requested, it will be reloaded.

This is untested code, of course, but it should show the gist of the idea. Using a resource manager, even if you don't follow this specific pattern, is probably a good idea, as it allows you to elegantly load and unload resources as they are used, without having to resort to global variables and other hacks to store your resources.

Beautiful! I had an idea of something similar to that but there where a few things that just... I dunno I felt like they would be messy. What you've written up there looks very clean and usable. There are a few keywords I've never seen before, but I'm sure I'll be able to look those up for the most part. I'll let you know if I'm having any troubles in that regard.

This topic is closed to new replies.

Advertisement