Results 1 to 2 of 2
  1. #1
    Join Date
    Apr 2003
    Posts
    4

    SpaceFighter 2D Collsion with Flipped Sprites

    I have have adapted much of the Space Fighter tutorial into a horizontal scrolling shooter but am having an issue with collision detection if you flip the sprite horizontally. I've seen a few tutorials online on how to do per pixel collision with rotated sprites, but so far nothing that would help with flipped sprites. I've also seen a bit about XNA Matrix structures, but not anything I understood would help with flipped sprites.

    Since the method used to detect collisions gets all the data and simply dumps it into an array you lose X and Y position so first I'll need to figure out the best way to get the data in that fashion. I think that a nested loop could work but I'm not sure how to put it all together. I only have to worry about horizontal flipping so I would be easy to put a check in the collision method to check if that node is facing left or right and which nested loop to use based on that information.

    In particular I think these lines would have to be updated

    Code:
                Color[] pixelsA = new Color[pixelCount];
                Color[] pixelsB = new Color[pixelCount];
    
                nodeA.Sprite.Texture.GetData<Color>(0, nodeA.normalizeBounds(collisionRect), pixelsA, 0, pixelCount);
                nodeB.Sprite.Texture.GetData<Color>(0, nodeB.normalizeBounds(collisionRect), pixelsB, 0, pixelCount);
    
                for (int i = 0; i < pixelCount; i++)
                {
                    if (pixelsA[i].A > ALPHA_THRESHOLD && pixelsB[i].A > ALPHA_THRESHOLD)
                    { return true; }
                }
    any suggestions would be appreciated. I've tinkered around for a few hours and came up with nothing that worked, and mostly just wrote code that slowed my pc to a crawl so I don't think its worth posting.

  2. #2
    Join Date
    Mar 2007
    Location
    Netherlands
    Posts
    46
    Not having done the SpaceFighter project myself, i am not quite sure where this code sits in the actual application. But i do have some suggestions based on the code you posted.

    First of all, if the code you posted is executed every single update, it will indeed slow you down, try to save it when a texture gets set or changed.

    I will post a bit of code that will contain my solution to the problem:
    Code:
            private bool[,] collisionMap;
    
            //Execture When texture is loaded or changed
            public void OnTextureChangeOrLoad()
            {
                //Create a temporary buffer
                Color[] tempCol = new Color[this.Texture.Width * this.Texture.Height]; 
                //Get the pixels from the texture put them in the temp buffer
                this.Texture.GetData<Color>(tempCol);
    
                //Instantiate the collision map
                this.collisionMap = new bool[this.Texture.Width, this.Texture.Height];
    
                //Loop trough the textures rows(y) and cols(x)   
                for (int y = 0; y < this.Texture.Height; y++)
    			{
                    for (int x = 0; x < this.Texture.Width; x++)
    			    {
                        //If the alpha value is above a certain value we want to collide with it
                        if (tempCol[x + (this.Texture.Width * y)].A > ALPHA_THRESHOLD)
                        {
                            //We set the collision to true
                            this.collisionMap[x, y] = true;
                        }
                        else
                        {
                            //We set it not to collide with this pixel
                            this.collisionMap[x, y] = false;
                        }
    			    }
    			}
                this.RotateCollisionMap();
            }
    
            //Execute this when your rotation changes
            public void RotateCollisionMap()
            {
                //We make a temporary new collisionmap that will hold the rotated points
                bool[,] tempMap = new bool[this.Texture.Width, this.Texture.Height];
                for (int y = 0; y < this.Texture.Height; y++)
                {
                    for (int x = 0; x < this.Texture.Width; x++)
                    {
                        //Make the point we want to rotate
                        Vector2 unRotatedPoint = new Vector2(x, y);
    
                        //use the method to rotate your point, 1st argument the point you want to rotate
                        //2nd argument the origin (more then likely center of your collionmap / texture)
                        //3rd argument is the rotation in radians, in this example it will only work with increments of 90deg / MathHelper.PiOver2
                        Vector2 rotatedPoint = _rotatePoint(unRotatedPoint, new Vector2(this.Texture.Width / 2, this.Texture.Height / 2), this.Rotation);
                        tempMap[(int)rotatedPoint.X, (int)rotatedPoint.Y] = this.collisionMap[x, y];
                    }
                }
                //We set the new rotated collionmap as the new collionmap
                this.collisionMap = tempMap;
            }
    
            //When given a Vector2 and its origin, it will return a Vector2 with the rotation in radians applied
            private Vector2 _rotatePoint(Vector2 PointToRotate, Vector2 OriginOfRotation, float ThetaInRads)
            {
                Vector2 RotationVector = PointToRotate - OriginOfRotation;
                Vector2 RotatedVector = new Vector2()
                {
                    X = (float)(RotationVector.X * Math.Cos(ThetaInRads) - RotationVector.Y * Math.Sin(ThetaInRads)),
                    Y = (float)(RotationVector.X * Math.Sin(ThetaInRads) + RotationVector.Y * Math.Cos(ThetaInRads))
                };
    
                return OriginOfRotation + RotatedVector;
            }
    This is by no means the best solution, however, every solution you can think of will use a function along the lines of _rotatedPoint.
    My solution will only work if you rotate the texture 90 degrees or 180 degrees(Pi / 2 and Pi respectively), since with a rotation other then that certain points will fall out of bounds of the array. But it seems to fulfill your request of horizontal flipping while at the same time not updating the collision map every frame and giving you a lot more cycles to play with.

    It is still possible to use the _rotatedPoint for any rotational value tho. Most important thing you should understand from my code is that you can use _rotatedPoint to rotate any Vector2 to find out its new position after rotation.

    Disclaimer: I typed this code up in nodepad++, so i have no clue if it compiles and works, it does in my head though. So please try to understand the concept behind it (rotation of points, caching of your collisionmap) instead of the exact code.
    Last edited by rme_2001; 12-11-2010 at 06:55 AM.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •