Posted: 9th Nov 2011 5:12
Creating independent modules in AppGameKit tier 1 is almost impossible due to the fact there is no way to declare global variables inside other modules, and also all variables declared in those other modules are not even global inside it.

Example:

main.agc
-------

#include module.agc

do
my_counter = Increment()
Print("hello world - " + str(my_counter))
Sync()
loop


module.agc
----------
Global counter = 10

Function Increment()
// do something herer
EndFunction counter

-----------------------------------------------------------
So declaring counter inside module.agc should make it global and persistent inside the functions declared in module.agc - this would be perfect since we could simulate "private" variables to that module.

The problem is that we can't do that, and also declaring "counter" as Global also doesn't make it global to the whole application, which could be fine too. What happen is that counter will be always zero, not 10.

This behaviour basically blocks any kind of reusable module we could create, without having to declare its variables in main.agc.

If one of the behaviours above are not possible, at least we could have the header file concept, where it would contain the global variables to the whole application as well.

I've added this same text to the bug system as feature request, but I'd like to hear from you guys what do you think?


Cheers
Posted: 9th Nov 2011 9:33
Use an gosub to declare it and after that use the include command so will it work.
Iam doing this all the time with boinkadroid.


gosub initiate_timers

#include timers

do

timers()

sync
loop

There is only one hickup with that you declare typed arrays last or something in initiate to get it to work?
I use modue files for my projects and it works.

agk dosent care that you call the gosub before the include!
Posted: 9th Nov 2011 12:56
The include just append your module to the end of main, you need to have the commands in the module inside a function, then call that function from the main file, ifnot, you will never run the code in the module. I had the same problem

+ Code Snippet
Main:
-----

#include module.agc
fun_global()

do
 my_counter = Increment()
 Print("hello world - " + str(my_counter))
 Sync()
loop


module.agc
----------
function FUN_global()
 Global counter = 10
endfunction

Function Increment()
 // do something herer
EndFunction counter



In other words, to understand the include, imagine you copy the text of your module, and glue it at the bottom of the main file, and you will see the error
Posted: 9th Nov 2011 12:57
The variables are not global as the code which defines them is not executed.

Personally, I don't recommend a specific declaration gosub, partly because I'm a grown up and gosubs are for kids, (queue the flames) but mostly as I declare all my variables for whatever module the first time the function is called.

What I do for example is when creating something like a player sprite, or a new text object, or a new shader effect in DBP, I check if a needed value, for example PlayerSpriteNumber is 0 or not.

