Is it possible to update dictionaries?

Godot Version

4.3

Question

So, essentially I am trying to update this dictionary every time I press mouse click. Currently I have this dictionary in my script:

var move = {
	1:{
		"Vector": Vector2(TilePosition)
	},
	2:{
		"Vector": Vector2((TilePosition.x + 1), TilePosition.y)
	},
	3:{
		"Vector": Vector2((TilePosition.x + 2), TilePosition.y)
	},
	4:{
		"Vector": Vector2((TilePosition.x + 3), TilePosition.y)
	},
	5:{
		"Vector": Vector2((TilePosition.x + 1), (TilePosition.y + 1))
	},
	6:{
		"Vector": Vector2((TilePosition.x + 1), (TilePosition.y + 2))
	},
	7:{
		"Vector": Vector2((TilePosition.x + 2), (TilePosition.y + 1))
	},
	8:{
		"Vector": Vector2((TilePosition.x + 2), (TilePosition.y + 2))
	},
	9:{
		"Vector": Vector2((TilePosition.x - 1), (TilePosition.y))
	},
	10:{
		"Vector": Vector2((TilePosition.x - 2), (TilePosition.y))
	},
	11:{
		"Vector": Vector2((TilePosition.x - 3), (TilePosition.y))
	},
	12:{
		"Vector": Vector2((TilePosition.x - 1), (TilePosition.y - 1))
	},
	13:{
		"Vector": Vector2((TilePosition.x - 1), (TilePosition.y - 2))
	},
	14:{
		"Vector": Vector2((TilePosition.x - 2), (TilePosition.y - 1))
	},
	15:{
		"Vector": Vector2((TilePosition.x - 2), (TilePosition.y - 2))
	},
	16:{
		"Vector": Vector2((TilePosition.x - 2), (TilePosition.y + 1))
	},
	17:{
		"Vector": Vector2((TilePosition.x - 2), (TilePosition.y + 2))
	},
	18:{
		"Vector": Vector2((TilePosition.x - 1), (TilePosition.y + 1))
	},
	19:{
		"Vector": Vector2((TilePosition.x + 1), (TilePosition.y - 1))
	},
	20:{
		"Vector": Vector2((TilePosition.x - 1), (TilePosition.y + 2))
	},
	21:{
		"Vector": Vector2((TilePosition.x), (TilePosition.y - 1))
	},
	22:{
		"Vector": Vector2((TilePosition.x), (TilePosition.y - 2))
	},
	23:{
		"Vector": Vector2((TilePosition.x), (TilePosition.y - 3))
	},
	24:{
		"Vector": Vector2((TilePosition.x), (TilePosition.y + 1))
	},
	25:{
		"Vector": Vector2((TilePosition.x), (TilePosition.y + 2))
	},
	26:{
		"Vector": Vector2((TilePosition.x), ((TilePosition).y + 3))
	}
}

(I am sure there are wayyyy better ways of doing this, but I couldnā€™t think of anyā€¦ I am quite new to godot)

then I have a code that uses this dictionary:

func _input(event):
	if event.is_action_pressed("Move") == false:
		return
	if tile_map_layer.local_to_map(get_global_mouse_position()) == tile_map_layer.local_to_map(global_position):
		TilePosition = tile_map_layer.local_to_map(global_position)
		print(TilePosition)
		for i in move:
			print(move[i]["Vector"])
			tile_map_layer.set_cell((move[i]["Vector"]), 1, Yellowtile)

Iā€™ve tried adding ā€œmove.update()ā€ or similar, but I get errors. Iā€™ve printed the outputs, and print(TilePosition) gives f.ex (4, 13), while print(move[i][ā€œVectorā€]) gives f.ex (3,0) - (-3, 0) and same with yā€¦ so the default values Iā€™ve put without TilePositionā€¦ So yes, It would be great if there was some way to update the dictionary every time I mouseclick or something

I donā€™t fully understand what you trying to do but you can detect mouse click with this

func _input(event:InputEvent) -> void:
	if event is InputEventMouseButton:
		if event.button_index == MOUSE_BUTTON_LEFT:
			update the dictionary

I already detect mouseclick using event.is_action_pressedā€¦ I just need some way for the dictionary to update based on the variable key. So when the TilePosition variable becomes f.ex (9, 13), the Vector2((Tileposition.x +1), TilePosition.y) should become (10, 13), not (1, 0) which is what it prints at the current moment. But I donā€™t know how variables work in dictionaries. but it would atleast be nice if it was possible for the dictionary to update every time my ā€˜event.is_action_pressedā€™ gets triggered. move.update() just does not work, and I donā€™t find anything else that works

Iā€™m unsure I fully understand your problem, but it seems like youā€™re making a bit of code where you can select a certain cell, and the code will color all tiles surrounding that space (and are no more than three spaces away) yellow. Is that correct?

You could probably simplify your code a whole lot.

func get_neighbours(tile_position : Vector2i)->Array[Vector2i]:
	var neighbours : Array[Vector2i] = []
	neighbours.append(Vector2i(tile_position.x + 1, tile_position.y + 1))
	neighbours.append(Vector2i(tile_position.x + 2, tile_position.y + 2))
	# et cetera
	return neighbours

This method accepts a single Vector2i, which should be the tile you selected. It returns a list of all neighbours. You only need to iterate over the returned list like so:

var some_position : Vector2i = Vector2i(100, 100) # Replace with your selected position.
var neighbours_array : Array[Vector2i] = get_neighbours(some_position)
for neighbour in neighbours_array:
	tile_map_layer.set_cell(neighbour, 1, Yellowtile)

Please note I havenā€™t actually tested this code.

1 Like

I tried your array, but it gave the error code ā€œError at (94,16): Invalid index type ā€œVector2iā€ for a base of type ā€œArray[Vector2i]ā€ā€

I see it now
can you try this

func get_neighbours(TILE: Vector2, X: int) -> Array:
	var surrounding_tiles = []
	for a in range(-X, X):
		for b in range(-X, X):
			var current_tile = Vector2(a, b)
			if not surrounding_tiles.has(current_tile) and current_tile != TILE:
				surrounding_tiles.append(current_tile)
	return surrounding_tiles

func _input(event):
	if event.is_action_pressed("Move") == false:
		return
	if tile_map_layer.local_to_map(get_global_mouse_position()) == tile_map_layer.local_to_map(global_position):
		TilePosition = tile_map_layer.local_to_map(global_position)
		move = get_neighbours(TilePosition,2)
		for i in move:
			tile_map_layer.set_cell((move[i]["Vector"]), 1, Yellowtile)
1 Like

`and yes, you are correct, I am trying to color all tiles surrounding my main character

uuuuh. I got the error ā€œInvalid access to property of key ā€˜(-3, -3)ā€™ on a base object of type ā€˜Arrayā€™ā€, I tried to #
for i in move: tile_map_layer.set_cell((move[i]["Vector"]), 1, Yellowtile)
and instead type print(get_neighbours(TilePosition, 2)) to check the values, but it still gives values between -3 and +3 instead of the actual position of TilePosition Ā±3

my bad

func get_neighbours(TILE: Vector2, X: int) -> Array:
	var surrounding_tiles = []
	for a in range(-X, X):
		for b in range(-X, X):
			var current_tile = Vector2(a, b)
			if not surrounding_tiles.has(current_tile) and current_tile != TILE:
				surrounding_tiles.append(current_tile)
	return surrounding_tiles

func _input(event):
	if event.is_action_pressed("Move") == false:
		return
	if tile_map_layer.local_to_map(get_global_mouse_position()) == tile_map_layer.local_to_map(global_position):
		TilePosition = tile_map_layer.local_to_map(global_position)
		move = get_neighbours(TilePosition,2)
		for i in move:
			tile_map_layer.set_cell((move[i]), 1, Yellowtile)

hmmm, it still gives the same error message

i forgot about for loop for dictionary

func get_neighbours(TILE: Vector2, X: int) -> Array:
	var surrounding_tiles = []
	for a in range(-X, X + 1):
		for b in range(-X, X + 1):
			var current_tile = TILE + Vector2(a, b)
			if current_tile != TILE:  # Ensure center tile is not included
				surrounding_tiles.append(current_tile)
	return surrounding_tiles

func _input(event):
	if event.is_action_pressed("Move") == false:
		return
	
	if tile_map_layer.local_to_map(get_global_mouse_position()) == tile_map_layer.local_to_map(global_position):
		TilePosition = tile_map_layer.local_to_map(global_position)
		move = get_neighbours(TilePosition, 2)
		
		for tile in move:
			tile_map_layer.set_cell(tile, 1, Yellowtile)
1 Like

thankyou, that works!

you can also change the radius dynamically with the function

1 Like

Yea, that is true. Right now it is also square. There is probably also a way to make it more circle-like?

try this

func get_circle_neighbours(TILE: Vector2, radius: int) -> Array:
	var surrounding_tiles = []
	for a in range(-radius, radius + 1):
		for b in range(-radius, radius + 1):
			var current_tile = TILE + Vector2(a, b)
			if current_tile != TILE and current_tile.distance_to(TILE) <= radius:
				surrounding_tiles.append(current_tile)
	return surrounding_tiles
1 Like

it sort of works. it creates a circle, however Iā€™m not able to put in values to make it bigger or smallerā€¦ other than that it creates a nice cirlce that surrounds the character

what do you mean by

well, in the first get_neighbourgs function, whatever I put in the ā€œfor a in range(-x, x + 1):ā€ would change the size of the square. but in the get_circle_neighbors nothing changes when I change numbers, the circle only covers the first tiles surrounding the character

that not exactly how you use the function, here let me make it clear for you

func get_circle_neighbours(TILE: Vector2, radius: int) -> Array:
	var surrounding_tiles = []
	for a in range(-radius, radius + 1):
		for b in range(-radius, radius + 1):
			var current_tile = TILE + Vector2(a, b)
			if current_tile != TILE and current_tile.distance_to(TILE) <= radius:
				surrounding_tiles.append(current_tile)
	return surrounding_tiles

func get_square_neighbours(TILE: Vector2, X: int) -> Array:
	var surrounding_tiles = []
	for a in range(-X, X + 1):
		for b in range(-X, X + 1):
			var current_tile = TILE + Vector2(a, b)
			if current_tile != TILE:  # Ensure center tile is not included
				surrounding_tiles.append(current_tile)
	return surrounding_tiles

func _input(event):
	if event.is_action_pressed("Move") == false:
		return
	
	if tile_map_layer.local_to_map(get_global_mouse_position()) == tile_map_layer.local_to_map(global_position):
		TilePosition = tile_map_layer.local_to_map(global_position)
		move = get_square_neighbours(TilePosition, 2) #this is where you modify the shape and radius, 2 is the radius of the circle or square
		
		for tile in move:
			tile_map_layer.set_cell(tile, 1, Yellowtile)

change it to
move = get_square_neighbours(TilePosition, 3) #if you want a 7x7 square
move = get_circle_neighbours(TilePosition, 4) #if you want a 4 radius circle

1 Like

Oh, I seeā€¦
In retrospect that seems rather logical.
Thank you, that works well