davidfig / pixi-viewport

A highly configurable viewport/2D camera designed to work with pixi.js
https://davidfig.github.io/pixi-viewport/
MIT License
1.04k stars 174 forks source link

Force to round values of hitArea when wheel or drag #156

Open serbol opened 5 years ago

serbol commented 5 years ago

I need to round x, y, worldScreenWidth and worldScreenHeight value on drag and wheel. Are there any opportunities to perform it?

Currently on zoom end or drag end I get something like this : { height: 646.6777064089624, width: 862.2369418786166, x: 6.126561955558547e-14, y: 6.126561955558547e-14, }

But I want this: { height: 647, width: 862, x: 6, y: 6, }

davidfig commented 5 years ago

Try something like this:

    function round()
    {
        viewport.x = Math.round(viewport.x)
        viewport.y = Math.round(viewport.y)
        viewport.width = Math.round(viewport.width)
        viewport.height = Math.round(viewport.height)
    }

    viewport.on('moved-end', round)
    viewport.on('zoomed-end', round)
serbol commented 5 years ago

Works fine on moved-end, but not on zoomed-end. Seems like there is no way to round viewport width or/and height.

davidfig commented 5 years ago

Hmmm...I checked the code, and I think the issue is with Math.round and the precision of rounding floating numbers.

If you add a console.log at the start and end of the round() function, you see that Math.round is being called on the width/height. You can find info and workarounds here: https://stackoverflow.com/questions/1458633/how-to-deal-with-floating-point-number-precision-in-javascript

Good luck!

serbol commented 5 years ago

Actually, for me viewport.width === worldWidth? Is that ok? I think this parameter - worldScreenWidth need to be rounded.

davidfig commented 5 years ago

Ah, that may be a problem. worldScreenWidth is calculated, not directly set:

get worldScreenWidth
{
    return this.screenWidth / this.scale.x
}

You can reverse it and solve for this.scale.x to find the right value to round, but that likely will result in a floating point precision problem. Why does it need to be rounded?

serbol commented 5 years ago

When I render a tiled-map I use container with sprites. One square sprite for each tile. On zoom in or zoom out I always get this net:

Screen Shot 2019-08-27 at 10 41 13 AM

That's because of float values for viewport width, height, x, y.

davidfig commented 5 years ago

I'm not sure I follow. The viewport is over the entire map. Why would its float value impact the locations of the sprites within containers within the viewport?

Just a thought: have you tried to extrude your sprite textures? I sometimes saw this issue when working with pixel graphics. I fixed it by extruding my textures (there's usually an option in your sspritesheet generator). Extruding pushes the color past the texture's edges so there's an extra pixel to work with when the scale changes.

serbol commented 5 years ago

I had this function to create map:

const createMapSprite = mapData => {
    const mapContainer = new PIXI.Container();
    const tileSetImage = PIXI.Texture.from('/map/desert.png');
    let row, col, sprite, texture;
    mapData.layers.forEach(layer => {
        if(layer.type == 'tilelayer') {
            row = 0;
            col = 0;
            layer.data.forEach(index => {
                if(index > 0) {
                    texture = new PIXI.Texture(tileSetImage, new PIXI.Rectangle(getSourceX(index), getSourceY(index), mapData.tilewidth, mapData.tileheight));
                    sprite = new PIXI.Sprite(texture);
                    sprite.x = col * mapData.tilewidth;
                    sprite.y = row * mapData.tileheight;
                    mapContainer.addChild(sprite);
                }
                col++;
                if(col > (mapData.width - 1)) {
                    col = 0;
                    row++;
                }
            });
        }
    });

    return mapContainer;
};

Then I performed:

const mapCanvas = createMapSprite(desertMap);
viewport.addChild(mapCanvas);

I solved this issue by updating this line: sprite = new PIXI.Sprite(texture); -> sprite = new PIXI.TilingSprited(texture, mapData.tilewidth, mapData.tileheight);

But appeared freezes on move :-(

Ok, anyway, will try to play with sprite parameters.