Search code examples
c#monogame

Disappearing Objects


so for my first project with MonoGame I decided to make a tetris clone but I have an issue which I don't know how to solve.

Currently my code is generating a block and moves it downwards until it reach a specific y position. The block need to stay at this position and a new block spawns. I'm doing this with a List which contains object of the block class and then just draw all the blocks in this list.

I took out parts which I believe are not involved in the problem:

 public class PlayField : DrawableGameComponent
    {
        private Game1 gameRef;
        private Texture2D fieldTexture;
        private BlockGenerator blockGenerator;
        private Texture2D[] allBlocks;

        private Block currentBlock;

        public bool[,] fieldFilled;
        private int down_Blocks = 22;
        private int side_Blocks = 10;

        public List<Block> placedBlocks;

        public PlayField(Game game) : base(game)
        {
            placedBlocks = new List<Block>();
            allBlocks = new Texture2D[4];
            blockGenerator = new BlockGenerator(allBlocks,gameRef);

        }   
        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
            try
            {
                if (currentBlock.isMoving == false)
                {
                    placedBlocks.Add(currentBlock);
                    currentBlock = null;
                    currentBlock = blockGenerator.GenerateBlock();
                }
                else
                {
                    currentBlock.UpdatePosition(gameTime);
                    if (InputManager.CheckForKeyBoardRelease(Keys.A))
                    {
                        currentBlock.MoveLeft();
                    }

                    if (InputManager.CheckForKeyBoardRelease(Keys.D))
                    {
                        currentBlock.MoveRight();
                    }
                }
            }
            catch(NullReferenceException e)
            {
                currentBlock = blockGenerator.GenerateBlock();
            }


        }

        public override void Draw(GameTime gameTime)
        {
            gameRef.SpriteBatch.Begin();

            if(currentBlock != null)
            {
                currentBlock.DrawBlocks();
            }

            foreach(Block b in placedBlocks)
            {
                b.DrawBlocks();
            }

            gameRef.SpriteBatch.End();
            base.Draw(gameTime);
        }

The method "GenerateBlock" returns a object of type "Block"

public class Block : DrawableGameComponent
    {
        Game1 gameRef;
        public Texture2D blockTexture;
        public Vector2[] blockPositions;
        TimeSpan lastMove;
        TimeSpan blockMove = TimeSpan.FromMilliseconds(500);

        public bool isMoving;


        public Block(Game game, Texture2D _blockTexture, Vector2[] _blockPositions) : base(game)
        {
            gameRef = (Game1)game;
            blockTexture = _blockTexture;
            blockPositions = _blockPositions;
            isMoving = true;
        }

        public void UpdatePosition(GameTime gameTime)
        {
            Vector2 bottomBlockPositon = FindBottomBlock();
            if(bottomBlockPositon.Y < 550)
            {
                if (WaitTillMove(gameTime))
                {
                    for (int i = 0; i < blockPositions.Length; i++)
                    {
                        blockPositions[i] = new Vector2(blockPositions[i].X, blockPositions[i].Y + 25);
                    }
                }
            }
            else
            {
                isMoving = false;
                Console.WriteLine("X: " +blockPositions[0].X + " Y:" + blockPositions[0].Y);
            }

        }

        public Vector2 FindBottomBlock()
        {
            Vector2 result = new Vector2(0, 0);
            for(int i = 0; i < blockPositions.Length; i++)
            {
                if(blockPositions[i].Y > result.Y)
                {
                    result = blockPositions[i];
                }
            }

            return result;
        }

        public bool WaitTillMove(GameTime gameTime)
        {
            if (lastMove + blockMove < gameTime.TotalGameTime)
            {
                lastMove = gameTime.TotalGameTime;
                return true;
            }
            return false;
        }

        public void DrawBlocks()
        {
            gameRef.SpriteBatch.Draw(blockTexture, blockPositions[0], Color.White);
            gameRef.SpriteBatch.Draw(blockTexture, blockPositions[1], Color.White);
            gameRef.SpriteBatch.Draw(blockTexture, blockPositions[2], Color.White);
            gameRef.SpriteBatch.Draw(blockTexture, blockPositions[3], Color.White);
        }
    }

Debugging says that my List contains an Element even though it has the wrong positions. But this shouldn't matter because I still only "see" one Block at the same time.

Hopefully someone can toss me into the right direction.

Edit:

public class BlockGenerator
    {
        Random random;
        Texture2D[] allBlocks;
        Vector2[] blockPositions;
        Texture2D currentBlock;
        BlockEnums currentBlockEnum;

        Game1 gameRef;

        public BlockGenerator(Texture2D[] blocks, Game1 game)
        {
            gameRef = (Game1)game;
            allBlocks = blocks;
            currentBlock = allBlocks[1];
            blockPositions = new Vector2[4];
            random = new Random();
        }

        public Block GenerateBlock()
        {
            int colorValue = random.Next(0, 4);     //0 = blue, 1 = green, 2 = red, 3 = yellow

            currentBlock = allBlocks[colorValue];
            currentBlockEnum = BlockEnums.Line;

            blockPositions[0] = new Vector2(100, 0);
            blockPositions[1] = new Vector2(125, 0);
            blockPositions[2] = new Vector2(150, 0);
            blockPositions[3] = new Vector2(175, 0);

            Block generatedBlock = new Block(gameRef,currentBlock, blockPositions);

            return generatedBlock;
        }

Solution

  • public class BlockGenerator
        {
            Random random;
            Texture2D[] allBlocks;
            Vector2[] blockPositions; // delete this
    

    Then move the initialization code from the constructor into GenerateBlock (add var).

    var blockPositions = new Vector2[4];
    

    Then it should work. You were creating new vectors each time you created a block but re-using the same instance of blockPositions each time, so both blocks do exist but will always have the exact same positions.

    I haven't had time to test but I think it's right...let me know :)

    edit: I'd also suggest moving blockPositions entirely into the Block class. I see no value (in the code you have posted, maybe you have plans for later) in having that logic outside of the class that really owns it...and if it was contained within the class to begin with you would have avoided this problem. Just a suggestion :)