• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

GameMaker Can you put an array inside a switch statement?

Retrofire

Member
Kind of a stupid question but ya. My testing suggests the answer is no (not easily anyway) but I'm looking for confirmation.

example ~

GML:
box[0] = puppies
box[1] = kittens

switch box {
    case box[0] == puppies
        (statement) ; break;
    case box[1] == kittens
        (statement) ; break;
}
 

Roldy

Member
Kind of a stupid question but ya. My testing suggests the answer is no (not easily anyway) but I'm looking for confirmation.

example ~

GML:
box[0] = puppies
box[1] = kittens

switch box {
    case box[0] == puppies
        (statement) ; break;
    case box[1] == kittens
        (statement) ; break;
}
The cases of a switch statement must be constants. Not variable. The value of the cases must be known at compile time.
Like so:
GML:
switch (someVariable) {

   case 0:  // Constant value, not variable.

    // do something;



  case 1:

   // do something;



}
The switch can work on a single element of the array but not the whole array at once.

GML:
switch (box[0]) {  // this makes sense, a single element of the array

}



switch (box) { // this doesn't make much sense in gml

}
From your sample code I can't really tell what you are trying to do.

But if you wanted to do something based on each element of an array you could do something like:

GML:
enum EAnimalType {
   puppies = 0,
   kittens = 1
}; // These are constants

myArray[0] = EAnimalType.puppies;
myArray[1] = EAnimalType.kittens;

arraySize = array_length_1d(myArray);

for (i = 0; i < arraySize; i++) {  // loop through each element of array and check case for each

switch(myArray[i]) {  // switch on a single element of the array at a time

        case EAnimalType.puppies:  // cases are constant values
        // do puppies stuff
        break;

        case EAnimalType.kittens:
        // do kittens stuff
        break;

        default:
        // do unhandled stuff
        break;
    }
}
If you are trying to do something different than that then explain in more detail.


If you need more complicated or variable expression for the cases then consider using if/else if blocks

GML:
if (box[i] == puppies) {
// do puppy stuff
} else if (box[i] == kittens) {
// do kitten stuff
} else if (box[i] != someVariable) {
// do some other stuff
} else {
// do some other stuff if no other case was met
}
A switch block and the above if/else block are basically equivalent except that the if statements can test variable (runtime) conditions where the switch needs constant (compile time) cases.
 
Last edited:

Retrofire

Member
I seem to be rather confused about some of these more complex statement types. Particularly once you start intertwining them. My example above was really poor.

Here is the code that I'm trying to optimize. Once I start adding tons of other objects into the array it will become really archaic looking fast. Which is why I'm trying to put the array inside the switch statement. Clearly I don't understand switch statements very well yet, seeing as the expression needs to be a constant.
Screenshot (3018).jpg
I tried replacing it with some of the logic you suggested below. But I'm naturally having syntax problems (evidently). Honestly I'm pretty 💩💩💩💩ed up right now. I really shouldn't be programming in this state. And I'm not really comprehending anything your saying. I'm kind to take a break tonight to reset my head. I've been programming 24/7 for the last week. I'm trying to learn game development.
 

Attachments

Nidoking

Member
You can't convert this to a switch statement; at least, not without skipping over a much easier method. A switch is shorthand for a bunch of if statements that use the same single variable.
GML:
if (var1 == value1)
...
else if (var1 == value2)
...
else if (var1 == value3)
Here, you would turn this into
GML:
switch(var1)
{
case value1:

case value2:

case value3:
}
If each condition is independent or uses a different variable, as in your case, just use the if-else. I think the problem here is that you're putting a lot of things into arrays that don't need to be in arrays. You can simplify all of this, the whole thing, to one line by giving all of the objects you're looking at a single parent object, maybe oClickable or oCollidable or something like that. Then that whole thing resolves to collision_id = instance_place(x, y, oClickable); unless you're using those arrays for other things. Even then, you're going about things in way too complicated a fashion.

If you really must find the index of the minimum value of a collection of numbers, don't call min more than once. For an array of a hundred numbers, that would be looking at every number 100 times. Instead, use a for loop to go through the array and keep track of which index corresponds to the lowest value:
GML:
var min_index = 0;
var min_value = array[0];
for (var i = 1; i < array_length_1d(array); i++)
{
  if (array[i] < min_value)
  {
    min_index = i;
    min_value = array[i];
  }
}
You can put this into a script and return the value of min_index at the end. Then just grab the value at min_index in the other array.
 

TheouAegis

Member
You don't need a switch. What you need is less redundant code logic.

Are you doing anything with species_array outside this code? If not, use temporary variables.

If one distance is closer than the other, a simple else will suffice.

Are you using minimum_distance_id outside this code to move the object toward the target? If so, your code i# fine enough (except for the redundancy). If not, the whole code is just long-winded.

var n = instance_place(x,y,Photuris);
if n collision_id=n;
else {
n = instance_place(x,y,Luciolinae);
if n collision_id=n;
}

It prioritizes one over the other, but maybe that's enough.

Or you give them all a parent and use the parent object in instance_place().
 

Retrofire

