How To: WASD or Arrow Movement with only drag and drop (No Scripts)

A

Awesmazing

Guest
Hey everyone, new to the forums but I've been tinkering with GM for a while. This may be old news to some people, but if you're like me, and have googled this exact topic only to get answers that are excellent and work well, but involve using scripts in your game. This can be great, because the GM scripts language is comparatively easy to understand, but if you're very fresh and expected more of a drag and drop experience in making games (as I do) this might help you understand more about both the inner-workings of the game engine and the drag and drop functions as well.

So basically... The attached image shows an object that can move freely up, down, left, right, and any combination of two directional keys. The movement is smooth and works as expected. The only con I've come across for this is that pressing any three keys simultaneously will stop movement. This can be fixed with only the drag and drop features as well but gets a bit more complicated. The method that is working here is based on the principle that a few lines of code can use with the control of a variable to essentially know what keys are pressed, and what direction that should move you in.

The create event simply sets the self variable "move" to 0

The step event in the image gives directions to the object based on the keys pressed. Each key is assigned a "value" and that value is either added to the "move" variable when the key is pressed, or subtracted from the "move" variable when released. Also note the alarm between the "move" variable check and the "move to position" action. The "move to position" action is set to move the object to the center of itself (stand still) after a short timer (set to 5) whenever "move" is set to 0. Without that timer, I found this setup to not work properly. I'm not sure as to why, since pressing keys should increase the variable more quickly than the set position action should take place but obviously not. Either way, that small delay allows this to work. If someone knows more about that I'd be interested.

Each other "move" variable check has 8 total numbers it looks for to determine whether to move up, down, left, right, up/left, up/right, down/left, or down/right. Each arrow key is assigned a value in the key press events, which are all relative to the current value of "move" I used up as +1, left to +3, right +5, and down +7. Releasing any of those keys triggers the key release event which removes the same value the key added from the "move" variable. So, if up and left are pressed, "move" will = 4 and cause the appropriate directional movement. The reason 1, 3, 5, and 7 were used was so that no combination of keys can have an overlapping value. Any numbers will work, just make sure the sums are all different for the 8 directions involving any 2 pressed keys.

Obviously this is not limited to the arrow keys and can be duplicated or substituted with WASD as well. I just figured after searching to find a completely drag and drop solution for this, I'd hammer it out and write one myself. Let me know if you have any questions or improvements!
 

Attachments

NeoShade

Member
1+7 and 3+5 both equal 8.
Try 1, 2, 4 & 8 instead, as these numbers allow ALL unique combinations of the 4 keys to be pressed simultaneously.
 
A

Awesmazing

Guest
1+7 and 3+5 both equal 8.
Try 1, 2, 4 & 8 instead, as these numbers allow ALL unique combinations of the 4 keys to be pressed simultaneously.
Noted but I haven't used 8 for anything. The numbers are arbitrary really, so those combinations cause nothing to happen, which is also up/down and left/right coincidentally, which handles itself nicely here.
 
A

Awesmazing

Guest
What's the problem with having key held events and moving the player in those?
Hmm, in binding any key to start moving in any direction, there still needs to be an implementation to stop. I've used both keyboard, and button pressed events, but when you release them you continue to move. You can change direction but you cannot stop. I must be missing something.
 

NeoShade

Member
I understand that you haven't used them for anything, but given this is a tutorial and the fact that those two combinations exist mean that somebody MIGHT want to.

Using 1, 2, 4, and 8 (0001, 0010, 0100, and 1000 in binary respectively) means that every combination is available and unique.
This can be easily seen when looking at the binary versions of the numbers:

Want to add 2 (0010) and 8 (1000)? Easy: 1010
1 (0001) and 4 (0100)? 0101
All four keys at once? 1111
None of the keys? 0000

When you look at the binary representations, you can see that each digit represents one of the keys.
Furthermore, it's easily scalable! Need to add a fifth key? Use 16. A sixth? Try 32! The rule still applies (keyboard hardware limitations aside).

I'd strongly recommend you use 1, 2, 4 and 8 for this sort of purpose. Binary exists for a reason. ;)
 
A

Awesmazing

Guest
I understand that you haven't used them for anything, but given this is a tutorial and the fact that those two combinations exist mean that somebody MIGHT want to.

Using 1, 2, 4, and 8 (0001, 0010, 0100, and 1000 in binary respectively) means that every combination is available and unique.
This can be easily seen when looking at the binary versions of the numbers:

Want to add 2 (0010) and 8 (1000)? Easy: 1010
1 (0001) and 4 (0100)? 0101
All four keys at once? 1111
None of the keys? 0000

When you look at the binary representations, you can see that each digit represents one of the keys.
Furthermore, it's easily scalable! Need to add a fifth key? Use 16. A sixth? Try 32! The rule still applies (keyboard hardware limitations aside).

I'd strongly recommend you use 1, 2, 4 and 8 for this sort of purpose. Binary exists for a reason. ;)
And I get all that, but for this purpose, I've no need to press 3 or 4 buttons at once, and even if i was adding all the variables using 1 2 4 and 8 you still would need a variable to get you the last button pressed or two buttons after you've hit your third key. Otherwise pressing up then right then down will have the same value as right then down then up, but with different results expected. This is just for basic top down movement, and stopping when the keys are released. I use binary fully more for tracking total amounts or inventorying large quantities, the idea is you don't even have to use numbers here. You can just name the variables a string of the direction is going to take you. Works the same way. I appreciate your passion though lol.
 

