Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

DarkBASIC Professional Discussion / Subroutines vs functions.....yes, this debate again!

Author
Message
Catalyst
21
Years of Service
User Offline
Joined: 6th Sep 2003
Location:
Posted: 7th Aug 2005 03:23
But I have a reason for it. I've had DBPro for a few years now, and have probably spent about a month in total time using it. Right now I'm getting back into it and to a project that I have currently functional, but messy. All of my code is just in the main loop, all the code for movement,health,collisions, etc. I'm trying to pull the chunks out and put them into functions that can just be called when needed, i.e. if there's no attack happening I don't need to run checks on health. But the problem I have is the massive amount of variables I have in here. Lots of them. Variables for the start and end frame of each animation, for every character attribute, for the current status of the character, etc. Now, each of the chunks of code needs to access these variables, if I tell it to move it has to make sure I'm not running into anything, or knocked down, or mid-attack, or whatever. So it needs constant access to these variables.

Here's my issue. I make it as functions, and it would seem that I'm going to have to global a lot of variables here. It's going to be a pain and I'm going to have to change around several bits of my code to make them work properly. If I do subroutines, I won't need to global anything (Really should have been thinking these things when I started on it!) and my code will require pretty minimal changes. However, then I think I'll be running into an issue. I jump, so each loop it goes through the jump function to make my character jump properly. Player 2 jumps, and if it's a subroutine it gets very messy to have player 2 access that same bit of code. Right now my jump routine is one of the few things that are functions, but if I remember correctly I was even having an issue with using the jump as a function and still being able to have both players access it properly.

Which brings me to me question. Unfortunately, I don't have one. I don't have one because I don't even really know what I need to be asking. I guess mainly if anyone can make sense of what I'm trying to do and has done something similar or knows what I should be doing with it. How do other people organize all their animation and any checks to know what state the player is in? Rather than using so many variables to see if a character is moving,jumping, etc, I think I can make a single character state command and just do the whole 1,2,4,8 coding to describe all possible states in one variable, but there's still a bunch of other things that need to be looked at. Should I just global every variable one by one?
CattleRustler
Retired Moderator
21
Years of Service
User Offline
Joined: 8th Aug 2003
Location: case modding at overclock.net
Posted: 7th Aug 2005 06:29
Quote: "I make it as functions, and it would seem that I'm going to have to global a lot of variables here. It's going to be a pain and I'm going to have to change around several bits of my code to make them work properly. If I do subroutines, I won't need to global anything "


that sounds a bit backwards since in dbp you pass values into functions as arguments, but not pass them into subs... That being true, why would you need more globals when using functions as opposed to when using subs?

am i following you correctly?

DBP Plugins Latest: MSAccess, SQLServer, MySQL plugins for DBP
Catalyst
21
Years of Service
User Offline
Joined: 6th Sep 2003
Location:
Posted: 7th Aug 2005 08:26
Say I press the key for attack. The code has to check to make sure the character is not on the ground or being hit already. If the character is in the air, it has to know it's an air attack and not a ground attack. If the character is ducking, it has to know to do a ducking attack. Then there's the other character. It has to be able to recieve the hit and know what kind of hit it is, where it is hitting and also things like if that recieving character is in the air,on the ground, or mid-attack, or whatever. Probably some other things that I can't think of off the top of my head.

Now, these all have to be tracked by variables. Each thing checks the variables to make sure whatever action that needs to happen can happen. And lots of things need access to this information. So, if each thing, like attack,move,jump,etc, is in a function, how is it going to know all of this and react to it properly? I could hand all that info into the function each time it's called and modify it with the return, but I'm already badly organized in my code and trying to make it neater. That doesn't seem neater to me, especially when we start dealing with animation and figuring out which frame it's on each time any of these things are happening.

If I do it as subroutines, I wouldn't need to make those global because the subs would always have direct access to them. But then I run into the problem of two things accessing the same subroutine, its starts getting ugly.

