Sign in to follow this  
yewbie

Breaking a switch and a for loop?

Recommended Posts

yewbie    677
I have a function that has a for loop and then a switch inside of it, if I break from inside the switch does that also break the for loop? the code works fine im just not sure if its doing what its supposed to =p
void DrawButtons(int iGameState)
{
	for (int i=0;i<MAX_BUTTONS;i++) //loop through all of our buttons and find one that is not used in the struct
	{
		switch(iGameState)
			{
				case GS_INTRO:
					{
						if (MyButtons[i].GameState == GS_INTRO && MyButtons[i].ButtonID > 0) //we found a  non blank button
							{
								DrawButton(i);
							}
						
					}break;
				case GS_MAINMENU:
					{
						if (MyButtons[i].GameState == GS_MAINMENU && MyButtons[i].ButtonID > 0) //we found a non blank button
							{
								DrawButton(i);
							}							
							
					}break;
				
				case GS_GAMEROOMSELECT:
					{
						if (MyButtons[i].GameState == GS_GAMEROOMSELECT && MyButtons[i].ButtonID > 0) //we found a non  blank button
							{
								DrawButton(i);
							}							
							
					}break;
				
				case GS_GAMESTART:
					{			
						if (MyButtons[i].GameState == GS_GAMESTART && MyButtons[i].ButtonID > 0) //we found a non blank button
							{
								DrawButton(i);
							}
					}break;
				case GS_TRANSITION:
					{
						//no buttons in transition (why would you want one)
					}break;
			}//end switch
	}//end for loop
}

Share this post


Link to post
Share on other sites
speciesUnknown    527
break; breaks out of the CURRENT construct. Your application should NOT be breaking out of the for loop. If you really want to write bad code, replace the entire thing with gotos. In the case of switch statements, using break is acceptable, since its a part of the actual construct. [lol]

I've been known to break out of a for loop like this:

int break_out = 0;

for(
x=0;
(x<10 && !break_out);
x++
)
{
if(whatever)
break_out = 1;
}



But only as a way to mock the examiner in a C test.

[Edited by - speciesUnknown on February 20, 2008 11:29:44 PM]

Share this post


Link to post
Share on other sites
Shiny    456
Ah yes, the ole premature closure argument.

Let's be frank -- production code has this sort of stuff in it all the time. CS profs disliking break have not stopped hojillions of client programmers sticking it in code all over the place. Generally speaking, the only time you want to get out of a loop early is when you've hit some sort of condition that means looping is no longer warranted or perhaps even possible. Many languages have a tool for solving this problem! ;)

While(condition holds)
{
Do stuff!
}

Different depending on which language you use -- but designed to allow you to hop out when you meet some condition -- much nicer than breaking out of a for-loop :)

That said, break shouldn't always be avoided -- it was put in for a reason after all. You ought to be careful however, because if you were to do something silly like allocate unmanaged memory in a nested scope such as a loop...and then break out prematurely -- you may end up with leaks. Some languages like C# & Java clean up the stuff you create in a loop (unless you went to lengths to avoid it...naughty!), but most of the time you should be a bit careful :)

~Shiny

Share this post


Link to post
Share on other sites
gekko    478
You could create a flag used to determine if it should break out, and just check it after the switch statement. Or you could use a goto, or turn the switch into a nested if/else and use break, or rewrite your code so you don't face this problem. No one ever said you needed to like your options :p

If this is the only thing the function is doing, you could simply return.

Share this post


Link to post
Share on other sites
Antheus    2409
I don't know, but I'd replace the above with:

void DrawButtons(int iGameState)
{
if (iGameState != GS_TRANSITION) {
for (int i=0;i<MAX_BUTTONS;i++) //loop through all of our buttons and find one that is not used in the struct
{
if (MyButtons[i].GameState == iGameState && MyButtons[i].ButtonID > 0) {
DrawButton(i);
break;
}
}//end for loop
}
}

Share this post


Link to post
Share on other sites
Saughmraat    140
How about this...


void DrawButtons(int iGameState)
{
for (int i=0;i<MAX_BUTTONS;i ++ )
{
bool flag = true;
if( iGameState == GS_TRANSITION) flag = false;
if(MyButtons[i].GameState != iGameState) flag = false;
if(MyButtons[i].ButtonID <= 0) flag = false;

if(flag)
{
DrawButton(i);
//return; if u wish u can return here
}
}
}

//errrrrrr how can I format the text?? It's removing the spaces :(

Share this post


Link to post
Share on other sites
Saughmraat    140
Quote:
Original post by Antheus
I don't know, but I'd replace the above with:
*** Source Snippet Removed ***


hmmmm

a small explaination..

My previous post didn't target u.

It targets the author.

Both of us posted in almost same time :D


Share this post


Link to post
Share on other sites
Antheus    2409
Quote:
Original post by Saughmraat
Quote:
Original post by Antheus
I don't know, but I'd replace the above with:
*** Source Snippet Removed ***


hmmmm

a small explaination..

My previous post didn't target u.

It targets the author.

Both of us posted in almost same time :D


Yes... your post came 4 minutes later.

And it's [ source ] or [ code ] tags for posting code, with former being preferred.

Share this post


Link to post
Share on other sites
Zahlman    1682
Simplify your code.

Right now, you have a logical structure equivalent to:


Check what kind of fruit I'm holding.
Apple?
If I like apples, eat it.
Orange?
If I like oranges, eat it.
Kumquat?
If I like kumquats, eat it.
// Repeat for every other kind of fruit.


This is needlessly repetitive: all you need to do is ask yourself if you like the kind of fruit that you're holding.

Similarly here. No matter what the 'case' is, you simply compare each button's game state to the provided game state, so there is no reason to switch. The 'transition' isn't a special case, because there won't be any buttons anyway, so the loop won't be even entered.


void DrawButtons(int iGameState)
{
for (int i=0;i<MAX_BUTTONS;i++) //loop through all of our buttons and find one that is not used in the struct
{
if (MyButtons[i].GameState == iGameState && MyButtons[i].ButtonID > 0) {
DrawButton(i);
}
}
}


I strongly suspect that you're making a lot of other things more complicated and/or less flexible than necessary, based on what I see here, but let's take it one step at a time...

Share this post


Link to post
Share on other sites
yewbie    677
Zahlman, thanks for taking the time to explain it!! looking at the code now, its pretty silly =p, yeah I had alot of overly broken up switches like this.. I think 90% of my problem is no actual schooling =p, alot of people tend to look at my code and go, "ugh, why did you do it that way?!"

Share this post


Link to post
Share on other sites
yewbie    677
Wanna tear this one apart too? haha im so awful


//this animates our tiles
void AnimateTiles()
{
DWORD currenttickcount = GetTickCount();

//loop through all of our animated tiles
for (int i=0;i<MAX_ANIM_TILES;i++)
{//#1
if (MyAnimTiles[i].iAnimNum == 0){break;} //break the loop if we are at the end of our list
if ((MyAnimTiles[i].iLastTickCount + MyAnimTiles[i].iAnimSpeed) < currenttickcount) //if its time to change the tile
{//#2

//Increment our tile by 1
MyAnimTiles[i].iTile++;

//if we are passed our last tile reset it to the original start tile in the animation
if (MyAnimTiles[i].iTile > (MyAnimTiles[i].iOrignalTile + MyAnimTiles[i].iAnimNum) -1)//reset if passed our anim count (-1 so we count our first tile)
{
MyAnimTiles[i].iTile = MyAnimTiles[i].iOrignalTile;
}

//only do below if its on scrren + 2 tiles
if ((MyAnimTiles[i].x > (MySceneData.topleftX - 2)) && //top left
(MyAnimTiles[i].x < (MySceneData.topleftX + TILE_SCREEN_MAX_X + 2)) &&//bottom right
(MyAnimTiles[i].y > (MySceneData.topleftY - 2)) && //top left
(MyAnimTiles[i].y < (MySceneData.topleftY + TILE_SCREEN_MAX_Y + 2)))
{//huge if statement with bounds start
//update the tiles on top of it
for (int layer=0;layer<TILEMAP_LAYERS;layer++)
{
if (layer == MyAnimTiles[i].layer)//if its our animation layer
{
//update the location on our off screen map
tsTileMap.PutTile(lpddsOffScreenMap,MyAnimTiles[i].x*TILE_SIZE_X,MyAnimTiles[i].y*TILE_SIZE_Y,MyAnimTiles[i].iTile);
}
else //any other layer (we have to do it this way to get the information of the tile from our struct to place it
{
if (MyMapInfo[MyAnimTiles[i].x][MyAnimTiles[i].y][layer].iTile > 0) //if there is a tile there
{
//update the location on our off screen map using our animated tile to show where we are
tsTileMap.PutTile(lpddsOffScreenMap,MyAnimTiles[i].x*TILE_SIZE_X,MyAnimTiles[i].y*TILE_SIZE_Y,
MyMapInfo[MyAnimTiles[i].x][MyAnimTiles[i].y][layer].iTile);
}
}
}

}//huge if statement with bounds end

MyAnimTiles[i].iLastTickCount=currenttickcount;//reset our timer
}//#2

}//#1



}//function end

