Best method for in game text widget autocomplete

Hello, I would like to implement a input text widget which would be able to provide autocomplete functionality as characters are typed based on matches from a predefined array of strings.

Wondering what might be the best way to achieve this.

thank you-

Hi and welcome here :slight_smile:
You’re asking for very advanced logic.
@MeX1Co could help you with this, as he created WordElations, but I think it involves a lot of JavaScript. Are you comfortable with JavaScript?

I have actually just implemented something like this on my game… It is in the form of a dictionary lookup where you check a word to see if it exists on the word list I have (javascript arrays). When you select show possible matches what it does is using javascript and shows the first three words on the word list that match what you type… Something like this…

For autocomplete what you could do is have the suggested word popup somewhere as you type and if you select it it would replace what you type…

If that suits you, I can help with the javascript code… Let me know…

1 Like

Wow, thank you… yes, that is exactly what I am trying to achieve. I’d be very grateful for the JS code help. Thanks!

Cool… I am going to need some context first. Will you be writing a sentence and you want autocomplete for each word or will it be like mine where you only type one word at a time? (It matters for word identification)

Also how many words will there be for the predefined array of strings? In my game I had about 80k words and I had to separate them to 26 different arrays by their starting letter since it would be easier to control and faster to search…

Thank you @MeX1Co ,

Yeah, just like what you are doing, like how most autocomplete text fields would work on a website… after about 3 characters, it might start finding matches to save the user from typing, and ensure data validation by selecting matches.

My data set ATM has 7753 items, so I can test the performance if needed… maybe it will need to be a bit slower, as I would like to match ‘between’, for cases such as input: [phantom], might match:
[The Phantom]
[Phantom of the Opera]
and so forth… so perhaps I could adjust your method to find substr matches.

Thank you-

So, since the two examples you gave were movies, I cooked up something quickly…

The javascript you need is the following:

var myWord = runtimeScene.getVariables().get("Word").getAsString();
var myWordC1 = runtimeScene.getVariables().get("WordC1");
var myWordC2 = runtimeScene.getVariables().get("WordC2");
var myWordC3 = runtimeScene.getVariables().get("WordC3");
var myWordCN = runtimeScene.getVariables().get("WordCN");

var myLex = ["La La Land","Lady Macbeth","The Handmaiden","Blade Runner 2049","Call Me By Your Name","Get Out","LadyBird","Mother!","The Shape of Water","Three Billboards Outside Ebbing, Missouri","Black Panther","Phantom Thread","The Greatest Showman","Crazy Rich Asians","Capernaum","A Star is Born","Avengers: Infinity War","Roma","Hereditary","The Favourite","Sorry to Bother You","Vice","BlacKkKlansman","Avengers: Endgame","Portrait of a Lady on Fire","For Sama","Booksmart","Once Upon a Time in Hollywood","The Farewell","Joker","Parasite","Monos","Little Women","The Lighthouse","Toy Story 4","Lamerica","The Vast Of Night","The Assistant","Rocks","Saint Maud","Tenet","Ma Rainey’s Black Bottom","Soul","Never Rarely Sometimes Always","Lovers Rock","Nomadland"];

var match = myLex.filter((str)=>{
  return str.toLowerCase().indexOf(myWord.toLowerCase()) >= 0; 
});

var lends = match.length;

var myWordCr1 = match[0];
var myWordCr2 = match[1];
var myWordCr3 = match[2];

myWordCN.setNumber(lends);
myWordC1.setString(myWordCr1);
myWordC2.setString(myWordCr2);
myWordC3.setString(myWordCr3);

So, what it does is this:
First it takes the scene variables “Word” (which is the word we are typing), “WordC1” (the 1st possible match), “WordC2” (the 2nd possible match), “WordC3” (the 3rd possible match) and “WordCN” (the number of matches)

Then you have the array (myLeX) in my case, with the elements (movie titles)
Then it creates the variable “match” that is essentially an array with all the elements of “myLex” that match the variable “Word”
Then it creates the variable “lends” which is the number of elements in the array “match”
Then we set the first 3 elements of “match” to the possible matches.

That is about as simple as I can explain it, but you can download the project here and see it for yourself…

https://drive.google.com/file/d/18dQO7w8DlpCRWCL4YnILes1IRrtvKszm/view?usp=sharing

Hope that helps…

3 Likes

Wow, thank you for the amazing response and support.

I have been able to integrate this method into my project, and it works great!

I’m new to this type of builder, so still wrapping my head around needing the drop these objects on the scene for interaction, but examining your demo was very helpful.

I think I was also hung up a bit trying to use the experimental text input object, which seems like it could fit, but doesn’t seem to have the same way of capturing the input as it is typed.

Anyway, thank you again.

glad i could help… good luck with your project and don’t forget to post it on the games showcase when it’s done…

1 Like

(note that you can do this with GDevelop events, no need for JavaScript)

I guess you probably could… but it is way simpler with javascript (provided you know a bit)…

Out of curiosity, how would you enter an array with 8000 strings in gdevelop?

1 Like

It is totally fine to do with JavaScript if that’s the tool you’re comfortable with, I just don’t want the takeaway from the post to be that this is only doable in JavaScript, I am sure many find it easier not to use JavaScript even if they know the language, because mixing JavaScript in is breaking the flow by requiring a change of mindset, and I honestly do not think it is any easier in JavaScript.

To input the variable, i would have done pretty much the same as you would in JavaScript. JavaScript literals follow the JSON standard, and GDevelop fully supports parsing and serializing to JSON. The most convenient way to do so would probably be using JSON resources to have the list in a separate JSON file, that cam be loaded in a variable with this extension: https://github.com/GDevelopApp/GDevelop-extensions/files/8836589/load-from-url.zip

For the actual filtering itself, I’d go about that way:

If (VariableString(MyWord) not equal VariableString(MyOldWord)) {
  Clear all children of collection Autocompletions
  Set MyOldWord to VariableString(MyWord)
  For each child variable Word of collection WordList {
    If (VariableString(MyWord) equals SubStr(VariableString(Word), 0, StrLength(VariableString(MyWord)))) {
      Append variable Word to array Autocompletions 
    }
  }
}
1 Like