Tip: Arrays and loops
ORBZ
Member Posts: 1,304
You can do arrays and loops in game salad.
The problem that most people coming to game salad don't understand is that GS executes everything in parallel.
Loops are linear
This is a problem.
So to solve this we need to figure out a way to tie some logic into a single thread of execution.
Fortunatly GS gives us such a tool, it's called a timer.
Every timer that executes executes inside its own thread. (This is the same in javascript btw for those webdevs out there).
Now then. How does this help you loop through an array? And for that matter, what arrays are you talking about ORBZ?!
Well, GS operates inside out from most other languages you may have used. You don't look at the actual program logic, instead you look at behaviors and relationships. You might say that you are the item being iterated over, unknowing that you are inside an array.
In this regard we can create an array like this:
Create an object and give it a variable called indexNum (orwhatever you like, call it tofuIndex, whatever)
that variable should be of type ... suprirse: Index
Indexes are integers that can't be negative, they max out at around 2 billion. That's a truncated signed int 32 for all you c programmers out there. It's really a waste of space because an unsigned int32 can actually hold 4 billion values, but ... i digress.
Anyhow, don't ever ever try to loop through 2 billion objects in GS because you will cause a black hole and the universe will implode... bad stuff will happen. Mostly you're computer will just get hot.
Now here is the sad part. Because we are using timers, we are limited to exactly how fast we can execute stuff. We can't go too quick or else GS will trip over itself. A good rule of thumb is go as fast as you need to but no faster. Try Timer ever 0.1 seconds to start. Then if you need a faster timer divide by 2: 0.05. Need faster? Div 2 again: 0.0025... etc. Sooner or later you will hit a point where GS can't keep up and that's unfortunately as fast as you can go.
Now then: How do i make this thing loop?
You create a game variable game.arrayIndex
and another: game.arrayMax
set game.arrayMax equal to the total number of elements in your array, let's say 5.
game.arrayMax = 5
now the loop:
There are two ways... you could use a game timer as i eluded to before. OR we could do it the sneaky awesome way using the built in game clock. I like the sneaky dangerous way so lets do that.
Here we go: No timers:
constrain attribute: game.arrayIndex = (game.time * 2.5) % (game.arrayMax - 1)
What the hell is that?! Let's break it down.
game.time is well.. the amount of time since the game started running. it's a float.
2.5 is speeding up the loop, 2.5 times. It makes your loop faster, but not too fast. It's just a tiral and error number i came up with that works pretty good for my needs. Play with this number to find what works best for you.
% = modulus, it's division where the remainder is kept. You already knew that didn't you.
game.arrayMax - 1 = the point at which you want the modulus to clip and wrap around.
So basically this one line is causing the value arrayIndex to count up from 0, 1, 2, 3, 4 and then at 5 it evaluates to 0 again because 5 divided by 5 is 0 remainder and so it repeats.
So there we have an index that's constantly clicking away... tick tick tick.
So how does that help us? Well that's our clock... that's our little pointer that keeps adjusting it's "current" index value.
Next we need to have that do something useful right? I mean, where's the array portion?
So inside our "array objects" (and i use that term loosly because after all this whole thing is a hack)
any object that is a member of the array we do this:
create a member variable called arrayIndex type Index.
set the first member of your array to index 0
the next object should have it's index set to 1
the next to 2
the next is 3
and the final is 4
because our max is 5 so we have max - 1 as the highest value.
If you need more objects don't forget to adjust game.maxArray
Now put a rule inside your object that says:
when self.arrayIndex = game.arrayIndex:
do stuff...
That is it. Now the clock will cycle through, adjusting the game.arrayIndex. Each of your objects will monitor the game.arrayIndex and when it's their tern to process they will.
It's not perfect, it's a hack, real arrays would be better, but this does work.
Oh, and you can use a timer too if you like. game.time is just an interesting way to achieve the same results. That constrain behavior is firing off events, the timer would create a separate thread... either is bad and good. pros and cons of each. try both see what works for you.
The problem that most people coming to game salad don't understand is that GS executes everything in parallel.
Loops are linear
This is a problem.
So to solve this we need to figure out a way to tie some logic into a single thread of execution.
Fortunatly GS gives us such a tool, it's called a timer.
Every timer that executes executes inside its own thread. (This is the same in javascript btw for those webdevs out there).
Now then. How does this help you loop through an array? And for that matter, what arrays are you talking about ORBZ?!
Well, GS operates inside out from most other languages you may have used. You don't look at the actual program logic, instead you look at behaviors and relationships. You might say that you are the item being iterated over, unknowing that you are inside an array.
In this regard we can create an array like this:
Create an object and give it a variable called indexNum (orwhatever you like, call it tofuIndex, whatever)
that variable should be of type ... suprirse: Index
Indexes are integers that can't be negative, they max out at around 2 billion. That's a truncated signed int 32 for all you c programmers out there. It's really a waste of space because an unsigned int32 can actually hold 4 billion values, but ... i digress.
Anyhow, don't ever ever try to loop through 2 billion objects in GS because you will cause a black hole and the universe will implode... bad stuff will happen. Mostly you're computer will just get hot.
Now here is the sad part. Because we are using timers, we are limited to exactly how fast we can execute stuff. We can't go too quick or else GS will trip over itself. A good rule of thumb is go as fast as you need to but no faster. Try Timer ever 0.1 seconds to start. Then if you need a faster timer divide by 2: 0.05. Need faster? Div 2 again: 0.0025... etc. Sooner or later you will hit a point where GS can't keep up and that's unfortunately as fast as you can go.
Now then: How do i make this thing loop?
You create a game variable game.arrayIndex
and another: game.arrayMax
set game.arrayMax equal to the total number of elements in your array, let's say 5.
game.arrayMax = 5
now the loop:
There are two ways... you could use a game timer as i eluded to before. OR we could do it the sneaky awesome way using the built in game clock. I like the sneaky dangerous way so lets do that.
Here we go: No timers:
constrain attribute: game.arrayIndex = (game.time * 2.5) % (game.arrayMax - 1)
What the hell is that?! Let's break it down.
game.time is well.. the amount of time since the game started running. it's a float.
2.5 is speeding up the loop, 2.5 times. It makes your loop faster, but not too fast. It's just a tiral and error number i came up with that works pretty good for my needs. Play with this number to find what works best for you.
% = modulus, it's division where the remainder is kept. You already knew that didn't you.
game.arrayMax - 1 = the point at which you want the modulus to clip and wrap around.
So basically this one line is causing the value arrayIndex to count up from 0, 1, 2, 3, 4 and then at 5 it evaluates to 0 again because 5 divided by 5 is 0 remainder and so it repeats.
So there we have an index that's constantly clicking away... tick tick tick.
So how does that help us? Well that's our clock... that's our little pointer that keeps adjusting it's "current" index value.
Next we need to have that do something useful right? I mean, where's the array portion?
So inside our "array objects" (and i use that term loosly because after all this whole thing is a hack)
any object that is a member of the array we do this:
create a member variable called arrayIndex type Index.
set the first member of your array to index 0
the next object should have it's index set to 1
the next to 2
the next is 3
and the final is 4
because our max is 5 so we have max - 1 as the highest value.
If you need more objects don't forget to adjust game.maxArray
Now put a rule inside your object that says:
when self.arrayIndex = game.arrayIndex:
do stuff...
That is it. Now the clock will cycle through, adjusting the game.arrayIndex. Each of your objects will monitor the game.arrayIndex and when it's their tern to process they will.
It's not perfect, it's a hack, real arrays would be better, but this does work.
Oh, and you can use a timer too if you like. game.time is just an interesting way to achieve the same results. That constrain behavior is firing off events, the timer would create a separate thread... either is bad and good. pros and cons of each. try both see what works for you.
Comments
Great stuff btw!
QS
Dr. Sam Beckett never returned home...
Twitter: https://twitter.com/Quantum_Sheep
Web: https://quantumsheep.itch.io
if you wanted a pause feature wrap the array looper inside a rule
when game.paused = false
constrain attribute: game.arrayIndex = (game.time * 2.5) % (game.arrayMax - 1)
I doubt I'll get round to using it, but I'm sure others will find it extremely helpful!
Cheers!
QS
Dr. Sam Beckett never returned home...
Twitter: https://twitter.com/Quantum_Sheep
Web: https://quantumsheep.itch.io
I've been thinking about using arrays and that's a very good walk-through.
Kudos to you for thinking outside the box!
Now I just need to apply it to a game...
create multiple objects, each object has an index variable created on it, your first object's index is set to 0, your next is set to 1, then 2, then 3, etc... YOU do this in design mode.
create a global index call it something like currentIndex
create a global maxArraySize and set it
create a timer (or use game.time) that increments the global index each tick
wrap the index back to the beginning when maxArraySize-1 has been reached via the modulus operator
each object has a rule on it that says "when my index matches the global index it's my turn to do some processing"
done.
I have a question...
`game.arrayIndex = (game.time * 2.5) % (game.arrayMax - 1)`
Why the -1? In a "display text" test I ran, it resulted in a 0,1,2,3 sequence instead of a 0,1,2,3,4 sequence. Why not just set the max to 4 to begin with?