local help

BlitzMax Forums/BlitzMax Beginners Area/local help

Cruis.In(Posted 2006) [#1]
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?


Gabriel(Posted 2006) [#2]
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.


Cruis.In(Posted 2006) [#3]
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.


Gabriel(Posted 2006) [#4]
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.


SculptureOfSoul(Posted 2006) [#5]
Yep, Gabriel is right. If you change your outermost if/endif to a while/wend it'll work as you expect.


SculptureOfSoul(Posted 2006) [#6]
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.


Jesse(Posted 2006) [#7]
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



Cruis.In(Posted 2006) [#8]
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.


Gabriel(Posted 2006) [#9]
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.


Jesse(Posted 2006) [#10]
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.


tonyg(Posted 2006) [#11]
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



Grey Alien(Posted 2006) [#12]
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.


tonyg(Posted 2006) [#13]
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.


Brucey(Posted 2006) [#14]
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...


Grey Alien(Posted 2006) [#15]
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.


Cruis.In(Posted 2006) [#16]
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


TomToad(Posted 2006) [#17]
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++


tonyg(Posted 2006) [#18]
... which is what people have been trying to say.


Cruis.In(Posted 2006) [#19]
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?


tonyg(Posted 2006) [#20]
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.