Strange problem
Steve Terry

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;

1void 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 
33void 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 
3using namespace std;
4 
5BlockScan::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 
61BlockScan::~BlockScan()
62{
63 DEBUG("BlockScan::~BlockScan()");
64}
65 
66void 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 
170bool 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.

Thomas Fjellstrom

Bump...

Steve Terry

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"}img

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 :)

Onewing
Quote:

featuring Alex

The alligator?

LennyLen
Quote:

The alligator?

I thought he meant this Alex. ;)

ImLeftFooted

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.

Steve Terry

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.

ImLeftFooted

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.

Steve Terry

What would be a good solution to this?

Jonatan Hedborg
if( doErase )
 theIter = list.erase(theIter)
else theIter++;

Oslt.

Steve Terry

Thanks.

Thread #589365. Printed from Allegro.cc