I have an animation that I'm pushing into a vector and updating upon the Update() method. Problem is that if I put the code in one class it works fine and all frames are played, if I move it into a different class I only get one frame and other strange errors.
Works:
typedef struct BlockTile { unsigned int x; unsigned int y; AnimTile tile; }BlockTile;
1 | void Game::GetBlock() |
2 | { |
3 | if(!mouse_click && (mouse_b & 1) && mouse_x > MAP_X && mouse_x < MAP_X + VIEW_W && mouse_y > MAP_Y && mouse_y < MAP_Y + VIEW_H) |
4 | { |
5 | Camera *cam = tileMap->cam; |
6 | |
7 | int mx = (mouse_x - MAP_X + (int)cam->x) / TILE_W; |
8 | int my = (mouse_y - MAP_Y + (int)cam->y) / TILE_H; |
9 | |
10 | AnimTile *tile = tileMap->GetTile(mx, my); |
11 | |
12 | if(tile && (tile->id == ID_BLOCK || tile->id == ID_INVBLOCK)) |
13 | { |
14 | BlockTile block; |
15 | block.tile = *tileMap->GetTile(SHRINKBLOCK); |
16 | block.x = mx; |
17 | block.y = my; |
18 | if(tile->id == ID_INVBLOCK) |
19 | block.tile.direction = ANIM_BACKWARD; |
20 | block.tile.Reset(); |
21 | vTiles.push_back(block); |
22 | BlockScan scan(tileMap, mx, my, tile->id); |
23 | vScan.push_back(scan); |
24 | tileMap->SetTile(mx, my, &vTiles[vTiles.size() - 1].tile); |
25 | } |
26 | |
27 | mouse_click = true; |
28 | } |
29 | if(mouse_click && !(mouse_b & 1)) |
30 | mouse_click = false; |
31 | } |
32 | |
33 | void Game::Update() |
34 | { |
35 | // Update tilemap animations |
36 | tileMap->Update(); |
37 | |
38 | // Update camera position |
39 | if(!UpdateCamera()) |
40 | { |
41 | // Scan blocks if clicked |
42 | GetBlock(); |
43 | } |
44 | |
45 | // Update blocks |
46 | vector <BlockScan>::iterator i; |
47 | for(i = vScan.begin(); i < vScan.end(); ++i) |
48 | { |
49 | if(i->isActive() == false) |
50 | i = vScan.erase(i); |
51 | else |
52 | i->Update(); |
53 | } |
54 | |
55 | // Update animations |
56 | vector <BlockTile>::iterator j; |
57 | for(j = vTiles.begin(); j < vTiles.end(); ++j) |
58 | { |
59 | if(j->tile.direction == ANIM_FORWARD && j->tile.CurFrame() == j->tile.NumFrames() - 1) |
60 | { |
61 | tileMap->SetTile(j->x, j->y, INVBLOCK); |
62 | j = vTiles.erase(j); |
63 | } |
64 | else if(j->tile.direction == ANIM_BACKWARD && j->tile.CurFrame() == 0) |
65 | { |
66 | tileMap->SetTile(j->x, j->y, BLOCK); |
67 | j = vTiles.erase(j); |
68 | } |
69 | else |
70 | j->tile.Update(); |
71 | } |
72 | } |
Doesn't work:
1 | #include "blockscan.h" |
2 | |
3 | using namespace std; |
4 | |
5 | BlockScan::BlockScan(TileMap *&map, unsigned int x, unsigned int y, unsigned int tile_id) : active(true), timer(gametick + SCAN_SPEED) |
6 | { |
7 | DEBUG("BlockScan::BlockScan()"); |
8 | |
9 | ASSERT(tileMap); |
10 | ASSERT(tile); |
11 | |
12 | this->x = x; |
13 | this->y = y; |
14 | this->tileMap = map; |
15 | this->tile_id = tile_id; |
16 | |
17 | BlockTile block; |
18 | block.tile = *tileMap->GetTile(SHRINKBLOCK); |
19 | block.x = x; |
20 | block.y = y; |
21 | |
22 | if(tile_id == ID_BLOCK) |
23 | { |
24 | new_tile = INVBLOCK; |
25 | block.tile.direction = ANIM_FORWARD; |
26 | } |
27 | else if(tile_id == ID_INVBLOCK) |
28 | { |
29 | new_tile = BLOCK; |
30 | block.tile.direction = ANIM_BACKWARD; |
31 | } |
32 | else |
33 | { |
34 | active = false; |
35 | return; |
36 | } |
37 | |
38 | block.tile.Reset(); |
39 | vTiles.push_back(block); |
40 | |
41 | AnimTile *tmp[2]; |
42 | tmp[0] = tileMap->GetTile(x, y - 1); |
43 | tmp[1] = tileMap->GetTile(x, y + 1); |
44 | |
45 | if((tmp[0] && tmp[0]->id == tile_id) || (tmp[1] && tmp[1]->id == tile_id)) |
46 | { |
47 | direction = DIR_VERTICAL; |
48 | val1 = y - 1; |
49 | val2 = y + 1; |
50 | } |
51 | else |
52 | { |
53 | direction = DIR_HORIZONTAL; |
54 | val1 = x - 1; |
55 | val2 = x + 1; |
56 | } |
57 | |
58 | tileMap->SetTile(x, y, &vTiles[vTiles.size() - 1].tile); |
59 | } |
60 | |
61 | BlockScan::~BlockScan() |
62 | { |
63 | DEBUG("BlockScan::~BlockScan()"); |
64 | } |
65 | |
66 | void BlockScan::Update() |
67 | { |
68 | if(active && gametick >= timer) |
69 | { |
70 | AnimTile *tmp; |
71 | |
72 | unsigned int mapW, mapH; |
73 | tileMap->GetWidth(mapW); |
74 | tileMap->GetHeight(mapH); |
75 | |
76 | if(direction == DIR_VERTICAL) |
77 | { |
78 | if(val1 != -1) |
79 | { |
80 | if(val1 > 0) |
81 | { |
82 | tmp = tileMap->GetTile(x, val1); |
83 | if(tmp && tmp->id == tile_id) |
84 | { |
85 | tileMap->SetTile(x, val1, new_tile); |
86 | --val1; |
87 | } |
88 | else |
89 | val1 = -1; |
90 | } |
91 | else |
92 | val1 = -1; |
93 | } |
94 | if(val2 != -1) |
95 | { |
96 | if(val2 < mapW) |
97 | { |
98 | tmp = tileMap->GetTile(x, val2); |
99 | if(tmp && tmp->id == tile_id) |
100 | { |
101 | tileMap->SetTile(x, val2, new_tile); |
102 | ++val2; |
103 | } |
104 | else |
105 | val2 = -1; |
106 | } |
107 | else |
108 | val2 = -1; |
109 | } |
110 | } |
111 | else |
112 | { |
113 | if(val1 != -1) |
114 | { |
115 | if(val1 > 0) |
116 | { |
117 | tmp = tileMap->GetTile(val1, y); |
118 | if(tmp && tmp->id == tile_id) |
119 | { |
120 | tileMap->SetTile(val1, y, new_tile); |
121 | --val1; |
122 | } |
123 | else |
124 | val1 = -1; |
125 | } |
126 | else |
127 | val1 = -1; |
128 | } |
129 | if(val2 != -1) |
130 | { |
131 | if(val2 < mapH) |
132 | { |
133 | tmp = tileMap->GetTile(val2, y); |
134 | if(tmp && tmp->id == tile_id) |
135 | { |
136 | tileMap->SetTile(val2, y, new_tile); |
137 | ++val2; |
138 | } |
139 | else |
140 | val2 = -1; |
141 | } |
142 | else |
143 | val2 = -1; |
144 | } |
145 | } |
146 | if(val1 == -1 && val2 == -1) |
147 | active = false; |
148 | else |
149 | timer = gametick + SCAN_SPEED; |
150 | } |
151 | // Update animations |
152 | vector <BlockTile>::iterator j; |
153 | for(j = vTiles.begin(); j < vTiles.end(); ++j) |
154 | { |
155 | if(j->tile.direction == ANIM_FORWARD && j->tile.CurFrame() == j->tile.NumFrames() - 1) |
156 | { |
157 | tileMap->SetTile(j->x, j->y, INVBLOCK); |
158 | j = vTiles.erase(j); |
159 | } |
160 | else if(j->tile.direction == ANIM_BACKWARD && j->tile.CurFrame() == 0) |
161 | { |
162 | tileMap->SetTile(j->x, j->y, BLOCK); |
163 | j = vTiles.erase(j); |
164 | } |
165 | else |
166 | j->tile.Update(); |
167 | } |
168 | } |
169 | |
170 | bool BlockScan::isActive() |
171 | { |
172 | return active; |
173 | } |
I'm trying to make all blocks that are scanned play the animation but for now I'm just trying to get the clicked tile to work. I can't see why the two implementations would cause different results. I've even tried just simply calling j->tile.Update() and in isActive() returning true always so that the Game class doesn't kill the scan when it is complete but I still only get the first frame of the animation in BlockScan whereas in Game I get all frames.
Bump...
I got it fixed, basically I just needed to use pointers rather than the default copy method which seemed to break things. Once I wrote my own copy constructor and used new and delete things worked smoothly. For those who are wondering what I'm working on here is a screenshot:
{"name":"img","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/2\/e\/2eacecb0198c4a3a94a588f9ce60ea59.jpg","w":650,"h":513,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/2\/e\/2eacecb0198c4a3a94a588f9ce60ea59"}
I'll have a download link available before long. It's going to be a semi-clone of Mario vs Donkey Kong II only featuring Alex
featuring Alex
The alligator?
The alligator?
I thought he meant this Alex.
Your update animations and update blocks for loops will skip the next element whenever you erase one. If you erase the last element that code should crash. You have to move the iterator increment out of the for statement and only execute it if you do not erase anything.
DDustin: What? Oh I see, I should check to make sure that j does not equal end or you will call update on an invalid element. Thanks.
Actually I'm not sure that case will ever happen, it's in an else clause.
Calling itr = list.erase(itr); is effectively the same as ++itr. Your for loop also executes ++itr, resulting (in cases where an erase occurs) in ++itr being executed twice.
If you erased the last element, you will ++ your way past list.end() and your loop will continue iterating infinitely (although your compiler may project you from this).
Even if its not the last element, you're still skipping the element just after the one you erased, since you've incremented your iterator twice.
What would be a good solution to this?
if( doErase ) theIter = list.erase(theIter) else theIter++;
Oslt.
Thanks.