Share this post


Link to post
Share on other sites
Zahlman    1682
Quote:
Original post by yewbie
Wanna tear this one apart too? haha im so awful


Sure thing. :)

Please skim through the whole post first, ignoring source, and then make sure to read it all later. All the ideas here are important, and aren't ordered by importance but by logical order of execution.

Step 1: tell, don't ask. One of the reasons for this is that "asking" imposes on the other object to be able to answer. Another is that solving a problem by "asking" tends to require doing a lot of asking, compared to just one round of telling that provides all the necessary information.

In our case, AnimateTiles constantly tries to "ask" MyAnimTiles[i] about itself. We should instead demand that it animate(), and "tell" it the necessary information. That requires that we add the .animate() function to the Tile interface, but in exchange we get to make lots of things private (like they ought to be) and/or remove accessors (if you were using them). That's real encapsulation.

Notice, though, that the tile needs to be able to break AnimateTiles' loop. To do that, we return a value, and check it in the loop.


// Notice how a zillion instances of 'MyAnimTiles[i]' simply disappear.
// Also notice how I stealthily removed a lot of useless comments, and
// reformatted a few things...

// Animate the tile. Return whether or not this is the "sentinel".
// I'm guessing about the names of your classes, of course. Adjust as needed.
bool Tile::Animate(int currenttickcount, const SceneData& scenedata, TileMap& tilemap, Surface* offscreenmap, const Tile* mapinfo) {
// I assume your "mapinfo" is a single rectangular array, and not some
// kind of dynamically allocated monstrosity.
if (iAnimNum == 0) {
return true;
}

if ((iLastTickCount + iAnimSpeed) < currenttickcount)
{
iTile++;

// if we are past our last tile, reset it to the original
// start tile in the animation.
if (iTile > (iOrignalTile + iAnimNum) - 1)
// reset if past our anim count (-1 so we count our first tile)
{
iTile = iOrignalTile;
}

//only do below if its on screen + 2 tiles
if ((x > (scenedata.topleftX - 2)) && //top left
(x < (scenedata.topleftX + TILE_SCREEN_MAX_X + 2)) && //bottom right
(y > (scenedata.topleftY - 2)) && //top left
(y < (scenedata.topleftY + TILE_SCREEN_MAX_Y + 2)))
{
//huge if statement with bounds start
//update the tiles on top of it
for (int layer = 0; layer < TILEMAP_LAYERS; layer++)
{
// Notice how we disambiguate the local variable
// from the member variable here:
if (layer == this->layer)
{
//update the location on our off screen map
tilemap.PutTile(offscreenmap, x * TILE_SIZE_X, y * TILE_SIZE_Y, iTile);
}
else
{
if (mapinfo[x][y][layer].iTile > 0)
// if there is a tile there
{
// update the location on our off screen
// map using our animated tile to show
// where we are
tilemap.PutTile(offscreenmap, x * TILE_SIZE_X, y * TILE_SIZE_Y, mapinfo[x][y][layer].iTile);
}
}
}
}
iLastTickCount = currenttickcount;
}
return false; // not the last one
}