NeoShade

Member
That's fair enough.

In that case however, I have to go back to Bayesian's question. Why use two events (key pressed and key up) to specifically initiate a 'start moving' and 'stop moving' when you could simply use one event (key down) and only move the object while the key is actually held down?

((Strangely, Key Up is not the opposite to Key Down... Key Up is in fact the opposite of Key Pressed. I think this is a poor design decision, I think Key Up should be called Key Released))
 
A

Awesmazing

Guest
That is a good question. I just tested it out, duplicated the object I have, and blanked the new one with just 8 events. 4 for moving in the desired direction when the corresponding arrow is pressed, 4 for stopping the object when any are released. The old one moves smoothly still and the new one cannot move diagonally and stops while other keys are held if any are let go while being held. Could you elaborate more on what do there? This doesn't seem to be implemented much easier than how I have it now. If you remove the step event that causes the object to stop, and put stop events on each key release, too many stop events happen. I don't know a way without checking per step to see if all keys are released.

I guess each key press could still add to a variable and each key release just have it decrease the variable and check it for 0 to stop. I tried that just now, and added variables that increase and decrease with key press/releases and variable checks to determine direction and it's still nowhere close. Random movements and not stopping accordingly.
 
Last edited by a moderator:

NeoShade

Member
You don't need to tell the object to stop at all, and you don't need 8 events, you should only need 4.

Here's an example focusing on only one direction. I also didn't know what speed you'd set, so I guessed 4.
Currently, what you're doing is the following (I'm going to use a code box, but only to separate out the logic a bit. This is still assuming drag & drop) :

Code:
When the [LEFT ARROW] is PRESSED:
   START moving LEFT (at a speed of 4).

When the [LEFT ARROW] is RELEASED:
   STOP moving LEFT.
Instead, you can do this:

Code:
When the [LEFT ARROW] is HELD DOWN:
   JUMP TO POINT: X = -4, relative.
With this method, when you release the key, even though you haven't told the game to specifically do anything when the key is released, the LACK of it being held down means that you're no longer issuing the JUMP TO POINT command means that the object stops moving.

Admittedly, this system doesn't use gamemaker's built in speed or direction variables, but that's not necessarily a bad thing. It's just a different way of moving.
 
A

Awesmazing

Guest
Exactly right, that was my initial issue. Moving and then getting it to stop properly, along with diagonal movement. But I also wanted to be able to just use the built in speed settings and directions. The jump to point is different, and not as smooth really as the movement this offers. But even with the 8 events, I cannot get it to work properly. Without the step even and the short timer to check for all of the keys being released, any other drag and drop setup I've tried fails to offer good movement and stop accurately.
 

NeoShade

Member
There's no difference in the smoothness, because all the move functions do is perform a jump to function each step.
If you're experiencing a difference in smoothness between setting the direction to left and the speed to 4 once, vs performing a jump to x = -4 every frame, then there's something else in your game causing the difference.
 
A

Awesmazing

Guest
I only have the two objects and a simple room in my game so far. One is moving with the jump to location with 3's for all the distances. The other is mine with the in game speed set to 3. The jump one moves fine, thanks for that, that's the first I've seen it so easily done. But the two objects move at different speeds. It's pretty much negligible, but the jumping object moves just a bit faster. Especially when changing directions, more so when you do it quickly, because each button press is moving the object another teleported distance and spamming up and down while moving left or right allows you to go much further than the in game's fixed movement does. So ultimately not the largest of difference, but still a way to get smooth moving with the in game speed settings.
 

NeoShade

Member
Ah! If it's most noticeable when changing directions, I think I might know what's going on.

If you set the direction of an object to up-left and set the speed to 3, that's not the same as setting X = -3 and Y = -3.
Using the move method, you're moving 3 units in the up-left direction.
Using the jump method, you're moving 3 units up and then 3 units left, or about 4.24 units in the up-left direction.

I will admit, this is another complication to using the jump-to method.
 
A

Awesmazing

Guest
Yes, and specifically, that's the only real difference as far as I can tell. I still may need to keep my setup as the step event and variable controlling the players movement is going to be useful elsewhere to me too. I'm glad we've met on the same page here though haha, and yes adjusting the jump to 4.25 or so made the negligible difference even more so. Hopefully now this thread solves 2 potential questions in the future.
 

icuurd12b42

TMC Founder
GMC Elder
in beginning step, set h variable to 0, set v variable to 0

in keyboard event left set h relative -4 (h = h - 4)
in keyboard event right set h relative 4 (h = h + 4)

in the step, h will be -4 or 0 or 4

set x variable to h relative... (x = x + h)

do the same thing for v... and y for up and down

and you have your movement aside the diagonals being a little speedy

you can also use the move free dd in direction of point_direction(0,0,h,v) at speed 4

that would rid all you if conditions and have the exact same movement

that would yield about 6 dd boxes


in any case, using your own code, you can at the very least

in beginning step, set h variable to 0, set v variable to 0
in keyboard event left, up, right and son one, set 1,2,3,4.... as you have and basically rid the pressed and release events, halving the code.
 
Top