I'm trying to get this to work... here is the pastebin if you'd rather look at it through that http://pastebin.bafserv.com/699
Anyway, when using an iterator to call the Draw() method nothing actually draws. Pressing space in the example will draw them as Draw() is being called directly.
1 | /* |
2 | * Author: Matthew Dalrymple |
3 | * Revision: One zero one zero zero zero zero one zero |
4 | * Title: Testing OpenLayer's Bitmap's and vectors/iterators |
5 | */ |
6 | |
7 | // Include the OpenLayer graphical library |
8 | #include <OpenLayer.hpp> |
9 | #include <vector> |
10 | |
11 | // Use the OpenLayer namespace |
12 | using namespace ol; |
13 | using namespace std; |
14 | |
15 | class Test |
16 | { |
17 | public: |
18 | Test(); |
19 | ~Test(); |
20 | void Draw(); |
21 | private: |
22 | int x; |
23 | int y; |
24 | Bitmap theimage; |
25 | }; |
26 | |
27 | Test::Test() |
28 | { |
29 | this->x = 5; |
30 | this->y = 10; |
31 | this->theimage.Load("gnolam.png"); |
32 | if(!theimage.IsValid()) |
33 | allegro_message("ZOMG ITS NOT VALID"); |
34 | } |
35 | |
36 | Test::~Test() |
37 | { |
38 | this->theimage.Destroy(); |
39 | } |
40 | |
41 | void Test::Draw() |
42 | { |
43 | this->theimage.Blit(x, y); |
44 | } |
45 | |
46 | |
47 | |
48 | int main() |
49 | { |
50 | // Sets up the devices needed |
51 | // keyboard, mouse, timer |
52 | Setup::SetupProgram(true, false, true); |
53 | |
54 | // Sets up the screen dimensions |
55 | // Screen Width, Screen Height, WINDOWED OR FULLSCREEN |
56 | Setup::SetupScreen(800, 600, WINDOWED); |
57 | |
58 | Bitmap TheScreen(800, 600, Rgba::WHITE); |
59 | Bitmap Logo("logo.png"); |
60 | |
61 | Test a, b, c, d; |
62 | |
63 | vector< Test > TheList; |
64 | TheList.push_back(a); |
65 | TheList.push_back(b); |
66 | TheList.push_back(c); |
67 | TheList.push_back(d); |
68 | |
69 | vector< Test >::iterator iter; |
70 | |
71 | /* |
72 | * This loop is a simple demonstration of continuing until |
73 | * a key is pressed, it is highly inefficient. It is strongly |
74 | * recommended that you read through the Allegro handbook for |
75 | * handling keyboard input. |
76 | */ |
77 | float deltaTime = 0; |
78 | FpsCounter::Start( 60.0 ); |
79 | while(!key[KEY_ESC]) |
80 | { |
81 | FpsCounter::NewFrameStarted(); |
82 | deltaTime = FpsCounter::GetDeltaTime(); |
83 | |
84 | |
85 | TheScreen.Blit(0, 0); |
86 | Logo.Blit(250, 250); |
87 | for(iter = TheList.begin(); iter != TheList.end(); iter++) |
88 | iter->Draw(); |
89 | |
90 | // press space and see that Draw works properly |
91 | if(key[KEY_SPACE]) |
92 | { |
93 | a.Draw(); |
94 | b.Draw(); |
95 | c.Draw(); |
96 | d.Draw(); |
97 | } |
98 | |
99 | Canvas::Refresh(); |
100 | rest(1); |
101 | } |
102 | |
103 | TheScreen.Destroy(); |
104 | Logo.Destroy(); |
105 | |
106 | return 0; |
107 | }END_OF_MAIN() // Required by Allegro & OpenLayer, YOU MUST HAVE THIS |
What am I doing wrong/how can I correct this?
Hehe don't ask why I used gnolam's avatar.
EDIT:
Here is the fix for this.. is there anyway to do this with the above example?
1 | /* |
2 | * Author: Matthew Dalrymple |
3 | * Revision: One zero one zero zero zero zero one zero |
4 | * Title: Testing OpenLayer's Bitmap's and vectors/iterators |
5 | */ |
6 | |
7 | // Include the OpenLayer graphical library |
8 | #include <OpenLayer.hpp> |
9 | #include <vector> |
10 | |
11 | // Use the OpenLayer namespace |
12 | using namespace ol; |
13 | using namespace std; |
14 | |
15 | class Test |
16 | { |
17 | public: |
18 | Test(); |
19 | ~Test(); |
20 | void Draw(); |
21 | private: |
22 | int x; |
23 | int y; |
24 | Bitmap theimage; |
25 | }; |
26 | |
27 | Test::Test() |
28 | { |
29 | this->x = 5; |
30 | this->y = 10; |
31 | this->theimage.Load("gnolam.png"); |
32 | if(!theimage.IsValid()) |
33 | allegro_message("ZOMG ITS NOT VALID"); |
34 | } |
35 | |
36 | Test::~Test() |
37 | { |
38 | this->theimage.Destroy(); |
39 | } |
40 | |
41 | void Test::Draw() |
42 | { |
43 | this->theimage.Blit(x, y); |
44 | } |
45 | |
46 | |
47 | |
48 | int main() |
49 | { |
50 | // Sets up the devices needed |
51 | // keyboard, mouse, timer |
52 | Setup::SetupProgram(true, false, true); |
53 | |
54 | // Sets up the screen dimensions |
55 | // Screen Width, Screen Height, WINDOWED OR FULLSCREEN |
56 | Setup::SetupScreen(800, 600, WINDOWED); |
57 | |
58 | Bitmap TheScreen(800, 600, Rgba::WHITE); |
59 | Bitmap Logo("logo.png"); |
60 | |
61 | Test a, b, c, d; |
62 | |
63 | vector< Test* > TheList; |
64 | TheList.push_back(&a); |
65 | TheList.push_back(&b); |
66 | TheList.push_back(&c); |
67 | TheList.push_back(&d); |
68 | |
69 | vector< Test* >::iterator iter; |
70 | |
71 | /* |
72 | * This loop is a simple demonstration of continuing until |
73 | * a key is pressed, it is highly inefficient. It is strongly |
74 | * recommended that you read through the Allegro handbook for |
75 | * handling keyboard input. |
76 | */ |
77 | float deltaTime = 0; |
78 | FpsCounter::Start( 60.0 ); |
79 | while(!key[KEY_ESC]) |
80 | { |
81 | FpsCounter::NewFrameStarted(); |
82 | deltaTime = FpsCounter::GetDeltaTime(); |
83 | |
84 | |
85 | TheScreen.Blit(0, 0); |
86 | Logo.Blit(250, 250); |
87 | for(iter = TheList.begin(); iter != TheList.end(); iter++) |
88 | (*iter)->Draw(); |
89 | |
90 | // press space and see that Draw works properly |
91 | if(key[KEY_SPACE]) |
92 | { |
93 | a.Draw(); |
94 | b.Draw(); |
95 | c.Draw(); |
96 | d.Draw(); |
97 | } |
98 | |
99 | Canvas::Refresh(); |
100 | rest(1); |
101 | } |
102 | |
103 | TheScreen.Destroy(); |
104 | Logo.Destroy(); |
105 | |
106 | return 0; |
107 | }END_OF_MAIN() // Required by Allegro & OpenLayer, YOU MUST HAVE THIS |
If Bitmap doesn't have a proper copy constructor, it won't be copied, and it won't be displayed. Maybe checking IsValid inside the Draw method will tell you something?
When you push the a, b, c, and d objects into the vector, you push the actual objects, so you actually make a copy of them. When this happens, OpenLayer has to send a copy of the Bitmap to the graphics card. I don't know if it handles this properly. One possible fix is to use a Bitmap* inside the class, and continue to use a vector of objects, but the pointer method is superior for most cases in terms of performance.
FYI: CGamesPlay was a major contributor to this being fixed :-D.
Another error that I'm having that CGamesPlay said was the right syntax and I thought so myself is this line:
... vector < Avatars* > CurrentList, AvatarList; // Avatar List gets filled so don't worry there is stuff in it ... CurrentList.reserve(MAX_AVATARS_ON_SCREEN); for(int i = 0; i < MAX_AVATARS_ON_SCREEN; i++) CurrentList.push_back(AvatarList.at(rand() % AvatarList.size()));
*.at() should return a pointer and so it compiles correctly. The problem is that it stops things from being drawn and causes my CPU to be 100% and lags like crazy. I comment that line out and "bam" it's fixed. Is their a correct way to do this or is their a workaround like maybe setting a temp Avatar instance setting it equal to *.at(...) then pushing it to the back of CurrentList? I would rather have a one line simple thing.
What is the value of MAX_AVATARS_ON_SCREEN?
Like I said: that line of code is fine. Show the part where you draw, for instance.
MAX_AVATARS_ON_SCREEN is set to 15 for now.
This is how they're drawn:
bool Game::DrawAvatars() { vector< Avatar* >::iterator curAvatar; for(curAvatar = CurrentList.begin(); curAvatar != CurrentList.end(); curAvatar++) (*curAvatar)->Draw(); //Log::log("CurrentList.size() = %i", CurrentList.size()); return true; }
This is the Avatar's Draw method:
bool Avatar::Draw(void) { this->m_Avatar.Blit(10, 10); return true; }
EDIT: I hate having difficult questions that no one knows the exact answer to or just ignore me
I wonder if you've found the answer yet?
Donno why its hanging there, likely a copy paste error or something.
CurrentList.reserve(MAX_AVATARS_ON_SCREEN); for(int i = 0; i < MAX_AVATARS_ON_SCREEN; i++) CurrentList.push_back(AvatarList.at(rand() % AvatarList.size()));
Should be:
#include <algorithm> CurrentList.resize(AvatarList.size()); random_sample(AvatarList.begin(), AvatarList.end(), CurrentList.begin(), CurrentList.end());
Here is the fix for this.. is there anyway to do this with the above example?
Its not pretty:
1 | class Test |
2 | { |
3 | public: |
4 | Test(); |
5 | ~Test(); |
6 | void Draw(); |
7 | |
8 | Test(const Test &t) |
9 | : x(t.x), y(t.y), theimage(t.theimage) |
10 | { |
11 | ((Test*)&t).theimage = 0; |
12 | } |
13 | |
14 | private: |
15 | int x; |
16 | int y; |
17 | Bitmap *theimage; |
18 | }; |
19 | |
20 | Test::Test() |
21 | : theimage(new Bitmap) |
22 | { |
23 | this->x = 5; |
24 | this->y = 10; |
25 | this->theimage->Load("gnolam.png"); |
26 | if(!theimage->IsValid()) |
27 | allegro_message("ZOMG ITS NOT VALID"); |
28 | } |
29 | |
30 | Test::~Test() |
31 | { |
32 | if(theimage) |
33 | this->theimage->Destroy(); |
34 | delete theimage; |
35 | } |
36 | |
37 | .. rest is same (except using -> instead of .) |
I wonder if you've found the answer yet?
Haha nope, well now that DD has posted I might have.
To DD (Or anyone else):
I'm reading about random_sample() from cppreference.com and it seems that it confuses me haha.
AvatarList holds 1 copy of each avatar, now CurrentList is supposed to be holding the actual avatars you'll see and fight. When one dies a random avatar from AvatarList will be popped onto CurrentList. Now will random_sample() work for what I'm doing (just for the initialization though)? Does it randomly put them into CurrentList depending on CurrentList's size? The way it looks it seems like CurrentList needs to already be full .
random_sample(AvatarList.begin(), AvatarList.end(), CurrentList.begin() + dead_avatar_index, CurrentList.begin() + dead_avatar_index + 1);That will make it replace 1. I have no idea why you wouldn't just use your code.
I would use my code because it doesn't work. It may be logically correct but its causing things to not work, I mean I can rar it up again and show you how it doesn't work
Edit: I keep getting the error: random_sample().. first use of this function. And I've included algorithm >.< Rebuilt all... Baaaah.
Eww totally had to include <algo.h> to get it to work I dunno why.
Edit: I keep getting the error: random_sample().. first use of this function. And I've included algorithm >.< Rebuilt all... Baaaah.
Eww totally had to include <algo.h> to get it to work I dunno why.
Err, maybe std::random_sample or "using namespace std;" would help? These seem like errors you get when you forget about a namespace . This and the fact that <algorithm> probably only wraps <algo.h> in a namespace .
When one dies a random avatar from AvatarList will be popped onto CurrentList.
[edit]Ah I see. Yes your code is better suited for this task. Just don't use reserve. Its generally useless unless you really know what you're doing. And even when you do, it pretty much will only apply to one compiler.
Err, maybe std::random_sample or "using namespace std;" would help?
Tried that and I am already using the standard namespace.
Just don't use reserve.
Then how do I set the size that CurrentList is going to be filled up to?
vec.resize(newsize);
Bah I never saw resize() on cppreference.com, I always overlook things. That's totally what I wanted to use in my other projects too not reserve(). Umm where can I get an update for all the standard libraries because no matter what I try I can't get random_sample() to work with <algorithm>.
What compiler are you using?
MinGW (the version that came with Dev-C++ beta 5 [4.9.9.2 or whatever])
Should support it just fine. Paste some code.
Paste some code.
#define MAX_AVATARS_ON_SCREEN 15 ... #include <algorithm> ... CurrentList.resize(MAX_AVATARS_ON_SCREEN); random_sample(AvatarList.begin(), AvatarList.end(), CurrentList.begin(), CurrentList.end());
When I use #include <algo.h>
I get errors when trying to draw my CurrentList using (*iter)->Draw() My logfile is full of
 is not valid
for all of my Avatars in CurrentList. I changed CurrentList and AvatarList from vector < Avatar* > to vector < Avatar > and I got their names instead of that weird A but they were still not valid >.<. I'm thinking about trying this with an array instead of a vector. Or maybe try and STL::List (but lists and vectors are so similar I wouldn't see how that would effect things.
Could you show the code that wrote the "Â is not valid", as well as the full code for the Avatar class?
Avatar.hpp
1 | #ifndef __AVATARS_HPP__ |
2 | #define __AVATARS_HPP__ |
3 | |
4 | #include "stdafx.hpp" |
5 | |
6 | #define TOPLEFT 0 |
7 | #define TOPRIGHT 1 |
8 | #define BOTLEFT 2 |
9 | #define BOTRIGHT 3 |
10 | |
11 | |
12 | class Avatar |
13 | { |
14 | public: |
15 | Avatar(); |
16 | Avatar(std::string fileName); |
17 | ~Avatar(); |
18 | bool Load(std::string fileName); |
19 | void Draw(void); |
20 | void Update(void); |
21 | |
22 | std::string GetName(void); |
23 | void SetName(std::string name); |
24 | |
25 | /** |
26 | * Position the image in one of the four corners of the screen |
27 | * Paramater takes: TOPLEFT | TOPRIGHT | BOTLEFT | BOTRIGHT |
28 | **/ |
29 | void Reposition(int corner); |
30 | private: |
31 | Bitmap m_Avatar; |
32 | std::string m_Name; |
33 | int x; |
34 | int y; |
35 | int m_Corner; |
36 | }; |
37 | |
38 | #endif |
Avatar.cpp
1 | #include "../include/stdafx.hpp" |
2 | |
3 | Avatar::Avatar() |
4 | { |
5 | // Starting the image at one of the four courners of the map |
6 | Reposition(rand() % 3); |
7 | } |
8 | Avatar::Avatar(std::string fileName) |
9 | { |
10 | Load(fileName); |
11 | } |
12 | Avatar::~Avatar() |
13 | { |
14 | this->m_Avatar.Destroy(); |
15 | } |
16 | bool Avatar::Load(std::string fileName) |
17 | { |
18 | this->m_Avatar.Load(fileName.c_str()); |
19 | Log::verify(this->m_Avatar.IsValid(), "%s did not load correctly", fileName.c_str()); |
20 | if(!this->m_Avatar.IsValid()) |
21 | return false; |
22 | return true; |
23 | } |
24 | void Avatar::Draw(void) |
25 | { |
26 | Log::verify(m_Avatar.IsValid(), "%s is not valid", m_Name.c_str()); |
27 | this->m_Avatar.Blit(10, 10); |
28 | } |
29 | |
30 | void Avatar::Update(void) |
31 | { |
32 | } |
33 | |
34 | /* DONT MIND THIS FUNCTION YET :D */ |
35 | void Avatar::Reposition(int corner) |
36 | { |
37 | m_Corner = corner; |
38 | |
39 | this->x = rand() % SCREEN_W; |
40 | this->y = rand() % SCREEN_H; |
41 | } |
42 | |
43 | std::string Avatar::GetName(void) |
44 | { |
45 | return this->m_Name; |
46 | } |
47 | void Avatar::SetName(std::string name) |
48 | { |
49 | this->m_Name = name; |
50 | } |
Ok to get the log file to produce this:
1 | Á is not valid |
2 | Á is not valid |
3 | Á is not valid |
4 | Á is not valid |
5 | Á is not valid |
6 | Á is not valid |
7 | Á is not valid |
8 | Á is not valid |
9 | Á is not valid |
10 | Á is not valid |
11 | Á is not valid |
12 | Á is not valid |
13 | Á is not valid |
14 | Á is not valid |
15 | Á is not valid |
16 | (null) is not valid |
17 | (null) is not valid |
18 | (null) is not valid |
19 | (null) is not valid |
20 | (null) is not valid |
21 | (null) is not valid |
22 | (null) is not valid |
23 | (null) is not valid |
24 | (null) is not valid |
25 | (null) is not valid |
26 | (null) is not valid |
27 | (null) is not valid |
28 | (null) is not valid |
29 | (null) is not valid |
30 | (null) is not valid |
This is what I did
Game.cpp area:
1 | bool Game::LoadAvatars() |
2 | { |
3 | ... |
4 | CurrentList.resize(MAX_AVATARS_ON_SCREEN); |
5 | random_sample(AvatarList.begin(), AvatarList.end(), CurrentList.begin(), CurrentList.end()); |
6 | ... |
7 | } |
8 | /** |
9 | * Draw the current list of avatars to the screen at their correct coordinates |
10 | **/ |
11 | bool Game::DrawAvatars() |
12 | { |
13 | vector< Avatar* >::iterator curAvatar; |
14 | for(curAvatar = CurrentList.begin(); curAvatar != CurrentList.end(); curAvatar++) |
15 | (*curAvatar)->Draw(); |
16 | //Log::log("CurrentList.size() = %i", CurrentList.size()); |
17 | return true; |
18 | } |
19 | |
20 | /** |
21 | * Update the Avatar sprites to their new locations |
22 | **/ |
23 | bool Game::UpdateAvatars() |
24 | { |
25 | vector< Avatar* >::iterator curAvatar; |
26 | for(curAvatar = CurrentList.begin(); curAvatar != CurrentList.end(); curAvatar++) |
27 | (*curAvatar)->Update(); |
28 | return true; |
29 | } |
Add a copy constructor to your object:
Avatar::Avatar(const Avatar& other) { Log::error("Object not allowed to be copied"); }
Same log file. The object isn't being copied. Is that good or bad?
Good
Unfortunately, I'm at a loss. Start dumping your objects at very frequent intervals and see what causes them to screw up. Make sure they are loaded correctly.
Baaaaah, this is what always defers me away from programming sometimes. Everything always looks right, seems like it should work... BAM! RUN TIME ERRORS that are hard as hell to solve.
Which is why strict typing is a wonderful language feature.
Which is why strict typing is a wonderful language feature.
Can you point me in a direction so I can learn more about this? I Google'd and Wikipedia'd this subject with no specific results. I don't see how this subject directly effects my current project, are you referring to the use of templates in the STL?
EDIT:
I think I might have narrowed down the problem. I am now trying to use an iterator just to draw AvatarList to the screen but that isn't working. So my problem is probably how I'm loading the avatars. Here's my loading code. Is the tempAvatar being erased after it leaves the scope of the do-while loop? Should AvatarList maybe be a vector of Avatar objects and not a vector of pointers to Avatar objects?
Anyway I'll be trying this out while I post the code here:
1 | bool Game::LoadAvatars() |
2 | { |
3 | Log::log("[LIST OF AVATARS]"); |
4 | string AvatarDirectory("images/avatars/"); |
5 | |
6 | // The allegro file info structure |
7 | al_ffblk info; |
8 | |
9 | // Checking to see if there are PNG files in there |
10 | if(al_findfirst("images/avatars/*.png", &info, FA_ALL) != 0) |
11 | { |
12 | Log::warning("No avatars were found"); |
13 | return false; |
14 | } |
15 | // While there are PNG files, lets grab them and load them |
16 | do |
17 | { |
18 | Log::log("%s", info.name); |
19 | string path = AvatarDirectory + info.name; |
20 | |
21 | /* PROBABLE PROBLEM AREA */ |
22 | |
23 | Avatar tempAvatar(path); |
24 | tempAvatar.SetName(info.name); |
25 | |
26 | this->AvatarList.push_back(&tempAvatar); |
27 | } |
28 | while (al_findnext(&info) == 0); |
29 | |
30 | // Close the file search |
31 | al_findclose(&info); |
32 | |
33 | Log::log("[/LIST OF AVATARS]"); |
34 | |
35 | return true; |
36 | } |
do { Log::log("%s", info.name); string path = AvatarDirectory + info.name; /* PROBABLE PROBLEM AREA */ Avatar tempAvatar(path); tempAvatar.SetName(info.name); this->AvatarList.push_back(&tempAvatar); } // tempAvater's destructor is called here
Corrected (don't forget to call delete later!):
do { Log::log("%s", info.name); string path = AvatarDirectory + info.name; /* PROBABLE PROBLEM AREA */ Avatar *tempAvatar = new Avatar(path); tempAvatar->SetName(info.name); this->AvatarList.push_back(tempAvatar); }
By calling delete later you mean after I push it onto AvatarList correct? Bah things still aren't drawing and the program is crashing when I try and end it by pressing escape.
No when you're done with this->AvatarList. For example in the destructor. But do it wherever is appropriate for you.
When you give up ownership of your memory is up to you.
Yes but tempAvatar is only in the scope of that do-while loop. Maybe I'm missing something here.
Oh and the crashing error I was having was caused by a new not fully implemented feature of my logging system.
Ok well things are totally drawing now, as I'm writing this I just removed the delete tempAvatar line and yeah.. shh <sarcasm> there probably isn't a memory leak now </sarcasm>
Now I'll go around deleting their allocated memory in the game's de-constructor. I'll get back in a little bit with an update.
I believe your ownership of tempAvatar extends beyond the do loop. Do you ever access the pointer again?
I don't ever access tempAvatar but I do access AvatarList.
Don't forget how pointers work! When you copy a pointer, you don't copy the data it points to, you copy the directions for how to get to the data. Since you made the data yourself (using new), you need to get rid of it yourself, using delete. When do you do that? When you don't need the data any more. Whenever you would erase the avatar from the avatar list, instead of just deleting it, delete the data, then remove it from the list.
Well what I was getting at was specifically having to delete tempAvatar, as tempAvatar was only used to load objects into AvatarList. This was done in the constructor of my Game class... So in the de-constructor I did this:
vector< Avatar* >::iterator curAvatar; for(curAvatar = CurrentList.begin(); curAvatar != CurrentList.end(); curAvatar++) delete *curAvatar;
I believe that is correct. What I was trying to get at with my questions was more specifically was if you guys were telling me to delete tempAvatar, which I thought you were which was confusing me. I keep poking at this because I'm a bit on the unsure side and I hate being unsure and still delving into things.
Things are working now and everything is drawing and logging correctly. But because I am ME, this has shown me new errors. Haha now the images aren't randomly drawing to the screen... they are drawing at the same random spots every time I run the program. I'm not even sure all 15 are being drawn.
I might also be having a PWD problem to, as when I compile + run in Dev-C++ I think all the *.png avatars show up... but when I double click on the executable only two show up.
I'll try and solve those problems on my own first of course as programming is about solving problems . I might just add on to this thread if I need more help as I don't like to create lots of threads.
EDIT: Haha I'm totally dumb. I forgot I was using the constructor that takes a path to load a file. So when I'm logging stuff in the other constructors I was freaking out on why they weren't getting called... That fixed the X and Y random coord thing I was working on.
EDIT 2: Well imma just give props as the problem is fixed and now I can focus on the logic of my game and have a early version of it up in a day or two on the depot.