Hello Guest, please login or register.
Did you miss your activation email?
Login with username, password and session length.

Pages: [1]   Go Down

Author Topic: Switch Statement Key Checks: Help Request!  (Read 2960 times)

0 Members and 1 Guest are viewing this topic.
Switch Statement Key Checks: Help Request!
« on: March 20, 2012, 12:34:16 am »
  • In the deepest reaches...
  • *
  • Reputation: +0/-0
  • Offline Offline
  • Posts: 11
Greetings, Hylians! I'm working on a (regretfully non Zelda-related) project that, you guessed it, involves the keyboard, and pressing its keys. Unfortunately, the code I'm working with has some minor issues  :'(

Code: [Select]
// --- Key Controls --- //
if keyboard_check_pressed(vk_anykey){
switch (keyboard_lastkey){
case (ord('A')): {playerstate+=0;break;}// --- Should check single keys pressed, to add the proper playerstate
case (ord('D')): {playerstate+=0;break;}
case (ord('W')): {playerstate+=1;break;}
case (ord('S')): {playerstate+=1;break;}
//
case (ord('A')) & (ord('D')): {playerstate+=0;break;}// --- Should check double ups of keys pressed, to add the proper playerstate
case (ord('A')) & (ord('W')): {playerstate+=1;break;}
case (ord('A')) & (ord('S')): {playerstate+=1;break;}
case (ord('D')) & (ord('W')): {playerstate+=1;break;}
case (ord('D')) & (ord('S')): {playerstate+=1;break;}
case (ord('W')) & (ord('S')): {playerstate+=1;break;}
//
}}
if keyboard_check_released(vk_anykey){
switch (keyboard_lastkey){
case (ord('A')): {playerstate-=0;break;}// --- Should check single keys released, to subtract the proper playerstate
case (ord('D')): {playerstate-=0;break;}
case (ord('W')): {playerstate-=1;break;}
case (ord('S')): {playerstate-=1;break;}
//
case (ord('A')) & (ord('D')): {playerstate-=0;break;}// --- Should check double ups of keys pressed, to subtract the proper playerstate
case (ord('A')) & (ord('W')): {playerstate-=1;break;}
case (ord('A')) & (ord('S')): {playerstate-=1;break;}
case (ord('D')) & (ord('W')): {playerstate-=1;break;}
case (ord('D')) & (ord('S')): {playerstate-=1;break;}
case (ord('W')) & (ord('S')): {playerstate-=1;break;}
//
}}

