Pixel Collision with Resized Sprites

My game uses a pixel art style, and therefore, all the sprites I’ve made are as low resolution as I can make them (e.g. the sprite for the button to open the inventory is actually 18x17 pixels).
I am, however, having a lot of trouble with per-pixel collision however, as when I get the spritedata of the Texture2D, it fills a Color array of the original Texture2D bounds, when the in-game resized sprite may be 105x100 pixels.

My question is how I can make my pixel collision work with there resized sprites (each sprite has a float linear scale factor that is added during the drawing process).
This is my first post on here so please tell me if I’ve missed anything out or you’d like more information.

Welcome!

This looks alot like my first post, if I’m understanding you correctly.

Dont resize the sprites one by one, keep everything the original size. Do all the collision and whatever you need. But instead of render everything to the screen you do it a new texture a RenderTarget2D and lastly scale the entire game up to the resolution you want?

If I misunderstood you problem I a polagise

Thanks for the welcome!

This is probably down to me not explaining well enough.
The issue is that everything is resized by different amounts, so a player sprite may have a scale factor of 50f and the bag, a scale factor of 100f. Essentially, each sprite has their own native size, and their own desired resize value.

I can’t do collision testing with the original sprite sizes since they’re not uniform, basically.

Thank you for reading.

I definitely agree with Gronk in that it’s much easier to deal with everything in world coordinates. You may well have different scale factors for different sprites in the world, but it’s still easier to take a single input coordinate (ie, mouse or touch location) and transform that to world coordinates than it is to transform every object in your game into screen coordinates to compare against the input location.

Either way, you’ll have to transform the sprite bounds to their world size. You should be able to do this by just multiplying the size by the scaling factor when you do your collision test. Do keep in mind your sprite’s local origin (ie, the top-left, centre, etc…).

Basically, calculate the scaled bounds for your sprite.

I have calculated the scaled bounds for my sprite, however when I use the sprite.GetData(), it populates the Color array with the original-sized sprites, and I can’t find a way to resize this. For example, with the bag sprite, it populates the Color array with 18x17 values. However, I want it to fill in the Color array with 105x100 values, since that’s what I’ve resized it to.
Hopefully that makes sense.
(also, everything is already dealt with in world coordinates)

Oh right, you said you wanted to do pixel perfect collision. You’ll have to scale the sprite data up to the new size. The easiest way is probably a render target. Create a render target at your scaled size, then use a SpriteBatch to draw the scaled sprite to the render target. Note that a render target is effectively a texture and you can use GetData from that.

You maaaaaaay want to reconsider pixel perfect collision in this way though. It’s going to be expensive, not only to generate those scaled textures, but to do the actual collision detection. If your scales never change at runtime you can probably precache the scaled data, but I have a feeling this might not be the case.

Instead, perhaps you might consider other collision detection alternatives. The easiest are bounding rectangle or bounding sphere, which I suspect you might already be using to even decide if you want to do pixel perfect collision. These can often be good enough on their own, but they certainly are imprecise. For a little more precision without sacrificing a ton of performance, bounding polygons could be useful.

Anyway, you gotta do what you gotta do, but just throwing that out there :slight_smile:

Ah okay thank you very much. My college was the one to teach me Monogame and they did a godawful job at it, so I don’t really know what a render target is.
Also, I appreciate the recommendation for using alternative collision methods however this is for a college project where “you need complex algorithms” is the focus, so that’s why I’m wasting my time with pixel perfect collision.

Thank you for your help.

lol, fair enough… good luck!

1 Like

Is there any place I can understand how to use a RenderTarget2D?
Reading into it on various websites and forums is giving me a headache lol.

Just scale down the coordinates you use for looking for a collision.

in a simple form:

public void Draw(GameTime gameTime)
{
   graphicsDevice.SetRenderTarget(renderTarget2D); //Makes you draw to rendertarget insted of screen.
   
   spriteBatch.Begin();
      //spriteBatch.Draw the game unscaled
   spriteBatch.End();

   graphicsDevice.SetRenderTarget(null); //Makes you draw to the screen buffer

   spriteBatch.Begin();
     //spriteBatch.Draw the renderTarget2D in whatever scale you want.
   spriteBatch.End();
}

This wont help you with the problem of scaling a collision data in an array. What we are all saying is to make the problem go away by not scaling the data. I may be wrong but i wouldn’t manipulate the data like this it sounds… strange.

in my experience the “complex algorithms” in games are an illusion. Simplifying the problem, cheating and moving away from complexity is my way of doing game programming :slight_smile:

If the scale of your sprites don’t change between frames eg. your scale factor is static once the game is running i would consider drawing them in the correct scale to start with. You could still keep things smal just think of everything in multiples of 2 if this make sens. This way the artist will have better control over how things look in the end as well. So your problem becomes how can i in the simplast way possible make everything the same scale i want.

if your sprites do change scale during the game you have to resample collision data every frame as you need it to be pixel perfect. This calls for more cheating… i would go the way @Trinith suggests with hit boxes and try to make my graphics so simple that it will be pixel perfect by using the minimal number of rektangels.

One example as your sprits, as you say, are super smal maybe one rectangle per pixel row isn’t that expensive. It all depends on the number of sprites you draw or if the scale between the smallest and the biggest sprite. Your class assignment of “using complex algoritms” could be about scaling x number of bounding boxes to the scale factor of the sprite. Its maybe a stupid idea but this sounds simpler to me then trying to figure out the math to scale an array.

Unfortunately the use of per pixel collision is non-negotiable, however I do understand what you’re saying and when I eventually do program my own game outside of this college thing I will definitely use the simpler tricks and the tips you’ve told me. lol

Quick question about RenderTarget2D: is each sprite it’s own render target? Or is the entire screen a render target?
Basically, if I draw the game unscaled then there’s going to be a sword twice the length of the player sprite. If I spriteBatch.Draw the renderTarget2D in whatever scale I want, then I’m going to need to rescale every sprite.

A rendertarget2d is the same as a texture2d

So to draw to a rendertarget set the graphicsdevice render target to the render target you want to draw to.

Then spritebatch will draw to that target

To draw to your main buffer set the render target to null

To draw a rendertarget as a texture in your spritebatch.draw just select the rendertarget as the texture

If your planning on drawing onto the same rendertargrt again without it getting wiped you need to set preserve contents in the rendertarget constructor

1 Like