Why might my Object Attributes become linked after refactoring?

As part of a game design class I'm taking this semester, I'm developing the basics of a game engine. I shared what I had in the GameDev chatroom, earlier, and everything was working as expected.

Then, because I knew it needed it, I started work on refactoring the core classes within my code. I modified the ancestor GameObject class, and after the tedious process of renaming all the method and field calls (I combined two float's, xPosition and yPosition into a single, Vector2d class - yes, I realize there are existing classes out there, but it was easier to simply write a new one, given that I can't make any assumptions on the installed libraries when it comes time for grading my work. I digress), prepared to test my newly refactored code.

The results were... perplexing. Suddennly, my SpawnPoint object was moving. Not only that, but it seemed attached to the PlayerEntity object itself, always matching the position of the controllable playerEntity (though it lagged a bit behind if you moved fast enough). And yet, I know that I never move the SpawnPoint, only the player entity; a quick search (ctrl+f) through my code confirmed that. But despite this, I had somehow managed to achieve quantum entanglement of these disparate objects.

I've reproduced both constructors below. Is this a case of passing by reference instead of by value? If so, is there a general way to avoid such troubles when instantiating objects with other objects as parameters?

Original Code:

public class PlayerEntity extends GameObject{

SpawnPoint playerSpawn;
public boolean isDead = true;
float xVelocity;
float yVelocity;

//constructor, single dimension
PlayerEntity(SpawnPoint spawn)
{
this.objClass = "entity";
this.playerSpawn = spawn;
this.xDiameter = 15;
this.yDiameter = 15;
this.xVelocity = 0;
this.yVelocity = 0;
}

void respawn(){
isDead = false;
this.xPosition = playerSpawn.xPosition;
this.yPosition = playerSpawn.yPosition;
}


Refactored (Bugged) Code

public class PlayerEntity extends GameObject{

SpawnPoint playerSpawn;
public boolean isDead = true;
Vector2d velocityVector;
float xDiameter;
float yDiameter;
//constructor, single dimension
PlayerEntity(SpawnPoint spawn)
{
this.objClass = "entity";
this.playerSpawn = spawn;
this.xDiameter = 15;
this.yDiameter = 15;
this.velocityVector = new Vector2d(0,0);
this.positionVector = this.playerSpawn.positionVector;
}

void respawn(){
isDead = false;
this.positionVector = playerSpawn.positionVector;
}


The first thing first thing the PlayerEntity does in its update() method is call "respawn()" if isDead = true (which is why I think I got away without initializing the position in the first, working, code).

With the help of a debugger, I've narrowed down the method call which (unintentionally) modifies the spawnpoint's position. I'll probably edit that into the question when I have exactly identified the culprit.

Edit: Here is the method where the value is changing (though I don't know why), taken from playerEntity.

Original (working correctly)

void moveEntity() {

    this.xPosition += this.xVelocity;
this.yPosition += this.yVelocity;
}


Refactored method (bugged behavior)

void moveEntity() {

    this.positionVector.xCor += this.velocityVector.xCor;
this.positionVector.yCor += this.velocityVector.yCor;
}


for whatever reason, this is causing the spawnPoint's positionVector to alter as well.

This program is written in Processing (which is just a java library, albeit one with its own IDE).

1 Answer

this.positionVector = this.playerSpawn.positionVector;

This seems to be your problem line. It is indeed a reference; try calling

this.positionVector = this.playerSpawn.positionVector.Clone();

Edit: Clone() seems to make no guarantees, so you should rather try:

Vector2d vector = this.playerSpawn.positionVector;

this.positionVector = new Vector2d(vector.X, vector.Y);

or

this.positionVector = new Vector2d(this.playerSpawn.positionVector);

One of those will work for sure.

• I didn't think this was it at first, until I realized that I was also re-referencing the vectors during my respawn() call. After changing both of those instances, the game now behaves as expected. Thanks! – Raven Dreamer Sep 14 '11 at 14:07