Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Strange problem

Credits go to Thomas Fjellstrom for helping out!
This thread is locked; no one can reply to it. rss feed Print
Strange problem
Steve Terry
Member #1,989
March 2002
avatar

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.

___________________________________
[ Facebook ]
Microsoft is not the Borg collective. The Borg collective has got proper networking. - planetspace.de
Bill Gates is in fact Shawn Hargreaves' ßî+çh. - Gideon Weems

Thomas Fjellstrom
Member #476
June 2000
avatar

Bump...

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Steve Terry
Member #1,989
March 2002
avatar

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

___________________________________
[ Facebook ]
Microsoft is not the Borg collective. The Borg collective has got proper networking. - planetspace.de
Bill Gates is in fact Shawn Hargreaves' ßî+çh. - Gideon Weems

Onewing
Member #6,152
August 2005
avatar

Quote:

featuring Alex

The alligator?

------------
Solo-Games.org | My Tech Blog: The Digital Helm

LennyLen
Member #5,313
December 2004
avatar

Quote:

The alligator?

I thought he meant this Alex. ;)

ImLeftFooted
Member #3,935
October 2003
avatar

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
Member #1,989
March 2002
avatar

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.

___________________________________
[ Facebook ]
Microsoft is not the Borg collective. The Borg collective has got proper networking. - planetspace.de
Bill Gates is in fact Shawn Hargreaves' ßî+çh. - Gideon Weems

ImLeftFooted
Member #3,935
October 2003
avatar

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
Member #1,989
March 2002
avatar

What would be a good solution to this?

___________________________________
[ Facebook ]
Microsoft is not the Borg collective. The Borg collective has got proper networking. - planetspace.de
Bill Gates is in fact Shawn Hargreaves' ßî+çh. - Gideon Weems

Jonatan Hedborg
Member #4,886
July 2004
avatar

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

Oslt.

Steve Terry
Member #1,989
March 2002
avatar

Thanks.

___________________________________
[ Facebook ]
Microsoft is not the Borg collective. The Borg collective has got proper networking. - planetspace.de
Bill Gates is in fact Shawn Hargreaves' ßî+çh. - Gideon Weems

Go to: