3D Title Menu Problems.

Blitz3D Forums/Blitz3D Beginners Area/3D Title Menu Problems.

Captain Wicker (crazy hillbilly)(Posted 2011) [#1]
Hi,
I was wondering if it would be possible to write a title menu with a 3d background scene. Could someone please tell me how to do this?

Thanks and happy Thanksgiving!,
Cpt. Wicker


Yasha(Posted 2011) [#2]
Check out Draw3D:

Draw3D 2
Draw3D, original

The original has a title menu with 3D background as one of the packaged examples, which is why I'm linking that too (I haven't used Draw3D 2 myself so I don't know what it packages, but I assume the library itself is better so you should probably use that one).


Captain Wicker (crazy hillbilly)(Posted 2011) [#3]
Thanks Yasha i will soon look into that. :)


Captain Wicker (crazy hillbilly)(Posted 2011) [#4]
How can I make a transition from the title menu to the actual game?


Yue(Posted 2011) [#5]
Thank Yasha =).

Edit: I greatly appreciate that you are always to help, I very much appreciate your help on all your posts on these forums are really worth to me friend.

Last edited 2011


Kryzon(Posted 2011) [#6]
Hi Cpt. Wicker,

How can I make a transition from the title menu to the actual game?

Tell me what kind of transition you're looking for. If you can visualize how the menu should swap to the game that's half way walked.


Yue(Posted 2011) [#7]
Any help with this paper on Draw3D 2???


Kryzon(Posted 2011) [#8]
What help, with what paper?


Yasha(Posted 2011) [#9]
If you want help with Draw3D/Draw3D 2, you may want to check out the German Blitz forums. Hectic (the original author) is a German-speaker, so it has more of a presence over there - in fact, it even has its own documentation in the Help section ( http://www.blitzforum.de/help/?cat=8 ).


Yue(Posted 2011) [#10]
Thank Yasha!! =)


_PJ_(Posted 2011) [#11]
@Captain Wicker:


How can I make a transition from the title menu to the actual game?



As mentioned by Kryzon, you need to eplain your aim in a little more detail, as well as perhaps describing or providing some example code of what you already have. Otherwise, it's pretty much impossible to know how to offer any advice.


Captain Wicker (crazy hillbilly)(Posted 2011) [#12]
Alright here is what I have. Im trying to figure out how to jump to the main game after I click on play.


Last edited 2011


Kryzon(Posted 2011) [#13]
You don't need to call HidePointer every loop-cycle; it's a toggle feature, so call it once at the beginning and it should stay hidden until the app ends or you call ShowPointer.

In my opinion you're having trouble leaving that loop because you are leaving it out on the open.
If you encapsulate it inside a function you can show this menu state whenever you call the function that shows it, making it easier to establish the flow of your program. You can have several functions, each performing a different part of your game (a different state).

These kind of functions should be setup like this:
Function SCENE_Menu%()

	-> Block of code to setup the scene this function executes. 
	This means declaring local variables, positioning the camera etc.

	-> Block of code with a loop to run the scene. In your case, 
	a 'menu screen with options'. Whenever the user selects an
	option, you can have a special animation\transition like a 
	fade-out, for instance, and as soon as the transition ends 
	(that's when the next scene should start), you 'store the chosen 
	option in a local variable' and exit the loop with the Exit command.

	-> Block of code to free\clean anything this scene might have 
	loaded and that won't be used again, like a graphic\sound\font
	that is only used here.

	-> Return the 'chosen option stored in that local variable' as an 
	integer. This represents the "ID" of the new state to be run.

End Function


So you can "script" your game like this:
Global CurrentState ;The only global you should use in your entire program...

While Not CurrentState = STATE_Quit
	Select CurrentState
		Case STATE_Play
			CurrentState = SCENE_Play()
		Case STATE_Menu
			CurrentState = SCENE_Menu()
		Case STATE_Options
			CurrentState = SCENE_Options()
		Case STATE_Quit ;Redundancy check just for clearance.
			End
	End Select
Wend

End
It's very important that you do not enter another state from an already running state. If you do this, you would end up hanging a lot of unfinished state functions. I don't know if the program would eventually fail because of this, but in my eyes it's bad practice.
I prefer using an external loop like the above. This means that every SCENE_ function should return at its end an integer value corresponding to the next scene\state that should be run, so it's properly called once it ends and the program gets back to that root loop.

Be aware of the transitions between different states that may use the same assets, like the menu state and options state. Say they use the same background.
For this reason, you need to conditionally release assets before leaving the menu function: at that part at the end of the menu function, when you are releasing the assets that this game state used, check the user's choice.
If he's going to the options state, don't release any assets that it will use. If he's going to the 'play' state then you can release everything - next time the user goes back to the menu, the first part of the menu function will take care of loading whatever assets this state uses.

PS: I'm listening to MediEvil 2 right now.

Last edited 2011


Captain Wicker (crazy hillbilly)(Posted 2011) [#14]
Thanks Kryzon that was really into depth on what I needed to know. :)
I really appreciate your help on the subject. :)


Yasha(Posted 2011) [#15]
Kudos Kryzon, that's a really nice breakdown.

you would end up hanging a lot of unfinished state functions. I don't know if the program would eventually fail because of this


Functions need an "activation record" that includes things like the instruction pointer for whatever was happening beforehand, all the local variables for that function (otherwise, a recursive invocation of a function could mutate the first invocation's variables - that wouldn't make much sense!), etc. These are placed in a linear block of memory to form a "call stack". Each time you call a function, a new activation record is allocated along this stack; when the function returns, control returns to the previous function and the "current" position moves back "down" the stack again.

Since the stack requires memory to work, it is bounded by the limitations of your OS. Notably, on Windows, it has a fixed size determined at program start (usually one megabyte). This translates into potentially thousands of nested function calls, so you should be fine as long as you don't write anything that results in an infinite, or potentially infinite, chain of calls.

When the current activation record reaches or exceeds the size allocated by Windows, this will result in an error. In older systems this was potentially a security risk (as was any situation where you could end up writing data to memory outside of where it was supposed to go). When a B3D program overflows the stack, it will immediately exit without warning and without an error message, even in Debug mode (note that since the stack has been used up, it doesn't actually have any resources left to use to call the error message box!).

Note however that whether deep recursion is good practice varies tremendously from language to language. In Blitz3D, it's obviously not sensible, and anything you could do with recursion can be restructured as a loop (although recursion is still a much clearer way to structure algorithms that walk tree-shaped data structures, like 3D model hierarchies). However, some languages may offer "tail call elimination", where the final call from a function (e.g. "Return TailCall()") "replaces" the current activation record, resulting in infinite in-place recursion (functionally similar to a loop, but with parameters and locals); others may allocate activation records on the heap, allowing for vary large stacks, or even tree-shaped call structures with multiple resumable branches. So, tools and practices go together.

Last edited 2011


Kryzon(Posted 2011) [#16]
Great post, thanks.


Captain Wicker (crazy hillbilly)(Posted 2011) [#17]
Ok, I think I have figured this part out.
Function Print_Hello%()
    
    
    Print "hello World"
    WaitKey()
    Repeat 
    Forever
    
End Function


Print_Hello()


Is this how I am supposed to write a function?
Thanks,
Cpt. Wicker


Yasha(Posted 2011) [#18]
Yes (assuming that infinite loop after the message is what you want...). There are however three (and a half) other features of functions that it's worth knowing about:

1) Functions may have parameters. These are variables that have to be supplied along with the function call; you will be familiar with this concept from the builtin commands:

Function Print_Hello%(msg$)    ;Now takes one argument
    
    
    Print msg
    WaitKey()
    Repeat 
    Forever
    
End Function


Print_Hello("Sup world")


...in this modified version of your example, Print_Hello will now print the message that is passed to it, whatever that is. Note that you can compose calls to form more complex expressions (e.g. "Print_Hello(Get_Some_Message() + "!")"). You can also give parameters default values, which makes them optional (come back to this later when you're happy with the concept).

2) Functions may return a value, so that they can be used as value elements in expressions:

Function Add_Then_Double#(x#, y#)
    Return (x + y) * 2
End Function

;... can be used as part of an expression
Print Add_Then_Double(2, Ceil(Log(31) / Log(2))) + 5


The type marker after the function name refers to the return type of the function, so that B3D knows what type the returned value will be when it's used as part of an expression. You can leave it off for ints or functions that don't return values (actually there is no distinction between these in B3D).

3) Functions may have "Local" variables. Parameters are a special kind of local variable - i.e. variable slots that are created when the function is called and disappear again when the function exits:

Local a = 1, b = 2, c = 3
Global g = 2, h = 4

Function Foo(a, b)    ;This a and b are completely unrelated to the outer ones
    Local c = a + b * g    ;The global variable g is visible from inside the function, and if we change it, it will change the global outside
    Print "My local c is " + c
    Local h = c * g    ;Local variables can however "shadow" globals - this h makes the global h outside invisible
    Return h
End Function

Print Foo(c, b + a)    ;Prints "My local c is 9", then 18
Print c        ;Prints 3


If the function recursively calls itself (or indirectly calls other functions that call it), those invocations of the function will also have their own instances of the local variables that do not affect the "outer" function call.

3.5) You don;t need parentheses if you want to use a function as a command that spans the whole line; you only need them if you want it to return a value:

PositionEntity ent, 10, 20, 30    ;Standalone command - no () needed
Local xPos# = EntityX(ent)    ;Function as value expression


Last edited 2011


Captain Wicker (crazy hillbilly)(Posted 2011) [#19]
Now I have a problem. My code will not run correctly. I don't know what the problem is. Could you take a look at these for me?

Main Code \/
;*******************
;** Bucky the Box **
;** Practice File **
;*******************

AppTitle "Bucky the Box"
Graphics3D 800,600,32
SetBuffer BackBuffer()

HidePointer ;hide the windows mouse

Include "Includes\Draw3D.bb" ;load draw commands file
Include "Functions.bb" ;include game functions



Functions code \/



And of course the Draw3D commands.

Could you please study this and help me fix my problem?
Thanks a bunch,
Cpt. Wicker

Last edited 2011


Kryzon(Posted 2011) [#20]
When you run in Debug mode the IDE tells you what's wrong. I'm sure it must be telling something about that 'Timer' variable.
It's local to your main scope, so the SCENE_Menu function can't "see" that variable, but it's still trying to use it with that 'WaitTimer(Timer)' call.

Create a local timer and release it when you're done with it (with FreeTimer()), all this inside the function.

Also those "STATE_Play" and "STATE_Quit" identifiers should be integer Constants, not functions. They are simply values.
Const STATE_Play = 1
Const STATE_Menu = 2
Const STATE_Quit = 3
You keep the value in a constant so you have something to name this value with. You know it represents the ID number for a certain game state.


_PJ_(Posted 2011) [#21]
(Posted 15 hours ago) #19

Now I have a problem. My code will not run correctly. I don't know what the problem is. Could you take a look at these for me?




Again, "will not run correctly" isn't extremely helpful, can you clarify just WHAT isn't working right, what OUGHT to happen or where (if) you pereive the problem to originate?

_____________

For a start, you only need the include lines in ONCE (presumably in the main program NOT repeated in the functions code) otherwise, you will receive compilation errors regarding Duplicate Variable assignments or Function names.

Second: I don't see any call to SCENE_Menu function (which ideally might have the % removed, since it is a void funciton, but that's not entirely necessary right now)

Third: As Kryzon mentions, the STATE_Play, STATE_Menu and STATE_Quit should be constants and this will then give you errors on compilation unless you also DELETE THE EMPTY FUNCTION DEFINITIONS!

Otherwwise, aside from the localised Timer usage, I didn't see any real problems, so whatever your issue with the code is, you need to be more specific.


Captain Wicker (crazy hillbilly)(Posted 2011) [#22]
I just ran it in debug mode and it specifically says "Handle Not Set".
What is Handle? How can I fix the error?
Thanks for your time guys. means a lot. :)


Kryzon(Posted 2011) [#23]
Paste the line that gives the error.


Captain Wicker (crazy hillbilly)(Posted 2011) [#24]
If FDrawHandle=0 Then Runtime Error "Handle not set"

This is very strange because this error is coming from the Draw3D command set! What should I do? I have been using the Draw3D commands throughout my program.


Yasha(Posted 2011) [#25]
FDrawHandle is the standard name Draw3D gives to images and drawing materials. So this means you passed 0 to the drawing function instead of a valid, loaded material/font/image.

1) What function is the line in?

2) Where are you calling that function?

3) What are the values you are passing to that function? Are they all valid? (If you're not using IDEal, it's possible a typo is causing this, by the way. Check your variable names are all spelled correctly.)

4) If a real variable, that you assigned a loaded material to, is causing this error, where is it being reset to zero?




(Answer:

The error, assuming you're using the same code pasted above, is the same one Kryzon pointed out with the timer - you're loading your font and images into variables local to the outer scope, but trying to use them from within the SCENE_Menu function, where they aren't visible. The names in the function refer to variables local to it - Blitz3D will, annoyingly, create a new local variable if you reference a new name, even without the "Local" declaration. A decent IDE like IDEal will highlight this error in red.)

Last edited 2011


Captain Wicker (crazy hillbilly)(Posted 2011) [#26]
I'm using IDEal from FGF. :)
Can this be fixed? How can I use FreeTimer to solve this problem?

Last edited 2011


Yasha(Posted 2011) [#27]
How can I use FreeTimer to solve this problem?


...eh? No, I just meant it was a scoping issue, similar to whatever he meant about timers. You don't need FreeTimer to do anything with Draw3D.

I'm using IDEal


At the right end of the top row of buttons there should be one labelled either "Strict On" or "Strict Off". Make sure it's set to "Strict On". This will highlight any undeclared names in red (it will also highlight all Draw3D commands, because they were declared in a separate file. To make it recognise declarations from other files, you have to add them all to the same project... I'm sure you can work out how to do that - start with the second button on the left, "New Project"). It will show you the undeclared variables in SCENE_Menu.


Now... do you understand the essentials of Blitz3D's "scope" rules? Refer to item 3 of my post about functions above for an example - make sure you understand it.

To recap, "local" variables are visible only in their own scope - either a function, or the outer program (henceforth "main scope"), and if you nest multiple calls to the same function, each invocation gets a new set of those locals so they don't interfere. "Global" variables are visible throughout the program at all times (assuming you don't shadow them). "Parameters" are a special kind of local that are set with external values when the function is called. Undeclared names - which should now be highlighted as errors in IDEal - default to local variables.

So, this means you have two main ways of getting the values from where you load the resources, in the main scope, to where you use them in the function scope. You can pass them into the function as parameters, which is essentially specifying to the function each time it's called which resources it can use; or you can assign them to global variables, and any function will be able to read from them at all times.

Assuming these resources are more or less constant "background" data that your program is going to use for all standard drawing calls (i.e. it assumes there is one "main" font that it always uses), putting them in globals, and then ignoring them, is probably easiest.

Last edited 2011


Captain Wicker (crazy hillbilly)(Posted 2011) [#28]
Could you tell me how to get the program running? What do I need to do exactly?

Last edited 2011


Kryzon(Posted 2011) [#29]
What do I need to do exactly?

Look, this happened a lot to me.
The answer is to pick a challenge you can work it out yourself - make a pong game without a menu screen. What you're trying now requires a bit more of experience, so leave it as the next challenge after you have this pong game going on.

In any case, here's the answer:
Function SCENE_Menu()
	;"-> Block of code to setup the scene [...]"	
	Local menuTimer = CreateTimer(60)
	Local menuMusic = PlayMusic( ... )
	Local menuTitle = LoadImage3D( ... )
	Local menuLogo = LoadImage3D( ... )	
	Local newState = 0

	;"-> Block of code with a loop to run the scene [...]"
	;[...]

	;"-> Block of code to free\clean [...]"
	FreeTimer menuTimer
	StopChannel menuMusic
	FreeImage3D menuTitle
	FreeImage3D menuLogo

	"-> Return the ID of the new scene that the game will show."
	Return newState
End Function

You also asked about how to use FreeTimer(). Nobody can give you a better answer than the documentation of the language you're using. It usually includes the description AND examples of the command in question.
Here is FreeTimer's documentation.

You can access the documentation lists online like with the previous link, or you can also find it in the IDE: you can surf to it or click on a command's highlighted name and press F1 twice.

Last edited 2011


_PJ_(Posted 2011) [#30]
I agree with Kryzon.

It seems pretty clear you're trying to run before you can walk. You need to get a better grasp of p[rogramming in Blitz overall.
Check out some tutorials, read the Docs and check their example programs too. Understand the syntaxz and specifics of the jargon.

I sinerely suggest that you leave your current game for the moment and work on making soimething much simpler and less ambitious. Where you already have tried implementing Draw3D has already overcomplicated your program a great deal and it's clear that you aren't really 'ready' to add in such complications and so for now, they only make a difficult job much harder.

One you are more confident and understand the language better, then you will know how to use Draw3D and implementing it will make things easier not more difficult.

This probably isn't what you want to hear, but otherwise, I honestly feel you will just be running into more and more bugs and problems and getting even more confused - once you find every change you try leads to a new post here, you're getting in over your head and it ecomes harder for people to help since the more complicated your program becomes (through poor implementation/understanding) the deeper and more technical advice is needed to try to sort it back out again.


Captain Wicker (crazy hillbilly)(Posted 2011) [#31]
Do you mean I should write a 2D game instead of 3D for now? No problem there. I think I'll go and read on some of those tuts that I was looking into before. http://blitzbasic.com/Community/posts.php?topic=96427
:)


_PJ_(Posted 2011) [#32]
You can still work on 3D stuff, since the biggest issues are with the general syntax and struccture of the Blittz language overal, not necessarily related to the differences in graphics architecture.

Just limit your scope, try not to do anything too ambitious, like Kryzon suggested, something like Pong or a space-invaders game (yes, they are 2D games, but can be made with 3D graphics all the same) to get an idea of the way to structure your program 'flow' and such :)


Captain Wicker (crazy hillbilly)(Posted 2011) [#33]
How hard is it to make a 2d platformer? Is this a good place to start? (2D Platform game with 3D Scenes)


Yasha(Posted 2011) [#34]
Is this a good place to start? (2D Platform game with 3D Scenes)


In a word, no.

2D vs. 3D has zero relevance to complexity of the game or difficulty of coding it (largely because Blitz3D is already doing 100% of the difficult stuff behind the scenes in a 3D project).

The reason people are recommending that you consider 2D classics is because the games themselves are very simple - Breakout, Pong, Space Invaders, Tetris etc. are things that you can conceptually outline on a single sheet of paper and implement in a single code file. The point of these games is that they can be implemented without any media, you don't need to mess about with menus and GUIs and consoles and scripting systems and all that crap, but instead you have a single, coherent goal that you can work towards while learning the language and programming in general.

Any project that you're envisaging as a commercial-quality, Steam-ready, beautiful, long game with rich storytelling, is too difficult to recommend at this stage.

Last edited 2011


Rob the Great(Posted 2011) [#35]
Yeah, you definitely need the basics down solid before you try the more advanced stuff in programming.

When I started learning, it took me a full year to understand what people were talking about with scopes. I'm still learning new things every day, and speaking of which, I have a question about local function variables below if anyone knows the answer. But, back knowing scopes, here's a good way to think of it.

1. You have two ways to declare a variable in a program: Global and Local.
a. Global means that the variable is always there, throughout the whole program, and any function can change it (as long as it isn't shadowed, but just ignore this for now.)
b. Local means that the variable will only exist inside of the function that it is called in. If you create a local variable inside of a function, that variable cannot be changed, seen, ect., outside of that function. If you create a variable in the main loop or outside of any loop and function, then the variable is only available inside loops not contained in functions. You might be wondering why there would be any purpose in having Local variables, since Globals seem like they are easier to keep track of. But consider this: if you were on a team of 200 programmers, and they each needed to have their own variables to help design a very large game, then the variable list would become insanely large, to the point where nobody could keep track of the variables and nobody would know if someone else was changing/modifying their variables in another part of the game. Too confusing. So, this is where the beauty of Local variables comes into play. Using Locals, now all of the programmers could use variables just for themselves, you don't have a giant Global variable list, and on top of that, you don't have the confusion of sharing Global variables from one function to the next. This is why Global variables are often times looked down upon, especially in excess. As a rule of thumb, only use Global variables when you have information that is accessed throughout the game, e.g. Global lifeleft = 10, Global characterstateofbeing$ = "idle", Global magicleft# = 100.0, ect. Know the difference between Global and Local, and then choose the variable type accordingly.

2. Next, let's talk about scopes. Think of a scope as a block of code in your game.
a. You have the "Outer Scope", which is usually the top-most lines of your game. The Outer Scope is not inside any loops or functions. Global variables can only be made in the Outer Scope, because Blitz needs to know before hand how much memory to reserved program-wide for any Global variables.
b. Next, you have the "Main Scope". This is the main loop of your game. From here, you will usually call gameplay functions to help divide the flow of your game based on what's happening.
c. After the main scope, you will have a bunch of "Function Scopes", sometimes called "Inner Scopes". Think of Function Scopes as miniature Blitz programs. Each Function Scope has it's own set of variables for that program (Local Variables), which cannot be accessed anywhere but from withing that "program" (the function, in this case). On top of that, you can also access Global variables, which you can use to change the game (such as taking life away, changing the current state of being, ect.).
d. If you look at the bottom of IDEal, you will be able to see the name of the current scope you are in. This is usually a Function Name if you are current typing in a function, but can also be a main loop or the outer scope. IDEal will also show you which mini-scope you are in, and this takes into account any If's, For's, While's, Wend's, basically anything that needs indenting. I don't know if I consider these scopes or not, but this is useful in larger blocks to know exactly where you are at.

Take a look at this example below:
;THIS IS ALL WITHIN THE OUTER SCOPE. ALL GLOBALS HAVE TO GO HERE
Graphics3D 800,600
SetBuffer BackBuffer()

Type enemy ;Types are useful for managing a bunch of data at once.
                    ;Types are Global in nature.
   Field body
End Type

Global camera = CreateCamera() ;Your camera is going to be
                                                     ;everywhere in your game!

Global hero = CreateSphere() ;This is your character's body, and needs
                                                ;to be accessible anywhere

Global lifeleft = 100 ;Your character has so much life, and it is going to be
                                ;everywhere

Local enemycount ;This variable is only used once, to make a certain
                              ;number of enemies. No need to have this available
                              ;throughout the whole program.
For enemycount = 1 To 100 ;Do this part 100 times, so we will have 100
                                             ;enemies total
   MakeNewEnemey() ;This will leave the Outer Scope and move into the
                                  ;"MakeNewEnemey() Scope", found below in the
                                  ;Function
Next

Function MakeNewEnemy() ;NOW WE HAVE MOVED INTO THE INNER
                                            ;SCOPE OF "MakeNewEnemy()"
   Local tempbody = CreateCube() ;"tempbody" is only going to exist
                                                       ;inside of this scope. Everywhere else,
                                                       ;it is non-existent.
   Local e.enemy ;Make a new Enemy Type, and the variable only needs
                           ;to exist in this scope. We can access all enemies later
                           ;in the "UpdateEnemies" function below the main loop.
   e\body = tempbody ;the enemy's body is now the temporary cube we
                                   ;created.
End Function ;WE ARE NOW LEAVING THE INNER SCOPE AND RETURNING
                      ;TO THE PREVIOUS SCOPE BEFORE WE CAME HERE.

;NOW LET'S MOVE INTO THE MAIN SCOPE
While Not KeyDown(1)

   UpdateEnemies() ;THIS WILL GO TO THE INNER SCOPE OF
                               ;"UpdateEnemies()" FOUND BELOW
   ;MoveEntity tempbody,0,1,0 ;Note that "tempbody" was local to the
                                                ;"MakeNewEnemy()" Scope, and will cause
                                                ;an error if you try to use it in the Main
                                                ;Scope. That's why it is commented out.
   UpdateWorld
   RenderWorld
   Flip

Wend

;NOTE THAT THIS SPACE IS OUTSIDE OF THE MAIN LOOP AND NOT INSIDE
;OF A FUNCTION, SO IT'S BACK IN THE OUTER SCOPE.

Function UpdateEnemies() ;THIS IS NOW IN THE "UpdateEnemies()"
                                           ;SCOPE
   Local e.enemy ;We are only going to use this variable in this function.
                           ;Even though we already used a variable with the same
                           ;name in the "MakeNewEnemy()" Scope, they are both
                           ;Local to the function they were created in, so they are
                           ;still completely different from each other.
   For e.enemy = Each enemy ;For every single enemy we've created
      If EntityDistance(hero,e\body) < 10 ;Here's where we can access Global variables.
                                                               ;Remember that "hero" is Global,
                                                               ;and can be seen anywhere in
                                                               ;our game.
         lifeleft = lifeleft - 10 ;Change the Global variable of lifeleft, and take
                                         ;away 10 units of life
      EndIf
   Next
End Function ;NOW WE WILL RETURN TO THE PREVIOUS SCOPE BEFORE
                     ;THIS FUNCTION


;NOTE THAT THIS SPACE IS OUTSIDE OF THE MAIN LOOP AND NOT INSIDE
;OF A FUNCTION, SO IT'S BACK IN THE OUTER SCOPE.
End

This turned into a much lengthier post than I intended, but I hope this helps you understand program flow a little more. Just remember some key points:

1. Global means a variable that is available anywhere, and Local means it is contained within the scope it was created in.
2. You have three basic types of scopes: The Outer (not inside any functions or loops, Globals have to go here), The Main (inside loops, but not in functions), and the Inner (inside any function, and this includes loops within that function).

Now, back to my question about local variables in Functions, I saw somewhere a line talking about local variables being wiped clean at the start of the function, but now I can't find it. I thought it was Yasha who posted it, but I'm not sure. Anyway, my question is:
Function BLAH()

   Local x
   x = x + 1
   If x >= 100
      Print "This is what I want to happen after multiple passes"
   EndIf
   Return

End Function

No matter how many times this function is called, x will never go above 1 because x is reset to 0 when the function ends and is called again. Not that it's a huge problem, but is there some sort of way to let Blitz know to save certain variables WITHOUT making them Global? If not, it's all good. I find ways around the problem, but it would save a lot of time if there was an easy way to do this.

Last edited 2011


Yasha(Posted 2011) [#36]
is there some sort of way to let Blitz know to save certain variables WITHOUT making them Global?


Not without using heap-allocated objects (type instances, banks, etc.).

Assuming you mean "statics" (to use C terminology): BlitzMax lets you declare "globals inside functions", but all they are are regular globals that happen not to be visible to the rest of the program. Personally, if I want the equivalent in Blitz3D, I just use a naming convention that reflects the fact that they're supposed to be ignored (e.g. "Module_VarName_private_").

If you mean you want to be able to create multiple versions of a function each with its own stored variables... the term you're looking for is a "closure", and those are waaay off the Blitz3D or even BlitzMax radar.

Last edited 2011


Rob the Great(Posted 2011) [#37]
Yep, types is one way of getting around the problem, and that's what I've used in the past. I actually have a specific type set up just for storing values like these. I was thinking there might be an easy way to do this natively, but that was just wishful thinking. I've noticed that you can do this with a single variable, such as:
Local x = BLAH(x)

Function BLAH(variable)

   variable = variable + 1
   If variable >= 100
      ;Do something
   EndIf
   Return variable

End Function

This works, but the problem is that you're limited to storing only 1 variable per function, plus you've used up the return value to use for something else. I like the naming convention idea, though. That might be easier to use than what I do right now.


Rob the Great(Posted 2011) [#38]
I'm looking at my post above (#35), and I need to correct some information.

The Outer Scope and the Main Scope do have access to the same local variables.
Local camera = CreateCamera() ;the camera variable is local

While Not KeyDown(1)

   MoveEntity camera,0,0,1 ;even though camera is local to the Outer Scope, it is still visible in this loop

Wend

The only reason why I separate the two scopes is because if you try to declare a variable as Global inside of a loop, such as:
While Not KeyDown(1)

   Global x = 0

Wend

You will get an error.