Legacy GM [SOLVED] Switch statement help

O

Oz Locke

Guest
Solved - Cannot use multiple conditions in a switch

As proivded below, changed to an if statement:
Code:
if (keyboard_check(vk_up) ||keyboard_check(ord('W'))){
    if(y > 2) y -= 2;
    };
if (keyboard_check(vk_right) || keyboard_check(ord('D'))){
    if(x < 1022) x += 2;
    };
if (keyboard_check(vk_down) ||keyboard_check(ord('S'))){
    if(y < 478) y += 6;
    };
if (keyboard_check(vk_left) || keyboard_check(ord('A'))){
    if(x > 6) x -= 6;  
    };
----------------------------------------------------------------------------------------------------------------------

I'm trying to build a switch statement to allow 8 directional movement (so straight off, if I'm doing it wrong, please tell me, though I'm trying trying to avoid the D&D)

The code seems right to me, but I think I'm missing a core concept, because it's throwing an error at compile. Any help with solving it would be appreciated :)

Here's the code:
Code:
switch (keyboard_key)
    {
    //--ORTHOGINAL--
    //up
    case vk_up:
    case ord('W'):
        if(y > 2) y -= 2;
        break;
    //right
    case vk_right:
    case ord('D'):
        if(x < 1022) x += 2;
        break;
    //down 
    case vk_down:
    case ord('S'):
        if(y < 478) y += 6;
        image_index = 0;
        image_speed = 0;
        break;
    //left
    case vk_left:
    case ord('A'):
        if(x > 6) x -= 6;
        image_index = 0;
        image_speed = 0;
        break; 
  
  
    //--DIAGONAL--
    //(note that the image_speed code is used to make the bird glide)
    //up + left
    case vk_up && vk_left:
    case ord('W') && ord('A'):
        if(y > 2) y -= 2;
        if(x > 6) x -= 6;
        break;
    //up + right
    case vk_up && vk_right:
    case ord('W') && ord('D'):
        if(y > 2) y -= 2;
        if(x < 1022) x += 2;
        break;
    //down + left
    case vk_down && vk_left:
    case ord('S') && ord('A'):
        if(y < 478) y += 6;
        if(x > 6) x -= 6;
        image_index = 0;
        image_speed = 0;
        break;
    //down + right
    case vk_down && vk_right:
    case ord('S') && ord('D'):
        if(y < 478) y += 6;
        if(x < 1022) x += 2;
        image_index = 0;
        image_speed = 0;
        break;
  
};
And here's the error:
Final Compile...Error : gml_Object_obj_bird_Key_ANYKEY_1(53) : duplicate case statement found
Error : gml_Object_obj_bird_Key_ANYKEY_1(54) : original here
Error : gml_Object_obj_bird_Key_ANYKEY_1(45) : duplicate case statement found
Error : gml_Object_obj_bird_Key_ANYKEY_1(46) : original here
Error : gml_Object_obj_bird_Key_ANYKEY_1(39) : duplicate case statement found
Error : gml_Object_obj_bird_Key_ANYKEY_1(40) : original here
Error : gml_Object_obj_bird_Key_ANYKEY_1(33) : duplicate case statement found
Error : gml_Object_obj_bird_Key_ANYKEY_1(34) : original here​
 
Last edited by a moderator:

jo-thijs

Member
Hi and welcome to the GMC!

You can't do this:
Code:
    case vk_up && vk_right:
GameMaker will interprete it as though you wrote:
Code:
    case 1:
The same goes for this:
Code:
    case ord('W') && ord('D'):
Now, you've got 2 times "case 1" which is a duplicate case statement.

@KingdomOfGamez, that's not true, keyboard_key is a variable.
 
O

Oz Locke

Guest
@jo-thijs, thanks for the warm welcome :)

I'm really sorry, but I don't understand what you mean:

Hi and welcome to the GMC!

You can't do this:
Code:
    case vk_up && vk_right:
GameMaker will interprete it as though you wrote:
Code:
    case 1:
