Search code examples
c#xna

Score not changing when collision occurs


I have been trying to get my score to work correctly when the player collides with one of the collectibles but the score does not seem to change when the collision occurs, I am not sure why this is happening.

In my collectible I have this:

class BlueBall : Obj
{
    public BlueBall(Vector2 pos) 
        : base(pos)
    {
        position = pos;
        spriteName = "BlueBall";
        solid = false;
        score = 0;
    }

    public override void Update()
    {
        if (!alive) return;

        Player player = CheckCollisionAgainst<Player>();
        if (player != null)
        {
            score = score + 20;
            alive = false;
        }

I am drawing in the Game1 class with:

spriteBatch.DrawString(font, "Score: " + score.ToString(), scorePos, Color.White);

So if the Player Collides with the BlueBall, 20 should be added to the score and the BlueBall should disappear, it does disappear but the score does not change, why is this?

At this moment I am declaring my score in the Game1 class with public int score and Vector2 scorePos to position it. I then Initialize the score with score = 0; and then Load in the scorePos values in Update.


Solution

  • From your code, and your comments, it is clear that there are actually two score variables. One that is owned by the game:

    public class Game
    {
        private int score;
    
        void Draw(...)
        {
           spriteBatch.DrawString(font, "Score: " + score.ToString(), scorePos, Color.White);
        }
    }
    

    and one that is owned by the ball:

    public class BlueBall : Obj
    {
        private int score;
    
        public void CheckCollisions()
        {
            if (collision)
               score += 20;
        }
    }
    

    Now, those two score variables have absolutely no relation to each other. The fact that they are named the same is totally irrelevant.

    To make a quick analogy, imagine programming objects are boxes. Each variable is a "counter". You put a counter in the "Game" box and call it "score". You put another counter in the "Ball" box and also call it "score". Obviously, modifying the counter in the "Ball" box won't affect the one in the "Game" box and vice versa. In general, this concept is called "scoping" in programming. Each variable is scoped to its box, which can be a class, function, or even a using block (scopes are created by {}).

    Now that you understand the problem, there are a couple ways to fix it:

    1. Create a global variable. You can't actually do that in C#, but you can create another object that both other objects have access to. Both objects than reference/modify it's "score" property. A simple (and poor practice) example would be:

      public static class GlobalState
      {
          public static int GameScore { get; set; }
      }
      

    All references to score would become GlobalState.GameScore. Again, this is just to get you going, this kind of code is really bad practice, and can cause bugs (especially in multi-threaded situations).

    1. Have the ball raise an event on collision. The game would register for this event and increment its "score" variable appropriately.

    2. Pass the game's "score" variable to the collision method by ref, so that it can change it. Warning: This is included for completeness, and this should only be done in specific circumstances, of which yours is probably not one of them.

    3. Pass a delegate to the ball on creation to invoke when it needs to increment the score. This is really a variation of the event method.

    I'm sure there are others. Given your experience level, I would start with the global approach (as its the simplest and requires the least amount of knowledge) and then move to learning about events and go with that approach in the future.