hey hey folks. I am making a tetris clone for my class project in college. langauge is XNA and I have run into a minor issue. When my bricks get to the bottom, rather than stack, they simply reset back up to the top. I have tried everything I can think of...to no avail. I have been working on this bad boy since about 2pm, its now 1:46 at the time of posting. I THINK the issue is somwhere inside my collision detection code way down at the bottom, but im not sure. any halp would surely be appreciated.

variables and declerations:

`GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Texture2D backgroundTexture;
        Texture2D storage;
        Texture2D block;
        Color[] blockColor;
        Random blockColorGen;
        SpriteFont MessageFont;

        int[,] bottomRow;


        int _total_frames = 0;
        float _elapsed_time = 0.0f;
        int _fps = 0;
        int fallSpeed = 5;
        int maxSpeed = 5;
        int color;

        List<Vector2> fallingBrick;
        int[,] rows;       

initialization method:

protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            graphics.PreferredBackBufferHeight = 620;
            graphics.PreferredBackBufferWidth = 600;
            graphics.ApplyChanges();
            rows = new int[700, 700];
            blockColorGen = new Random();
            bottomRow = new int[700,700];
            blockColor = new Color[] { Color.Red, Color.Blue, Color.Orange, Color.Purple, Color.Green, Color.Yellow };
            for (int i = 0; i < bottomRow.GetLength(0); i++)
            {
                for (int j = 0; j < bottomRow.GetLength(1); j++)
                {
                    bottomRow[i, j] = -1;
                    blockColorGen.Next(0, 6);

                }
            }

            Window.Title = "Adavidson_tetris";

            blockReset();
            base.Initialize();

  `protected override void Update(GameTime gameTime)
    {

        collisionDetection();
        _elapsed_time += (float)gameTime.ElapsedGameTime.TotalMilliseconds;
        // 1 Second has passed
        if (_elapsed_time >= 1000.0f)
        {
            _fps = _total_frames;
            _total_frames = 0;
            _elapsed_time = 0;
        }

        base.Update(gameTime);
    }

  draw method:
  `       protected override void Draw(GameTime gameTime)
    {
        int currentColor = color;            
        _total_frames++;
        GraphicsDevice.Clear(Color.CornflowerBlue);

        spriteBatch.Begin();

        spriteBatch.Draw(storage, new Vector2(0f, 0f), Color.White);

        for (int i = 0; i < bottomRow.GetLength(0); i++)
        {
            for (int j = 0; j < bottomRow.GetLength(1); j++)
            {
                currentColor = bottomRow[i, j];
                if (currentColor != -1)
                {
                    spriteBatch.Draw(block, new Rectangle(i * 32, j * 32, 32, 32), blockColor[color]);
                }

            }
        }

        for (int i = 0; i < fallingBrick.Count; i++)
        {
            int x = (int)fallingBrick[i].X;
            int y = (int)fallingBrick[i].Y;
            spriteBatch.Draw(block, new Rectangle(x, y, 32, 32), blockColor[color]);

        }

        spriteBatch.DrawString(MessageFont, string.Format("FPS={0}", _fps),
        new Vector2(10.0f, 20.0f), Color.Black);


        spriteBatch.End();

        base.Draw(gameTime);
    }`

    collision detection:

     private void collisionDetection()
    {

        bool spaceEmpty = true;
        KeyboardState currentKey = Keyboard.GetState();
        if (currentKey.IsKeyDown(Keys.Left))
        {
            for (int i = 0; i < fallingBrick.Count; i++)
            {
                var brick = fallingBrick[i];
                if (brick.X < 135)
                {
                    var brickLocation = brick.X;


                }

                else
                {

                    brick.X--;
                    fallingBrick[i] = brick;
                }
            }
        }

        if (currentKey.IsKeyDown(Keys.Right))
        {

            for (int i = 0; i < fallingBrick.Count; i++)
            {
                var brick = fallingBrick[i];
                if (brick.X > 433)
                {
                    var brickLocation = brick.X;


                }
                else
                {
                    brick.X++;
                    fallingBrick[i] = brick;
                }
            }

        }

        if (currentKey.IsKeyDown(Keys.Down))
        {
            for (int i = 0; i < fallingBrick.Count; i++)
            {
                var brick = fallingBrick[i];
                brick.Y++;
                fallingBrick[i] = brick;
            }

        }



        if (fallSpeed <= 0)
        {

            fallSpeed = maxSpeed;
            for (int i = 0; i < fallingBrick.Count; i++)
            {
                var brick = fallingBrick[i];

                brick.Y++;
                int x = (int)brick.X;
                int y = (int)brick.Y;
                spaceEmpty &= brick.Y <= 585 && bottomRow[x, y] == -1;
                fallingBrick[i] = brick;
            }

            if (spaceEmpty)
            {

                for (int i = 0; i < fallingBrick.Count; i++)
                {
                    var brick = fallingBrick[i];
                    brick.Y++;
                    int x = (int)brick.X;
                    int y = (int)brick.Y;
                    spaceEmpty &= brick.Y <= 585 && bottomRow[x, y] == -1;
                    fallingBrick[i] = brick;

                }

            }
            else
            {
                while (fallingBrick.Count > 0)
                {
                    var brick = fallingBrick;
                    int x = (int)fallingBrick[0].X;
                    int y = (int)fallingBrick[0].Y;
                    bottomRow[x,y] = color;
                    fallingBrick.RemoveAt(0);
                    Console.WriteLine(bottomRow[x,y]);


                }

                blockReset();
            }

        }
        else
        {
            fallSpeed--;
        }



    }

    private void blockReset()
    {
        fallingBrick = new List<Vector2>();
        fallingBrick.Add(new Vector2(275, 0));
        color = blockColorGen.Next(0,6);

    }

    any ideas?

Recommended Answers

All 11 Replies

Hi, not to sure if this could be it but try changing line 20 to
List<Vector2> fallingBrick = new List<Vector2>();
And remove line 204, could be completely wrong as I'm a student myself

no dice, thanks for the input though. anything that makes the code look a tad more effecient is always welcome

played around a bit with the code and the best way I can see to make it work would be to create a class for the blocks something like follows

class block
    {
        Texture2D blockImage;
        Color[] blockColor;
        Vector2 position;
        bool active;


        public block(Texture2D blockImage, Color[] blockColor, Vector2 position, bool active)
        {
            this.blockImage = blockImage;
            this.blockColor = blockColor;
            this.position = position;
            this.active = active;
        }
    }

then you can create a list of blocks that will move only when active so once it hits the bottom of the screen you set it to false

I was thinking about going this route, and just creating different classes for the diffrent shapes. Thats what I did in my programming two course and It worked fine...so tomorrow I will start down that path and hopefully things will work. will update.

For a brick that has reached the bottom, I'm presuming that the fall speed is 0?

On that presumption;
You enter your if statement on line 145.
When you iterate your for loop, spaceEmpty will be set to false (because your block now occupies the space).
This will cause you to execute your else clause, which resets the block position.

Strictly speaking, your code is a little bit messy. If I were you, I would separate out your collisionDetection method (and please format your MethodNames as such ;) ) into different functions.

The key detection for block movement should definitely not be there too :)

For a brick that has reached the bottom, I'm presuming that the fall speed is 0?

On that presumption;
You enter your if statement on line 145.
When you iterate your for loop, spaceEmpty will be set to false (because your block now occupies the space).
This will cause you to execute your else clause, which resets the block position.

correct. and thats the thing, the block needs to reset, but its final position isnt stored. so what happens is when said block hits the lower barrier, it up and disapears rather than being realocated into a different instance. In this case bottomRow.

oh and yes my movement will eventaully get removed from the collision detection group. Keep in mind this bad boy isnt due until the middle of september. rather than make a bunch of various classes and what not, I decided to initially get everything on paper as it were to verify functionality. once I get that all down it will get broken down into a bunch of different methods and what not

oh and yes my movement will eventaully get removed from the collision detection group. Keep in mind this bad boy isnt due until the middle of september. rather than make a bunch of various classes and what not, I decided to initially get everything on paper as it were to verify functionality. once I get that all down it will get broken down into a bunch of different methods and what not

What you will find when you start working on later projects is that it's easier to do this in reverse, so, think of the functionality that's required and the possible methods that it will need. Obviously as you start development, you will come across issues that require a little refactoring, but believe me what I say (because I was the same in Uni) that designing the thing first is much easier than coding it first.

correct. and thats the thing, the block needs to reset, but its final position isnt stored. so what happens is when said block hits the lower barrier, it up and disapears rather than being realocated into a different instance. In this case bottomRow.

I think I understand what your code is kind of doing now. It would have been better had you had "brick" objects that you kept track of, rather than just adjusting the colour of an array based on where it lands. You would be able to see what was happening a lot easier that way :)
As for the issue, I'm not quite sure what fall speed is used for, however, if it isn't 0 by the time you reach the bottom, then none of your logic will work.

The reason it disappears is because your block doesn't really exist, all you're doing is recording the colour value of its final resting place.

Oh, you don't need line 170, lists are reference based.

Performance warning as well; make sure you draw by colour. Context switching on a graphics card is a very expensive operation. Changing the draw colour is a context switch, I advise doing this as little as possible.
This is something I found in Uni. I had 4 colours in a 256x256 grid. Drawing every squared in the grid in a row or column based fashion gave an fps around 15-20. Switching it to colour based drawing gave an fps of around 3000. Slight difference :)

that designing the thing first is much easier than coding it first.

hehe, I spent 8 years army, 4 year in the infantry. I like banging my head against a wall just to say i did it the hard way xD.

fall speed is used to regulate the speed at which said brick of doom falls to the bottom of the bucket/screen. with out it...it just kinda sits there. outside of taking about 2 hours to watch a movie and try to fall asleep I have had 0 sleep so dont mind eh silliness.

edit:

I shoulda also note that the reason why I have a keydown input allocated is so that the end user can speed up the brick to make it a little less boring watching a brick fall down the screen. my bucket/collection area is larger than I intended, so this makes it a little less boring to run with. but with that said, even if i had stuck with your typical 10x20 tetris screen, I still would have the command in there
.

You need to use something called CPU Independant Animation. I think they might even call it Frame Independant Animation now.

Essentially, pick a speed in units per second, calculate how long it takes to update and draw a frame, then increment the animation by said units.

So each frame, record the time down to the millisecond, then subtract the old time from the new time to get the delta time. In a 60fps application this will be about 16ms. You then divide the speed by the delta time to get the number of units you moved that frame.

So if you move 100 units per second and it takes 16ms to update the frame, your unit position would update by 6.25 units per frame.

As you said this has a hand in of September I presume you're doing some study on the subject, so, I suggest you add this kind of animation to your application as it should be worth some marks and it's relatively simple to implement.

PS. I agree with your choice of the down button, teris would be boring without it ;)

sounds relativly simple to put in, but until i fugre out what is going on with this issue, I really dont wanna press my luck. have been going backwards all day and basically scraped my last 7 hours of work and went to a previous version that i didnt mess up. thanks for your help so far folks. I did manage to remove my movement commands from the collision detection group without breaking anything...but thats about it >.<

dusregard here guys. completly scrapped the project and starting over. too many things i dont like about how I coded the whole bloddy thing

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.