Danran
Danran

Reputation: 471

Another issue: Passing argument by reference

So i thought i had the idea of passing by reference down, but it seems i'm still struggling with it a bit.

Here's my issue, i've been debugging my game for awhile, and i left the enemies section of my code untouched for ages. It's a long story but i thought my projectiles were doing damage to the enemies, I changed the enemies health to being very high, so i thought they were doing the damage but because of the high health, not killing it. Only now have i realised that they are not doing any damage and that the code is wrong :/

So here is were i begin:

void Towers::Update(std::vector<Enemies>& enemies, SDLib& lib, Map cMap)   

Here i'm passing the enemies by reference, into my update function. Which then i go onto see if there is any enemy within range of the tower;

for (int numOfEnemies = 0; numOfEnemies < lib.numberOfEnemies; numOfEnemies++)
{
    float y =  pow(enemies[numOfEnemies].position.y - position.y, 2);
    float x = pow(enemies[numOfEnemies].position.x - position.x, 2);

    if (sqrt(y + x) < range && enemies[numOfEnemies].alive)
    {
        cEnemy = enemies[numOfEnemies];
        acquiredTarget = true;
        break;
    }
}

cEnemy (currentEnemy), then holds the enemy that's within range. After this, i then create the projectile to fire, and here is were i think i'm messing up;

bullet = Projectile((float)position.x, (float)position.y - 8, 8, 8, 0, 0, damage, 1, speed, cEnemy);

And the function arguments for that are:

Projectile::Projectile(float x, float y, int w, int h, int sX, int sY, int dmg, int type, float mxSpeed, Enemies bulletTarget)
{
     //....other values set. 
     target = bulletTarget;
}

(Target is the following)

Enemies target;

The idea here is that target should hold the reference to the initial enemy that i set it to via the function... But it isn't working as i want. I'm not too sure, but i'm guessing some form of pointer might be required here. It seems to be out of everything the concept i'm finding hardest to grasp *and have done for some time now.

Any help appreciated!

Upvotes: 1

Views: 133

Answers (4)

Grizzly
Grizzly

Reputation: 20191

Your question is missing some information about the type of cEnemy and how you use the target, so I'm guessing that cEnemy is defined as Enemies and you need a reference for target to update the correct object. In this case your problems are the following:

  1. cEnemy = enemies[numOfEnemies]; makes a copy instead of a reference
  2. since bulletTarget is of type Enemies bullet = Projectile((float)position.x, (float)position.y - 8, 8, 8, 0, 0, damage, 1, speed, cEnemy); makes a copy
  3. since target is type Enemies target = bulletTarget; makes a copy

References generally only take addresses when they are constructed, later assignments make copies. So to solve the first item you need to make cEnemy a pointer:

Enemies* cEnemy;
//some code
cEnemy = &enemies[numOfEnemies];
//some more code

The second item can be solved by defining the constructor as

Projectile::Projectile(float x, float y, int w, int h, int sX, int sY, int dmg, int type, float mxSpeed, Enemies& bulletTarget)

The third item can be solve by defining target as a reference and initialising it in an initialisation list (the last part is important), making it

Enemies& target;
Projectile::Projectile(float x, float y, int w, int h, int sX, int sY, int dmg, int type, float mxSpeed, Enemies& bulletTarget):target(bulletTarget)
{}

Since assignement to references is a copy operation (only the construction of a reference takes the address, if you can't initialise target in the initialisation list, you need to make it a pointer:

Enemies* target;
Projectile::Projectile(float x, float y, int w, int h, int sX, int sY, int dmg, int type, float mxSpeed, Enemies& bulletTarget)
{  
   target = &bulletTarget;
}

`

Upvotes: 0

Mike Seymour
Mike Seymour

Reputation: 254431

You're passing the Enemies argument to the Projectile constructor by value, and then also storing it by value.

If you want target to be a reference to cEnemy, then both will need to be references. Also note that reference members have to be initialised in the constructor's initialiser list, as they can't be reassigned in the body as your code does.

class Projectile 
{
public:
    Projectile(/*lots of args*/, Enemies & target) :
        target(target)
    {}

private:
    Enemies & target;
};

Upvotes: 0

ereOn
ereOn

Reputation: 55726

We are missing some information here, but one line that could cause that is:

cEnemy = enemies[numOfEnemies];

I don't know what is the type of cEnemy but it seems you are copying your enemy object from the list instead of just refering to it.

Did you know you can create a local reference like that:

Enemies& cEnemy = enemies[numOfEnemis];

That is, cEnemy will refer to the enemy in the list, and not to a copy.

If you do that, just beware, because cEnemy is just a reference, and if you modify your list, this reference might be silently lost.

Are you sure your Enemies class should be copiable ? If it should not, fixing it not to be copiable would make the compiler your best friend to find such "mistakes".

Upvotes: 0

aschepler
aschepler

Reputation: 72271

You are making a copy of the Enemies object:

  • On cEnemy = enemies[numOfEnemies];
  • When passing a value to the Projectile constructor, since it takes an Enemies by value.
  • On target = bulletTarget;

To fix all of these, you need to consider what code "owns" an Enemies object and makes sure it lives long enough for all code that tries to use it. If there is such a place, all other places should use a reference or pointer. If not, maybe you can give the responsibility to shared_ptr<Enemies>.

Upvotes: 1

Related Questions