Getting letter placement from a string

Godot Version

v4.6.2

Question

Hello Godot people,

I have been trying to figure out how to check a string for the letters so that I can create objects based on those letters. For example I am making a book that has secret letters that represent real letters, eg - A = (a drawing of a square or something).

The plan is to have the string recorded in code and player can input the answer into a text box.

I want to be able to simply change the string in the code and the symbols in the game change to the relevant secret letters.

So I figured I need to identify the letters in the string and their placement, store that in a array or dict and set the positions relevent to my artwork. Then I will instantiate the letters which are all individual animatedsprite2d nodes.

I hope that makes sense. The problem I am facing is I can’t figure out how to make the code check for multiple letters.

I have a string to test that is just “Hello”.

Using a for loop I put each letter into an array. As below.

var stringTest = "Hello."
var lettersDict = []


func testString():
	for x in stringTest:
		lettersDict.append(x)

I tried using find and the main issue is when looking for a letter that comes up more than once like the “l”. If I do find it come up with a 2 which is correct for the first L. But I can’t work out how to do a simple bit of code to check again for the 2nd one.

So I thought if I run the whole alphabet against the lettersDict (which is actually an array), I could see how many times a letter is in there, but using a find it just tells me the first letter it finds not the second like with the “l” mentioned above.

var alphabetArray = ["a","b","c","d","e","f","g","h","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]

for y in alphabetArray:	
var index = lettersDict.find(y,0)	

I’ve been going back and forth with putting the letters into an array, with using count and find but the problem is I can’t work out a simple way to make sure it repeatedly checks each letter except for doing multiple IF statements.

I think I am missing something simple and probably had a better solution before I got to this point but now I am lost!

I tried some If statements where I increase a variable called Index by +1 (which I use as the from in find) if there is more than 1 entry of the letter which kind of works but it just has gotten so messy.

		if index >= 0:
			var index2
			index2 = lettersDict.find(y,index+1)
			print("more than 1. ", index2)
			if index2 >= 0:
				var index3
				index3 = lettersDict.find(y,index+2)
				print("more than 2. ", index3)

Any help would be much appreicated!!

Thanks

Is this what you’re looking for?

func find_all(source: String, what: String) -> Array[int]:
	var indices: Array[int] = []

	while true:
		var from: int = 0 if indices.is_empty() else indices[-1] + 1
		var index: int = source.find(what, from)
		if index < 0:
			break

		indices.push_back(index)

	return indices

It just loops forever until it can’t find any more indices and adds all found ones to the array, increasing the from parameter to find new occurences

1 Like

Why letters need to be copied into an array? String is already an array of characters btw.

A string is already an array of characters. But if you absolutely need to work with a list, you can also use .split() to automatically get an array object of said characters.

>>> list("Hello.")
['H', 'e', 'l', 'l', 'o', '.']

No need to manually scour through the string and append them to an array.

You can then use a for loop to go through each letter and do what you need to do.
But if its the index of those characters what you need, just use a for loop with the length of your string (or array).

The ‘index’ is the individual ‘letter placement’.

var str = "Hello."
for index in range(str): # goes from 0 to the length of the string or array
   print(str[index]) # or do what you need to do
1 Like

Maybe in Python. There’s no list() in GDScript. The GDScript equivalent would be "Hello".split("")

Right, whoops, I typed .split() at first but the python brain acted up. Still get confused sometimes rahh :face_with_spiral_eyes:

1 Like

I’m a bit unsure about what exactly you want to do. Change some characters in a book to e.g. change them in a painting or something somewhere else? A specific string or any mix of characters?

If you just need to do a check if two strings are the same you could just compare them. Then switch from secret language to latin letters using a dictionary with key value pairs like A = ∆. Maybe i have misunderstood you completely. Why would you need to count the number of each character?

You’re overcomplicating your solution.

extends Node

var hello: String = "Hello"


func _ready() -> void:
	for letter in hello:
		match letter:
			"H":
				print_rich("[color=red]S[/color]")
			"e":
				print_rich("[color=blue]t[/color]")
			"l":
				print_rich("[color=orange]o[/color]")
			"o":
				print_rich("[color=green]b[/color]")

Replace the print statements with adding nodes to something.

Or if you want to create a translation Dictionary:

extends Node

var hello: String = "Hello"
var translation: Dictionary[String, String] = {
	"H": "S",
	"e": "t",
	"l": "o",
	"o": "b",
}

func _ready() -> void:
	for letter in hello:
		print(translation[letter])

Just make it a Dictionary that holds a Texture2D or Control or Node2D or Label3D or whatever you want, and instantiate them and add them to the scene.

Which looks like this:

extends Control

const translation: Dictionary[String, Texture2D] = {
	"h": preload("uid://cjjjm7sghub3i"),
	"e": preload("uid://75qkuby0lq8e"),
	"l": preload("uid://cnq3avpy03k8c"),
	"o": preload("uid://wqcmn7jh72fc"),
}

var hello: String = "Hello"

@onready var rune_container: HBoxContainer = $RuneContainer


func _ready() -> void:
	for letter in hello.to_lower():
		var rune: TextureRect = TextureRect.new()
		rune.texture = translation[letter]
		rune_container.add_child(rune)

With a scene tree like this:

image
(A Control root node unedited, and an HBoxContainer that is centered.)

And you get this:

(Using four images from Kenney’s Runes Pack.)

3 Likes

Thanks you dragonforge-dev!! This is exactly what I needed.

Got it working and just need some fine tuning but you got me unstuck so thanks a lot!

1 Like

Thanks everyone for your answers, dragonforge-dex’s answer is exactly what I was looking for.