Been using that ^^^ (Don't mind the lack of indention and such, my brain works better in chunks, not lines  XD )

Anyways: It works relatively well, except for when you press two keys, and release them one at a time, and suchlike. Unfortunately, GM8 doesn't allow for switch statements that go like this, which would save me the entire issue:

Code: [Select]
// --- Key Controls --- //
{
switch (keyboard_check_pressed){
case (ord('A')): {playerstate+=0;break;}// --- Should check single keys pressed, to add the proper playerstate
case (ord('D')): {playerstate+=0;break;}
case (ord('W')): {playerstate+=1;break;}
case (ord('S')): {playerstate+=1;break;}
//
}}

I was wondering if anyone had any idea how to fix this, or better circumvent the issue, as it is an egregious one. Help would be awesome :D
Logged
Re: Switch Statement Key Checks: Help Request!
« Reply #1 on: March 20, 2012, 05:16:56 am »
  • *
  • Reputation: +1/-0
  • Offline Offline
  • Gender: Male
  • Posts: 446
Hey, and welcome. It's been a while since I've touched Game Maker, but let's see if I can help you out. This'll be a bit long, but try to bear with me.

I'm not sure what playerstate does, but moving forward I'm going to assume it's a regular integer and go from there. I'll start from the top. (And I'll stick to your style of coding throughout.)

Code: [Select]
// --- Key Controls --- //
if keyboard_check_pressed(vk_anykey){
switch (keyboard_lastkey){
case (ord('A')): {playerstate+=0;break;}// --- Should check single keys pressed, to add the proper playerstate
case (ord('D')): {playerstate+=0;break;}
case (ord('W')): {playerstate+=1;break;}
case (ord('S')): {playerstate+=1;break;}
//

First, here's a little trick to do with switch statements, when multiple cases have the same associated statement:
Code: [Select]
// --- Key Controls --- //
if keyboard_check_pressed(vk_anykey){
switch (keyboard_lastkey){
case (ord('A')):
case (ord('D')): {playerstate+=0;break;}
case (ord('W')):
case (ord('S')): {playerstate+=1;break;}
//
Here, I've "chained" the cases -- do you follow me? This is equivalent to the previous code box.

Now, I notice that in two of these cases, you're adding 0 to playerstate. But adding 0 doesn't really do anything, does it? (Although I understand if writing down every case helps keep things straight.) You might as well use the following equivalent code:
Code: [Select]
// --- Key Controls --- //
if keyboard_check_pressed(vk_anykey){
switch (keyboard_lastkey){
case (ord('W')):
case (ord('S')): {playerstate+=1;break;}
//


Let's look at the rest of the first switch statement in full, now:
Code: [Select]
// --- Key Controls --- //
if keyboard_check_pressed(vk_anykey){
switch (keyboard_lastkey){
case (ord('W')):
case (ord('S')): {playerstate+=1;break;}
//
case (ord('A')) & (ord('D')): {playerstate+=0;break;}// --- Should check double ups of keys pressed, to add the proper playerstate
case (ord('A')) & (ord('W')): {playerstate+=1;break;}
case (ord('A')) & (ord('S')): {playerstate+=1;break;}
case (ord('D')) & (ord('W')): {playerstate+=1;break;}
case (ord('D')) & (ord('S')): {playerstate+=1;break;}
case (ord('W')) & (ord('S')): {playerstate+=1;break;}
//
}}
& is a bitwise operator, and I don't think you meant to use it here. What you want is either && or and, both of which are the logical conjunction. Also, let's remove that extra code, and the case where you add 0 in the second half:
Code: [Select]
// --- Key Controls --- //
if keyboard_check_pressed(vk_anykey){
switch (keyboard_lastkey){
case (ord('W')):
case (ord('S')): {playerstate+=1;break;}
//
case (ord('A')) && (ord('W')):
case (ord('A')) && (ord('S')):
case (ord('D')) && (ord('W')):
case (ord('D')) && (ord('S')):
case (ord('W')) && (ord('S')): {playerstate+=1;break;}
//
}}
That's a little nicer to look at, and more efficient too. But there are a couple problems here that become increasingly clear.

  • keyboard_lastkey only ever holds a single value, and that value is the single key that was pressed last. For example, if I press A and Z together, even if I think I've pressed both at the exact same time, the computer will still register that I pressed A before Z, or vice-versa. We can't use keyboard_lastkey to check two values at once.
  • The expression statement1 && statement2 will evaluate to a boolean value, i.e. either true or false. In Game Maker, true and false are actually stored as 1 and 0, respectively. Also, a value less than 0.5 is evaluated as false and a value greater than or equal to 0.5 is evaluated as true in statements that require a boolean value. So (ord('W')) && (ord('S')) (and in fact any && between two ord calls) will return 1, and only 1. Comparing that to keyboard_lastkey isn't going to be of much use.


I'm going to offer a solution here, but pay attention: I don't actually know what your code does or why, so if this solution doesn't help you, come back with more information about your code, or try to solve it on your own.

My solution involves the idea that when, for example, A and W are both pressed, you actually just care about W, because pressing the A key adds or subtracts 0 i.e. doesn't do anything. Using this idea, you'll find a lot of your statements become logically equivalent. As a result, the following code performs more or less the exact same function as the code in your first post (except for potential odd behaviour you might have noticed as a result of using bitwise & instead of &&).
Code: [Select]
// --- Key Controls --- //
if keyboard_check_pressed(vk_anykey){
switch (keyboard_lastkey){
case (ord('W')):
case (ord('S')): {playerstate+=1;break;}
}}
if keyboard_check_released(vk_anykey){
switch (keyboard_lastkey){
case (ord('W')):
case (ord('S')): {playerstate-=1;break;}
}}
Since the code can be shrunken so much, it seems to me that it probably doesn't yet do what you want it to do. Please come back with some more information about your code's intended function.  XD

EDIT:

Notice as well that the last box can also be written as follows (again in your style):
Code: [Select]
// --- Key Controls --- //
if keyboard_check_pressed(vk_anykey){
if (keyboard_lastkey == ord('W') || keyboard_lastkey == ord('S')) {playerstate+=1;break;}
}
if keyboard_check_released(vk_anykey){
if (keyboard_lastkey == ord('W') || keyboard_lastkey == ord('S')) {playerstate-=1;break;}
}
(Notice the use of ||, the logical disjunction.)

In this case, using an if statement probably makes more sense, since you're only switching over two identical cases. You follow me?
« Last Edit: March 20, 2012, 05:37:53 pm by Niek »
Logged
Re: Switch Statement Key Checks: Help Request!
« Reply #2 on: March 20, 2012, 07:41:48 pm »
  • In the deepest reaches...
  • *
  • Reputation: +0/-0
  • Offline Offline
  • Posts: 11
Thanks Nabeshin! I just got home from school, so I'll try and test this when I can. What playerstate is intended to do, is be an intiger that denotes the current state of action for the object. I'm using a binary type scaling system, where say:
Base = 0
Walking = 1
Jumping = 2
Attacking = 4
Hurt = 8
etc etc etc, so you can never have duplicates by adding (1+2+3 = 4+2).
So, when you press W, it adds 1 (walking) to the playerstate, indicating that the player is moving, in addition to anything else it's doing. So, if for example, playerstate = 5, your player is moving and attacking.

What concerns me slightly as to your examples is this:

Quote
My solution involves the idea that when, for example, A and W are both pressed, you actually just care about W, because pressing the A key adds or subtracts 0 i.e. doesn't do anything. Using this idea, you'll find a lot of your statements become logically equivalent. As a result, the following code performs more or less the exact same function as the code in your first post (except for potential odd behaviour you might have noticed as a result of using bitwise & instead of &&).

For cases other than just 0 and 1, (Base + Walking), say, 1 and 4, (Walking + Jumping) you do care about both keys. I havn't experimented with your code, or read it through too closely yet, but I'm concerned that it wouldn't cover both inputs.

It looks good though, and I'm eager to play around with it, and see what tweaking needs to be done, but it looks solid from what I read briefly. Thanks a bunch, and I'll get back to y'all with any further issues on this subject once I play around some!

EDIT:

What I was trying to find was the word bitmask. That's currently what I'm looking to do, with the playerstate, which means I'm googling and rewriting code atm. Will post later.
« Last Edit: March 20, 2012, 09:25:41 pm by DarkHearts »
Logged
Re: Switch Statement Key Checks: Help Request!
« Reply #3 on: March 21, 2012, 02:03:57 am »
  • *
  • Reputation: +1/-0
  • Offline Offline
  • Gender: Male
  • Posts: 446
I see. But do you understand what I've said about adding or subtracting 0 to something? As I said, my very short version of your code is logically equivalent to yours because it eliminates cases where you were adding or subtracting 0, which is the same thing as doing nothing at all.

Also, you seem to be adding or subtracting 1 for both keys W and S -- do they have the same function? If they do, then I assume WASD are the walking keys, correct? So you just haven't coded other actions yet.

In that case, your switch cases aren't going to suffice, because switches only run one of their case statements every time they're processed. You need to update multiple keys each step (again, an assumption on my part). Also, you'll have to use a different method than you have been, because keyboard_lastkey only records the last key pressed, not keys plural.


Here's a potential algorithm (again, I assume this code runs once per step):
  • Set playerstate to 0
  • Check if any key at all has been pressed since the last step
  • If so, check if any game-relevant keys are pressed
  • If so, add each pressed key's corresponding power of 2 to playerstate
  • We're done! (Do you understand why?)


In code, that's as follows:
Code: [Select]
// --- Let's pretend for now that J and K are keys in your game.

playerstate = 0;

if keyboard_check_pressed(vk_anykey){
    if (keyboard_check_direct(ord('W')) || keyboard_check_direct(ord('S'))) {playerstate+=1;break;}
    if keyboard_check_direct(ord('J')) {playerstate+=2;break;}
    if keyboard_check_direct(ord('K')) {playerstate+=4;break;}
}

For example, if I'm pressing W and K, my resultant playerstate is 5. The following step, playerstate will be reset to 0 and keys will be checked again.
Logged
Pages: [1]   Go Up

 


Contact Us | Legal | Advertise Here
2013 © ZFGC, All Rights Reserved



Page created in 0.037 seconds with 45 queries.

anything