If it is, I then can assume the variable had not been declared and declare it. (If it's already been declared, it's ok as since the value is 0, no data would be lost) This way, you can create drag and drop modules which declare their own variables.
(If only types could be defined in this way, all my modules AppGameKit and DBP would be 100% perfectly portable!
Posted: 9th Nov 2011 13:20
Thanks for all. I don't think the gosub is a problem. Sometimes even goto is better than having a complex flow just to avoid it - Clarity is the most important, imho.

Maybe the gosub idea will do the job for my drop in modules. I'll make some tests...

As for Mobiius solution, could you explain or maybe give a example about what you mean. I'm not sure if I followed your idea. As far as I understand, using your technique you still have to declare the variable in the main.agc. My goal for modules is that you don't have to know all variables that will be used inside it at all, which a include or "global for the module" will do.

Thanks
Posted: 9th Nov 2011 13:27
Personally, I don't recommend a specific declaration gosub, partly because I'm a grown up and gosubs are for kids, (queue the flames) but mostly as I declare all my variables for whatever module the first time the function is called.


When you buy agk so will you find that its missing alot and still in development

Then will gosubs do the job sometimes
Posted: 9th Nov 2011 15:24
Using my solution, you shouldn't need to declare variables in the main source file.

See this example, where we start using a variable, but check if it exists or not. If not, instantiate it. If it does exist, we use it.
+ Code Snippet
`See, we don't setup TestVariable before we use it...
Do
   UseVariable()
   Sync()
Loop
End

`For simplicity, assume these functions are in a separate module file and are #included at the top. It makes no difference and works the same.

Function UseVariable()
   If TestVariable = 0 Then SetupVariable()

   `Since this is an example, we'll just print the contents of the variable.
   Print( TestVariable )
EndFunction

Function SetupVariable()
   Global TestVariable : TestVariable = 69

   `Imaging this is where we create a sprite or something...
EndFunction
Posted: 9th Nov 2011 16:55
Now everything makes sense! Basically your solution and Cliff Mellangard 3DEGS's are the same-ish, with the difference you initialize the variables "under the hood".

So the "secret" is declare global variables inside the functions (or subroutines) in the second module, and call this function before using the variable. Genius...

To be very portable, I'd even would put all my variables in a type definition, to keep them inside the module namespace...

Now I can see the light!

Thanks guys!
Posted: 9th Nov 2011 17:17
To be very portable, I'd even would put all my variables in a type definition, to keep them inside the module namespace...

And that's where portability ends! lol

You can't define typed variables in functions. I wish you could, but you can't.

To get around that, I include in a comment block at the top of the include file, all the variables and types needed, plus a list of all dependant addins, plugins and modules required, ready to cut and paste into the main source file. Not ideal, but it'll have to do! lol
Posted: 9th Nov 2011 17:19
So, based on the ideas I've got from here... I think I can do a very well "encapsulated" module, using some name conventions.

here is my new main.agc:


#include module.agc
// call once to "instantiate" module
module_constructor()
rem A Wizard Did It!
do
Print("hello world - " + str(module.counter))
Print("And the object b " + module.b)
Print("And the object a " + Str(module.a))
Sync()
loop


and here the module.agc (for some reason I cannot make it as code snippet):


// My "module-private" variables
Type _module
a as integer
b as string
counter as integer
EndType

Function module_constructor()
Global module as _module
module.counter = 10
module.a = 10
module.b = "AGK"
EndFunction

Function module_increment()
// do something here
module.a = module.a + 1
EndFunction


The idea to call the global type with the same name as the filename just gives an better way to keep the module-only variables properly identified throughout the code, since they are all globals, and using simple variables could bring problems with namespace conflicts (imagine "counter" being using by two different modules in two different ways.

Thanks again!
Posted: 10th Nov 2011 10:37
That won't work. You (A) define your types in the include file and (B) never execute the code which defines your types.

This will work however...
+ Code Snippet
#include module.agc
// My "module-private" variables
Type _module
   a as integer
   b as string
   counter as integer
EndType


// call once to "instantiate" module
module_constructor()


do
   Print("hello world - " + str(module.counter))
   Print("And the object b " + module.b)
   Print("And the object a " + Str(module.a))
   Sync()
loop

`Include File...
Function module_constructor()
Global module as _module
module.counter = 10
module.a = 10
module.b = "AGK"
EndFunction

Function module_increment()
// do something here
module.a = module.a + 1
EndFunction


But what I'd do to make it simpler is this.....
+ Code Snippet
#include module.agc
// My "module-private" variables
Type _module
   a as integer
   b as string
   counter as integer
EndType


do
   Print("hello world - " + str(module.counter))
   Print("And the object b " + module.b)
   Print("And the object a " + Str(module.a))
   Sync()

   module_increment()
loop

`Include File...
Function module_constructor()
Global module as _module
module.counter = 10
module.a = 10
module.b = "AGK"
EndFunction

Function module_increment()
// do something here
   If module.a = 0 Then module_constructor()

   module.a = module.a + 1
EndFunction
Posted: 10th Nov 2011 16:12
Hi Mobiius,

thanks for the code, but my code is working properly (I just retested it again). Declaring the the structure in the module.agc didn't cause any problem. For example, I could see the values I set by default (in the constructor) being displayed properly on screen.

I did a quick test regarding this behaviour (main.agc):

+ Code Snippet
aaa as _obj
aaa.new = 999

do
 Print("aaa.new = " + Str(aaa.new))
 Sync()
loop

TYPE _obj
    new as integer
EndType


So I believe it doesn't matter where you declare your TYPE, and therefore, you can declare it inside your module.agc. That's is actually great!


Cheers
Posted: 10th Nov 2011 17:25
Hmmm, I'll have to investigate this!
Posted: 23rd Nov 2011 16:50
So I believe it doesn't matter where you declare your TYPE, and therefore, you can declare it inside your module.agc. That's is actually great!


Nope, tested it and you definitely can't define types within functions.

Shame.
Posted: 23rd Nov 2011 17:04
hame.

I know... I'm on the verge of just leaving functions behind in AGK. Their outputs alway return values equal to the given data type's minumum for me, and seem to do the same for any globals altered as well. AND, this is if it doesn't thow a "sprite does not exist at line (random)," upon the programs execution, and at a line that never has any relation to sprites in the first place... I've had this problem a couple of times with gosubs as well though... (at least the latter one)
Posted: 24th Nov 2011 14:10
Their outputs alway return values equal to the given data type's minumum for me

They work fine for me, and indeed everyone else??

and seem to do the same for any globals altered as well.

What code are you using because this also works for everyone?
Posted: 24th Nov 2011 15:17
Mobiius,

I just noticed I expressed myself badly. You can't declare the TYPE inside the function - that's true. However, you can declare your TYPE in the module.agc file at the beginning for example, and declare the global variables of that type within a function.

Doing this way, we can have the module code isolated inside the module file.

Check the module file again:

+ Code Snippet
// My "module-private" variables
Type _module
a as integer
b as string
counter as integer
EndType

Function module_constructor()
  Global module as _module
  module.counter = 10
  module.a = 10
  module.b = "AGK"
EndFunction

Function module_increment()
  // do something here
  module.a = module.a + 1
EndFunction


And the main.agc doesn't have to have anything other than the include *and* call the module_constructor().

+ Code Snippet
#include module.agc

// call once to "instantiate" module
module_constructor()
do
  Print("hello world - " + str(module.counter))
  Print("And the object b " + module.b)
  Print("And the object a " + Str(module.a))
  Sync()
loop


So, my conclusion is that code "encapsulation" is possible with the code above.


Cheers
Posted: 25th Nov 2011 13:58
Holy t**ty f***ing c***st!

You're right!! That's the most awesomest thing I've learnt about AppGameKit!!!

You can indeed include the type declaration at the top of your include file, and do the declarations within a function!

Thats the best news I've heard about AppGameKit yet!!!