local help
BlitzMax Forums/BlitzMax Beginners Area/local help
| ||
hey guys take a look at this If hit = True Local frame:Float SetAlpha 1.0 SetRotation 0 DrawImage explosion,targetship.x,targetship.y,frame frame :+ 0.5 If frame > 6 hit = False frame = 0 End If End If if i use local frame:float then frame does not update and the anim image hence does not animate, but if i change that to global it works. I dont understand...why? |
| ||
Because you're defining the scope of the variable to that section of code, not the entire function or whatever you think the scope is. In this case, I would imagine, it's local to within that If..EndIf you've shown above. Every time program execution goes out of that If..EndIf section, the variable goes out of scope and is gone. Then when you come back in again, it's recreated. |
| ||
but the program doesnt go out, while that condition is true. hit remains true until all the frames have gone by. i even draw text for hit being true if it is, to the screen. and it says hit is true and frame wont update. so it isn't going outside the scope. |
| ||
If and While are two completely different things. Your code says "If" hit is true. That condition is only evaluated at the top of the code section. At the end, program execution carries on regardless, because no further checking is done. So you are leaving that section. I presume you have some kind of loop which is constantly running this section of code. As soon as you go past the EndIf, you're out of scope. |
| ||
Yep, Gabriel is right. If you change your outermost if/endif to a while/wend it'll work as you expect. |
| ||
Further, you might want to separate your frame update code from the actual hit event, otherwise each time a hit registers, your game is going to waste 13 loop cycles (since it's increasing your frame variable by .5 and the loop will only exit once it's at 6.5), and nothing else will be updated (the explosion essentially pauses the game briefly.) Instead of handling the animation right then, you could just create an object that represents your explosion, add it to a list, and then every frame call Update on everything in the list. THen your update function can draw the object each frame , increase the objects internal frame counter and test to see if the animation is over and the object should be destroyed. |
| ||
I'll show you what exactly is happening here:If hit = True Local frame:Float everytime the if statement is executed frame is recreated. in other words, frame will be allocated and assigned the value of zero. SetAlpha 1.0 SetRotation 0 DrawImage explosion,targetship.x,targetship.y,frame frame :+ 0.5 If frame > 6 hit = False frame = 0 End If End If and when the if statement is completed "end if" the variable is released and it will no longer exist. if your if istatement is within a loop, create the local variable at the begining of the loop. it will take care of the problem. Just take in consideration that it will exist only with in the scope of the loop - same principle as the if statement and will behave the same in methods and functions. an example program code useless but explains most of the points: local a:float = 3.0 ' it will be abailable for the whole program exept types and functions. while not keydown(key_esacape) local b:float = 5.0 'will exist with in the scope of the loop a = a + 3.0 'a is available inside the while loop if a = 6.0 then local c:float = 33.0 c:+ (b+a) ' all variables are available within the if statement print c end if 'c will no longer exist print b+a ' b and a still exist wend ' b will no longer exist print a ' a is the only variable available while the program exists |
| ||
that function is already called in the main loop. so when the if condition evaluates to true, it keeps doing the instructions. putting while, wend, freezes the computer. |
| ||
that function is already called in the main loop So, as I said, program execution is leaving the chunk of code you posted above. And, as I said, the solution is to define your variable as global or as local to the entire section of code in which it is used, not just part of it. |
| ||
yes and every time it cycles through the if, it recreats frame and it initialize to 0 and frame will allways be .5 put a print after adding .5 to frame and you will see what I mean. if you dont mind, post all of your code or at least a larger chunk and we can help you with it. Otherwise we are only guessing. |
| ||
Setting frame to global within the if statement will initialise it once and then keep it's value...SuperStrict Graphics 640,480 Local HIT:Int=-1 While Not KeyHit(KEY_ESCAPE) If KeyHit(KEY_SPACE) HIT = - HIT If HIT = 1 Cls Global MYINT:Int MYINT:+ 1 DrawText MYINT,0,0 EndIf Flip Wend |
| ||
reallly it would be much better as global and moved outside of that chunk of code to the top of your code where you should declare all globals and consts. |
| ||
Wouldn't that depend on what else is happening? Ideally 'frame' would be a field within an 'explosion' object. If you set 'frame' as global to the whole program and you have, say, 10 explosions, you'd need 10 seperate global statements which is cumbersome and, most likely, unworkable. |
| ||
Hmmm... Cruis, I guess your main problem is understanding what is called "variable scope". Variable scope describes when certain information is accessible. Local variables declared inside If, When, For loops (etc) are only "accessible/visible" from within that block of code. Once you leave that block the variable no longer exists. Here's a quick example, looking at the scope of a local variable "frame" : While something = True ' frame doesn't exist here (not in scope) If stuff = False Then ' frame doesn't exist *yet* (still not in scope) Local frame:Int ' frame is set to zero ' frame is now in scope until the End If DrawAFrame(frame) frame:+ 1 If frame > 6 Then ' in this example, we'll never get here, because frame ' will always be 1 when we get here, because of "scope" frame = 0 End if End If ' frame doesn't exist here (not in scope) Wend When frame "goes out of scope" it ceases to exist. Therefore, the next time we want to use it, it is recreated (and hence its value is reset to zero) Rather you do something like : Local frame:Int ' frame is set to zero ' frame is now in scope... While something = True ' frame is still in scope If stuff = False Then DrawAFrame(frame) ' since frame is still in scope, its value will increment ' as the program iterates over the While loop. frame:+ 1 If frame > 6 Then frame = 0 End if End If ' frame is still in scope Wend ' frame is still in scope here As you can see, any nested blocks of code remember the scope of local variables declared before they are called. .. Try googling for "variable scope" examples, which might help you to get a better understanding of the concept... |
| ||
TonyG: Yeah you are right of course. I was just talking about for that simple example, however I would totally recommend having a sprite Type with a frame field as you suggest. |
| ||
Wouldn't that depend on what else is happening? Ideally 'frame' would be a field within an 'explosion' object. If you set 'frame' as global to the whole program and you have, say, 10 explosions, you'd need 10 seperate global statements which is cumbersome and, most likely, unworkable. which is why now I have moved everything back into a type, and created various functions for various explosions. a missile impact, a ship blowing up etc etc... also I believe the reason I started this thread was because I HAD put the local frame outside the if statemment at one point to see if that helped and it didn't make a difference. I think. Ill do it again when I leave work and let you know for sure. Regardless I thought it was weird hence why I posted, since I am sure that I had it outside that scope, maybe not in the example I posted, but I did try it like that to see if it had solved the problem. as for posting more code, thats it basically... thats the function and the function was in the loop and when you got HIT, the boolean hit became true and started the block, and it works when frame was a global. thanks again |
| ||
as for posting more code, thats it basically... thats the function and the function was in the loop and when you got HIT, the boolean hit became true and started the block, and it works when frame was a global. Wait a minute, are you saying that the If/End If is a seperate function from the main game loop? Something like this? Global Hit:Int = False While Not GameOver UpdateShips() If Bullet Collides With Ship Then Hit = True Do Explosions() Wend Function DoExplosions() If Hit = True Local frame:int DrawImage Explosion,ShipX,ShipY,frame frame :+ .5 If Frame > 6.0 Hit = False Frame = 0 End If End If End Function If that's the case, then it explains why frame keeps loosing it's value. Whenever the function ends, frame loses scope and has to be recreated the next time the function is called. By using Global instead of Local, you are then keeping the value between function calls, which is the proper way to do that. Don't worry about it interfering with another frame declared elsewhere in your code, Globals declared within a function remain Global only to that function. Edit: Globals within a function act like static variables in C++ |
| ||
... which is what people have been trying to say. |
| ||
that is almost exact, the if bullet collides with ship part is in a collision function. which is called before your doexplosions() example code.'main while other main loop code..... collision() doexplosions() wend so you mean I could revert back to using functions and create 3 functions all with the same "global frame" instead of having to use my oop code? oh my, i know its either or, but which do you guys recommend I stick with? |
| ||
The static/'global within the scope of a function' method works with both OOP and modular. However, frame would work better as a field in an object. |