One thing I'm thinking would help is to make each variable that watches things into an array. Say for instance, a variable that checks to see if the character is in an attack move. I currently have an atk1 and atk2 flag, just 1 or 0 for is player 1 attacking and is player 2 attacking. If I make that be an array and say atk(1) or atk(2), I can then change that to just atk(x) and re-use code, just feeding the different variables in.

Am I making sense yet? Please tell me I am, even if you have to make it up. At this point I might have to post some code. Here's a section of my code to make sure movement is possible. It's been a long time since I wrote it and I never claim to be any good at this, so best of luck figuring it out. Hopefully all those variables in there that are not really labelled will make sense, ani if it's currently playing an animation I think(It's been that long since I wrote it), go I think was just a general kill switch. But most of the rest should be fairly readable.
Me!
19
Years of Service
User Offline
Joined: 26th Jul 2005
Location:
Posted: 7th Aug 2005 11:06
yeah, I see where you are coming from, what you mean is that although you can call a function with several variables, the way you wrote the code means that the functions would have to return several modified variables, either that or you make most of the variables in the code global.
Since you have got so far with it the way you have you might like to just quickly polish off what you have so far and then write version 2, you will find that you can go a lot quicker the second time around and add improvements that you didn`t think about the first time around.
the problem you will have is that hacking your code into a more structured shape will probably take more time than starting over, its hard to drop something when you put so much work into it, but think how far your skills have come from the day you originaly installed DB, you should be able to make V2 MUCH more capable than the original version.
writing with functions can become very natural after a while, you get used to the idea of having a "display_score" function, or "update_enemys" or a "move_clouds", it makes the main loop very simple and you can write your code a bit at a time, heres an example of a simple "no media" game I wrote, note how everything is broken into functions and calls one another, you will even find functions that do nothing but call functions (this game was never finished btw).

Attachments

Login to view attachments
Grog Grueslayer
Valued Member
20
Years of Service
User Offline
Joined: 30th May 2005
Playing: Green Hell
Posted: 7th Aug 2005 12:05 Edited at: 7th Aug 2005 12:06
When you use nested if statements code is a whole lot easier to read.

Your code nested:


All those variables could be easily put into arrays instead. Arrays are automatically global (when defined outside functions). When a function is called it does it's thing and goes back. There is no way for a function to be called at the same time for both players. I wrote some code for a basic design for what you're looking for. I probably got some of the infomation wrong but you can easily change that.

Hope this helps.

CattleRustler
Retired Moderator
21
Years of Service
User Offline
Joined: 8th Aug 2003
Location: case modding at overclock.net
Posted: 7th Aug 2005 18:32 Edited at: 7th Aug 2005 23:42
Xolatron old
21
Years of Service
User Offline
Joined: 25th Jan 2004
Location: The Star Forge Language: DBpro
Posted: 7th Aug 2005 19:12
Yes, use arrays. Then for calling a sub for a different object, I usually have a global subID variable, which I set to the subroutine's parameter. Example:


-Xol

RiiDii
20
Years of Service
User Offline
Joined: 20th Jan 2005
Location: Inatincan
Posted: 7th Aug 2005 19:58
I prefer functions for many reasons, but here are a few.

Readability/Structure
Error Checking
Multi-program functionality
Use functions as values
Functions can have local variables

Readability/Structure: This could be argued for sub routines as well - they both can be readable and lend to code structure. Functions add one thing that subs don't (by default). The variables that are passed into a function help any coder using the function to know what variables are needed up front. So, for example, if I have a function for gravity that starts of like so:

Function Gravity(ObjectID as DWord, Acceleration as Float, CurrentVel as Float)

Almost anyone can quickly understand which variables are needed and what type each variable is. Granted, this does not help with globals or arrays that are passed over to functions, but this is one of the benefits functions do have (imo). For a subroutine, added rem statements would be needed.

Error Checking: Almost every situation where a funtion isn't closed, the default IDE catches an error during compile. For subroutines, no error will ever occur as a direct result of failing to put in a Return. This means the code will run. There is even a pretty good chance it will work to some degree - until the return stack uses up all the memory. Debugging a missed Return statement would be like looking for a needle in a haystack. Debugging a missed EndFunction is as simple as looking at the Function that caused the compiler to halt (though, it might state that your EndIf is out of place, you know to look at the EndFuntion as well).

Multi-program functionality: Similar to Readability/Structure, I find that moving most functions from code to code is simply a matter of copy/paste. It's just as functional and useable in the new code as it was in the previous code. Granted, this can be done with a subroutine, but you would have to know a subroutine in and out (or it has to be well remarked). With a function, you just look at which variables to pass in and the rest is taken care of. It's like creating your own personal DBPro commands. Again, this doesn't apply when using globals to carry data into a function, but otherwise, it's another reason to use functions.

Use functions as values: Can't do this with a subroutine:

a=pi()*r^2

Function pi()
v#=22.0/7.0
Endfunction v#

And that's just a simple example!


Functions can have local variables: Another thing Subroutines can't do.

Since it seems like you are asking for advice, this is mine; I would take the time to re-write the subroutines as functions and convert all my variables to globals as needed. Once you become proficient at writing functions, you will start experiencing a lot more benefits. For example; you will start to reduce your reliance on global variables and utilize the function's ability to pass variables. You can even pass UDT's into a function (not back out though).

"Droids don't rip your arms off when they lose." -H. Solo
REALITY II
Catalyst
21
Years of Service
User Offline
Joined: 6th Sep 2003
Location:
Posted: 7th Aug 2005 20:40
Thanks for the input everyone. I'm thinking making it all work as functions will be better in the long run than just making something that works for now.

Grog, the revised code you wrote is basically what I was thinking I might have to do. I wrote a few lines, then stopped to see if it was the way I should go. Looking at what people have to say and back at my code, I'm thinking that it probably is. A couple of things though. Arrays are automatically global....I heard that they were, but there were some potential issues trying to use them in functions. I think someone was saying if you wanted to use them in and out of functions they should be started with global dim array. Anyone clarify this? Also, with two players using the same function at once. I didn't mean so much at the exact same time codewise, but the functions track things like current frame of animation,height of jump, etc. My jump is currently a function, but I was running into issues with both players jump at once, it would make one of them fall down. Looking a things now, I'm going to guess that I just really sucked that much at coding and screwed something up with them that won't happen this time around.

Good thing I'm taking a week and a half off from work, looks like it's time for version 2. How fitting, since the game is a Street Fighter style game, version 1 is a bit of junk that very few people ever see and version 2 is the one that gets finished off nicely. Good omens?
Xolatron old
21
Years of Service
User Offline
Joined: 25th Jan 2004
Location: The Star Forge Language: DBpro
Posted: 7th Aug 2005 22:10
Functions really shouldn't be used unless they can work in a different program with all different variables. There are a few times that exceptions to this are best, but functions, I feel, are really meant to be user made commands - they should work in any program, not just one with certain global variables.

Too many people discredit subroutines. They are included for a reason! (other than compatibility with other languages)

-Xol

Catalyst
21
Years of Service
User Offline
Joined: 6th Sep 2003
Location:
Posted: 7th Aug 2005 22:58
The working in other programs is one of the main reasons I wanted to change this around. Well, that and because currently I have two sets of code, one for each character. Though the latter of the two reasons can be fixed without functions, I still want to be doing everything as functions with portability in mind. This game can be made, then with just a few adjustments it can be another type of game.

But yes, I agree that too many people seem to be against subroutines. I like subroutines too and had a hard time getting the hang of functions. Another reason that I want to make them into functions right there, more than having a finished product I'd rather know the language better so that those finished products are easier to make. So, I need to make it work using things I don't know well yet.
Lost in Thought
21
Years of Service
User Offline
Joined: 4th Feb 2004
Location: U.S.A. : Douglas, Georgia
Posted: 8th Aug 2005 01:13
Put reusable code and code that needs a return value in functions. For all else I use gosubs.

Grog Grueslayer
Valued Member
20
Years of Service
User Offline
Joined: 30th May 2005
Playing: Green Hell
Posted: 8th Aug 2005 08:50 Edited at: 8th Aug 2005 08:57
Catalyst, when an array is defined outside of a function their global automatically... they work outside functions and inside functions. If arrays are defined within a function they only work in that function.

You could always change your jump function to use the player arrays as well. You can also use the player arrays to keep the height of each players jump and current animation frame. Arrays give you the option to add new abilitys to the players at will... just increase the dim statement and go for it.

Good coding comes with practice... even people that have been coding for 20+ years still learn better ways to code.

I'm not against subroutines... I just prefer to use functions... mostly as a glorified gosub.

CattleRustler, thanks.
RiiDii
20
Years of Service
User Offline
Joined: 20th Jan 2005
Location: Inatincan
Posted: 8th Aug 2005 18:53
Quote: "If arrays are defined within a function they only work in that function."

I think I would like that too, but DBPro don't work that way.



Also, this is something a function can do that a subroutine cannot do (see code below). You could write a subroutine that would return the same results, but a function could be written the same way. In other words: A function can always do what a subroutine can do, but a subroutine cannot always do what a function can do. A perfectly valid reason to use functions (not just for exportability).



And finally, take a look at the next two codes. The first is a subroutine in which "I forgot" to put in the Return. The second is a function in which "I forgot" to put in the End Function. Compile both. The first will compile and even seem to run with no problem (i.e. won't crash). The second will not even compile. Now these are simple examples, but imagine 1000 lines of code (not very large at all) with quite a few subroutines or functions - and typing away at 2:00 a.m., you forget to Return or EndFunction. I can tell you - I would rather have option 2 since the compiler will happily tell me I screwed up.





Please don't take this as an opposition to using subroutines as there really is no reason not to. But here's the question I pose as a challenge for a valid response. If I can use a function just as well as a subroutine in every case, and in some cases, a function has clear advantages, why would I use subroutines?

"Droids don't rip your arms off when they lose." -H. Solo
REALITY II
Xolatron old
21
Years of Service
User Offline
Joined: 25th Jan 2004
Location: The Star Forge Language: DBpro
Posted: 8th Aug 2005 19:20
RiiDii, I'll answer your question. Subroutines are often better:
- Don't waste memory creating and deleting new variables
- Don't have to declare their own for-next loop variables
- Can create global variables and arrays
To list a few examples.

-Xol

Drew Cameron
21
Years of Service
User Offline
Joined: 30th Jan 2004
Location: Scotland
Posted: 8th Aug 2005 19:40
I am ashamed to say I've never used a function before.

I'll learn for my next project, honest.


Katie Holmes does not endorse D&C or Drew Cameron.
RiiDii
20
Years of Service
User Offline
Joined: 20th Jan 2005
Location: Inatincan
Posted: 8th Aug 2005 20:32 Edited at: 8th Aug 2005 20:36
Quote: "Don't waste memory creating and deleting new variables"

Can't say that I would ever worry about this as an issue considering:
1) Todays pcs have tons of memeory. You have to try to use it up using variables (like: Dim a#(2000,2000000)). But it's normally not an issue.
2) DBPro is a 3D coding environment. Each object takes up tons of memory compared to any given variable.
3) Variables inside a function are only local and the memory is freed up once the function is done. A function declared in a subroutine is local as well, but doesn't get freed up (in most cases) since the variable hangs around as a local variable in the main code.

Quote: "Don't have to declare their own for-next loop variables"

Not sure what you mean by this. However; when used, For a= 1 to 20:Next a is technically declaring a the variable "a" regardless if it's in a function, subroutine, or anywhere. Again, in a function, the variable is only local and is freed up once the function is done.

Quote: "Can create global variables and arrays"

Specifically; Functions cannot declare global variables, unless the variable is a User Defined Type. Did you try the first example in my previous post? A Function can also declare a global array.

I find it good practice to declare my globals and arrays at the beginning of a code (sets aside the memory for the variables right from the start). And I would definately consider declaring variables in an include file, if the compiler would work with include files a little better. But until then, I don't find much use in declaring in a subroutine or a function (although not for lack of trying to find a reason).

"Droids don't rip your arms off when they lose." -H. Solo
REALITY II
dark coder
22
Years of Service
User Offline
Joined: 6th Oct 2002
Location: Japan
Posted: 8th Aug 2005 21:04
whats the point of this debate? just use both ha ha sorted


RiiDii
20
Years of Service
User Offline
Joined: 20th Jan 2005
Location: Inatincan
Posted: 8th Aug 2005 21:20
Learning experience: What can each do and when to use them?

"Droids don't rip your arms off when they lose." -H. Solo
REALITY II
Hamish McHaggis
22
Years of Service
User Offline
Joined: 13th Dec 2002
Location: Modgnik Detinu
Posted: 8th Aug 2005 23:59 Edited at: 9th Aug 2005 00:03
Global UDT arrays cannot be defined in functions, therefore gosubs have to be used.

Remark differently to test function call


But they can be used to re-define these arrays (ie. change the number of items in one).



The compiler doesn't disagree with declaring non-UDT global arrays in functions (it also detects if there are out of range calls to them), but they don't actually work.



Local arrays of all sorts work fine in functions.



And RiDii, the only reason to declare arrays in sub-routines is if they are declared above size 0, and in a separate source code to the main source.

In my opinion the only advantages to functions are...

- They can be self contained (copy and paste-able, plus local variables)
- Passing variables is a nicer way than assigning to globals and calling a sub-routine

Xolatron old
21
Years of Service
User Offline
Joined: 25th Jan 2004
Location: The Star Forge Language: DBpro
Posted: 9th Aug 2005 01:36
Thanks Hamish for explaining the globals+arrays declared in functions issue

RiiDii,
Quote: "[quote]Don't have to declare their own for-next loop variables"

Not sure what you mean by this. [/quote]
global variables cannot be used for loops when they are in a function. Functions have to declare their own for-next loop variables NO MATTER WHAT. This can be annoying when I use my temp variables for for-next loops.

-Xol

RiiDii
20
Years of Service
User Offline
Joined: 20th Jan 2005
Location: Inatincan
Posted: 9th Aug 2005 02:52
Hrmm.. Hamish. Give this a try. Remember, you don't need "Global" to declare a global Array. It seems the compiler has a problem with using the word Global in a function.



Quote: "global variables cannot be used for loops when they are in a function."

Wow! Gave this one a try. That's one serious bug - but you made your point on that one. Once (if) they fix this though... anyway.
Thanks for pointing that out.

Quote: "In my opinion the only advantages to functions are..."

That's my point. There are a few advantages in using functions over subroutines (and I admit, a few). But what are the advantages of using subroutines over functions? I might be wrong, but we've got one bug so far, and half a reason because one might want to declare global variables somewhere other than in the main code.

"Droids don't rip your arms off when they lose." -H. Solo
REALITY II
Grog Grueslayer
Valued Member
20
Years of Service
User Offline
Joined: 30th May 2005
Playing: Green Hell
Posted: 9th Aug 2005 05:45
Quote: "I think I would like that too, but DBPro don't work that way."


I searched the internet for why this is and found in the Beta 3 of Upgrade 5 they wrote:

"For backwards compatibility, a DIM without LOCAL or GLOBAL declaration will default to a GLOBAL if global exists"

I believe TGC didn't intend for it to effect functions. But until TGC change it to the way it should be... the only way to do it is to add local to any dim statements within a function.

This code produces an error because a() is now defined as local.

Hamish McHaggis
22
Years of Service
User Offline
Joined: 13th Dec 2002
Location: Modgnik Detinu
Posted: 9th Aug 2005 15:54
Quote: "Quote: "global variables cannot be used for loops when they are in a function."
Wow! Gave this one a try. That's one serious bug - but you made your point on that one. Once (if) they fix this though... anyway.
Thanks for pointing that out. "


I noticed this problem a while ago, but didn't report it. Has anyone done so?

Login to post a reply

Server time is: 2025-06-06 09:47:19
Your offset time is: 2025-06-06 09:47:19