void AnimateTiles()
{
DWORD currenttickcount = GetTickCount();
for (int i = 0; i < MAX_ANIM_TILES; i++)
{
if (MyAnimTiles[i].Animate(currenttickcount, MySceneData, tsTileMap, lpddsOffScreenMap, MyMapInfo))
{
break;
}
}
}



Step 2: Fix our container. This is C++; we don't need to make an array of some "max" size and then check how many elements are actually being used with some kind of "flag" data. Instead, we use the standard library container std::vector. This will avoid the need for our hack to break the loop.

I'm a little worried about something at this point. Is there, in fact, a Tile for every coordinate on the map? If there is, then there's no reason to store x and y values within each tile. I'm going to assume, though, that you only have Tiles for the parts of the map which are animating.

Anyway, while I'm on this step, I'm going to fix up some names to be a little more consistent, mostly by getting rid of the useless Hungarian notation. The C++ type system is much stronger than C's, and it wants to help you; let it.


// More comments disappear as the names become clearer.
void Tile::Animate(int currentTickCount, const SceneData& sceneData, TileMap& tileMap, Surface* offScreenMap, const Tile* mapInfo) {
if ((lastTickCount + ticksPerAnimationFrame) < currentTickCount)
{
frame++;

// if we are past our last tile, reset it to the original
// start tile in the animation.
if (frame > (firstFrame + frameCount) - 1)
{
frame = firstFrame;
}

// Check if the tile is within the scene bounds.
// BTW, I think you'll agree that names like 'topleftX' and
// 'topleftY' are quite strangely round-about ways of saying...
if ((x > (sceneData.left - 2)) && // left
(x < (sceneData.left + TILE_SCREEN_MAX_X + 2)) && // right
(y > (sceneData.top - 2)) && // top
(y < (sceneData.top + TILE_SCREEN_MAX_Y + 2))) // bottom
{
// Update each layer at the tile's location.
for (int layer = 0; layer < TILEMAP_LAYERS; layer++)
{
if (layer == this->layer)
// draw our tile in the current layer.
{
tilemap.PutTile(offScreenMap, x * TILE_SIZE_X, y * TILE_SIZE_Y, frame);
}
else
// draw tiles from the map info in other layers.
{
if (mapInfo[x][y][layer].frame > 0)
// there is a tile to draw
{
// update the location on our off screen
// map using our animated tile to show
// where we are
tilemap.PutTile(offScreenMap, x * TILE_SIZE_X, y * TILE_SIZE_Y, mapInfo[x][y][layer].frame);
}
}
}
}
lastTickCount = currentTickCount;
}
}

void AnimateTiles()
{
DWORD currentTickCount = GetTickCount();
std::vector<Tile>::iterator end = animatedTiles.end();
for (std::vector<Tile>::iterator it = animatedTiles.begin(); i != end; ++it)
{
it->Animate(currentTickCount, sceneData, tileMap, offScreenMap, mapInfo);
}
}



Step 3: Use "guard clauses" in the Animate function (early returns) to avoid deep nesting. The basic idea is, we replace "if something, do the rest of this function" with "if not something, ignore the rest of this function". Notice that we want to update the tick count even if the sprite is off screen, so we can't just return there. However, the inner if scope doesn't care about the value of the tick count, so we can fix the problem by just updating the tick count before checking if the tile is in bounds.


// More comments disappear as the names become clearer.
void Tile::Animate(int currentTickCount, const SceneData& sceneData, TileMap& tileMap, Surface* offScreenMap, const Tile* mapInfo) {
if ((lastTickCount + ticksPerAnimationFrame) >= currentTickCount)
{
return; // not time to update this tile.
}

frame++;

// if we are past our last tile, reset it to the original
// start tile in the animation.
if (frame > (firstFrame + frameCount) - 1)
{
frame = firstFrame;
}

lastTickCount = currentTickCount;

// Check if the tile is within the scene bounds.
// Pay close attention to how the condition is inverted. The ands get
// replaced by ors. Google 'de Morgan' if you don't understand why.
if ((x <= (sceneData.left - 2)) || // left
(x >= (sceneData.left + TILE_SCREEN_MAX_X + 2)) || // right
(y <= (sceneData.top - 2)) || // top
(y >= (sceneData.top + TILE_SCREEN_MAX_Y + 2))) // bottom
{
return;
}

// Update each layer at the tile's location.
for (int layer = 0; layer < TILEMAP_LAYERS; layer++)
{
if (layer == this->layer)
// draw our tile in the current layer.
{
tilemap.PutTile(offScreenMap, x * TILE_SIZE_X, y * TILE_SIZE_Y, frame);
}
else
// draw tiles from the map info in other layers.
{
if (mapInfo[x][y][layer].frame > 0)
// there is a tile to draw
{
// update the location on our off screen
// map using our animated tile to show
// where we are
tilemap.PutTile(offScreenMap, x * TILE_SIZE_X, y * TILE_SIZE_Y, mapInfo[x][y][layer].frame);
}
}
}
}

void AnimateTiles()
{
DWORD currentTickCount = GetTickCount();
std::vector<Tile>::iterator end = animatedTiles.end();
for (std::vector<Tile>::iterator it = animatedTiles.begin(); i != end; ++it)
{
it->Animate(currentTickCount, sceneData, tileMap, offScreenMap, mapInfo);
}
}



Step 4: Same idea as step 1, again.

When we check the tile bounds, what are we checking against? The bounds of the SceneData, yes? Who has that information? The SceneData - so that's who should perform the check. Similarly, the MapInfo knows what non-animating tiles are at the current location, so it is what should do the drawing of that "stack" of tiles. In the first case, we just pass the x and y along, so the SceneData knows what location to check. In the second, we need to communicate x and y, but also our frame - so that the MapInfo can substitute it in where appropriate - and our layer - so that the MapInfo knows where it goes in the order.

Oh, but there's a problem, you say - the MapInfo isn't an object! It's just some multi-dimensional array. Well, we can easily fix that - just make the existing array be a member of some object, and instantiate the object instead of an array. I'll assume we call that member 'data'.

That will make a lot of other things easier, too. For example, the previous steps don't actually work, because passing the array as a pointer lost the information about the array size. ;) (You could make them work by doing arithmetic with the known dimensions of the array, but it's not very much fun.)


// Even more comments disappear, too. Creating new functions gives you a way to
// attach descriptive names to processes, which avoids having to explain what
// you are doing.

bool SceneData::isInBounds(int x, int y)
{
// I re-inverted the check. Sorry! :)
return (x > (left - 2)) &&
(x < (left + TILE_SCREEN_MAX_X + 2)) && // right
(y > (top - 2)) &&
(y < (top + TILE_SCREEN_MAX_Y + 2)); // bottom
}

void MapInfo::drawLocationWithAnimatedTile(int x, int y, int layer, int frame, TileMap& tileMap, Surface* offScreenMap)
{
// I change the counter variable now to avoid a name conflict.
for (int i = 0; i < TILEMAP_LAYERS; i++)
{
if (i == layer)
// draw our tile in the current layer.
{
tilemap.PutTile(offScreenMap, x * TILE_SIZE_X, y * TILE_SIZE_Y, frame);
}
else
// draw tiles from the map info in other layers.
{
if (data[x][y][i].frame > 0)
// there is a tile to draw
{
// update the location on our off screen
// map using our animated tile to show
// where we are
tilemap.PutTile(offScreenMap, x * TILE_SIZE_X, y * TILE_SIZE_Y, data[x][y][i].frame);
}
}
}
}

void Tile::Animate(int currentTickCount, const SceneData& sceneData, TileMap& tileMap, Surface* offScreenMap, const MapInfo& mapInfo) {
if ((lastTickCount + ticksPerAnimationFrame) >= currentTickCount)
{
return; // not time to update this tile.
}

frame++;

// if we are past our last tile, reset it to the original
// start tile in the animation.
if (frame > (firstFrame + frameCount) - 1)
{
frame = firstFrame;
}

lastTickCount = currentTickCount;

if (!sceneData.isInBounds(x, y))
{
return;
}

mapInfo.drawLocationWithAnimatedTile(x, y, layer, frame, tileMap, offScreenMap);
}

