per pixel collision

Hi, I was just curious if anyone might know how to impliment per pixel collision into a project? I'm making a game for my A level Computer Science course - it's c# Monogame. The per pixel code is in each class that needs it, but how would I go about implimenting it in the game itself, and furthermore, should I put the code in a globals class instead? Thanks for any help in advance. I've attached screenshots of my code and where it needs to be used.
No description
64 Replies
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
to add to this, I need 3 kinds of collision responses - one for collectables, one to move the player position and one for enemies. I'll attach an image of the game to show what I mean
No description
TheRanger
TheRanger2mo ago
and you want the 3 of them to collide by pixel?
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
yeah, I need the three collision responses to respond to per-pixel collision detection
TheRanger
TheRanger2mo ago
well for the enemy, first you have to check if the player's rectangle is intersecting with the enemy's rectangle in line 199 it seems ur trying to check if the player's rectangle is intersecting with itself
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
yeah i think i am, i'm a bit confused on the logistics of implimenting it between multiple objects if that makes sense?
TheRanger
TheRanger2mo ago
yeah i get what u mean well first lets start with the enemy
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
okay one second, i i'll take a screenshot of the enemy collision code in the class itself
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
i used the exact same code for the enemy as seen here
No description
TheRanger
TheRanger2mo ago
first try not to allocate a new array every time, this will affect the performance of your game you should only allocate the array once, and add its color data
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
okay, so should i put the array outside of the bool method and call it in the method?
TheRanger
TheRanger2mo ago
this is monogame right? the colors of the sprites are already stored when you load them
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
ohh okay, i didn't know that. for added context all my knowledge has come off tutorials and whatnot, we were given no beforehand knowledge of the engine. this is my first project also. so should i remove the array entirely?
TheRanger
TheRanger2mo ago
yeah what is EnemyTXTR?
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
its the texture for the enemy that the animation is drawn onto
TheRanger
TheRanger2mo ago
is its type Texture2D ?
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
yes it is
Mango lol
Mango lol2mo ago
i hear ya brother!
TheRanger
TheRanger2mo ago
yeah the colors of ur enemy are already stored in that instance of a class
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
okay, i'll remove the colour data from the method then and try and rewrite it
TheRanger
TheRanger2mo ago
u can probably access the colors directly
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
okay, i'll try that
TheRanger
TheRanger2mo ago
hmm seems u cant do that in monogame 😒 then have the Color[] as a field or theres a better way use a bool array each Color represents 4 bytes, we dont need to store 4 bytes in every element of the array, we can store only 1 byte for every element we can use a bool array of trues and falses you only need to check if there's a pixel in this position of the image or not with that way you will save alot of memory allocations for your RAM
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
okay thank you! i'll give that a go and see what I can do 🙂 thanks!
TheRanger
TheRanger2mo ago
remember, store it as a field instead of a local variable so u can only initialize it once
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
i will thanks so much for your help!
TheRanger
TheRanger2mo ago
to greatly enhance maintability its better to encapsulate it in a class
public class TexturePixelCollision
{
bool[] _pixels;
int width;
int height;
public TexturePixelCollision(Texture2D texture)
{
var colors = new Color[texture.Width * texture.Height];
texture.GetData(colors); // store the colors of the texture into this array
_pixels = new bool[colors.Length];

for(int i = 0; i < colors.Length; i++)
{
if (colors[i].A > 0)
{
_pixels[i] = true;
}
}
width = texture.Width;
height = texture.Height;
}

// methods you can put for accessing pixels
public bool HasPixel(int x, int y)
{
return _pixels[y * width + x];
}
}
public class TexturePixelCollision
{
bool[] _pixels;
int width;
int height;
public TexturePixelCollision(Texture2D texture)
{
var colors = new Color[texture.Width * texture.Height];
texture.GetData(colors); // store the colors of the texture into this array
_pixels = new bool[colors.Length];

for(int i = 0; i < colors.Length; i++)
{
if (colors[i].A > 0)
{
_pixels[i] = true;
}
}
width = texture.Width;
height = texture.Height;
}

// methods you can put for accessing pixels
public bool HasPixel(int x, int y)
{
return _pixels[y * width + x];
}
}
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
this is really heplful thank you so much! I'll trace it through so i fully understand and use it as reference when i rewrite it!
TheRanger
TheRanger2mo ago
for the intersection part u only need to loop on the intersecting pixels between the 2 rectangles, no need to loop on the entire pixels of an object
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
okay so, if i make the class static so i can acess it from anywhere, if i then feed in my objects in the gamestate class and set up what I want to happen if they return true, that should work?
TheRanger
TheRanger2mo ago
what class? the one i provided?
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
yes that one
TheRanger
TheRanger2mo ago
no? each texture has its own pixel collision sonic has his own texture, egg pawn has its own
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
so should I just write what I want to happen when the rectangles collide in the classes or in the state they're used in?
TheRanger
TheRanger2mo ago
what do u mean by state
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
hold on let me show you
TheRanger
TheRanger2mo ago
does sonic have multiple textures? ie running textures, jumping texture, etc...
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
in this project i have states that are swapped between and the gamestates are where the objects will interact
No description
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
yes he does, all the objects are animated
TheRanger
TheRanger2mo ago
yeah and each texture has its own color data
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
i'll show you how i did animations, i created a list for them in the globals class i have, one second
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
No description
TheRanger
TheRanger2mo ago
what is the type of _animations well anyway this is monogame im sure ur using spritebatch
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
its the pass in of the animation class, the animation class sets the properties like frame width, height, speed etc yes i use that to draw my objects
TheRanger
TheRanger2mo ago
u have alot to fix later your code is a bit messy
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
yeah i know like i said this is the first project im working on so im still learning lol
TheRanger
TheRanger2mo ago
ur gonna have to initialize this for each sprite is each frame, say for the running animation, stored in each texture or are all the frames of that animation stored in a single texture?
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
they're stored in one texture i believe, i used sprite sheets and essentially it cycles to the next x co-ordinate corresponding to the speed of the animation if that makes sense?
TheRanger
TheRanger2mo ago
ok show me the class of _animations
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
okay one second
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
No description
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
thats the animation class, as i said _animation is the pass in for this class
TheRanger
TheRanger2mo ago
the type of _animations is it a dictionary? i assume its Dictionary<string, Animation> correct?
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
yes it is
TheRanger
TheRanger2mo ago
show me the Play method of _animationManager so its a sprite sheet ok then this wont work, we're gonna have to do some changes
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
No description
TheRanger
TheRanger2mo ago
ur gonna have to initialize the bool array for each sprite
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
okay, i'll try that
TheRanger
TheRanger2mo ago
i never coded the animation class this way i just create a class called Sprite and store its position and size :when: greater maintability, and readability also judging by your animation it seems all the sprites in the sprite sheet are stored in the same row its better to create a class called Sprite or Frame
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
okay, thank you, i'll try and fix it by doing that
TheRanger
TheRanger2mo ago
it should be easy to fix and it will be easy to access too and it should be fine to store the pixel collision array into it
public class Sprite
{
public Rectangle rectangle; // location of the sprite and its size in the texture
bool[] _pixelCollision;

// constructor and some useful methods

public void InitializePixelCollisionArray(Texture2D texture)
{
Color[] colors = new Color[texture.Width * texture.Height];
_pixelCollision = new bool[colors.Length];


texture.GetData(0, rectangle, colors, 0, colors.Length); // gets the colors of the area indicated by the rectangle

for(int i = 0; i < _pixelCollision.Length; i++)
{
if (colors[i].A > 0)
{
_pixelCollision[i] = true;
}
}
}

// methods you can put for accessing pixels
public bool HasPixel(int x, int y)
{
return _pixelCollision[y * rectangle.Width + x];
}
public bool HasPixel(Vector2 vec)
{
return HasPixel(vec.X, vec.Y);
}
}
public class Sprite
{
public Rectangle rectangle; // location of the sprite and its size in the texture
bool[] _pixelCollision;

// constructor and some useful methods

public void InitializePixelCollisionArray(Texture2D texture)
{
Color[] colors = new Color[texture.Width * texture.Height];
_pixelCollision = new bool[colors.Length];


texture.GetData(0, rectangle, colors, 0, colors.Length); // gets the colors of the area indicated by the rectangle

for(int i = 0; i < _pixelCollision.Length; i++)
{
if (colors[i].A > 0)
{
_pixelCollision[i] = true;
}
}
}

// methods you can put for accessing pixels
public bool HasPixel(int x, int y)
{
return _pixelCollision[y * rectangle.Width + x];
}
public bool HasPixel(Vector2 vec)
{
return HasPixel(vec.X, vec.Y);
}
}
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
thank you this is really useful to look at, i'll compare this to the one i write myself. Thanks so much for your help!
TheRanger
TheRanger2mo ago
public bool PerPixelCollision(LandEnemy eggpawn)
{
// get their sprite based on their current frame in their current animation
var sonicsCurrentSprite = GetSprite();
var eggpawnsCurrentSprite = eggpawn.GetSprite();

// their rectangle in world space whose size should be the same as their current sprite's size
var sonicsRectangle = GetRectangle();
var eggpawnsRectangle = GetRectangle();

// no intersection, return false
if (!sonicsRectangle.Intersects(eggpawnsRectangle))
{
return false;
}

// get the new rectangle that contains overlapping region of two other rectangles.
var intersectedRectangle = Rectangle.Intersect(sonicsRectangle, eggpawnsRectangle);

for(int y = intersectedRectangle.Top; y <= intersecretRectangle.Bottom; y++)
{
for(int x = intersectedRectangle.Left; x <= intersecretRectangle.Right; x++)
{
// do some math to get the local coordinates of x,y in their rectangle (the method below doesnt exist, you can create one as an extension method for the Rectangle class or put it in a static class and call it RectangleUtility)
Vector2 sonic = sonicRectangle.GetLocalPosition(x, y);
Vector2 enemy = eggpawnsRectangle.GetLocalPosition(x, y);

if (sonicsCurrentSprite.HasPixel(sonic) && eggpawnsCurrentSprite.HasPixel(enemy))
{
return true;
}
}
}
return false;
}
public bool PerPixelCollision(LandEnemy eggpawn)
{
// get their sprite based on their current frame in their current animation
var sonicsCurrentSprite = GetSprite();
var eggpawnsCurrentSprite = eggpawn.GetSprite();

// their rectangle in world space whose size should be the same as their current sprite's size
var sonicsRectangle = GetRectangle();
var eggpawnsRectangle = GetRectangle();

// no intersection, return false
if (!sonicsRectangle.Intersects(eggpawnsRectangle))
{
return false;
}

// get the new rectangle that contains overlapping region of two other rectangles.
var intersectedRectangle = Rectangle.Intersect(sonicsRectangle, eggpawnsRectangle);

for(int y = intersectedRectangle.Top; y <= intersecretRectangle.Bottom; y++)
{
for(int x = intersectedRectangle.Left; x <= intersecretRectangle.Right; x++)
{
// do some math to get the local coordinates of x,y in their rectangle (the method below doesnt exist, you can create one as an extension method for the Rectangle class or put it in a static class and call it RectangleUtility)
Vector2 sonic = sonicRectangle.GetLocalPosition(x, y);
Vector2 enemy = eggpawnsRectangle.GetLocalPosition(x, y);

if (sonicsCurrentSprite.HasPixel(sonic) && eggpawnsCurrentSprite.HasPixel(enemy))
{
return true;
}
}
}
return false;
}
☆ nubbs ☆
☆ nubbs ☆OP2mo ago
thank you so much for your help 🙂
TheRanger
TheRanger2mo ago
i need to go, maybe we continue tomorrow
Want results from more Discord servers?
Add your server