Level Changing?

Blitz3D Forums/Blitz3D Beginners Area/Level Changing?

Cubed Inc.(Posted 2010) [#1]
For the past couple of days now, I have been trying to find out how to make my game change from screen to screen.

For example, I'm trying to make it so that my game could go from the 2d title opening to the 3d menu and finally to the gameplay and to the levels. I have made my own code using functions to hold each screen,menu and level in the game, but the transition between each screen looks terrible and I can't make it so that you can go back to anothe screen( for example, if you wanted to go back to the starting menu ).

Does anyone know the right way to do it? Please reply. thanks.


Matty(Posted 2010) [#2]
Given you want to use individual functions for 2d title, 3d menu, & gameplay/levels this is a simple example that may be helpful.

function Title2D()
; whatever goes in here
End Function 

function Menu3D$()
; whatever goes in here

return action$
end function 

function loadlevel(filename$)

end function 

function gameplay()

end function

function unloadlevel()

end function 


function main()

title2d()
repeat

action$=Menu3d()

if action$="play" then
	loadlevel("level1.dat")
	gaemplay()
	unloadlevel()
endif
if action$="something else..like view title screen again.."
	title2d()
endif

until action$="quit"
end


end function 




This is a basic kind of structure, not necessarily the best, but it kind of implements what you descrbed above.


Cubed Inc.(Posted 2010) [#3]
Matty
Seems simple, but I have some questions.
Why is the Menu3d$ function have a string integer, where does LoadLevel come from and why does it say filename$ in it's brackets? Also, where does action$ come from? Could you please explain the code better? I'm kinda new to some of the functions and code that are in you example. please reply.


Kryzon(Posted 2010) [#4]
Hello, I'm not Matty but I can help nonetheless.

The "$" suffix at the function's name means that that function returns a string value. If it were a "#", the function would return a float (and functions without any suffix at all are defaulted to returning integers, but you can still put a "%" so it means integer as well).
Mind you don't necessarily have to return anything at all, even if you put one of those symbol-suffixes. They can just be used if you have to return something and that something isn't integer.

Now for the pseudo-code (that's probably why you didn't understand much - that and the fact that it didn't have much INDENTATION - bad Matty >:( ), it's portraying the layout of your program flow. The way things should happen to get the result you want.

You keep drawing the menu\game\whatever and checking the current game state.
If, for instance, you are in the menu and the state is "menu", then keep at the menu (meaning, don't do anything - you don't even need to check this specific state).
If it's "play", then start the game.
If it's "quit", end the game. And so on.
If the player puts the cursor on the "Options" button and hits the mouse\keyboard, then you could change the state to "options" so that checking you keep doing every frame will understand that and change the screen to the options screen.

You need to code what you want to happen when something happens, in the cleanest, fastest and most economic way you can.

EDIT: I hope you noticed that you write code just by thinking what you want to do - Blitz3D is so high-level you can almost write in english. Taking for example those states I mentioned "If it's 'quit', end the game":
If gameState = STATE_QUIT Then
	End
Endif



Cubed Inc.(Posted 2010) [#5]
ok, now I think I understand the string integer in the function name.

The string integer allows you to use a string code to determine when to change levels instead of using variable or constants or needing to create a type for each screen.

I understand that, but I am still puzzed by matty's example. Why does it say filename$ in the LoadLevel function's brackets. What does filename$ mean? Why does LoadLevel say "level1dat"? How do I unload each screen and level.

Sorry for sounding so nieve and picky, it's just that I want to understand this code as much as possible so I don't run into any problems and come back here later.

please reply.


Kryzon(Posted 2010) [#6]
Doesn't mean it's clearer or easier to use. Strings are slower to compare than integers. You could use just-as-easy-to-understand constants:
Const STATE_QUIT = 1
Const STATE_PLAY = 2
About that LoadLevel function, he was showing how you could start a function that loads a level. You would code it so it would take a single parameter (the filename of the level to be loaded). You would code it so once you call it, it takes care of loading the level and setting up the data for you.
If you're doing a tile-based game, for instance, you could code a LoadLevel function that would parse the file and set up the tile arrays for your map, load the graphics, etc.
He placed "level1.dat" just as an example of how you would call that function. When you have your game going on, later, that's how you'll call the functions - "if now we have to play level 3, then I'll call the LoadLevel function with that level-3 file I made in my game editor that I coded myself".

If it's hard for you to understand these concepts, I suggest you take a look at the old BlitzCoder articles that cover much of 2D game programming, and a bit of 3D coding as well:

http://membres.multimania.fr/blitzcoder/articles.shtml

Although somewhat pop-uppy, that website holds all the information you are looking for, with classic articles that seem to have been forgotten - they cover a LOT of game coding aspects.
Please give yourself the time to see what articles it has; it's by far the best suggestion and material I can give you or anyone wanting to improve with BlitzBasic\Blitz3D.


Cubed Inc.(Posted 2010) [#7]
Kryzon
Thanks for trying to help me, but I just can't put this code together in my mind.

What would be the upmost easiest and simplest way to change screens and levels in blitz3d? I absolutly need to learn how to do this, and if I don't understand it, I can't make any projects.

I'm sorry if I'm starting to sound offensive or whiney, it's just so important.

Thanks for trying to explain it to me, but I just simply don't understand.


Adam Novagen(Posted 2010) [#8]
Well, you're certainly asking nicely and helping us understand your position, so bonus points there, TaGames. :)

For my part, I usually do something like this in my program. Keep in mind this is just an example, it wouldn't really work on its own. Anyway, my main loops usually look like this:

Global GameStatus = 100 ;If the program isn't actually a game, I call this "APPMode" instead. :p


While Not KeyHit(1)


Cls


Select GameStatus
    Case 0;The end :p
        QuitGame()
    Case 100;Title screen loading
        LoadTitleScreen()
    Case 101;The title screen itself
        UpdateTitleScreen()
    Case 200;Load the selected level
        LoadLevel(CurrentLevel)
    Case 201;Main game engine, where STUFF HAPPENS :D
        UpdateGame()
    Case 202;Still in-game, but paused
        UpdatePauseMenu()
End Select


Flip


Wend


End



As I said, this is just an example, and won't work as is. Anyway, the concept here is that I use a single variable, GameStatus or APPMode, to tell the program what it should be doing. Then, I use a Select...Case loop to make the program do the appropriate... Stuff... According to what mode it's on. Does that make sense to you? I'm not always the best explainer. XD


Serpent(Posted 2010) [#9]
And if you want your code in English, use constants :)



The beauty of this layout is if you want to change what you're game is doing (e.g. move from the main menu to the options menu) all you have to do is type something like:
GameStatus = Status_OptionsMenu

So you control your 'program navigation' as such by changing the variable which tells the program what to do.


Drak(Posted 2010) [#10]
Have a function that is only called when the level needs to be changed. I don't know what type of game you're working on but for this example I'll say it's a FPS.

For this example we'll say the player touches a door or a portal to end the level. Something has to trigger\signal the end of the level. When this happens, you just need to do a few simple steps, and go through a chunk of code just 1 time. Something like this:

1. Hide the player
2. Delete the old level
3. Delete any props\trees\badguys\etc. (I store all my props in the same type to make it easy to delete them all)
4. Load the next level
5. Load the new props\trees\badguys\etc.
6. Position the player where you want him to start the next level
7. Unhide the player.

It's basically the same as first initialization with 1 level. You're doing the same thing, although you need to clear the previous level first.


K(Posted 2010) [#11]
If this is helpful...

I am working on a game with nearly 20 levels.Naturally,that's a lot of meshes and stuff to load. So, my solution is to have two simultaneous programs. Note that this is not the only way to do it. But, imagine you load your record and it puts you in your spaceship looking at a map. You select the destination and it sends you there.Once there, you can get back in your ship and it puts the map back, as you last saw it.
The mechanics are fairly simple:

1) You load your game which goes to a different loop in the program WHICH IS JUST THE MAIN MENU and THE MAP.This program is consantly writing one number value to a data file, that being the level you will be at.

2) When you go to the level your program performs ReadFile() on that file, telling it which level to load in your setup coding/functions.

3) When you get back in your ship your GAME PROGRAM saves your record and ends itself.


The key lies just before Step_2. Look up in your command reference ExecFile(), an obscure but phenomenal command. The game is then divided into two parts: a 2D menu and a 3D game. Your menu program calls the game executable with this command: ExecFile("3D.exe") but make sure that you keep it running, so that when you end the other, it's still showing. The main purpose of this is to not have to load all your resources, so that your game can run smoother. The downside is that you have two programs running, but if your menu isn't too complex, it shouldn't be too bad.
Another isssue is that you can't do this if you have the demo version of Blitz3d. As I said,I'm sure there are other ways to do this, but it works best for my game so far.
This is just an example though, it doesn't have to be a spaceship, it could be portal or a path or whatever.Further, there doesn't nees to be a map, it can all be done behind the scenes and the player might not even know...especially if it's fullscreen.

This maybe was too long, but I hope it helps.

EDIT:Cool example, Novagen.

EDIT: This I guess isn't the normal way, but my whacked solution when I was stuck. However, SilentHunterII used a similiar system, so it's not absolutely terrible to use.

Last edited 2010


Cubed Inc.(Posted 2010) [#12]
Adam Novagen and Serpent and everyone who helped me:

I have just one last problem. I'm trying to test out Serpents variation of Novagen's code by making it so that when you press space, GameeStatus = Status_Quit and when you press Enter, GameStatus = Status_LoadTitleScreen.

When I inserted by very small code to do this for me, it doesn't seen to work for some reason.

I inserted this code into the example. It comes after Global GameStatus = Status_LoadTitleScreen at the top and before Cls.



Could someone help me out?
Please reply and thanks for helping.


Adam Novagen(Posted 2010) [#13]
I'd need to see the whole code file (or at least the whole main loop) to really be of help. However, at a guess I'd say it sounds like you forgot to make your program end (or some such) when GameStatus is set to quit or show the title screen. Like I said though, need the whole loop.


Cubed Inc.(Posted 2010) [#14]
well here it is.


For the functions, I just reused the same code for each function to save time for testing( lazy me -_-)


K(Posted 2010) [#15]
I can't tell from your next-to-last example, but it looks like that code you added is in the main loop instead of in the loops within the functions. Note that your main loop never actually gets run in the above code.



EDIT:While this is true ,readers note that that is not the imperitve issue.

Last edited 2010


Adam Novagen(Posted 2010) [#16]
*rubs hands together* Okay, let's have a go at this.

First rule of efficient, convenient, easy-to-read-and-understand coding: indent, indent, indent! White space makes no difference to Blitz, but it makes a HUGE difference to humans for telling what's what. For example, this little beauty of an If statement:

If bomb_y
If bomb_y>=29
bomb_y=0
Else If bomb_y>=skyline(bomb_x)
score=score+5
skyline(bomb_x)=skyline(bomb_x)+30
If skyline(bomb_x)>=29
skyline(bomb_x)=29
score=score+15
EndIf
bomb_y=0
EndIf
EndIf


Yech. I'd have to read it three times just to be sure what connected to what. Have a look at this, same code, but with indentation:

If bomb_y
    If bomb_y>=29
        bomb_y=0
    Else If bomb_y>=skyline(bomb_x)
        score=score+5
        skyline(bomb_x)=skyline(bomb_x)+30
        If skyline(bomb_x)>=29
            skyline(bomb_x)=29
            score=score+15
        EndIf
        bomb_y=0
    EndIf
EndIf


Easier, eh? Now you can tell at a glance which code belongs to which If.

Next item. Why are you calling title(), level1() and level2() before the graphics have even been set? That could be part of your problem right there.

Also, look at your code a sec. Having an entire copy of the main loop inside a separate function for each level is... Well, inelegant at best and downright clunky at worst. It adds WAY more repeated bulk to your program than it needs. Try something cleaner like this:

Graphics 640,480,0,1


Const Title_Screen = 101
Const In_Game = 201
Const In_Game_Paused = 202
Global GameStatus = Title_Screen


;---ALL YOUR STARTUP CODE HERE---;


While Not KeyDown(1)


Cls


Select GameStatus
    Case Title_Screen
        title()
    Case In_Game
        ;---ALL YOUR ACTUAL GAMEPLAY CODE HERE---;
    Case In_Game_Paused
        WaitKey
        GameStatus = In_Game
End Select


Flip False


Wend


End


;---FUNCTIONS HERE, AS USUAL---;



That's a much simpler method. This way, you only have to make one main loop. Imagine, with the code you've got now, if you made 50 levels, then decided to change the way the main loop works. That's a LOT of rewriting, even with cut-and-paste. The less times you have to repeat something, the less chance there is of you overlooking an important detail. So basically, lose the main-loops-inside-the-functions, since apart from anything this code is useless with that. XD The code in the functions should just be one-shot code that the program passes through, runs, and continues on through the main loop.

If you need variations in the levels - i.e. different sets of enemies, different behaviours, etc - then try something like this:


Graphics 640,480,0,1


Const Title_Screen = 101
Const In_Game = 201
Const In_Game_Paused = 202
Global GameStatus = Title_Screen,Level = 1


;---ALL YOUR STARTUP CODE HERE---;


While Not KeyDown(1)


Cls


Select GameStatus
    Case Title_Screen
        title()
    Case In_Game
        PlayGame(Level)
    Case In_Game_Paused
        WaitKey
        GameStatus = In_Game
End Select


Flip False


Wend


End


Function PlayGame(LevelNum)


Select LevelNum
    Case 1
        ;Level 1 code
    Case 2
        ;Level 2 code
    Case 3
        ;Level... Well, you get the picture. Add levels as needed.
End Select


End function


This should get your ball rolling for a bit. Hope it helps! :D


Cubed Inc.(Posted 2010) [#17]
Adam Novagen
I apoligize for the inconvienience, but I accidentlly put in the wrong code at post #14:(

Regardless, I still implemented your example into the code that I was originally going to use.



sorry if it's so ugly. It seems to work, but I still can't make it so that I can change the GameStatus.

This is what changes screens and levels.


I've tried to make it so that you can change screens and levels by just pressing the space and 1 key.


When I tried to implement this into the game..

It say "wend without while"
(Very Annoying)

Could you help me work this out? I apoligize for asking for so much help, but it's crucial for me to know and get right.

Please Reply.


GIB3D(Posted 2010) [#18]
If KeyDown(2)
Game_Status = In_Game
Else
If KeyDown(57)
Game_Status = Title_Screen
EndIf


should be

If KeyDown(2)
Game_Status = In_Game
ElseIf KeyDown(57)
Game_Status = Title_Screen
EndIf



Rob the Great(Posted 2010) [#19]
Hello again,

Just making a note that you may have a variable issue. In one box, you have "GameStatus = Title_Screen", and in another, you have a different variable "Game_Status". The underscore will make Blitz think that you have two different variables, "GameStatus" and "Game_Status". I'm not sure if this is only a typo in the post, but you may want to double check the variables in your program.

Also, I think it's pulling the "wend without while" error because you are using the "Else" statement in an unusual way. I rarely ever use that command, but I believe that the "Else" statement is expecting an argument on the same line. I could very well be wrong, and if I am, please correct me, but try replacing your code from:
While Not KeyDown(1)


Cls

If KeyDown(2)
Game_Status = In_Game
Else
If KeyDown(57)
Game_Status = Title_Screen
EndIf

Select GameStatus
    Case Title_Screen
        title()
    Case In_Game


to:

While Not KeyDown(1)


Cls

If KeyDown(2)
Game_Status = In_Game
EndIf
If KeyDown(57)
Game_Status = Title_Screen
EndIf

Select Game_Status
    Case Title_Screen
        title()
    Case In_Game


That might fix the problem? Also, note that I changed the code above from "Select GameStatus" to "Select Game_Status". Remember, "GameStatus" and "Game_Status" are completely different variables, so the code you provided would actually make Blitz return "0" or "", because you never actually changed "GameStatus". Whichever variable you choose, just make sure it's consistent throughout the whole program. You can use the Find and Replace function in Blitz if you want to be sure you've gotten them all.


Rob the Great(Posted 2010) [#20]
I guess that GIB3D beat me to the post. lol.


Adam Novagen(Posted 2010) [#21]
Yep. Okay, here's why your error's popping up, step by step.

Here's a non-working example of what your code looks like to the Blitz compiler:

If KeyDown(2) <-----------------+
Game_Satus = In_Game            |
Else <--------------------------+
If KeyDown(57) <-------------+  |
Game_Status = Title_Screen   |  |
EndIf <----------------------+  |
                                |
                                |


See, the program spots If KeyDown(2) as the beginning of an If statement. Then, it sees Else as the beginning of an Else statement, which is basically saying "if none of the above is true then do this." It then sees KeyDown(57) as the beginning of a new If statement inside the current Else statement. Then, it sees EndIf, and ends that If statement, but the first one's still in session, and everything afterwards still seems to be inside it, to the compiler.

Here's a tip: to avoid such confusion, never use Else If. Put them together in one word: ElseIf. Then your programs will come out like this, and the compiler will interpret them correctly:

If KeyDown(2) <--------------+
Game_Status = In_Game        |
ElseIf KeyDown(57) <---------+
Game_Status = Title_Screen   |
EndIf <----------------------+




See the difference? Now, it's all one multi-condition, correctly terminated If statement. One final alternative would be to do it this way:

If KeyDown(2) <------------------+
Game_Status = In_Game            |
Else <---------------------------+
If KeyDown(57) <-------------+   |
Game_Status = Title_Screen   |   |
EndIf <----------------------+   |
EndIf <--------------------------+


This makes two separate If statements, one inside the other, but terminates them both correctly. Either method will work, but the first option is cleaner, quicker and more efficient.

Basically, what you had before was this: you had an If, then an Else, then you had a new If inside the Else. When the second If ended, the program was still inside the Else, right the way down to the Wend command. Since the While command, at the start of the main loop, was outside that Else statement, but the Wend was inside, the compiler wouldn't match them together, thereby thinking you had a Wend with no While.

EDIT: After reading that last "explanation" paragraph of mine, even I can barely understand it. All I see is "blah blah blah If blah Wend blah blah blah Else If Wend If Wend Else blah blah BLAH." I'll clarify it (hopefully) with another little diagram, partly because I love making diagrams with text. ;) This is just a sample, not a word-for-word quote of your code.

While Not KeyHit(1) <----------------+
                                     |
Cls                                  |
                                     |
If KeyDown(2) <------------------+   |
Game_Status = In_Game            |   |
Else <---------------------------+   |
If KeyDown(57) <-------------+   |   |
Game_Status = Title_Screen   |   |   |
EndIf <----------------------+   |   |
                                 |   |
Flip                             |   |
                                 |   |
Wend <---?                       |   |
                                 |   |
End                              |   |
                                 |   |
                                 |   |


Hopefully this shows it more clearly. The first If statement hasn't been terminated yet, and so Blitz doesn't connect Wend to the While at the start of the main loop.


Cubed Inc.(Posted 2010) [#22]
damn, it didn't work>:(
It's not your guy's fault, it's mine. I though of the idea of making it so that you can change screens back and forth by pressing the 1 and space key.

You guys made the code work, but it didn't change between screens and levels.

What would be the correct way to do this? I tried to create my own code, but it didn't work, even with you guy's help.

What would be the right way to do this.

please reply, thanks.


Matty(Posted 2010) [#23]
I'm beginning to think that maybe you should start on something simpler.

Those of us old enough to have programming experience with computers in a day when text output was all a computer was capable of started with things like mini text-adventures, naughts and crosses / tic tac toe and other similar games.

While they may not be as exciting as a '3d world' they're a good place to start to get the hang of both how the language (blitz3d) works and how to structure your code and get a grasp on the logic behind the code you write.

So what I'm saying is, perhaps try something simpler to start with. Some people suggest things like Pong / Tetris - which are good but I'd even suggest something like Tic Tac Toe, or even a simple text-based adventure (perhaps with multiple choice options rather than full text input).

Even with something as simple as these you can learn the basics of loops, conditional statements, data management, functions/procedures and so on.

Thanks,
Matt


Adam Novagen(Posted 2010) [#24]
...I'd even suggest something like Tic Tac Toe...


Actually, it's surprising how complex TTT can be, compared to Pong and the like. Assuming you code in a computer opponent, of course.

Anyway, TaGames, I'm in agreement with Matty over this: try something more basic, no pun intended. We're not trying to discourage you; you should absolutely shoot high, just not so much so soon.


K(Posted 2010) [#25]
I agree too. Don't make the same mistake as me and try to pretty much make Jak&Daxter on the the demo version. I almost literally did.
I'm two years in and almost done... the first year being spent trying to learn how to program (oops, I meant both years!..{applause+drumbeat})

EDIT: Wow, I really missed the point back there.Duh... sorry, actually I was probably making it worse.


Kryzon(Posted 2010) [#26]
@TaGames: http://www.gamedev.net/reference/design/features/makegames/

Please read this; helped me, and will definitely help you. Section 2 is probably the most important.


Cubed Inc.(Posted 2010) [#27]
I understand. You guys helped me get this far, now its my turn to work it out from here. Thanks to everybody who helped me. I definently understand it better now. I'm very grateful. thanks.