Impact

This forum is read only and just serves as an archive. If you have any questions, please post them on github.com/phoboslab/impact

1 decade ago by wands

As above.
I have a canvas size of 800 x 600. And I would like my entity to move only within the canvas size. Without showing a tile on the canvas how can I achieve that?
Greatly appreciate anyone's help

1 decade ago by Joncom

So you want all tiles outside of the collision map to be considered "non-passable" so that the entity can't escape the bounds of the collision map?

Make a new file called collision-map.js.
Put it in /lib/game/.
Give it the following code:
ig.module('game.collision-map')
.requires('impact.collision-map')
.defines(function(){ "use strict";

    // This CollisionMap has been modified to allow
    // negative value coordinates. Additionally,
    // points with undefined values will be treated
    // as if they are "this.defaultPermission".

    ig.CollisionMap.inject({

        data: {},
        width: null,
        height: null,
        pxWidth: null,
        pxHeight: null,
        defaultPermission: 1, // blocked

        init: function( tilesize, data, tiledef ) {
            this.tilesize = tilesize;
            this.data = data;

            this.tiledef = tiledef || ig.CollisionMap.defaultTileDef;

            for( var t in this.tiledef ) {
                if( t|0 > this.lastSlope ) {
                    this.lastSlope = t|0;
                }
            }
        },

        _traceStep: function( res, x, y, vx, vy, width, height, rvx, rvy, step ) {

            res.pos.x += vx;
            res.pos.y += vy;

            var t = 0;

            // Horizontal collision (walls)
            if( vx ) {
                var pxOffsetX = (vx > 0 ? width : 0);
                var tileOffsetX = (vx < 0 ? this.tilesize : 0);

                var firstTileY = Math.floor(y / this.tilesize);
                var lastTileY = Math.ceil((y + height) / this.tilesize);
                var tileX = Math.floor( (res.pos.x + pxOffsetX) / this.tilesize );

                // We need to test the new tile position as well as the current one, as we
                // could still collide with the current tile if it's a line def.
                // We can skip this test if this is not the first step or the new tile position
                // is the same as the current one.
                var prevTileX = Math.floor( (x + pxOffsetX) / this.tilesize );
                if( step > 0 || tileX == prevTileX ) {
                    prevTileX = null;
                }

                for( var tileY = firstTileY; tileY < lastTileY; tileY++ ) {

                    if( prevTileX != null ) {
                        if( this.data[tileY] === undefined ||
                                this.data[tileY][prevTileX] === undefined ) {
                            t = this.defaultPermission;
                        } else {
                            t = this.data[tileY][prevTileX];
                        }
                        if(
                            t > 1 && t <= this.lastSlope &&
                            this._checkTileDef(res, t, x, y, rvx, rvy, width, height, prevTileX, tileY)
                        ) {
                            break;
                        }
                    }

                    if( this.data[tileY] === undefined ||
                            this.data[tileY][tileX] === undefined ) {
                        t = this.defaultPermission;
                    } else {
                        t = this.data[tileY][tileX];
                    }
                    if(
                        t == 1 || t > this.lastSlope || // fully solid tile?
                        (t > 1 && this._checkTileDef(res, t, x, y, rvx, rvy, width, height, tileX, tileY)) // slope?
                    ) {
                        if( t > 1 && t <= this.lastSlope && res.collision.slope ) {
                            break;
                        }

                        // full tile collision!
                        res.collision.x = true;
                        res.tile.x = t;
                        x = res.pos.x = tileX * this.tilesize - pxOffsetX + tileOffsetX;

                        rvx = 0;
                        break;
                    }
                }
            }

            // Vertical collision (floor, ceiling)
            if( vy ) {
                var pxOffsetY = (vy > 0 ? height : 0);
                var tileOffsetY = (vy < 0 ? this.tilesize : 0);

                var firstTileX = Math.floor(res.pos.x / this.tilesize);
                var lastTileX = Math.ceil((res.pos.x + width) / this.tilesize);
                var tileY = Math.floor( (res.pos.y + pxOffsetY) / this.tilesize );

                var prevTileY = Math.floor( (y + pxOffsetY) / this.tilesize );
                if( step > 0 || tileY == prevTileY ) {
                    prevTileY = null;
                }

                for( var tileX = firstTileX; tileX < lastTileX; tileX++ ) {

                    if( prevTileY != null ) {
                        if( this.data[prevTileY] === undefined ||
                                this.data[prevTileY][tileX] === undefined ) {
                            t = this.defaultPermission;
                        } else {
                            t = this.data[prevTileY][tileX];
                        }
                        if(
                            t > 1 && t <= this.lastSlope &&
                            this._checkTileDef(res, t, x, y, rvx, rvy, width, height, tileX, prevTileY) ) {
                            break;
                        }
                    }

                    if( this.data[tileY] === undefined ||
                            this.data[tileY][tileX] === undefined ) {
                        t = this.defaultPermission;
                    } else {
                        t = this.data[tileY][tileX];
                    }
                    if(
                        t == 1 || t > this.lastSlope || // fully solid tile?
                        (t > 1 && this._checkTileDef(res, t, x, y, rvx, rvy, width, height, tileX, tileY)) // slope?
                    ) {
                        if( t > 1 && t <= this.lastSlope && res.collision.slope ) {
                            break;
                        }

                        // full tile collision!
                        res.collision.y = true;
                        res.tile.y = t;
                        res.pos.y = tileY * this.tilesize - pxOffsetY + tileOffsetY;
                        break;
                    }
                }
            }

            // res is changed in place, nothing to return
        }

    });

});