The same goes for this:
Code:
    case ord('W') && ord('D'):
Now, you've got 2 times "case 1" which is a duplicate case statement.

@KingdomOfGamez, that's not true, keyboard_key is a variable.
Why would
Code:
case vk_up && vk_right:
not work, when
Code:
case vk_up:
does? Does the function not accept multiple conditions in a check?
 

spe

Member
Well, at first glance, I'd say the problem is that you can't use && in a switch statement. Try finding a way around that, and see if it solves your problem.

EDIT: ninja'd. Still, I believe that is what's causing your problem. You could try using a bunch of if, if else statements instead. It's not as clean, but it would allow you to use the && sign.
 
Last edited:

jo-thijs

Member
@KingdomOfGamez, motion_add wouldn't be a good solution though because of 4 reasons:
1) it should be motion_set.
2) motion_set would work with speeds and te OP wants to change x and y directly.
3) motion_set would not include the if checks (though I'm not sure if that'd be a bad thing).
4) motion_set would give every direction the same speed, which is also ot what the OP wants.

@Oz Locke, Now, looking at your code, it looks like you can just seperate horizontal from vertical movement.
Like this:
Code:
if keyboard_check(vk_up) ||keyboard_check(ord('W'))
    if y > 2
        y -= 2;
if keyboard_check(vk_right) || keyboard_check(ord('D'))
    if(x < 1022)
        x += 2;
if keyboard_check(vk_down) ||keyboard_check(ord('S'))
    if y < 478
        y += 6;
if keyboard_check(vk_left) || keyboard_check(ord('A'))
    if(x > 6)
        x -= 6;
 
O

Oz Locke

Guest
Thanks guys, was thinking the same thing as it looks like the issue is definitely with trying to use multiple conditions.

Going the if statement route :)

@jo-thijs Makes sense, I'd gotten trapped in the rabbit hole of the SWITCH statement and ended up making things more complicated than they needed to be XD
 
Just a small advice, you shouldn't use keyboard_key. It's a very unreliable function and will sometimes glitch when you press more than 3 keys at the same time.

Instead, use a first script that generate inputs depending on key presses,
for instance:
Code:
press_left=0
if keyboard_chek(vk_left) or keyboard_check(ord('A'))
   press_left=1;
And then have actions happen depending on those input variables.

Code:
if press_left=1 && x>2
   x-=2;
 

spe

Member
In case you're still wondering...
Why would
Code:
case vk_up && vk_right:
not work, when
Code:
case vk_up:
does? Does the function not accept multiple conditions in a check?
That is simply because vk_up is a case, but vk_up && vk_right is more like an equation. Whenever you use the && sign, it basically adds the two together. Not mathematically, but as Boolean values. When vk_up is pressed, then the case for keyboard_key will be vk_up. But when you have vk_up && vk_right, it creates a Boolean value from the two. If both are pressed, the result is 'true', or 1. If one or neither are pressed, the result is 'false', or 0. This is not a valid case for keyboard_key, because it's not looking for a true or false (Boolean) value, it's looking for one of the keys, like vk_up. The 'duplicate case statement found' error refers to the fact that you can't have multiple identical cases. So while 'vk_up && vk_right' looks totally different than 'vk_down && vk_left', they both equate to 0 when the buttons are not pressed, so the case is basically 0 for both of them. You can't have more than one case in a switch that is 0, or 1, or any other value. They all need to be different.
Besides, even if you didn't get the duplicate error, the code still wouldn't accept the input, and your player wouldn't move properly, because the switch is looking for one of the four potential cases for keyboard_key. 0 is not one of the cases.

And there's the long-winded explanation. :) Hope you learned something, and good luck!
 
Last edited:
O

Oz Locke

Guest
In case you're still wondering...


