1 decade ago by Silent
Hello :)
I am currently developing a game with grid-based movement, and I happened to stumble across this code. I really liked Joncom's work, so I ended up using it. I even put a link to the thread in my source.
I wanted to be able to move in 8 directions so I modded the code a bit. It works as it should, except when colliding with corners. Consider the following example(0 is a wall, @ is the player):
Assume the following situation:
If I move left-up, I should end up here:
The problem is I end up sliding up and then teleporting into position, like so:
As far as I understand, the code properly moves the player into position, but the engine detects that it's going into a wall and won't let it move in the y axis. When it's done moving, it snaps to the grid based on it's target tile.
What I want is a system that checks for such situations and prevents diagonal movement.
Could someone please help?
Here's my code:
I am currently developing a game with grid-based movement, and I happened to stumble across this code. I really liked Joncom's work, so I ended up using it. I even put a link to the thread in my source.
I wanted to be able to move in 8 directions so I modded the code a bit. It works as it should, except when colliding with corners. Consider the following example(0 is a wall, @ is the player):
Assume the following situation:
00@
If I move left-up, I should end up here:
@ 00
The problem is I end up sliding up and then teleporting into position, like so:
@ 00
@ 00
As far as I understand, the code properly moves the player into position, but the engine detects that it's going into a wall and won't let it move in the y axis. When it's done moving, it snaps to the grid based on it's target tile.
What I want is a system that checks for such situations and prevents diagonal movement.
Could someone please help?
Here's my code:
// Taken from here:
// http://impactjs.com/forums/code/top-down-rpg-style-tile-based-grid-movement
ig.module(
'game.entities.base.gridEntity'
)
.requires(
'impact.entity'
)
.defines( function () {
EntityGridEntity = ig.Entity.extend({
// Override
// 50 fits 8x8 entities
speed: 50,
moveType: {
'UP': 1,
'UP_RIGHT': 2,
'RIGHT': 3,
'RIGHT_DOWN': 4,
'DOWN': 5,
'DOWN_LEFT': 6,
'LEFT': 7,
'LEFT_UP': 8,
'NONE': 0
},
moveIntention: null,
lastMove: null,
destination: null,
init: function (x, y, settings) {
this.parent(x, y, settings);
this.maxVel.x = this.maxVel.y = this.speed;
},
update: function () {
// It's iportant to call the parent first because I don't know.
// It works, don't mess with it.
this.parent();
this.moveIntention = this.getMoveIntention();
// Stop the moving entity if at the destination.
if(this.isMoving() && this.justReachedDestination() && !this.moveIntention) {
this.stopMoving();
}
// Stop the moving entity when it hits a wall.
else if(this.isMoving() && this.justReachedDestination() && this.moveIntention &&
!this.canMoveDirectionFromTile(this.destination.x, this.destination.y, this.moveIntention)) {
this.stopMoving();
}
// Destination reached, but set new destination and keep going.
else if(this.isMoving() && this.justReachedDestination() && this.moveIntention &&
this.canMoveDirectionFromTile(this.destination.x, this.destination.y, this.moveIntention) &&
this.moveIntention === this.lastMove) {
this.continueMovingFromDestination();
}
// Destination reached, but changing direction and continuing.
else if(this.isMoving() && this.justReachedDestination() && this.moveIntention &&
this.canMoveDirectionFromTile(this.destination.x, this.destination.y, this.moveIntention) &&
this.moveIntention !== this.lastMove) {
this.changeDirectionAndContinueMoving(this.moveIntention);
}
// Destination not yet reached, so keep going.
else if(this.isMoving() && !this.justReachedDestination()) {
this.continueMovingToDestination();
}
// Not moving, but wanting to, so start!
else if(!this.isMoving() && this.moveIntention &&
this.canMoveDirectionFromCurrentTile(this.moveIntention)) {
this.startMoving(this.moveIntention);
}
},
getCurrentTile: function() {
var tilesize = ig.game.collisionMap.tilesize;
var tileX = this.pos.x / tilesize;
var tileY = this.pos.y / tilesize;
return {
x: tileX,
y: tileY
};
},
getTileAdjacentToTile: function(tileX, tileY, direction) {
if(direction === this.moveType.UP) {
tileY += -1;
} else if(direction === this.moveType.UP_RIGHT) {
tileY += -1;
tileX += 1;
} else if(direction === this.moveType.RIGHT) {
tileX += 1;
} else if(direction === this.moveType.RIGHT_DOWN) {
tileX += 1;
tileY += 1;
} else if(direction === this.moveType.DOWN) {
tileY += 1;
} else if(direction === this.moveType.DOWN_LEFT) {
tileY += 1;
tileX += -1;
} else if(direction === this.moveType.LEFT) {
tileX += -1;
} else if(direction === this.moveType.LEFT_UP) {
tileX += -1;
tileY += -1;
}
return {
x: tileX,
y: tileY
};
},
startMoving: function(direction) {
// Get current tile position.
var currTile = this.getCurrentTile();
// Get new destination.
this.destination = this.getTileAdjacentToTile(currTile.x, currTile.y, direction);
// Move.
this.setVelocityByTile(this.destination.x, this.destination.y, this.speed);
// Remember this move for later.
this.lastMove = direction;
},
continueMovingToDestination: function() {
// Move.
this.setVelocityByTile(this.destination.x, this.destination.y, this.speed);
},
continueMovingFromDestination: function() {
// Get new destination.
this.destination = this.getTileAdjacentToTile(this.destination.x, this.destination.y, this.lastMove);
// Move.
this.setVelocityByTile(this.destination.x, this.destination.y, this.speed);
},
changeDirectionAndContinueMoving: function(newDirection) {
// Method only called when at destination, so snap to it now.
this.snapToTile(this.destination.x, this.destination.y);
// Get new destination.
this.destination = this.getTileAdjacentToTile(this.destination.x, this.destination.y, newDirection);
// Move.
this.setVelocityByTile(this.destination.x, this.destination.y, this.speed);
// Remember this move for later.
this.lastMove = newDirection;
},
stopMoving: function() {
// Method only called when at destination, so snap to it now.
this.snapToTile(this.destination.x, this.destination.y);
// We are already at the destination.
this.destination = null;
// Stop.
this.vel.x = this.vel.y = 0;
},
snapToTile: function(x, y) {
var tilesize = ig.game.collisionMap.tilesize;
this.pos.x = x * tilesize;
this.pos.y = y * tilesize;
},
justReachedDestination: function() {
var tilesize = ig.game.collisionMap.tilesize;
var destinationX = this.destination.x * tilesize;
var destinationY = this.destination.y * tilesize;
var result = (
(this.pos.x >= destinationX && this.last.x < destinationX) ||
(this.pos.x <= destinationX && this.last.x > destinationX) ||
(this.pos.y >= destinationY && this.last.y < destinationY) ||
(this.pos.y <= destinationY && this.last.y > destinationY)
);
return result;
},
isMoving: function() {
return this.destination !== null;
},
canMoveDirectionFromTile: function(tileX, tileY, direction) {
var newPos = this.getTileAdjacentToTile(tileX, tileY, direction);
return ig.game.collisionMap.data[newPos.y][newPos.x] === 0;
},
canMoveDirectionFromCurrentTile: function(direction) {
var currTile = this.getCurrentTile();
return this.canMoveDirectionFromTile(currTile.x, currTile.y, direction);
},
// Sets the velocity of the entity so that it will move toward the tile.
setVelocityByTile: function(tileX, tileY, velocity) {
var tilesize = ig.game.collisionMap.tilesize;
var tileCenterX = tileX * tilesize + tilesize / 2;
var tileCenterY = tileY * tilesize + tilesize / 2;
var entityCenterX = this.pos.x + this.size.x / 2;
var entityCenterY = this.pos.y + this.size.y / 2;
this.vel.x = this.vel.y = 0;
if(entityCenterX > tileCenterX) {
this.vel.x = -velocity;
} else if(entityCenterX < tileCenterX) {
this.vel.x = velocity;
}
if(entityCenterY > tileCenterY) {
this.vel.y = -velocity;
} else if(entityCenterY < tileCenterY) {
this.vel.y = velocity;
}
},
// Override
getMoveIntention: function() {
return this.moveType.NONE;
}
});
});
