Confine Game Objects to Screen (Accounting for Rotation) [SOLVED]

So I recently wanted to confine a game object to the screen, i.e. so that it is not able to leave it. The way that I know how to do this is to simply get the width and height of the screen and compare it with the object’s position to set the position accordingly. In addition, one should get half the size of the game object (I do that by getting the size of the sprite multiplied by the game objects scale factor) and add that to their calculations so that the object is fully on the screen and not only half of it. Which is where my problem takes place.

The objects that I want to confine are created through a factory and can have an arbitrary rotation applied to them. As soon as the applied rotation is not zero the confining method is less effective. And I’m sure this is the case because I’m only capable of getting the object’s width and height through the sprite size, but this size does not represent the correct width and height of the game object after applying a rotation to it. You could say I’m looking for a way to acquire width and height as a variable from a game object by relying on something like a bounding box rather than a sprite. Is there some way to achieve this in Defold or an alternative?

One thing that comes to mind is to use collision shapes and physics to detect when you hit the edge. Create a barrier of static box shapes around the screen and a kinematic shape on the object.

1 Like

Alright thanks, that’s what I’m currently doing, i.e. receive the contact points normal and collision and push my object towards this direction according to the distance stored in the contact point response message. Though I did combine this with the screen clamping functionality as it was possible to just overshoot the colliders and go offscreen if one dragged their object for long enough.

So I guess there is no way of getting an objects accurate size independent of their sprite?

This is a bit hard to define to be honest. For a rectangular sprite it’s fairly easy, but what if the game object has particle effects or other visual components? Sure, we could look at the bounding box of what is being rendered but this is highly dependent on your render script and it is not information that the engine has access to on a script level.

But for a sprite you can get the rotation and size so that should be enough?

1 Like

To me it sounds like you want to convert an OBB (oriented bounding box) to a AABB (axis aligned bounding box. It comes down to calculating the max extents of the OBB projected to each principal axis. There should be materials online that will explain the process.

3 Likes

I see, that makes sense. In case of a sprite this wouldn’t be enough as the dimensions of the sprite don’t change when rotating. If I have a rectangle that is 200 units wide and 100 units high, its width will stay the same even if I rotate it by 90°, in which case I would expect its width to be 100 units instead. But I can see how that is not achievable with the sprite size.

Allright! Sounds like what I used in Unity (getting the bounds/extends of a collider). For now I’ll stick with the collision solution that @britzl suggested, as it already works. Though I’ll look into it when I get the time. :slight_smile:

I’ll mark the thread as solved for now.

3 Likes

Small addendum.

This was indeed enough, I just wasn’t aware of how to use these values to get what I want. But this answer on StackOverflow contained a working solution.

So all one has to do to get the bounding box of a rotated game object is the following:

	height = height * math.abs(math.sin(rot)) + width * math.abs(math.cos(rot))
	width = width * math.abs(math.sin(rot)) + height * math.abs(math.cos(rot))

Where the ‘height’ and ‘width’ are retrieved from getting a sprites size property and ‘rot’ being the ‘euler.z’ value of the game object (in radians). With these values one can confine game objects (independent of rotation) to a screens dimension, by doing the usual position check and adding an objects size on top.

5 Likes