1. Hello Guest! It's with a heavy heart that we must announce the removal of the Legacy GMC Archive. If you wish to save anything from it, now's the time! Please see this topic for more information.
    Dismiss Notice

GML Weird typing mechanism glitches

Discussion in 'Programming' started by XirmiX, Jul 3, 2017.

  1. XirmiX

    XirmiX Member

    Joined:
    Jul 18, 2016
    Posts:
    365
    Two problems; if I have this code, I will be able to:
    * Type by pressing keys
    * Delete by pressing backspace
    * Delete by holding down backspace

    Code:
    ///Typing code
    //Checks whether this text box is selected
    if self.selected == true
    {
        //Keys held down
        if keyboard_check(keys_allowed) && (string_length(text_written) < 30) && type_timer == 2
        {
            text_written = text_written+(keyboard_string);
            type_timer = 0;
            keyboard_string = "";
        }
        //Backspace held down
        if keyboard_check(vk_backspace) && !keyboard_check_pressed(vk_backspace) && type_timer == 2
        {
            text_written = string_delete(text_written, string_length(text_written), 1);
            type_timer = 0;
            keyboard_string = "";
        }
        //Backspace pressed
        if keyboard_check_pressed(vk_backspace)
        {
            text_written = string_delete(text_written, string_length(text_written), 1)
            type_timer = -8;
            keyboard_string = "";
        }
        //Resetting the timer for typing
        if type_timer != 2
        {
            type_timer++;
        }
    }
    
    But if I add in a block of code, so that this is the code that I have, then I will be able to:
    * Type by pressing keys
    * Type by holding down keys
    * Delete by pressing backspace

    Code:
    ///Typing code
    //Checks whether this text box is selected
    if self.selected == true
    {
        //Keys held down
        if keyboard_check(keys_allowed) && (string_length(text_written) < 30) && type_timer == 2
        {
            text_written = text_written+(keyboard_string);
            type_timer = 0;
            keyboard_string = "";
        }
        //Backspace held down
        if keyboard_check(vk_backspace) && !keyboard_check_pressed(vk_backspace) && type_timer == 2
        {
            text_written = string_delete(text_written, string_length(text_written), 1);
            type_timer = 0;
            keyboard_string = "";
        }
        //Keys pressed
        if keyboard_check_pressed(keys_allowed) && (string_length(text_written) < 30)
        {
            text_written = text_written+(keyboard_string);
            type_timer = -8;
            keyboard_string = "";
        }
        //Backspace pressed
        if keyboard_check_pressed(vk_backspace)
        {
            text_written = string_delete(text_written, string_length(text_written), 1)
            type_timer = -8;
            keyboard_string = "";
        }
        //Resetting the timer for typing
        if type_timer != 2
        {
            type_timer++;
        }
    }
    
    But I will no longer be able to delete by holding down backspace... why? And how do I fix this?

    And secondly, this is my selection code (for when the Left mouse button clicks on the text box):
    Code:
    ///If the text box is clicked on
    //Text box is selected
    {
    selected = true;
    }
    
    if I have not selected the textbox via mouse first, I will not have the keys drawn, which is what I want, but when I click the box, the keys I previously pressed will be in there. Why? And how do I fix this?

    And just in case, here's my creation code:
    Code:
    ///Initial textbox code
    {
    keys_allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_-";
    type_timer = 2;
    text_written = "";
    textbar_selected = false;
    max_symbols_allowed = 30;
    selected = false;
    display_x = x+6;
    display_y = y+16;
    }
    
    And this is my draw code:
    Code:
    ///Text box and text is drawn
    {
    draw_self();
    draw_set_color(c_lime);
    draw_text(display_x, display_y, text_written);
    }
    
     
  2. sp202

    sp202 Member

    Joined:
    Sep 26, 2016
    Posts:
    967
    That's a strange countdown you've got there, use the built in alarms instead to save a variable and a couple of lines of code:
    Code:
    if alarm[0]=-1 && backspace held stuff
    {
    }
    if backspace pressed
    {
    alarm[0]=10
    }
    
    
    You need to clear the keyboard string when you select the textbox.
     
  3. XirmiX

    XirmiX Member

    Joined:
    Jul 18, 2016
    Posts:
    365
    Okay, but why is it glitching out like that? Simply because I'm not using alarms? There's got to be a different reason than that, I mean the code for it to be able to do all 4 actions is there, but something must be interfering with one another in some way, but I'm not seeing it. I don't care the way it's done, I simply want to understand why it doesn't work the way it's supposed to and how to fix it.

    That solved it, thanks. Any idea how to make it so that when I click anywhere else other than the text box, the text box to then deselect?
     
  4. sp202

    sp202 Member

    Joined:
    Sep 26, 2016
    Posts:
    967
    keyboard_check(keys_allowed) isn't actually doing anything, it's always returning true regardless of which key is being pressed. Which is why the timer keeps getting reset and backspace can't be held. To deselect the textbox just set select to false upon global mouse click if the mouse isn't hovering over the textbox.
     
  5. XirmiX

    XirmiX Member

    Joined:
    Jul 18, 2016
    Posts:
    365
    Huh, so the keys_allowed variable isn't taken into account and instead, it's registered as just any key... I've tried using a DS list, but it seems that I can't do that either for some reason. Global mouse click makes it so that even if I click on the text box, I can't type.
     
  6. sp202

    sp202 Member

    Joined:
    Sep 26, 2016
    Posts:
    967
    You can't expect a string with a bunch of letters to work as a valid input for keyboard_check, you need to loop through the string and check it against input. Post your code for text box deselection.
     
  7. XirmiX

    XirmiX Member

    Joined:
    Jul 18, 2016
    Posts:
    365
    I have no idea how you would even loop through a string... I made a complex attempt at making a for loop with all sorts of functions like "string_char_at", "string_ord_at" and "keyboard_get_map", but then confused myself in the process. I know what I need to do, but I don't know how to write it in code; how am I supposed to check that a key is one from a list, and then say that if it is, then set a variable as the key?. The code for the box deselection is just the selection variable set to false inside the Global Left Pressed event:

    Code:
    ///If the text box is clicked off
    //Text box is unselected
    {
    selected = false;
    }
    
     
  8. Wild_West

    Wild_West Member

    Joined:
    Jun 25, 2016
    Posts:
    911
    Make sure to take into account the fact that the mouse isn't meeting the text box when you click globally, because global mouse click will mean anywhere on the game window objects or no objects.
     
  9. XirmiX

    XirmiX Member

    Joined:
    Jul 18, 2016
    Posts:
    365
    Well, how do I do that? I put in this:

    Global Left Mouse Pressed code
    Code:
    if (self.x != mouse_x && self.y != mouse_y)
    selected = false;
    
    And it stops me from being able to select the object completely. You would think, and I myself would think, that this sort of stuff would be obvious to me, but apparently it isn't.
     
  10. sp202

    sp202 Member

    Joined:
    Sep 26, 2016
    Posts:
    967
    Replace all your typing code with this:
    Code:
    if !string_count(string_char_at(keyboard_string,string_length(keyboard_string)),keys_allowed)
    {
    keyboard_string=string_delete(keyboard_string,string_length(keyboard_string),1)
    }
    keyboard_string=string_copy(keyboard_string,0,30)
    
    Windows already covers the functionality you're trying to simulate so why reinvent the wheel? Just remember to clear the keyboard_string before starting to type.
     
  11. Wild_West

    Wild_West Member

    Joined:
    Jun 25, 2016
    Posts:
    911
    I was curious about that too because I just set up a thing using keyboard_string to make an ametuer style calculator as well as a number input for a different object to hold onto and you don't have to add in the deleting using backspace it does that just on it's own.
     
  12. Wild_West

    Wild_West Member

    Joined:
    Jun 25, 2016
    Posts:
    911
    This is in the textbox object right? so why say self.x? Just using x is referencing the object's X value.
    You only need the dot operator if you're talking about another object.

    Like bullet.speed used in a gun that makes the bullets. If it were the gun itself being talked about the gun object's code then just say speed. Plus I think mouse x and mouse y aren't gonna be exactly the same as an object's because of the center x and y of an object's sprite.
    A simple work around could be just use an invisible object that follows the mouse and use that as a pointer object to collide with things you want to click on.
     
  13. XirmiX

    XirmiX Member

    Joined:
    Jul 18, 2016
    Posts:
    365
    ...keyboard_string is magic, I don't even know how that can even work! Index of the sub-string being the length of the key pressed? What?! My head can't handle the sheer complexity of that one line of code! Instructions not clear though. What are you refering to exactly as typing code? All of the code I've posted here? Just this part:
    Code:
            if keyboard_check(keys_allowed) && (string_length(text_written) < 30) && type_timer == 2
            {
                text_written = text_written+(keyboard_string);
                type_timer = 0;
                keyboard_string = "";
            }
            //Keys pressed
            if keyboard_check_pressed(keys_allowed) && (string_length(text_written) < 30)
            {
                text_written = text_written+(keyboard_string);
                type_timer = -8;
                keyboard_string = "";
            }
    
    Tried both, nothing happened, and yes, I did disable the deselection, and in fact made selection of the text box as the default for testing this. I do understand what the check is doing at least

    I used self. because I plan to use this object for all the text boxes that will be in the game, so it needs to refer to its instance rather than any instance of that object. I know I need to get the instance ID, something which I haven't tried doing in a long time, but I'm attempting anyway...

    So, from what I can understand,when referring to the x and y values of an object, you're referring to their centre points of an instance. Any way I can make it so that my code refers to anywhere on the sprite of a given object instead? So, if a mouse cursor's x and y value are meeting an instance? Game Maker could sure do with an Off-mouse click event and function...
     
  14. sp202

    sp202 Member

    Joined:
    Sep 26, 2016
    Posts:
    967
    This talk of keyboard_string representing key press has led me to believe you don't actually know what the keyboard_string is. The keyboard_string contains all the letters you've typed since the last time it was cleared. To break down the code I've written; what I've done step by step is to:

    1. Check the last character typed
    2. Check whether that character exists within keys_allowed
    3. If it isn't, delete that character
    4. That last line is just to limit the keyboard_string to 30 characters.

    The code to replace is everything within the selected=true if statement. You should treat keyboard_string similarly to how you treated text_written, keyboard_string contains everything the user has typed. You can save keyboard_string to text_written for safekeeping and then copy text_written back to keyboard_string when editing is required.

    Also, self isn't needed - ever. Local variables refer to the instance's own values.

    As for selection/deselection, get rid of your previous code and put this in the global mouse click event:
    Code:
    selected=position_meeting(mouse_x,mouse_y,id)
     
    Last edited: Jul 5, 2017
  15. XirmiX

    XirmiX Member

    Joined:
    Jul 18, 2016
    Posts:
    365
    @sp202 but, I placed the code exactly as you say here and it doesn't do anything; nothing gets typed at all. Are you sure I need to replace everything? I'm just getting more confused along the way, because at first you just pointed out a problem that I need to fix, but then afterwards tell me to remove the entire code with something completely different.

    I used self here just like in the global mouse pressed event, to refer to the instance of the object. Seemingly as self isn't used for that, I would need to use the "id" variable instead, from what I can gather.

    Somehow, that code works. I edited it so that it would make sense to me as well, because it doesn't.
    Global Left Mouse Pressed event code
    Code:
    if !position_meeting(mouse_x,mouse_y,id)
    {
        selected = false;
    }
    
    Selected is a binary true/false statement, how can this work:
    Code:
    selected=position_meeting(mouse_x,mouse_y,id)
    
    It does work, but how?
     
  16. sp202

    sp202 Member

    Joined:
    Sep 26, 2016
    Posts:
    967
    The reason it's not showing up is maybe because you're still drawing text_written rather than keyboard_string. If you want to keep drawing text_written you could copy keyboard_string to text_written each step. Self is pretty much the same as id, but I chose to use id because other than this one plausible context, nowhere else would you use self so it's best to just forget about it. Assigning the result of position_meeting to selected works because position_meeting returns a boolean.
     
    XirmiX likes this.
  17. chamaeleon

    chamaeleon Member

    Joined:
    Jun 21, 2016
    Posts:
    991
    Side-note, self is a deprecated feature (per the GMS 2.0 manual), and as such should ideally not be used in new code.
     
  18. XirmiX

    XirmiX Member

    Joined:
    Jul 18, 2016
    Posts:
    365
    @sp202, welp, I feel stupid now. A large portion of coding is problem-solving, yet this being pretty simple, I couldn't do myself. I do wonder why there are tutorials that try to reinvent the wheel of text writing though, if you can simply use this kind of code easily. The global mouse press code doesn't work now, however, as a result of the changes typing code, however and for some reason, selected goes automatically to being true, despite selecting it to false upon creation. I still don't know how this piece of code can work though, like it makes no sense, selected is a boolean, how can it check where the mouse is and set itself to false in the process with this:

    Code:
    selected=position_meeting(mouse_x,mouse_y,id)
    
    I do wonder, how do you come up with these solutions in the first place.
     
  19. sp202

    sp202 Member

    Joined:
    Sep 26, 2016
    Posts:
    967
    position_meeting tests for collisions at a certain point with a particular object. In this case, instead of a stationary point I use the mouse position and test for collisions with the textbox object. As the function returns true or false I can directly assign that to selected as that's exactly what I need. How do I come up with these solutions? Experience mainly; knowledge of what functions exist and how I can use them, but to gain experience you must expose yourself to different methods of doing things and be willing to think things through yourself.
     
    XirmiX likes this.
  20. chamaeleon

    chamaeleon Member

    Joined:
    Jun 21, 2016
    Posts:
    991
    "selected" is just a result of an operation (position_meeting(...)), it doesn't "do" or "check" anything. position_meeting() "checks" stuff, and "selected" holds the result of this check by way of the assignment to it. This is an enormously common way of doing things, across a multitude of programming languages.
     
    XirmiX likes this.
  21. XirmiX

    XirmiX Member

    Joined:
    Jul 18, 2016
    Posts:
    365
    @sp202 clever indeed! Though, again, this code:
    Code:
    id.selected = position_meeting(mouse_x,mouse_y,id);
    
    Stops working when I place in this code:
    Code:
    if !string_count(string_char_at(keyboard_string,string_length(keyboard_string)),keys_allowed)
    {
        keyboard_string = string_delete(keyboard_string,string_length(keyboard_string),1);
    }
    keyboard_string = string_copy(keyboard_string,0,30);
    
    Where applicable. Any idea why and how I might fix this?
     
  22. chamaeleon

    chamaeleon Member

    Joined:
    Jun 21, 2016
    Posts:
    991
    Since your two pieces of code have literally nothing in common on any level (quite a feat in and of itself), odds are you'll be asked to provide complete context.
     
  23. sp202

    sp202 Member

    Joined:
    Sep 26, 2016
    Posts:
    967
    Once again, you don't need to do id.selected, selected alone is enough. When you refer to your mother you'd say mum, rather than my mum right? The my is implied.
     
  24. XirmiX

    XirmiX Member

    Joined:
    Jul 18, 2016
    Posts:
    365
    But then, if I have two instances of the text object, won't two of them get selected at the same time? Either way, this had nothing to do with the issue and it has all stayed the same.

    Alright, here's the entire code as of now for the Text box:
    Create event
    Code:
    ///Initial textbox code
    {
    keys_allowed= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_-";
    
    type_timer = 2;
    text_written = "";
    textbar_selected = false;
    max_symbols_allowed = 30;
    selected = false;
    display_x = x+6;
    display_y = y+12;
    }
    
    Step event
    Code:
    if selected == true
    {
        if keyboard_check(vk_anykey)
        {
            if !string_count(string_char_at(keyboard_string,string_length(keyboard_string)),keys_allowed)
            {
                keyboard_string = string_delete(keyboard_string,string_length(keyboard_string),1);
            }
            keyboard_string = string_copy(keyboard_string,0,30);
        }
    }
    
    Left Mouse Pressed event
    Code:
    ///If the text box is clicked on
    //Text box is selected
    {
    selected = true;
    keyboard_string = "";
    }
    
    Left Global Mouse Pressed event
    Code:
    ///If the text box is clicked off
    //Text box is unselected
    selected = position_meeting(mouse_x,mouse_y,id);
    
    Draw event
    Code:
    ///Text box and text is drawn
    {
    draw_self();
    draw_set_color(c_lime);
    draw_text(display_x, display_y, keyboard_string);
    }
    

    I don't understand how the step event code still goes, even though "selected" variable is set to false at the beginning and I haven't clicked anything to make it true, which by the code should be the textbox itself.
     
  25. IndianaBones

    IndianaBones Member

    Joined:
    Jul 5, 2016
    Posts:
    2,304
    No. Each instance has it's own unique and independent copy of the variable selected.

    The problem is you are drawing keyboard_string. keyboard_string will be filled automatically by Gamemaker with the last few keyboard inputs, regardless of whether textbox is selected or not.
     
    XirmiX likes this.
  26. XirmiX

    XirmiX Member

    Joined:
    Jul 18, 2016
    Posts:
    365
    Hmmm, I'm starting to get this. I guess I'll need to work through this. Perhaps a string variable, like before, which would hold onto the data of keyboard_string at times, so as not to make this glitch happen.
     
  27. IndianaBones

    IndianaBones Member

    Joined:
    Jul 5, 2016
    Posts:
    2,304
    Typing from phone here so will be brief.

    Yes. I would.

    In step event copy keyboard string to text_written.

    Draw event, draw text_written.
     
  28. sp202

    sp202 Member

    Joined:
    Sep 26, 2016
    Posts:
    967
    Get rid of the "if keyboard_check(vk_anykey)", it's redundant. Delete the left pressed event, it's not doing anything useful, move the keyboard_string resetting into the global mouse click.

    Like @IndianaBones said add "text_written=keyboard_string" after "keyboard_string = string_copy(keyboard_string,0,30)" and draw text_written instead.

    You should also change the keyboard_string="" to "keyboard_string=written_text".

    No point in having some of those initialized variables if you never use them; you can safely get rid of text_timer, I don't see textbar_selected being used anywhere either. You should probably incorporate max_symbols_allowed into the code, replace the hardcoded 30 in the keyboard_string limiter with it.
     
    Last edited: Jul 6, 2017

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice