Hello, I’m having some trouble with a recursive function.
The code below consists of two (different) get functions that return dictionaries with indexes of cells in a grid.
in a perfect I would have the second function repeat itself to keep getting and adjusting cells, but this dosen’t work. I think it’s because instead of getting two copies of the dictionary values the second time the get_neighbors_recursive is called, it overwrites the first instance of the function.
for idx in neighbor_idx.values(): # on cell body entered get cell idx and its neighbors - this dict is a bit more constant and should not be called more than once
if idx != null:
neighbor_tex = cell_dict[idx]["cell_texture"]
neighbor_ray = cell_dict[idx]["cell_ray"]
neighbor_ray.target_position = mouse_vel
update_shader_param(neighbor_tex, neighbor_ray)
for idx_rec in get_neighbors_recursive(idx).values():
if not idx_rec == null:
neighbor_tex = cell_dict[idx_rec]["cell_texture"]
neighbor_ray = cell_dict[idx_rec]["cell_ray"]
neighbor_ray.target_position = mouse_vel * 0.75
update_shader_param(neighbor_tex, neighbor_ray)
for idx_rec2 in get_neighbors_recursive(idx_rec).values():
if not idx_rec2 == null:
neighbor_tex = cell_dict[idx_rec2]["cell_texture"]
neighbor_ray = cell_dict[idx_rec2]["cell_ray"]
neighbor_ray.target_position = mouse_vel * 0.5
update_shader_param(neighbor_tex, neighbor_ray)
The function is supposed to grab neighboring cells and modify cell_data (havent made this yet)
function in question:
func get_neighbors_recursive(cell_index: int) -> Dictionary:
var neighbors_rec_idx : Dictionary = {}
var cell_data = cell_dict[cell_index]
var cell_ray = cell_data["cell_ray"]
var cell_ray_angle = cell_ray.target_position.angle() # in rad
var angle_check_arr = [-1.55, -0.80, -2.35, 3.15, 0.0, 2.35, 0.8, 1.55,]
var closest_numb = closest(cell_ray_angle, angle_check_arr) # get closest number
@warning_ignore("integer_division")
var row = cell_index / columns
var column = cell_index % columns
#gets cell dict key (idx)
#gets cell dict key (idx)
var get_above
var get_top_left
var get_top_right
var get_bottom_left
var get_bottom_right
var get_left
var get_below
var get_right
# check if idx exceeds rows or columns (e.g. prevents values from returning index in nonexisting row or column)
if row > 0:
get_above = cell_dict.get((row - 1) * columns + column)["cell_idx"]
if column > 0:
get_top_left = cell_dict.get((row - 1) * columns + (column - 1))["cell_idx"]
if column < columns - 1:
get_top_right = cell_dict.get((row - 1) * columns + (column + 1))["cell_idx"]
if row < rows - 1:
get_below = cell_dict.get((row + 1) * columns + column)["cell_idx"]
if column > 0:
get_bottom_left = cell_dict.get((row + 1) * columns + (column - 1))["cell_idx"]
if column < columns - 1:
get_bottom_right = cell_dict.get((row + 1) * columns + (column + 1))["cell_idx"]
if column > 0:
get_left = cell_dict.get(row * columns + (column - 1))["cell_idx"]
if column < columns - 1:
get_right = cell_dict.get(row * columns + (column + 1))["cell_idx"]
match closest_numb: # match ray angle to closest direction (cardinal and intercardinal)
-1.55: # above
neighbors_rec_idx["above"] = get_above
neighbors_rec_idx["top_left"] = get_top_left
neighbors_rec_idx["top_right"] = get_top_right
-0.80: # top right
neighbors_rec_idx["above"] = get_above
neighbors_rec_idx["top_right"] = get_top_right
neighbors_rec_idx["right"] = get_right
-2.35: # top left
neighbors_rec_idx["above"] = get_above
neighbors_rec_idx["top_left"] = get_top_left
neighbors_rec_idx["left"] = get_left
3.15: #left
neighbors_rec_idx["top_left"] = get_top_left
neighbors_rec_idx["left"] = get_left
neighbors_rec_idx["bottom_left"] = get_bottom_left
0.0: #right
neighbors_rec_idx["top_right"] = get_top_right
neighbors_rec_idx["right"] = get_right
neighbors_rec_idx["bottom_right"] = get_bottom_right
2.35: #bottom left
neighbors_rec_idx["left"] = get_left
neighbors_rec_idx["bottom_left"] = get_bottom_left
neighbors_rec_idx["below"] = get_below
0.8: # bottom right
neighbors_rec_idx["right"] = get_right
neighbors_rec_idx["bottom_right"] = get_bottom_right
neighbors_rec_idx["below"] = get_below
1.55: #below
neighbors_rec_idx["bottom_left"] = get_bottom_left
neighbors_rec_idx["below"] = get_below
neighbors_rec_idx["bottom_right"] = get_bottom_right
return neighbors_rec_idx
This problem is pretty easily solved by making a duplicate of the function and calling that instead of re-calling the same function. But that doesn’t seem like good practice to copy and paste existing functions?
Whatever you can do with a recursive call, you can as well do by pushing/popping state to/from a stack. So practice implementing things in that way, without recursion.
EDIT: ok you posted the code after I wrote the above. Still, implement a recursion-less version. You’ll learn a lot.
What does the function get_neighbours_recursive() write into? If you have a global array then i am sure the function would over write the contents. Perhaps you should pass the array into the function …
If thats not working, make a seperate gdscript file and create a class with the function defined. Then make another instance of the class to call the function again, this way the memory the function writes to is local to the instance of the class.
I wouldnt say recursive calls are wrong but maybe the recursion stack isnt too deep in gdscript. For example I once made a binary tree search that caused a stack overflow (in C++) on a binary sort of 3 million names in a data table - the problem occurred when they were already sorted. I dont know how deep gdscript will go anyway.
What does the function get_neighbours_recursive() write into?
im not 100% sure what you mean, but the function returns 3 values (and keys). The values are indexes that are used to get the cells around the start cell. the reason I want it to be recursive is so that it can get some neighboring cells (and modify them) and then get those neighboring cells and modify them differently
The start cell is just wherever the mouse is moving to.
I don’t think it “writes into” anything, but maybe I’m misunderstanding what you’re saying.
If thats not working, make a seperate gdscript file and create a class with the function defined. Then make another instance of the class to call the function again, this way the memory the function writes to is local to the instance of the class.
Wouldn’t this be the same as copying, pasting, renaming and calling the function again
I’m not very seasoned in using godot, so I may (again) be misunderstanding
Sorry for being slow on giving all the information
If I understand right would this be akin to saving the returned values from the first instance of the function and then later using them as the new indexes?
how would i go about pushing a state to a stack and then later calling the state from the stack.
Or rather is there a “technical term” that i can google myself?
I have a 20x20 grid thats filled with cells. This grid is created at runtime and each cell is assigned an index. The get_neighbors_recursive(cell_index) function returns a dictionary with 3 values (and keys) This is gotten by looking at a start cell (the callable : cell_index). the start cell is wherever the mouse is moving. It wont let me show video
later (this havent been implented yet) I want to modify the returned neighbors
A visual effect. each grid has a direction (this is what decides which neighbors neighbors are gotten ) And then later i will make the visual effect follow the directions the cells have
If the player is creating those arrows as they move, just store those in a dictionary as the player is creating them. Then you won’t need to retrieve anything from anywhere. You’ll always have them in that dictionary.
The vectors are made with cells they just turn and get larger or smaller based on how the player moves around. It’s the get_neighbors function thats gets called as the player moves around in the grid and later it will also calculate vector direction and length/size
Vectors will decide smoke direction and velocity
Could you elaborate on :
Whatever you can do with a recursive call, you can as well do by pushing/popping state to/from a stack. So practice implementing things in that way, without recursion.
Why do you need to store this in a tilemap? Just put this data in a dictionary as it’s being generated. When player enters a cell (1,1) put that cell into a dictionary with key (1,1) and value of all needed arrow data. Do this whenever the player enters a new cell. That way you maintain a dictionary of all relevant data at all times. You don’t need anything else. Nothing to retrieve from anywhere. It’s all there
so you said the result seemed to be overwritten with successive calls, so the “neighbours_rec_idx” dictionary returned from the next calls to the function seems to break the original data … without going into too much depth (fully understanding) its intuitive to suggest that the dictionary should be ouside the function…
class_name CellNeighbourGetter # or whatever
extends ref_counted
var neighbors_rec_idx : Dictionary = {}
func get_neighbors_recursive(cell_index: int) -> Dictionary:
#... define function here writing to the dictionary as normal
call that file ‘CellNeighbourGetter.gd’ then in the file where you call the function …
@onready var cell_getter :CellNeighbourGetter = preload("/res/scriptsCellNeighbourGetter.gd")
# you can use the cell_getter var, then instantiate another
var cell_getter_2 : CellNeighbourGetter = CellNeighbourGetter.new()
and they each return unique dictionary’s
and then you should be able to call them in the way you intended to.
Ah, I think i get it. Do you think this can be used for different situations? The smoke isnt just being moved behind the player. in other situations I’d like for the smoke to move ahead of the player and around the player
The get_neighbors functions purpose is to calculate ahead of the player and around the player (e.g. whereever the player isn’t but where smoke needs to be)