0
\$\begingroup\$

In my player class I have my players position set to update when you tap the directional keys, that works fine, but when I access my Players position variables, in my projectile class constructor, they aren't updating, I don't know why. In my main.cpp file,I update my players position before I update the projectiles position. I want the projectile to look like its being shot by the player, So I am trying to make the projectile be in front of the player and move with the player.

Player class:

Player::Player()
{
    Health = 100;
    Position.x = Position.y = 0;
    Position.w = Position.h = 100;
}

void Player::Update(SDL_Renderer* rend)
{

    //saves keystates for the player
    const Uint8* keyState;
    keyState = SDL_GetKeyboardState(NULL);

    //Use the key board
    if (keyState[SDL_SCANCODE_LEFT])
    {
        Position.x -= moveSpeed * playerAnimation.deltaTime;

    }
    if (keyState[SDL_SCANCODE_RIGHT])
    {
        Position.x += moveSpeed * playerAnimation.deltaTime;
    }
    if (keyState[SDL_SCANCODE_UP])
    {
        Position.y -= moveSpeed * playerAnimation.deltaTime;

    }
    if (keyState[SDL_SCANCODE_DOWN])
    {
        Position.y += moveSpeed * playerAnimation.deltaTime;
    }
    //Make sure that player does not go out of bounds
    if (Position.x > 700)
        Position.x = 700;

}
SDL_Texture* Player::Draw(SDL_Renderer *gRender)
{
    playerTexture = LoadTexture("shipAnimation.png", gRender);
    playerAnimation.Animate(playerTexture, 8, 1, gRender,Position);
    return playerTexture;

}

Projectile Class:

Projectile::Projectile(SDL_Renderer* render)
{
    projectileTexture = LoadTexture("laser.png", render);
    /*SDL_QueryTexture(projectileTexture, NULL, NULL, &width, &Height);*/
    Active = true;
    Damage = 2;
    projectileMoveSpeed = 20.0f;
    //ProjectilesPostion.x = playersPosition.x + PlayersPosition.w divided by 2
    projRect.x = p.Position.x + p.Position.w / 2;
    projRect.w = projRect.h = 100;
    projRect.y = 0;
    fireTime = 0.15f;

}
void Projectile::Update()
{
    projRect.x += projectileMoveSpeed;
    if (projRect.x + projRect.w / 2 > 800)
        Active = false;
}
void Projectile::Draw(SDL_Renderer* render)
{
    SDL_RenderCopy(render, projectileTexture, NULL, &projRect);
}
void Projectile::DrawProjectile(SDL_Renderer* render)
{
    for (int i = 0; i < projectiles.size(); i++)
    {
        projectiles[i]->Draw(render);
    }
}
void Projectile::AddProjectile(SDL_Renderer* render)
{
    projectiles.push_back(new Projectile(render));
}
void Projectile::UpdateProjectiles(SDL_Renderer* render)
{

    for (int i = 0; i < projectiles.size(); i++)
    {
        projectiles[i]->Update();
        if (projectiles[i]->Active == false)
        {
            projectiles.erase(projectiles.begin() + i);
        }
    }
    if ((SDL_GetTicks() - previousFireTime)/1000.0f > fireTime)
    {
        //Reset our current time
        previousFireTime = SDL_GetTicks();
        //Add Projectile
        AddProjectile(render);
    }
}

Main.cpp

int main(int argc, char* args[])
{
    SDL_Window *window = nullptr;
    SDL_Renderer *gRenderer = nullptr;




    if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
        std::cout << "video initialization error: " << SDL_GetError() << std::endl;

    window = SDL_CreateWindow("Shooter", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, ScreenWidth, ScreenHeight, SDL_WINDOW_SHOWN);
    gRenderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    ParallaxingBackground mainbg("mainbackground.png", gRenderer);

    Enemy enemyobj(gRenderer);

    if (window = NULL)
        std::cout << "Window creation Error: " << SDL_GetError() << std::endl;
    bool isRunning = true;
    Player p;
    Projectile proj(gRenderer);
    SDL_Event ev;

    //AddEnemy(gRenderer);
    //Game loop
    while (isRunning)
    {
        p.Draw(gRenderer);
        //Event Loop
        while (SDL_PollEvent(&ev) != 0)
        {
            if (ev.type == SDL_QUIT)
                isRunning = false;
        }
        SDL_RenderClear(gRenderer);
        //Updates characters in game
        p.Update(gRenderer);
        enemyobj.UpdateEnemies(gRenderer);
        proj.UpdateProjectiles(gRenderer);

        //Draws characters in game
        mainbg.Draw(gRenderer, mainbg.position);
        p.Draw(gRenderer);
        enemyobj.DrawEnemy(gRenderer);
        proj.DrawProjectile(gRenderer);

        //Checks for collsion
        enemyobj.Intersects(p);

        //Renders objects to screen
        SDL_RenderPresent(gRenderer);

    }
    SDL_DestroyWindow(window);
    SDL_DestroyTexture(p.Draw(gRenderer));
    SDL_DestroyRenderer(gRenderer);
    window = nullptr;
    gRenderer = nullptr;

    SDL_Quit();


    return 0;
}
\$\endgroup\$
3
  • 1
    \$\begingroup\$ "main header"? What would that be? Could you post your header files for your classes? \$\endgroup\$
    – Vaillancourt
    Commented Mar 31, 2016 at 0:45
  • \$\begingroup\$ @AlexandreVaillancourt I meant main.cpp and I just added its code, are you sure you want me to add the header files for all my classes as well? it would make a pretty long post. \$\endgroup\$ Commented Mar 31, 2016 at 1:12
  • 1
    \$\begingroup\$ You seem to reference a p in your projectile class constructor? What is that? Where does it come from? \$\endgroup\$
    – user35344
    Commented Mar 31, 2016 at 10:18

1 Answer 1

0
\$\begingroup\$

From what I understand, you probably have a line like this:

Player p;

in your Projectile header, and you assume that it's the same thing that you declared in your main function.

It's not.

Both are different instances and they don't know about each other, they have their own separate life, like twins that have been separated at birth.

You could change this in your Projectile.h

Player p;

for this

static Player* P; // Make it a pointer, and the capital P is to indicate that it is a static
                  // variable (makes code easier to read).

Player* Projectile::P = nullptr; // This should be added to your Projectile.cpp file, this 
                                 // will 'create' the variable. 

and in your Projectile.cpp

projRect.x = p.Position.x + p.Position.w / 2;

for

projRect.x = P->Position.x + P->Position.w / 2; // to use P as a pointer

And change this in your main:

Player p;
Projectile proj(gRenderer);

for this:

std::unique_ptr<Player> p = std::make_unique<Player>(); // Make your player as a pointer
Projectile::P = p.get(); // Make sure the Projectile class use the right instance of player
Projectile proj(gRenderer); // Carry on

... and change everything p. to p-> in your main function.

The goal here is to have a single instance of Player and have all the projectiles refer to it.


This will probably solve your current issue, but there is a lot of weird things going on with the rest of your code.

I understand you're new at this and it's not that easy to figure things out at the beginning.

In an OOP design, the collection of Projectiles would be managed outside of the Projectile class; the Projectile would not know about the Player, it would only know where it should be created (an external 'entity' would make the link between the two); I would expect the Update methods not needing the gRenderer, only a delta-time (a timestep).

That would be a good start :)

Also, we often use naming conventions to distinguish local variables, from class variables, from static class variables, from method parameters; this help read the code and figure out easily where the variable is coming from. This is a short example:

class MyClass
{
public:
  int mMyInt; // the code style for class attribute: start with a lowercase 'm' (for 'module')

  static int MyStaticInt; // the code style for class static: start with a capital letter.

  // the code style for the method attributes: start with a lowercase 'a' (for 'attribute')
  int method( int aParam1, int aParam2 )
  {
    // the code style for local variables: start with a lowercase (no special treatment)
    int localVar = mMyInt + aParam1 + aParam2;
    MyStaticInt = localVar * 2;
    return localVar;
  }
};

Of course, some conventions are more popular than others, but the idea is to be consistent across your code.

\$\endgroup\$
10
  • \$\begingroup\$ Sounds like such a good answer. When I get home I will try it \$\endgroup\$ Commented Mar 31, 2016 at 14:21
  • \$\begingroup\$ Whaaat? Does the "m" stand for module and not member? \$\endgroup\$
    – user35344
    Commented Mar 31, 2016 at 19:44
  • 1
    \$\begingroup\$ @Tyyppi_77 both would be valid :) \$\endgroup\$
    – Vaillancourt
    Commented Mar 31, 2016 at 19:50
  • \$\begingroup\$ @AlexandreVaillancourt I did what you said but now it gives me this error LNK2020: unresolved token (0A000450) "public: static class Player * Projectile::P" (?P@Projectile@@2PAVPlayer@@A) \$\endgroup\$ Commented Mar 31, 2016 at 21:26
  • \$\begingroup\$ @AlexandreVaillancourt it also says I have 3 unresolved externals. \$\endgroup\$ Commented Mar 31, 2016 at 21:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .