Getting a rectangle to land on top of a rectangle

Started by
9 comments, last by PhilObyte 9 years, 10 months ago

diagram_zps9d235ff9.png

diagram1_zpsd10299e0.png

I decided to ask for advice after having been stuck with this problem for half a day.

My goal is to get the blue rect to land on the orange rect.

I drew diagrams to illustrate my thought process on the coordinates of both objects(blue rect and orange rect).

I'm 100% sure, my coordinate on the diagrams are labeled correctly.

I figure if I evaluate each x coordinate of blue rect against the orange rect x coordinate as well applies this idea with the y coordinate, I would get somewhere. I was mistaken.

One thing to note: I am keeping the blue rect at the middle of the screen throughout the game so its coordinates won't change. But the blocks coordinate for drawing will change because it needs to take into account the camera system I have in place.

Where did I go wrong?

The first two conditions in the if statement use knowledge from the first diagram. The last two conditions use knowledge from the second diagram.

Here is my Java code:


if( (rectangle.getX() + idleRightAnim.getWidth()) >= (block.getX() - camera.getX())
&& (rectangle.getY() + idleRightAnim.getHeight()) >= (block.getY() - camera.getY())
&& rectangle.getX() <= (block.getX() - camera.getX()) + block.getWidth()
&& rectangle.getY() + idleRightAnim.getHeight() <= block.getY() - camera.getY()
)
{
System.out.println("collide");
}

FINAL EDIT: Spotted my mistake: the last condition should be: rectangle.getY() + idleRightAnim.getHeight() <= block.getY() - camera.getY() + block.getHeight()

I was forgot to add the block.getHeight(). No wonder...

I decided to post the solution here: This is for only for checking collision of edges case of the left side of the block.


// edge case for left side of block
if(rectangle.getX() + idleRightAnim.getWidth() >= block.getX() - camera.getX()
&& rectangle.getX() <= block.getX() - camera.getX() + block.getWidth()
&& rectangle.getY() + getHeight() >= block.getY() - camera.getY()
&& rectangle.getY() + getHeight() <= block.getY() - camera.getY() + block.getHeight()
) 
Advertisement

Why does the camera location affect whether the blocks collide?

Why does the camera location affect whether the blocks collide?


I have a camera system where if the user presses a key to move, the camera coordinates changes which means the block coordinates change with respect to the camera coordinates. The blocks are the only objects affected by the camera.
See if this helps:
http://www.gamedev.net/topic/652441-bounding-box-collision-in-a-platformer-game/?view=findpost&p=5125126

The way I've implemented scrolling in my game, the "camera" position does not affect the logical game world position of any objects. The camera is more of a way of determining what objects and tiles I want to display on the screen. And though the camera affects where on the screen an object is displayed it doesn't affect where in the game world it is, As a simplified example, if my world is 128*128 tiles and my camera position is at 25, 30 (this is where I start bltting objects) and my view is 10*8 tiles wide, I display everything that's within tiles 25,30 through 35,38. If I do something to move the camera, the co-ordinates for the camera change but I still display 10*8 tiles of game world stuff starting from my new position.

But my sprites and other game objects all work in game world co-ordinates. That means when I'm testing if things collide with each other, I don't do any calculations based on the camera co-ordinates. Unless maybe I was only going to test stuff that's occurring on screen but then if two things were to collide off screen, the collision wouldn't be processed.

I suggest you start with looking at a solution that doesn't involve scrolling or cameras first. Once that's working, look into ways to display objects on the screen based on camera position without affecting the game world co-ordinates of the objects.

(I have a feeling my example is poorly worded but I hope the basic idea gets across)

I don't know whether I understood you right, but I think you need to do is intersection resolving. When your moving rectangle collides with the static (and it is not important from which side) you need to find out how deep and from what direction they overlap to push it out so that they are next to each other perfectly aligned but not penetrating.

The code for is tricky. I took it from the XNA's platformer example and modified it a bit. I have not tested the normal it outputs but the rest should work perfectly:


/// <returns>Depth of intersection relative to rectA</returns>
        public static Vector2 GetIntersectionDepth(Rectangle rectA, Rectangle rectB)
        {
            float halfWidthA = rectA.Width / 2f;
            float halfHeightA = rectA.Height / 2f;
            float halfWidthB = rectB.Width / 2f;
            float halfHeightB = rectB.Height / 2f;

            Vector2 centerA = new Vector2(rectA.Left + halfWidthA, rectA.Top + halfHeightA);
            Vector2 centerB = new Vector2(rectB.Left + halfWidthB, rectB.Top + halfHeightB);

            float distanceX = centerB.X - centerA.X;
            float distanceY = centerB.Y - centerA.Y;
            float minDistanceX = halfWidthA + halfWidthB;
            float minDistanceY = halfHeightA + halfHeightB;

            if (Math.Abs(distanceX) >= minDistanceX || Math.Abs(distanceY) >= minDistanceY)
                return Vector2.Zero;

            float depthX = distanceX > 0 ? minDistanceX - distanceX : -minDistanceX - distanceX;
            float depthY = distanceY > 0 ? minDistanceY - distanceY : -minDistanceY - distanceY;
            return new Vector2(depthX, depthY);
        }

        /// <returns>[0] position to add to B [1] normal</returns>
        public static Vector2[] ResolveIntersection(Rectangle rectA, Rectangle rectB)
        {
            Vector2 depth = GetIntersectionDepth(rectA, rectB);
            Vector2 normal;

            if (Math.Abs(depth.X) > Math.Abs(depth.Y))
            {
                if (depth.Y > 0) normal = Vector2.UnitY; else normal = -Vector2.UnitY;
            }
            else
            {
                if (depth.X > 0) normal = Vector2.UnitX; else normal = -Vector2.UnitX;
            }

            if (Math.Abs(depth.X) > Math.Abs(depth.Y))
            {
                return new Vector2[2] { new Vector2(0, depth.Y), normal };
            }
            else
            {
                return new Vector2[2] { new Vector2(depth.X, 0), normal };
            }
        }

Hope I could help, Phil


Once that's working, look into ways to display objects on the screen based on camera position without affecting the game world co-ordinates of the objects.

I actually got this feature to work already. The object x and y coordinates technically don't change even when the user presses the key. What changes is the camera x and y. The object are drawn relative to the camera coordinates.

psuedo code:

block.getImage(x - camera.getX(), y - camera.getY(),getWidth(), getHeight() );

I don't know whether I understood you right, but I think you need to do is intersection resolving. When your moving rectangle collides with the static (and it is not important from which side) you need to find out how deep and from what direction they overlap to push it out so that they are next to each other perfectly aligned but not penetrating.

The code for is tricky. I took it from the XNA's platformer example and modified it a bit. I have not tested the normal it outputs but the rest should work perfectly:


/// <returns>Depth of intersection relative to rectA</returns>
        public static Vector2 GetIntersectionDepth(Rectangle rectA, Rectangle rectB)
        {
            float halfWidthA = rectA.Width / 2f;
            float halfHeightA = rectA.Height / 2f;
            float halfWidthB = rectB.Width / 2f;
            float halfHeightB = rectB.Height / 2f;

            Vector2 centerA = new Vector2(rectA.Left + halfWidthA, rectA.Top + halfHeightA);
            Vector2 centerB = new Vector2(rectB.Left + halfWidthB, rectB.Top + halfHeightB);

            float distanceX = centerB.X - centerA.X;
            float distanceY = centerB.Y - centerA.Y;
            float minDistanceX = halfWidthA + halfWidthB;
            float minDistanceY = halfHeightA + halfHeightB;

            if (Math.Abs(distanceX) >= minDistanceX || Math.Abs(distanceY) >= minDistanceY)
                return Vector2.Zero;

            float depthX = distanceX > 0 ? minDistanceX - distanceX : -minDistanceX - distanceX;
            float depthY = distanceY > 0 ? minDistanceY - distanceY : -minDistanceY - distanceY;
            return new Vector2(depthX, depthY);
        }

        /// <returns>[0] position to add to B [1] normal</returns>
        public static Vector2[] ResolveIntersection(Rectangle rectA, Rectangle rectB)
        {
            Vector2 depth = GetIntersectionDepth(rectA, rectB);
            Vector2 normal;

            if (Math.Abs(depth.X) > Math.Abs(depth.Y))
            {
                if (depth.Y > 0) normal = Vector2.UnitY; else normal = -Vector2.UnitY;
            }
            else
            {
                if (depth.X > 0) normal = Vector2.UnitX; else normal = -Vector2.UnitX;
            }

            if (Math.Abs(depth.X) > Math.Abs(depth.Y))
            {
                return new Vector2[2] { new Vector2(0, depth.Y), normal };
            }
            else
            {
                return new Vector2[2] { new Vector2(depth.X, 0), normal };
            }
        }

Hope I could help, Phil

Thanks Phil for the code! I managed to fix the bug in my code.

I recommend never involving the camera with object coordinates. What if you want to change the perspective of the camera later? Or rotate it?

I recommend never involving the camera with object coordinates. What if you want to change the perspective of the camera later? Or rotate it?

Involving the camera with object coordinates as in what scenarios? I'm not storing the coordinates into the camera if that is what you are saying.

The game objects do retain their instantiated x and y coordinates. It is only drawn respect to the camera coordinates just to give the "illusion that the coordinates were changed."

So what I am actually doing is something like this in Java for drawing with respect to a 2D camera system.


g.drawImage(block.getImage(), getX() - camera.getX(), getY() - camera.getY(),null);

This topic is closed to new replies.

Advertisement