Member
If each condition is independent or uses a different variable, as in your case, just use the if-else. I think the problem here is that you're putting a lot of things into arrays that don't need to be in arrays. You can simplify all of this, the whole thing, to one line by giving all of the objects you're looking at a single parent object, maybe oClickable or oCollidable or something like that. Then that whole thing resolves to collision_id = instance_place(x, y, oClickable); unless you're using those arrays for other things. Even then, you're going about things in way too complicated a fashion.
I think it's quite clear that I was over my head this time. But regardless, I'm still kind of impressed with myself, seeing as I found a way to accomplish this, even if it was in a ridiculously overcomplicated stressful way. I've never used parent objects before.

One benefit of the method that I used is that it takes distance into consideration while displaying data. So it will always display only the nearest possible instance, which will always exist, avoiding conflicts. Although, I suppose I could somehow accomplish this in a simpler way using the parent object method. That would only make things easier!

Actually, I think I simplified it a lot using your advice. Just for some context, even though I think you already understand, I'm trying to use the player's cursor to display local variable information in the nearest instance ID.

GML:
collision_id = instance_nearest(x, y, (instance_place(x, y, oClickable)));

//draw_event//

if collision_id != noone and instance_exists(collision_id)
    { draw_text(x+15, y+15, (collision_id).size)
    draw_text(x+15, y+35, (collision_id).age) }
This would effectively place every instance in the cursor's collision mask inside a list. And it would return the instance ID that is nearest. This would avoid any conflicts entirely using the parent method. Which is objectively better. Wow... I just turned like probably a thousand lines of code into 1. That's crazy! haha. I don't know whether this code will work yet. I have to test it :)

One potential problem could be that the first line of code technically isn't accessing a real list. It would be constantly cycling through every colliding instance separately. Which could lead to some unusual behavior.

That would resolve to something like

collision_id = instance_nearest(x, y, 80012)

at every pace in game time. So I need to put the actual colliding instances inside a list somehow. I'll be trying to figure that out.

This is potentially an example of where an array could actually be helpful
 
Last edited:

Nidoking

Member
collision_id = instance_nearest(x, y, (instance_place(x, y, oClickable)));
This is still doing too much. The instance_place is giving you an instance id. You're then asking "What is the nearest instance with that id to itself?", which is exactly the same id. Either use instance_place to get the instance at x,y, or use instance_nearest to get the one closest to x,y.

There are no lists involved in anything that you've done. Whatever you're thinking about efficiency, it's not right, and I don't think you need to worry about that.
 

Retrofire

Member
This is still doing too much. The instance_place is giving you an instance id. You're then asking "What is the nearest instance with that id to itself?", which is exactly the same id.
I'm aware... I was just trying to figure this out.

Either use instance_place to get the instance at x,y, or use instance_nearest to get the one closest to x,y.

There are no lists involved in anything that you've done. Whatever you're thinking about efficiency, it's not right, and I don't think you need to worry about that.
How would you account for distance then? Consider that there are two of the oClickable objects being detected. Using the place_meet function it will return multiple conflicting instance ID's, which will make the data distorted. Using the instant_nearest function it will return the data regardless of whether there is an actual collision occurring. I'm trying to display the nearest instance ID to avoid those data conflicts, in order to accomplish this I need to identify which is the nearest instance_id, and then make sure that a collision is taking place. I'm having a hard time solving that puzzle.

Perhaps I'm just overthinking this. idk...

I FIGURED IT OUT!!

GML:
collision_id = instance_place(x, y, obj_fireflies);

if collision_id != noone
    { collision_id = instance_nearest(x, y, obj_fireflies); }
else
    { collision_id = noone }
obj_fireflies is basically oClickable. First this finds (and stores) whether a collision is taking place. Once it detects a collision, this allows for the conditional expression to be satisfied as true. The statement underneath the conditional stores the true nearest instance value that is currently in a collision event. The draw event displays it.

Thanks for so much for helping me! :)
 
Last edited:

Nidoking

Member
Using the place_meet function it will return multiple conflicting instance ID's
This is not true. place_meeting will return true or false. instance_place, on the other hand, will return a single instance ID. If there are multiple instances at that location, it will choose one of the collided instances to check. Since I don't know what the shape of the instance that's calling this code is, I can't tell you how to resolve exactly what you want, but you could use instance_nearest and then determine the actual distance to see whether it's within the range you want. I expect there to be some strange edge cases in what you've posted, but if it works for you, then so be it.
 

Retrofire

Member
This is not true. place_meeting will return true or false. instance_place, on the other hand, will return a single instance ID. If there are multiple instances at that location, it will choose one of the collided instances to check. Since I don't know what the shape of the instance that's calling this code is, I can't tell you how to resolve exactly what you want, but you could use instance_nearest and then determine the actual distance to see whether it's within the range you want. I expect there to be some strange edge cases in what you've posted, but if it works for you, then so be it.
Right, sorry, I was using them interchangeably by accident. I meant to say instant_place. I'm kind of unsure about what your saying? Why wouldn't the code I posted address this problem? It's checking the instance ID, returning a value, this satisfies the collision detection. The statement underneath it will only return the nearest instance of the object in question (which is the parent object of all the other objects). Which (at least in theory) would always return the nearest collided instance ID. Am I wrong about this? It seems to be working, but you suggest that there could be problems.
 

Nidoking

Member
I'm saying that if there's a collision, then you're colliding with something. How often is that not the nearest instance? What is nearer than "right here"?
 

Retrofire

Member
I'm saying that if there's a collision, then you're colliding with something. How often is that not the nearest instance? What is nearer than "right here"?
Good question. I'm making kind of a weird game. It basically uses the cursor in the same manner as a game like insaniquarium. The screen is filled with little fireflies, tons of them. Sometimes they pile up. The cursor could very well have in excess of 10 of them within the collision mask. So if the player wants to access, say, the species of a specific firefly, this would be challenging in that situation. Using this code the player, using a degree of precision, can always access the information they want. If I didn't implement this, it would frustrate the player.
 

Nidoking

Member
I've never played Insaniquarium and still don't understand a situation where the nearest instance doesn't collide with instance_place, but a different one does.
 

Retrofire

Member
I've never played Insaniquarium and still don't understand a situation where the nearest instance doesn't collide with instance_place, but a different one does.
I'm a complete novice, so 💩💩💩💩 me if I'm wrong. But I guess my understanding was that using instance_place it would return the first instance that enters the collision mask. So I guess the question I asked myself, building off that inference, was what if there are multiple instances within the collision mask? How do you prioritize which one to select? So I wanted the nearest one in particular, instead of whatever displays first and is retained inside the function. This becomes important when there are multiple instances within the collision mask. Maybe the instance ID that first enters the mask is maintained over the other (closer) instances. Because technically the more distant one is the first one received, and likely to be retained. At least hypothetically. I don't entirely understand how the game engine would prioritize instances using this function.

Please correct me if I'm wrong here...
 
Last edited:

Nidoking

Member
what if there are multiple instances within the collision mask?
If the answer to this question matters to you, then instance_place is not the function that you want to use. There is no "first" or "retained" or "maintained" or "distant". There is "Find me an instance whose bounding box overlaps mine, and I don't care which one."

If you want the nearest instance, use instance_nearest. That's what the name is, that's what it does. If you then want to know whether it's within a certain distance, you can find the distance to it using distance functions, or you can check whether there's overlap by using place_meeting and that single instance id, rather than checking all instances twice over.
 

TheouAegis

Member
Using instance_place_list(clickList,x,y,oClickable) will fill the list with ID clickList wait a list of all instances colliding at the current coordinates. If the size of that list is 0, there are no instances. If the size of that list is one, there is only one instance and that is your clickable ID. If the size is 2 or higher, then, and only then, would you LOOP through the entire list and check distances of each instance inside that list to the current coordinates (x,y) using the point_distance() function. You do not want to use distance_to_object() because they will all have the same distance, but the point distance will vary. And if you're unsure of how to do this, look up FrostyCat's "With Recipes", as this is one of the most common fundamentals.
 

Retrofire

Member
If the answer to this question matters to you, then instance_place is not the function that you want to use. There is no "first" or "retained" or "maintained" or "distant". There is "Find me an instance whose bounding box overlaps mine, and I don't care which one."

If you want the nearest instance, use instance_nearest. That's what the name is, that's what it does. If you then want to know whether it's within a certain distance, you can find the distance to it using distance functions, or you can check whether there's overlap by using place_meeting and that single instance id, rather than checking all instances twice over.
I think there is some kind of fundamental misunderstanding between us. I don't want to frustrate you, so you don't have to keep responding if you don't want. I'm entirely aware that instance_place doesn't care which instance it grabs within the collision mask. That's what I'm trying to account for. I'm also entirely aware that instance_nearest returns the nearest instance. Using instance_nearest alone would perpetually display the data, instead of activating during a collision. When you use either of these independently it doesn't give you the right result. But if you combine the two of them like I did, it does.

GML:
collision_id = instance_place(x, y, obj_fireflies);

if collision_id != noone
    { collision_id = instance_nearest(x, y, obj_fireflies); }
else
    { collision_id = noone }
  1. the first line evaluates whether any instance exists within the collision mask
  2. the if conditional passes if an instance exists within it
  3. at this point the collision has taken place. So using the instance_nearest function you can get what the nearest collision is, in real time. And return that data specifically. This is precisely what I was trying to accomplish.
 

Nidoking

Member
And if you combine the two of them the other way, it also works. I cannot understand why you translate that into not doing two checks. I said to do two checks. You quoted me saying to do two checks. It's right there in your quote. I suggested changing the order of the checks, not the number of checks. That means doing the second check first and the first check second. The advantage is that the second check can then be much simpler, because you already know what the closest instance is. You only have to check whether that single instance meets the instance_place/place_meeting check, rather than checking all instances and then checking all instances again with instance_nearest. You still do both checks. The two checks that you have remain in the final version which will have two checks. Not one, but two full checks. Hopefully, somewhere in there, you can understand what I'm saying.
 
Top