Array of user defined class not being handled properly

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By linklight2

Hello. In my project, I have an array of my custom class, SnakeInfo, shown here.

class SnakeInfo:

var x : float
var y : float

var dir : int
var type : int
var curve : int

func toVector2() -> Vector2 : return Vector2(x, y)

and the array

var bodyPositions : Array

Every element of the array is assigned with the type SnakeInfo, so, you can expect to access individual elements of my class snake info. bodyPositions[0] should return a value of type’SnakeInfo, which I can then edit the values of by using the . operator.
Like so: bodyPositions[0].curve = 15 or something like that.

The problem I’m having is this. In one of my functions, when I assign a variable of bodyPositions[0], I am also editing the value of bodyPositions[1] Tried and tested below:

bodyPositions[0].dir = direction
bodyPositions[0].type = TYPE.head
bodyPositions[0].curve = CURVE.noCurve

var beforeBug0 = bodyPositions[0].toVector2()
var beforeBug1 = bodyPositions[1].toVector2()

match direction:

		DIRECTION.up:

			bodyPositions[0].y -= Global_Vars.sector

		DIRECTION.down:

			bodyPositions[0].y += Global_Vars.sector

		DIRECTION.right:

			bodyPositions[0].x += Global_Vars.sector

		DIRECTION.left:

			bodyPositions[0].x -= Global_Vars.sector

if bodyPositions[0].toVector2() == beforeBug0:
	
	# This branch doesn't execute
	print("bodyPositions[0] didnt change?")
	
if bodyPositions[1].toVector2() != beforeBug1:
	
	# This branch executes
	print("bodyPositions[1] changed???")

Here I only change the values of bodyPositions[0], but the values of bodyPositions[1] and bodyPositions[0] change at the same time. This was a nightmare to figure out where in my code this went wrong, and the result doesn’t make any sense to me.

I wish to know why this happens, and how I can prevent this kind of bug from happening. Thanks for your time and help in advance

did you initialize array? like var bodyPositions : Array = []

volzhs | 2019-05-22 22:29

I did. In my initialization function, i initialize it, and I call that function from _ready(): Here it is below:

func _ready():
initialize()

func initialize() -> void:

# Reset the snake body
while bodyPositions.size() > 0:
	
	bodyPositions.remove(0)

direction = DIRECTION.stopped
bodyPositions.append(setRandHeadPos())

bodyPositions.append(SnakeInfo(bodyPositions[0].x, bodyPositions[0].y + Global_Vars.sector))

bodyPositions.append(SnakeInfo(bodyPositions[1].x, bodyPositions[1].y + Global_Vars.sector, DIRECTION.up, TYPE.tail))

The setRandHeadPos() function returns a new object of type SnakeInfo and is listed below

func setRandHeadPos() -> SnakeInfo:

# Set the x and y pos to a point on the game grid
var randX : int = rand.randi_range(leftR, rightR) * Global_Vars.sector
var randY : int = rand.randi_range(topR, bottomR) * Global_Vars.sector

# Return the random position
return SnakeInfo(randX, randY, DIRECTION.stopped, TYPE.head, CURVE.noCurve)

And here is the constructor that returns an object of type SnakeInfo

func SnakeInfo(x : float = 0, y : float = 0, dir : int = DIRECTION.up, type : int = TYPE.body, curve : int = CURVE.noCurve) -> SnakeInfo:

var snake = SnakeInfo.new()

snake.x = x
snake.y = y
snake.dir = dir
snake.type = type
snake.curve = curve

return snake

linklight2 | 2019-05-22 23:12

Additionally, initializing the array like you said var bodyPositions : Array = [] did not change the incorrect behavior at all

linklight2 | 2019-05-22 23:39

:bust_in_silhouette: Reply From: linklight2

I figured out my issue, and why. I read up on the array documentation on how godot stores arrays, and realized how bodyPositions[0] returns a reference to the object at array position 0, not a value. I come from a c++ background, and usually assigning array[0] = array[1] is completely fine and viable. However, in godot that same statement assigns the reference at array[0]with a reference to the element at array[1]. Meaning every assignment was changing both values, haha.

I fixed it by creating a copy by value function for my class, and then using that when necessary instead of the default copy assignment. Thanks to those who were confused at my problem, but tried to find out the solution anyways~!