Did you notice the line defaultPermission: 1? Basically this says that any tile which does not have a defined persmission in the collision map will be treated like a "1", which is to say, not-passable.

1 decade ago by wands

Wow! Thank you so much for this reply! Will try this out.

1 decade ago by wands

Just a quick check, does the code stops entity from moving out of edges of the canvas?

1 decade ago by Joncom

No. It stops entities from moving outside the collision map. However, if you make your canvas the same size as you map and collision map, then yes.

8 years ago by Xander

I know this is an old post, but I used a different approach to solving this for my own needs. For my purposes, when using screen-shake I didn't want the game to show the edges of the game that didn't have any tiles on them.

Like you, I was initially thinking that I'd want tiles located outside of the playing field. I came up with a very different, yet simple, solution: change the camera. My camera code never shows the tiles bordering a map.

The code looks something like this:
        //right edge of the map with a one tile buffered edge        
		if(entity.pos.x > (ig.game.collisionMap.width*ig.game.collisionMap.tilesize - ig.system.width/2 - entity.size.x/2 - ig.game.collisionMap.tilesize))
		{
		  this.pos.x = ig.game.collisionMap.width*ig.game.collisionMap.tilesize-ig.system.width-ig.game.collisionMap.tilesize;
		}
		//left edge of the map with a one tile buffered edge    
		else if (entity.pos.x < ig.system.width/2 - entity.size.x/2 + ig.game.collisionMap.tilesize) 
		{
		  this.pos.x = 0 + ig.game.collisionMap.tilesize;
		}
		//somewhere in the middle
		else 
		{
		  this.pos.x = entity.pos.x - ig.system.width/2 + entity.size.x/2;
		}
		
		//bottom of the map with a one tile buffered edge 
		if( (entity.pos.y - entity.offset.y) > (ig.game.collisionMap.height*ig.game.collisionMap.tilesize - ig.system.height/2 - (entity.size.y+entity.offset.y)/2) - ig.game.collisionMap.tilesize )
		{
		  this.pos.y = ig.game.collisionMap.height*ig.game.collisionMap.tilesize-ig.system.height-ig.game.collisionMap.tilesize;
		}
		//top of the map with a one tile buffered edge 
		else if ( (entity.pos.y - entity.offset.y) < ig.system.height/2 - (entity.size.y+entity.offset.y)/2 + ig.game.collisionMap.tilesize ) 
		{
		  this.pos.y = 0 + ig.game.collisionMap.tilesize;
		}
		//somewhere in the middle
		else 
		{
		  this.pos.y = (entity.pos.y - entity.offset.y) - ig.system.height/2 + (entity.size.y+entity.offset.y)/2;
		}

		ig.game.screen.x = this.pos.x ;
		ig.game.screen.y = this.pos.y;

By always adding or subtracting ig.game.collisionMap.tilesize from screen position if your entity is near the edge, the last tile (the edge tiles) will never be displayed on screen. And when you screen-shake (with values up to the tilesize) you won't see blank tiles while at the edge of the screen (you'll see bits of these edge tiles).

You just have to keep in mind when building your levels in WM that you need to include that border of tiles around the map that your player won't see. And obviously, you can set those as solid collision tiles so that the player can't move past them.
Page 1 of 1
« first « previous next › last »