That is simply because vk_up is a case, but vk_up && vk_right is more like an equation. Whenever you use the && sign, it basically adds the two together. Not mathematically, but as Boolean values. When vk_up is pressed, then the case for keyboard_key will be vk_up. But when you have vk_up && vk_right, it creates a Boolean value from the two. If both are pressed, the result is 'true', or 1. If one or neither are pressed, the result is 'false', or 0. This is not a valid case for keyboard_key, because it's not looking for a true or false (Boolean) value, it's looking for one of the keys, like vk_up. The 'duplicate case statement found' error refers to the fact that you can't have multiple identical cases. So while 'vk_up && vk_right' looks totally different than 'vk_down && vk_left', they both equate to 0 when the buttons are not pressed, so the case is basically 0 for both of them. You can't have more than one case in a switch that is 0, or 1, or any other value. They all need to be different.

And there's the long-winded explanation. :) Hope you learned something, and good luck!

Awesome, clears it right up, thank you :D
 

jo-thijs

Member
@Oz Locke,
case vk_up: will check if keyboard_key == vk_up
case vk_up && vk_right: will check if keyboard_key == (vk_up && vk_right)

Now, what (a && b) does, is it returns 0 if a < 0.5 or b < 0.5
and it returns 1 otherwise, if a >= 0.5 and b >= 0.5.

Since vk_up and vk_right are both actually just numbers in disguise that are both larger than 1,
this: (vk_up && vk_right)
gets replaced by this: 1

So this:
case vk_up && vk_right: will actually check if keyboard_key == 1

@spe,
That's indeed what's causing the issue, but just using ifs won't help, seeing as keyboard_key can only have 1 value, not both vk_up and vk_right and the same time.
He'll also need to use keyboard_check instead of keyboard_key.

@Adrien Dittrick,
Good advice.
It might also be good advice to use clamp instead of those if statements he's using.

PS: You guys really give me no time to write a reply here, ninja'd so many times...
 

spe

Member
@spe,
That's indeed what's causing the issue, but just using ifs won't help, seeing as keyboard_key can only have 1 value, not both vk_up and vk_right and the same time.
He'll also need to use keyboard_check instead of keyboard_key.

PS: You guys really give me no time to write a reply here, ninja'd so many times...
Yes, I know, but I still would have rewritten this whole thing using if statements instead. :)
I got ninja'd too, btw. :p
 
O

Oz Locke

Guest
@Oz Locke,
case vk_up: will check if keyboard_key == vk_up
case vk_up && vk_right: will check if keyboard_key == (vk_up && vk_right)

Now, what (a && b) does, is it returns 0 if a < 0.5 or b < 0.5
and it returns 1 otherwise, if a >= 0.5 and b >= 0.5.

Since vk_up and vk_right are both actually just numbers in disguise that are both larger than 1,
this: (vk_up && vk_right)
gets replaced by this: 1

So this:
case vk_up && vk_right: will actually check if keyboard_key == 1

@spe,
That's indeed what's causing the issue, but just using ifs won't help, seeing as keyboard_key can only have 1 value, not both vk_up and vk_right and the same time.
He'll also need to use keyboard_check instead of keyboard_key.

@Adrien Dittrick,
Good advice.
It might also be good advice to use clamp instead of those if statements he's using.

PS: You guys really give me no time to write a reply here, ninja'd so many times...

Happy to go find out more about CLAMP (not heard of it before) but could you let me know what you're take on it's value here is? If nothing else it'll help guide my research :)
 

spe

Member
Basically, clamp is a function that takes three arguments. The first is the value you want to clamp. The second is the minimum value, and the third is the maximum value. Clamp prevents the clamped value from going above the maximum or below the minimum.
 
O

Oz Locke

Guest
OK, works perfectly, thanks :)
I'm still a little unclear on what it's doing though, and would really appreciate any guidance...

Code:
if (keyboard_check(vk_up) || keyboard_check(ord('W'))){
    y = clamp(-2, y-2, 478);
    };
if (keyboard_check(vk_right) || keyboard_check(ord('D'))){
    x = clamp(2, x+2, 1022);
    };
if (keyboard_check(vk_down) ||keyboard_check(ord('S'))){
    y = clamp(2, y+6, 478);
    image_index = 0;
    image_speed = 0;
    };