void AnimateTiles()
{
DWORD currentTickCount = GetTickCount();
std::vector<Tile>::iterator end = animatedTiles.end();
for (std::vector<Tile>::iterator it = animatedTiles.begin(); i != end; ++it)
{
it->Animate(currentTickCount, sceneData, tileMap, offScreenMap, mapInfo);
}
}



Step 5: We can now go backwards a little - our second guard clause doesn't make much sense any more in Tile::Animate(), because it only "guards" one statement.

Meanwhile, the drawLocationWithAnimatedTile() implementation can be simplified: in both cases, we calculate a tile to draw, and call a function with all the same parameters. If we determine the tile index *first*, then we only have to write the function call once. Also, SceneData::isInBounds() is a little paranoid with the brackets.

Finally, we can do an arithmetic simplification on the frame, if we change our convention: store the frame *relative to the sequence*, as well as the frame count. Then, our 'frame' member loops from 0 up to (frameCount - 1) and back, which we can do with a simple increment-and-modulus. Then to get the "actual" frame, we just add the 'frame' to the "offset" represented by 'firstFrame'. (This will presumably require changes to some of your other code which isn't illustrated here. In particular, the Tile constructor.)


bool SceneData::isInBounds(int x, int y)
{
return x > (left - 2) &&
x < (left + TILE_SCREEN_MAX_X + 2) && // right
y > (top - 2) &&
y < (top + TILE_SCREEN_MAX_Y + 2); // bottom
}

void MapInfo::drawLocationWithAnimatedTile(int x, int y, int layer, int frame, TileMap& tileMap, Surface* offScreenMap)
{
// I change the counter variable now to avoid a name conflict.
for (int i = 0; i < TILEMAP_LAYERS; i++)
{
int toDraw = (i == layer) ? frame : data[x][y][i];
if (toDraw > 0)
// There is a tile to draw. That will always happen when
// i == layer, but it doesn't hurt to check. :)
{
tilemap.PutTile(offScreenMap, x * TILE_SIZE_X, y * TILE_SIZE_Y, toDraw);
}
}
}
}

void Tile::Animate(int currentTickCount, const SceneData& sceneData, TileMap& tileMap, Surface* offScreenMap, const MapInfo& mapInfo) {
if ((lastTickCount + ticksPerAnimationFrame) >= currentTickCount)
{
return; // not time to update this tile.
}

frame = (frame + 1) % frameCount;

lastTickCount = currentTickCount;

if (sceneData.isInBounds(x, y))
{
mapInfo.drawLocationWithAnimatedTile(x, y, layer, frame + firstFrame, tileMap, offScreenMap);
}
}

void AnimateTiles()
{
DWORD currentTickCount = GetTickCount();
std::vector<Tile>::iterator end = animatedTiles.end();
for (std::vector<Tile>::iterator it = animatedTiles.begin(); i != end; ++it)
{
it->Animate(currentTickCount, sceneData, tileMap, offScreenMap, mapInfo);
}
}



Step 6: Conceptually, this is the big one. Separate updating and rendering logic. The 'drawLocationWithAnimatedTile' function tries to do too much - as you can tell by the name. Besides, what if you put two animated tiles one on top of the other? The first will get overwritten with a normal tile, when you process the second. What you want to do is let the MapInfo object track the changes to the data - by storing the frames into the array! - and then render, all at once, everything that needs to be rendered.

But those are still not steps that need to follow each other directly. By separating updating and rendering logic, you gain the ability to render several times per update, or vice versa. A common strategy in games, to keep the physics consistent, is to update at regular intervals, while rendering as often as possible in the remaining CPU time. This way, the game doesn't *behave differently* if there is some lag; it merely looks a little blocky for a while.

To make this work, we'll need to add some data to the MapInfo to keep track of whether a "column" (set of layers at a given x, y) has changed since the last rendering. To update it, we'll set the appropriate tile, and also flag the corresponding column. To render it, we'll render all the tiles in every flagged column, and clear all the flags. This also avoids special case code in the rendering: we just read the tile values, since they're already set as needed.

We should update every tile, not just those that are in bounds; otherwise, animations can get out of sync. We'll only render the tiles that are in bounds, by having the SceneData ask the MapInfo to do the rendering, telling it what bounds to use. Notice that the control flow changes radically, but the guiding principle of "tell, don't ask" is the same.


