cseibert

Custom Tile Collision Width

Recommended Posts

so I have a tilemap with tiles that make up a bridge (see attached image).  I'm trying to figure out if there is a way I can customize the bounds of the tiles to have the player collide only where the water starts on the tile.  I'm trying to read through the phaser3 code, but I'm not sure where it calculates the tile x, y, width, height for collision.

Is it possible for me to manually change the bounds x, y, width, height for certain tiles?  

Is there a different approach I should be using to handle these collisions (separate collision layer? modify my tiles to have the bridge almost be full width?).  One thing I have tried is just treating the tiles as 16x16 so that I can declare the water tiles with setCollision, but it seems hacky..

Screen Shot 2018-07-21 at 11.35.58 PM.png

Share this post


Link to post
Share on other sites

I think if you load the tilemap as a dynamic layer, you can loop through the tiles or something and change the body dimensions. Otherwise, use matter.js. I had a similar concern myself, I'd even set the collision boxes in tiled, but with arcade physics, you can only use plain axis aligned boxes for collision. 

The first suggestion - dynamic layer- is just a guess tho really, but as dynamic tiles have bodies and bodies can be resized, it made your only option. If you're suing tiled, you could add custom properties to the tiles you need to change, possibly even add their desired width/height as properties also so when looping you can automate the process somewhat.

Share this post


Link to post
Share on other sites

well, I have managed in my own efforts to make the collisions the right size for my needs, sadly though, collision just doesn't work for me at the minute. Cant get playergroup to collide with bounds or with these colliders i have just arranged. Anyways, here's code for making your colliding tiles a better fit.

 

        this.layer5 = this.map.createStaticLayer('WallLayer', this.tiles, 0, 0).setOrigin(0, 0);
        this.layer5.tilemap.layer.data.forEach( i =>{
            i.forEach(j =>{
                if(j.index !== -1)
                {
                    var wall = this.physics.add.sprite(j.x * 32, j.y * 32, null, null).setOrigin(0, 0).setVisible(false);
                    var props = this.layer5.tileset.getTileProperties(j.index);
                    wall.body.setOffset(props.x + 16, props.y + 16);
                    wall.body.width = props.w;
                    wall.body.height = props.h;
                    this.wallGrp.add(wall);
                }
            });
        });
       
        this.physics.add.collider(this.playerGrp, this.wallGrp, function(p, w){
            console.log(p, w, "collision detected");
        });

Also see the picture below, the tiles are 32x32, but the colliders are now various sizers, all smaller than 32x32 tho.

There is a downside to this and that is you need to us Tiled, and you have to manually set the properties for each tile (in the tileset, not the map thankfully) that you want to have this info. I set my tiles to have a bool called collides, and 4 ints, x, y, w, and h. These numbers are RELATIVE to the tile's position, not their global position. To see the properties of the collision box, you have to draw it on in the tileset editor, and then make sure you have the collider selected, otherwise you can only see the tile's normal info etc.

Anyways, hopefully this helps someone, I'm off to try and fix my collision woes

 

collisionboxes.PNG

Share this post


Link to post
Share on other sites

Oh and the collision issue I was having seems to be because the first argument in a collider can't be static, I think its because it implies that it caused the collision, when obviously that's not possible if you're static. Like being drunk and accusing the lamp post of walking into you :P 

So just bear in mind that the code would need adjusting

Share this post


Link to post
Share on other sites

Just a quick update, sorry to bump, but further to  the above, I realised that the built-in tilemap collider is way more efficient, ofc it only depends on the size of your map, mine is 10k tiles, so pretty big. So i counted up the collision tiles and I had 1768 collision tiles, and it was noticeable because lag. So I optimised further. I found out that using the tiled object layer, although tedious, allows for more simple data loading. I went back into my tiled map, and added another object layer for collision tiles, and instead of having one per tile, I made all the walls into long tiles etc and loaded them. 

I went from 1768 collision tiles, to 850 something...

Here's a pic:

 

 

large_hadrons.PNG

and this is how I extract the data I need to remake the colliders how they are in Tiled. Best avoid rotation, I had to redo half my map because lazily rotating selections in Tiled resulted in unusable collision tiles 😕

 

this.map.objects[1].objects.forEach(ele=>{
        var wall = this.physics.add.sprite(ele.x, ele.y, null, null).setVisible(false).setActive(true).setOrigin(0, 0);
        wall.body.setOffset(16, 16);
        wall.body.width = ele.width;
        wall.body.height = ele.height;
        wall.body.immovable = true;
        this.wallGrp.add(wall);
    });

 

Share this post


Link to post
Share on other sites

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.