I have drawn a line. That’s not very spectacular, I know
I wanted to get that line into a staticGroup. But all I managed was to generate a texture out of it and then use that in the staticGroup. Then it was able to use the overlap function. (this.physics.add.overlap(player, spriteLine)
Here is my code:
lines = this.add.graphics();
lines.lineStyle(3, ‘black’, 1);
lines.lineBetween(0, 0, 0, 150);
lines.generateTexture(‘myLine’, 3, 150);
spriteLine = this.physics.add.staticGroup();
spriteLine.create(200, 500, ‘myLine’);
lines.destroy();
My question: is it possible to make that line get an overlap without that texture generation?
Since Graphics objects are just a set of commands that draw something, they don’t have an intrinsic size and you can’t put a physics body on them. You can work around this by adding x, y, displayWidth, and displayHeight properties to the Graphics object to let the physics engine work with it.
My recommendation, however, would be to use one of the shape objects - such as a line or a rectangle. They’re more efficient than Graphics objects and you don’t need workarounds to add physics to them.
That interesect looks interesting.
And I found a phaser function that should work even with a circle.
I just have to figure out how to use it.( Especially with my physical melon that phaser thinks is a rectangle … because phaser is seeing transparent pixels! )
<static> LineToCircle(line, circle [, nearest])
Checks for intersection between the line segment and circle.
I want to, but I simply cannot do it at the moment.
I just cannot code it.
It makes no sense for me and therefore I have a block in my head.
When I have a function that can detect an overlap, why doesn’t it work only for non-transparent pixels? It seems to be a flaw of the whole framework …
In my head it makes much more sense to use inline svg, too.
All any overlap does is a rectangle intersect. So it is not interested in color per pixel.
It has nothing to do with the framework. Per pixel collision is rarely used, because it’s rarely necessary. In your case however…
Let’s try to have it make more sense.
From the example (in C#):
static bool PerPixelCollision(Sprite a, Sprite b)
{
// Get Color data of each Texture
Color[] bitsA = new Color[a.Texture.Width * a.Texture.Height];
a.Texture.GetData(bitsA);
Color[] bitsB = new Color[b.Texture.Width * b.Texture.Height];
b.Texture.GetData(bitsB);
// Calculate the intersecting rectangle
int x1 = Math.Max(a.Bounds.X, b.Bounds.X);
int x2 = Math.Min(a.Bounds.X + a.Bounds.Width, b.Bounds.X + b.Bounds.Width);
int y1 = Math.Max(a.Bounds.Y, b.Bounds.Y);
int y2 = Math.Min(a.Bounds.Y + a.Bounds.Height, b.Bounds.Y + b.Bounds.Height);
// For each single pixel in the intersecting rectangle
for (int y = y1; y < y2; ++y)
{
for (int x = x1; x < x2; ++x)
{
// Get the color from each texture
Color a = bitsA[(x - a.Bounds.X) + (y - a.Bounds.Y)*a.Texture.Width];
Color b = bitsB[(x - b.Bounds.X) + (y - b.Bounds.Y)*b.Texture.Width];
if (a.A != 0 && b.A != 0) // If both colors are not transparent (the alpha channel is not 0), then there is a collision
{
return true;
}
}
}
// If no collision occurred by now, we're clear.
return false;
}
I’ve changed the sprite origins to make the calculations a bit more obvious, so the images are a bit out of place.
This is what’s new:
player = this.physics.add.sprite(p_x, p_y, 'melon').setOrigin(0);
barrier = this.physics.add.sprite(barrier_x, barrier_y, barrier_pic).setOrigin(0);
this.physics.add.overlap(player, barrier,
function overlap(player, barrier) {
this.scene.start('sceneA');
},
function process(player, barrier) {
// Calculate the intersecting rectangle
x1 = Math.max(Math.round(player.x), barrier.x);
x2 = Math.min(Math.round(player.x) + player.width, barrier.x + barrier.width);
y1 = Math.max(Math.round(player.y), barrier.y);
y2 = Math.min(Math.round(player.y) + player.height, barrier.y + barrier.height);
// For each pixel in the intersecting rectangle
for (y = y1; y < y2; ++y)
for (x = x1; x < x2; ++x) {
// Get the color from both textures
colorPlayer = canvasPlayer.getPixel(x - Math.round(player.x), y - Math.round(player.y));
colorBarrier = canvasBarrier.getPixel(x - barrier.x, y - barrier.y);
// If both colors are not transparent (the alpha channel is not 0), then there is a collision
if (colorPlayer.a != 0 && colorBarrier.a != 0) return true;
}
return false;
},
this
);
if (typeof canvasPlayer == "undefined") {
src_player = this.textures.get('melon').getSourceImage();
canvasPlayer = this.textures.createCanvas('canvasPlayer', src_player.width, src_player.height);
canvasPlayer.draw(0, 0, src_player);
}
src_barrier = this.textures.get(barrier_pic).getSourceImage();
this.textures.remove('canvasBarrier');
canvasBarrier = this.textures.createCanvas('canvasBarrier', src_barrier.width, src_barrier.height);
canvasBarrier.draw(0, 0, src_barrier);
I create 2 canvases, draw the player and level images on them, and then use getPixel to check the alpha (transparency) for each corresponding pixel in the intersecting rectangle.
I will go through that in detail and try to find out what each thing does.
I mean I have a hunch about most things, but I need to look at that in detail.
If you use getPixel directly on a texture, this happens for every pixel:
ctx.clearRect(0, 0, 1, 1);
ctx.drawImage(textureFrame.source.image, x, y, 1, 1, 0, 0, 1, 1);
var rgb = ctx.getImageData(0, 0, 1, 1);
So for performance reasons, you want to get all the pixel data only once, by creating a canvas, and drawing the texture on it. You can then directly access the data as an array.
This is all a canvas getPixel does:
var data = this.data;
var r = data[index + 0];
var g = data[index + 1];
var b = data[index + 2];
var a = data[index + 3];
I try to add a rectangle to a static group. How to make it?
function create() {
const ground = this.add.rectangle(361, 348, 721.35, 48.4, 0xcccccc);
ground.setStrokeStyle(1, 0xff0000);
platforms = this.physics.add.staticGroup();
// How to add a ground to a static Group?
}