Search code examples
javascriptcollision-detectiongetimagedataradial

Detect radial Pixel


I Wan't to check the collision from radial Elements.

The Problem is, currently i check only the pixels as an rectangle because the other images are native with HTML-Elements.

I'm only using the canvas to draw the boundary background to check the alpha-transparency.

this.checkCollision = function checkCollision() {
    var width   = 34;
    var height  = 32;
    var image   = _context.getImageData(_position.x - (height / 2), _position.y - (width / 2), width, height);
    var pixels  = image.data;
    var size    = image.data.length;

    // HERE I WANT TO CHECK A RADIAL AREA
    for(var index = 0; index < size; index += 4) {
        var RED     = image.data[index];
        var GREEN   = image.data[index + 1];
        var BLUE    = image.data[index + 2];
        var ALPHA   = image.data[index + 3];

        if(_debug) {
            document.querySelector('#debug').innerHTML = JSON.stringify({
                POSITION:   _position,
                INDEX:      index,
                COLOR: {
                    R:  RED,
                    G:  GREEN,
                    B:  BLUE,
                    A:  ALPHA
                }
            }, 0, 1);
        }

        if(ALPHA !== 0) {
            return true;
        }
    }
    _context.putImageData(image, 0, 0);
    return false;
};

Preview

enter image description here

Here is a working Fiddle:

https://jsfiddle.net/2bLfd6xp/

How i can select a radial pixel range on getImageData to check the collision with the alpha-transparency from the boundary.png?

My idea is to modify the pixel data array from here:

var image   = _context.getImageData(_position.x - (height / 2), _position.y - (width / 2), width, height);

and remove the invisible edges. But what is the best practice to calculate from an rectangle based pixel array an radial area to remove these unwanted pixels?

For sample:

var image   = _context.getImageData(_position.x - (height / 2), _position.y - (width / 2), width, height);

var radial_area = selectRadialArea(image, radius);

function selectRadialArea(pixelArray, radius) {
   /*
      Modify `pixelArray` with given `radius`...
      All pixels outside the `radius`  filled with `null`...
   */
   return theNewArray;
}

Solution

  • I've found the answer with logical thinking:

    First, we create a temporary drawable context and draw in this new area two elemengts:

    • an red rectangle
    • an transparent arc/circle with an destination-composite

    The resulted Uint8ClampedArray will be compared with the original Uint8ClampedArray. If the area is RED, we hide the pixels with null-entries:

    this.rectangleToRadial = function rectangleToRadial(source, width, height) {
        var test        = document.createElement('canvas');
        var context     = test.getContext('2d');
    
        // Create an transparent circle and a red removeable area
        context.beginPath();
        context.fillStyle = 'rgba(255, 0, 0, 1)';
        context.fillRect(0, 0, width, height);
        context.globalCompositeOperation = 'destination-out';
        context.arc(width / 2, height / 2, width / 2, 0, 2 * Math.PI);
        context.fillStyle = 'rgba(0, 0, 0, 1)';
        context.fill();
    
        // get the data
        var destination = context.getImageData(0, 0, width, height);
        var size        = destination.data.length;
    
        // check the pixels
        for(var index = 0; index < size; index += 4) {
            var RED     = destination.data[index];
            var GREEN   = destination.data[index + 1];
            var BLUE    = destination.data[index + 2];
            var ALPHA   = destination.data[index + 3];
    
            /*
                if the >>red removeable area<< is given, null the pixel from the source
            */
            if(RED == 255 && GREEN == 0 && BLUE == 0) {
                // Remove this from source
                source.data[index]      = null;
                source.data[index + 1]  = null;
                source.data[index + 2]  = null;
                source.data[index + 3]  = null;
            }
        }
    
        // Return the source `Uint8ClampedArray`
        return source;
    };
    

    It was easy, when we try to think :)

        var image   = _context.getImageData(_position.x - (height / 2), _position.y - (width / 2), width, height);
        var pixels  = this.rectangleToRadial(image, width, height);