void SceneData::render(const MapInfo& mapInfo, TileMap& tileMap, Surface* offScreenMap)
{
// Check that the constant values are what they ought to be:
// the width and height of the map, not "corrected" by -1.
mapInfo.render(x, y, TILE_SCREEN_MAX_X, TILE_SCREEN_MAX_Y, tileMap, offScreenMap);
}

void MapInfo::render(int x, int y, int width, int height, TileMap& tileMap, Surface* offScreenMap)
{
for (int i = x; i < x + width; ++i) {
if (i < 0 || i >= MAP_WIDTH) {
continue;
}
for (int j = y; j < y + height; ++j) {
if (j < 0 || j >= MAP_HEIGHT || !dirty[i][j])
{
continue;
}
for (int layer = 0; layer < TILEMAP_LAYERS; ++layer)
{
tilemap.PutTile(offScreenMap, x * TILE_SIZE_X, y * TILE_SIZE_Y, data[x][y][layer]);
}
dirty[i][j] = false;
}
}
}

void MapInfo::Update(int x, int y, int layer, int frame)
{
data[x][y][layer] = frame;
dirty[x][y] = true;
}

// Our old "Animate" function for the tile will really only update;
// rendering is taken care of completely by the MapInfo.
// We end up removing a whole bunch of parameters here.
void Tile::Update(int currentTickCount) {
if ((lastTickCount + ticksPerAnimationFrame) >= currentTickCount)
{
return; // not time to update this tile.
}

frame = (frame + 1) % frameCount;

lastTickCount = currentTickCount;

mapInfo.Update(x, y, layer, frame + firstFrame);
}

void UpdateTiles()
{
DWORD currentTickCount = GetTickCount();
std::vector<Tile>::iterator end = animatedTiles.end();
for (std::vector<Tile>::iterator it = animatedTiles.begin(); i != end; ++it)
{
it->Animate(currentTickCount);
}
}
// To render the tiles, we call the sceneData.Render().



There are probably further steps, depending on the rest of your code :)

Share this post


Link to post
Share on other sites
yewbie    677
Heh good any good tutorials or book recommendations I have really not been exposed to very much C++ with the class and how you declared those functions with the ::, nothing is in classes as is :(, gunna have more time to mill over this tonight.

Share this post


Link to post
Share on other sites
Intrigue7    122
Quote:

Anyway, while I'm on this step, I'm going to fix up some names to be a little more consistent, mostly by getting rid of the useless Hungarian notation. The C++ type system is much stronger than C's, and it wants to help you; let it.


I'm a C programmer and I am wondering why you consider Hungarian notation as useless.. It intrigued me so I started to dig more info on google and everyone seems to agree with you... But... I still do not know why.. lol. I'd appreciate a small clarification on this. Also, what do you mean by C++ type system wants to help you ?

I found this web site last week-end and it's now my new homepage :P Good job for the replies !

Thanks !

Share this post


Link to post
Share on other sites
yewbie    677
It might also help a little to tell you what I actually do to render my map, I have a large off screen surface that holds my complete map that is drawn when the map loads, I just blt out my data from that offscreen surface to my screen and draw my gui elements etc around it.

Animate tiles is called every frame and what it does is update that tile on the map and all the tiles above it and below it (it only actually draws it if its on screen). heh this all looks amazing, but its kinda hard to understand seeing as I have never used this before =p, also when the map is loaded any tile that does animation is loaded into our array below.


struct ANIMTILES
{
int x;
int y;
int layer;
int iTile;
int iOrignalTile;
DWORD iLastTickCount; //this is the last tick we changed the tile
DWORD iAnimSpeed;//speed in MS of animation
int iAnimNum;//number of tiles in the animation
};ANIMTILES MyAnimTiles[MAX_ANIM_TILES];


what im not understanding is this


std::vector<Tile>::iterator end = animatedTiles.end();
for (std::vector<Tile>::iterator it = animatedTiles.begin(); i != end; ++it)


im going to look up vector im assuming its something like a linked list, I tried to implement a linked list setup for all my structs containing variable ammounts of information like this and failed miserably =p

Share this post


Link to post
Share on other sites
Valeranth    100
Quote:
Original post by yewbie

struct ANIMTILES
{
int x;
int y;
int layer;
int iTile;
int iOrignalTile;
DWORD iLastTickCount; //this is the last tick we changed the tile
DWORD iAnimSpeed;//speed in MS of animation
int iAnimNum;//number of tiles in the animation
};ANIMTILES MyAnimTiles[MAX_ANIM_TILES];



Just a pit of advice, and some kool knowledge you can chage the last line from
'};ANIMTILES MyAnimTiles[MAX_ANIM_TILES];'
to
'} MyAnimTiles[MAX_ANIM_TILES];'
and get the same thing.. Might save you time later, and Is also used with anonymous structs...

Say it with me
KNOWLEDGE IS POWER

Share this post


Link to post
Share on other sites
Ezbez    1164
Quote:
Original post by Intrigue7
I'm a C programmer and I am wondering why you consider Hungarian notation as useless..


C++ already checks types for you. Hungarian notation is nothing more than redundant in C++. And with a half-decent IDE, you can find out all the information that it provides in a fraction of a second. Read this article for an explanation of using Hungarian notation helpfully rather than redundantly.

Share this post


Link to post
Share on other sites
kloffy    1318
for(int i=0;;i++)
{
switch(i)
{
case 10: goto stop;
}
}
stop:

Edit: I just realized gekko beat me to it.

[Edited by - kloffy on February 23, 2008 7:04:18 PM]

Share this post


Link to post
Share on other sites
DevFred    840
Quote:
Original post by yewbie
what im not understanding is this

std::vector<Tile>::iterator end = animatedTiles.end();
for (std::vector<Tile>::iterator it = animatedTiles.begin(); i != end; ++it)


Isn't there an error in the loop condition? It should be it instead of i, right?

Share this post


Link to post
Share on other sites
Zahlman    1682
Quote:
Original post by Intrigue7
Quote:

Anyway, while I'm on this step, I'm going to fix up some names to be a little more consistent, mostly by getting rid of the useless Hungarian notation. The C++ type system is much stronger than C's, and it wants to help you; let it.


I'm a C programmer and I am wondering why you consider Hungarian notation as useless.. It intrigued me so I started to dig more info on google and everyone seems to agree with you... But... I still do not know why.. lol. I'd appreciate a small clarification on this. Also, what do you mean by C++ type system wants to help you ?


The primary reason you don't understand this is because you are a C programmer. :) The basic idea is that the whole point of having a type system is to catch type errors; otherwise, it is getting in your way. The idea with Hungarian notation is to supplement the "physical" type of a variable (the one the compiler understands) with a "logical" one (as indicated by the prefix). This loses the benefit of "the compiler understands", and comes at the expense of making humans do extra work to think about these cryptic prefixes.

In C++, we can create new types easily. Consider, for example, Joel Spolsky's example with "safe" and "unsafe" strings. Granted, his example is for PHP, which is dynamically typed. (I've often wanted to do Hungarian notation in my Python code, but it seems that some combination of unit testing and explicit type checking works much better.)

All we do is create the "safe string" type, by making a structure and writing the relevant functionality. Unsafe strings can continue to be represented with std::string. By requiring explicit conversions from unsafe -> safe, we cannot use an unsafe string without "escaping" it.


class SafeString {
std::string data;

explicit SafeString(const std::string& unsafe); // does the escaping logic.

public:
// The concatenation of two SafeStrings is always safe.
SafeString& operator+=(const SafeString& ss) { data += ss.data; return *this; }
SafeString operator+(const SafeString& ss) { return SafeString(*this) += ss; }
// We can't modify a SafeString's characters directly, because we could
// inject an unsafe character. But we can read them:
char operator[](size_t index) const { return data[index]; }
friend ostream& operator<<(ostream& os, const SafeString& ss) { return os << data; }
// etc. etc.

// Force clients to use a named function instead of a constructor, to make it
// clear what is going on. This, strictly speaking, probably isn't necessary.
friend SafeString escape(const std::string& unsafe) { return SafeString(unsafe); }

std::string unescape() { return data; } // makes an "unsafe" copy.
};

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this