Search code examples
c#animationspritemonogame

Monogame multiple objects same animation


as the titel say's I'm trying to make a game in Monogame, a Bomberman clone, but atm when I try to spawn more then one bomb the animation just moves to the new location. The game object stays where it is supposed to, but it does not have the animation. I think the problem is that it loads the same animation which has been loaded but I just cant seem to figure out how to get it to spawn a new animation everytime a bomb spawns. I use Content.Load to get the sorite animation, and spawn the bomb with a clone() function with the animation.

var bombAni = new Dictionary<string, Animation>() {
            {"Bomb", new Animation(Content.Load<Texture2D>("Obstacle/Bomb"), 3) },
        };

        _sprites = new List<Sprite>() {

            new Player(animations) {
                _bomb = new Bomb(bombAni),
                Position = new Vector2(32, 32),
                Input = new Input() {
                    Up = Keys.W,
                    Down = Keys.S,
                    Left = Keys.A,
                    Right = Keys.D,
                    Space = Keys.Space,
                }
            }

        };

public void Play(Animation animation) {
        if (animation == _animation) {
            return;
        }

        _animation = animation;

        _animation.CurFrame = 0;

        _timer = 0;
    }

private void AddBomb(List<Sprite> sprites) {

        var bomb = _bomb.Clone() as Bomb;
        switch (_direction) {
            case "Up":
                bomb.Position = _position + new Vector2(0, -32);
                break;
            case "Down":
                bomb.Position = _position + new Vector2(0, 32);
                break;
            case "Left":
                bomb.Position = _position + new Vector2(-32, 0);
                break;
            case "Right":
                bomb.Position = _position + new Vector2(32, 0);
                break;
        }
        bomb.lifeSpan = 3f;
        bomb.Parent = this;
        bombCount++;

        sprites.Add(bomb);
    }

public Sprite(Dictionary<string, Animation> animations) {

        _animations = animations;
        _animationManager = new AnimationManager(_animations.First().Value);

    }


namespace CompetenceWeek.scripts {
public class Bomb : Sprite {

    public float lifeSpan;
    private float _timer;

    public Bomb(Dictionary<string, Animation> animations) : base(animations) {

    }

    public Bomb(Texture2D texture) : base(texture) {

    }


    public override void Update(GameTime gameTime, List<Sprite> sprites) {
        _timer += (float)gameTime.ElapsedGameTime.TotalSeconds;

        SetAnimations();

        _animationManager.Update(gameTime);

        if (_timer > lifeSpan) {
            isDead = true;
        }

    }

}

}

namespace CompetenceWeek.scripts {
public class Sprite : ICloneable {

    protected AnimationManager _animationManager;

    protected Dictionary<string, Animation> _animations;

    protected Vector2 _position;

    protected Texture2D _texture;

    public bool Walkable { get; set; } = false;

    public bool isDead = false;


    public Player Parent { get; set; }

    public Input Input;

    public Vector2 Position {
        get { return _position; }
        set {
            _position = value;

            if(_animationManager != null) {
                _animationManager.Posistion = _position;
            }
        }
    }

    public float Speed = 2.5f;

    public Vector2 Velocity;

    public virtual void Draw(SpriteBatch spriteBatch) {

        if(_texture != null) {
            spriteBatch.Draw(_texture, Position, Color.White);
        } else if (_animationManager != null) {
            _animationManager.Draw(spriteBatch);
        } else {
            throw new Exception("somthings not right");
        }


    }



    public Sprite(Dictionary<string, Animation> animations) {

        _animations = animations;
        _animationManager = new AnimationManager(_animations.First().Value);

    }

    public Sprite(Texture2D texture) {
        _texture = texture;
    }

    public virtual void Update(GameTime gameTime, List<Sprite> sprites) {
        SetAnimations();

        _animationManager.Update(gameTime);

        Position += Velocity;
        Velocity = Vector2.Zero;


    }

    protected virtual void SetAnimations() {
        if (Velocity.X > 0) {
            _animationManager.Play(_animations["PlayerRight"]);
        } else if (Velocity.X < 0) {
            _animationManager.Play(_animations["PlayerLeft"]);
        } else if (Velocity.Y > 0) {
            _animationManager.Play(_animations["PlayerDown"]);
        } else if (Velocity.Y < 0) {
            _animationManager.Play(_animations["PlayerUp"]);
        }
    }

    public object Clone() {
        return this.MemberwiseClone();
    }
}

}


Solution

  • The problem is with this segment:

    protected Dictionary<string, Animation> _animations;
    
    public object Clone() {
        return this.MemberwiseClone();
    }
    

    When you perform a memberwise clone, it creates a shallow copy, reusing existing references to reference-type objects. This means that the Clone will share the same animation state with the original object.

    The solution to this, is to instantiate a new copy of all of the Animations every time you want to clone Bomb.

    Something like this:

    public object Clone() {
        var bomb = (Bomb)this.MemberwiseClone();
        bomb.InitAnimations(new Dictionary<string, Animation>() {
            {"Bomb", new Animation(Content.Load<Texture2D>("Obstacle/Bomb"), 3) },
        };
        return bomb;
    }