dittofittoe Posted July 19, 2021 Share Posted July 19, 2021 (edited) Is there anything in Pixi.js where I can read the colour data of a texture or sprite? I have a large map and instead of drawing collision lines, I want to just use an identical map but with 2 colours (magenta, alpha clear) and when the player collides with that colour pixel, it counts as a collision. Edited July 28, 2021 by dittofittoe Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted July 20, 2021 Share Posted July 20, 2021 No, there's nothing in pixi for that. You have to hack it yourself: https://github.com/pixijs/pixijs/discussions/7591 https://github.com/pixijs/pixijs/wiki/v5-Hacks#pixel-perfect-interaction Quote Link to comment Share on other sites More sharing options...
dittofittoe Posted July 20, 2021 Author Share Posted July 20, 2021 17 hours ago, ivan.popelyshev said: No, there's nothing in pixi for that. You have to hack it yourself: https://github.com/pixijs/pixijs/discussions/7591 https://github.com/pixijs/pixijs/wiki/v5-Hacks#pixel-perfect-interaction Thanks I took a look, Nothing was loading for me for the second example excapt a white square. Quote Link to comment Share on other sites More sharing options...
dittofittoe Posted July 20, 2021 Author Share Posted July 20, 2021 I get errors in the console for both examples. Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted July 20, 2021 Share Posted July 20, 2021 (edited) Someone modified those examples, they are public. Sorry, cant do much about it, you have to look in source code and find whatever is wrong there. Code looks fine, at least you know where to go Edited July 20, 2021 by ivan.popelyshev Quote Link to comment Share on other sites More sharing options...
dittofittoe Posted July 24, 2021 Author Share Posted July 24, 2021 (edited) The demos dont seem to be working for me. Edit nvm got it working,t y OK, I now get the pixel data returned as an array, how do I check for any collision with a RGB value greather than 1? (Black area is walkable, white i a block). Edited July 24, 2021 by dittofittoe Quote Link to comment Share on other sites More sharing options...
dittofittoe Posted July 28, 2021 Author Share Posted July 28, 2021 (edited) On 7/20/2021 at 11:16 PM, ivan.popelyshev said: Someone modified those examples, they are public. Sorry, cant do much about it, you have to look in source code and find whatever is wrong there. Code looks fine, at least you know where to go I have decided to take a slightly different approach. I am using this function to convert a sprite into an rgba array. function convImage(_sprite){ var imageData = app.renderer.plugins.extract.pixels(_sprite); var _red = imageData[0]; var _green = imageData[1]; var _blue = imageData[2]; var _alpha = imageData[3]; console.log(_red); console.log(_green); console.log(_blue); return imageData; } It gets converted to something but the values don't match the image, var _red, _green and _ blue (x:0 and y:0) should have the value of: 255,255,255,255, But instead it it becomes 0, 0, 0, 255. There are some white values in there but for some reason it doesn't match the image. The image shows the console output, and what x 0 and y 0 look like. Edit: added ab image of the collision map. maybe it needs to be rotated or something? As sometimes a collision is logged but in random spots, not the white parts (where collision should be be logged). Edited July 28, 2021 by dittofittoe Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted July 28, 2021 Share Posted July 28, 2021 > I am using this function to convert a sprite into an rgba array. this function estimates sprite bounds, creates renderTexture, readPixels it. that means, if you have any transform on sprite - pixi has to render it shifted. There were so many of errors in those, that we really cannot guarantee the result. Alternative: you can do renderTexture creation, bounds estimation and readPixels yourself. My advice is to actually use good old getImageData on canvas with said image, like in code i provided. Quote Link to comment Share on other sites More sharing options...
dittofittoe Posted July 28, 2021 Author Share Posted July 28, 2021 (edited) 7 hours ago, ivan.popelyshev said: > I am using this function to convert a sprite into an rgba array. this function estimates sprite bounds, creates renderTexture, readPixels it. that means, if you have any transform on sprite - pixi has to render it shifted. There were so many of errors in those, that we really cannot guarantee the result. Alternative: you can do renderTexture creation, bounds estimation and readPixels yourself. My advice is to actually use good old getImageData on canvas with said image, like in code i provided. using getImageData returns the same kind of array as I got before; Function to return sprite as array: function convImage(_sprite){ const texture = _sprite._texture; const width = texture.orig.width; const height = texture.orig.height; const baseTexture = texture.baseTexture; var _uint8array = genColorMap(baseTexture); var _red = _uint8array.data[0]; var _green = _uint8array.data[1]; var _blue = _uint8array.data[2]; var _alpha = _uint8array.data[3]; console.log(_red.data); console.log(_green.data); console.log(_blue.data); return _uint8array.data; } genColorMap function: function genColorMap(baseTex) { if (!baseTex.resource) { return false; } const imgSource = baseTex.resource.source; let canvas = null; if (!imgSource) { return false; } let context = null; if (imgSource.getContext) { canvas = imgSource; context = canvas.getContext('2d'); } else if (imgSource instanceof Image) { canvas = document.createElement('canvas'); canvas.width = imgSource.width; canvas.height = imgSource.height; context = canvas.getContext('2d'); context.drawImage(imgSource, 0, 0); } else { return false; } const w = canvas.width, h = canvas.height; baseTex.colormap = context.getImageData(0, 0, w, h); // console.log(baseTex.colormap); return baseTex.colormap; } Edit: After carefully inspecting the collision map it appears the first two pixels were black not white, I fixed the image and the pixel array is correct. Time to check some logic, I will update this with the solution. Edited July 28, 2021 by dittofittoe Quote Link to comment Share on other sites More sharing options...
dittofittoe Posted July 28, 2021 Author Share Posted July 28, 2021 (edited) Cool, so for anyone who wants to do this (I had trouble finding a source on how to do this): 1. Create 2 functions which a) Convert a sprite into an RGBA pixel array, b) convert that array into a multidimensional array seperating X and Y. I used these two functions from the link Ivan provided (slightly modified, but you need these mods for it to work) const checkPixels = (sprite) => { const texture = sprite._texture; const width = texture.orig.width; const height = texture.orig.height; const baseTexture = texture.baseTexture; genColorMap(baseTexture); const colormap = baseTexture.colormap; const data = colormap.data; const res = baseTexture.resolution; let count = 0; let tmpArr = []; let lineArr = []; const newArr = []; for(let i = 0, len = data.length; i <= len; i++){ if(count > 3){ lineArr.push(tmpArr); tmpArr = []; count = 0; } if(lineArr.length === width){ newArr.push(lineArr); lineArr = []; } tmpArr.push(data[i]) count++; } return newArr; } function genColorMap(baseTex) { if (!baseTex.resource) { return false; } const imgSource = baseTex.resource.source; let canvas = null; if (!imgSource) { return false; } let context = null; if (imgSource.getContext) { canvas = imgSource; context = canvas.getContext('2d'); } else if (imgSource instanceof Image) { canvas = document.createElement('canvas'); canvas.width = imgSource.width; canvas.height = imgSource.height; context = canvas.getContext('2d'); context.drawImage(imgSource, 0, 0); } else { return false; } const w = canvas.width, h = canvas.height; baseTex.colormap = context.getImageData(0, 0, w, h); return true; } 2. Create an array of the result of the checkPixels function, similar to this (cSprite is the sprite of my collision map): var cSpriteArray = checkPixels(cSprite); Now cSpriteArray gets the value of all the pixel data in cSprite. To correspond an index to the players position; you can call it like this: cSpriteArray[playersY][playersX][RGBA value (out of 4)] The RGBA is stored as; [0] Red [1] Green [2] Blue [3] Alpha. My collision map is just black and white, and I need to check where the player collides with a white value (basically any RGB value higher than 0); 5. Here is how I do that (simplified version just under it) - Here I am taking into account the edges of the player by adding the width/2 or height/2 because the anchor point is in the middle of the player sprite: if(this.cSpriteArray[_player.y+ _player.currentSprite.height/2][_player.x][0] > 0 || this.cSpriteArray[_player.y- _player.currentSprite.height/2][_player.x][0] > 0 || this.cSpriteArray[_player.y][_player.x+ _player.currentSprite.width/2][0] > 0 || this.cSpriteArray[_player.y][_player.x- _player.currentSprite.width/2][0] > 0){ console.log("map collision"); } simplified (not precise with the players edge: if(this.cSpriteArray[_player.y][_player.x][0] > 0){ console.log("map collision"); } I hope anyone who spends hours looking for a solution to this can find this useful GL Edited July 28, 2021 by dittofittoe Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.