if (keyboard_check(vk_left) || keyboard_check(ord('A'))){
    x = clamp(2, x-6, 1022); 
    image_index = 0;
    image_speed = 0;
    };
Where I'm unclear is on the order of the arguments: it appears that the first is the min value the change can be applied within, the second the value to apply and the third the max?
That doesn't really fit with what I'm seeing in the manual, where the first argument is "the value to clamp" and then the others are a min and max :/

Sorry for being a bit dense, I just want to be absolutely clear on what's happening so I can be sure I'm using it correctly.
 

spe

Member
Nope. The first argument will be changed to fit in between arguments 2 and 3. So if, for example, argument 1 (actually argument0, but who cares) is 2, argument 2 is 7, and argument 3 is 58, clamp will change the number 2 into the number 7, because the first argument must be at least as much as the second argument, and no more than the third. You can use this to increase or decrease a number or variable to a given amount whenever clamp is used.
 

spe

Member
OK, works perfectly, thanks :)
I'm still a little unclear on what it's doing though, and would really appreciate any guidance...

Code:
if (keyboard_check(vk_up) || keyboard_check(ord('W'))){
    y = clamp(-2, y-2, 478);
    };
if (keyboard_check(vk_right) || keyboard_check(ord('D'))){
    x = clamp(2, x+2, 1022);
    };
if (keyboard_check(vk_down) ||keyboard_check(ord('S'))){
    y = clamp(2, y+6, 478);
    image_index = 0;
    image_speed = 0;
    };
if (keyboard_check(vk_left) || keyboard_check(ord('A'))){
    x = clamp(2, x-6, 1022);
    image_index = 0;
    image_speed = 0;
    };
Where I'm unclear is on the order of the arguments: it appears that the first is the min value the change can be applied within, the second the value to apply and the third the max?
That doesn't really fit with what I'm seeing in the manual, where the first argument is "the value to clamp" and then the others are a min and max :/

Sorry for being a bit dense, I just want to be absolutely clear on what's happening so I can be sure I'm using it correctly.
Basically, here's what's happening in your code:
In "y = clamp(2, y+6, 478);" for example, the y coordinate of your object is going to be set to the number 2, which is the variable that clamp is being applied to. Basically, so far, it's the same as saying y = 2. Then the number 2 is getting 'clamped' to the second variable, which is the current y coordinate plus 6. So, if 2 is already more than y + 6, nothing happens here. However, if 2 is less than y + 6, the number gets 'clamped' up to whatever y + 6 equals. Then, it's basically like saying y += 6. This is how you move your character down. If the number doesn't get clamped up, it checks to see if y is more than 478. If not, nothing happens. It'll still be 2. If y is greater than 478, then the number 2 gets clamped down to 478. The code at this point basically says 'y = 478'. And, that's all it does. However, since 2 is a static number and not a variable, and nothing is adding to it, it will never go above 478, so that part doesn't matter. But you could use a variable in a similar code, and that's what would happen. Basically, it allows for three possible results: move the instance to y position 2, move the instance to y position 478, or move the instance down by 6. And it's all based on the current y position. This basically 'clamps' the vertical movement of your object, so it can't go above y position 2, or below y position 478, while allowing you to move in the given direction while anywhere in between. Seems like a pretty smart code for character movement within a boundary. I may have to try it sometime. :p

Of course, I could also be completely wrong on my explanation, and then I'd feel like an idiot. I'm still kinda new here. :D
 
Last edited:
Where I'm unclear is on the order of the arguments: it appears that the first is the min value the change can be applied within, the second the value to apply and the third the max?
That doesn't really fit with what I'm seeing in the manual, where the first argument is "the value to clamp" and then the others are a min and max :/

Sorry for being a bit dense, I just want to be absolutely clear on what's happening so I can be sure I'm using it correctly.
Oh yeah you're right, I inverted the arguments XD
 
O

Oz Locke

Guest
Thanks all, and @spe, that makes sense to me now, thank you for helping clear it up for me :)
 
Top