Maybe you could find these useful. They were used in my game
Digga. Sorry if it's a bit chaotic. I'd be happy to answer any questions if you have them.
/* ladder.js */
ig.module('game.entities.ladder')
.requires('impact.entity')
.defines(function() {
EntityLadder = ig.Entity.extend({
size: {
x: 16,
y: 16
},
// Width of ladders in game.
real_width: 10,
_wmDrawBox: true,
_wmScalable: true,
zIndex: 256,
nature: 'ladder',
gravityFactor: 0,
animSheet: new ig.AnimationSheet('media/palette.png', 16, 16),
init: function(x, y, settings) {
this.parent(x, y, settings);
this.addAnim('idle', 1, [5]);
if(!ig.global.wm) {
var offset = (this.size.x - this.real_width)/2;
this.offset.x = offset;
this.size.x = this.real_width;
this.pos.x += offset;
}
},
update: function() {},
draw: function() {
if(!ig.global.wm) {
// Draw tiles except the first one.
if( this.currentAnim ) {
var tilesize = ig.game.collisionMap.tilesize;
var tile_height = this.size.y / tilesize;
for(var i=1; i<tile_height; i++) {
this.currentAnim.draw(
this.pos.x - this.offset.x - ig.game._rscreen.x,
this.pos.y - this.offset.y - ig.game._rscreen.y + (i * tilesize)
);
}
}
// Draw first tile, and debug info.
this.parent();
}
}
});
});
/* humanoid.js */
ig.module('game.entities.humanoid')
.requires('impact.entity')
.defines(function() {
EntityHumanoid = ig.Entity.extend({
size: {
x: 16,
y: 16
},
_wmIgnore: true,
fallSpeed: 30,
speed: 60,
defaultGravityFactor: 3,
animSheet: new ig.AnimationSheet('media/player.png', 16, 16),
input: null, // left, right, down, up
climbing: false,
over_ladder: false,
ladder: null,
over_bridge: false,
bridge_that_entity_is_over: null,
possible_land_on_entity: false,
init: function(x, y, settings) {
this.parent(x, y, settings);
this.maxVel.x = this.speed;
this.maxVel.y = Math.max(this.speed, this.fallSpeed);
this.addAnim('idle', 0.1, [19]);
this.addAnim('falling', 0.1, [12,13,14,15,16,17]);
this.addAnim('climbing', 0.1, [6,7,8,9,10,11]);
this.addAnim('running', 0.1, [0,1,2,3,4,5]);
},
update: function() {
// Handle input. ie 'left', 'up', etc.
if(this.input === null) this.stop();
else this.handle_movement_input(this.input);
// Disable gravity when over a ladder or on a bridge.
if(this.over_ladder || this.over_bridge) this.gravityFactor = 0;
else this.gravityFactor = this.defaultGravityFactor;
// Do not update climbing animation while still.
if(this.climbing && this.input !== 'up' && this.input !== 'down')
this.currentAnim.timer.pause();
if(this.climbing && (this.input === 'up' || this.input === 'down'))
this.currentAnim.timer.unpause();
this.parent();
this.after_movement_and_collision();
// Must receive input again for it to count.
this.input = null;
// Handle animations.
if(!this.standing && this.anims.falling) this.currentAnim = this.anims.falling;
else if(this.climbing && this.anims.climbing) this.currentAnim = this.anims.climbing;
else if(this.vel.x !== 0 && this.anims.running) {
this.currentAnim = this.anims.running;
this.currentAnim.flip.x = (this.vel.x > 0 ? true : false);
} else if(this.anims.idle) {
this.currentAnim = this.anims.idle;
this.currentAnim.flip.x = !this.is_facing_left();
}
},
handleMovementTrace: function( res ) {
this.parent(res);
if(this.over_ladder || this.over_bridge) this.standing = true;
},
after_movement_and_collision: function() {
// Handle smoothly getting off ladder.
if(this.climbing && this.input === 'down' && this.at_bottom_of_ladder()) {
this.climbing = false;
} else if(this.climbing && this.input === 'up' && this.at_top_of_ladder()) {
this.pos.y = this.ladder.pos.y - this.size.y;
this.vel.y = 0;
this.climbing = false;
}
// If position has changed, recalculate if over ladder.
if(this.last.x !== this.pos.x || this.last.y !== this.pos.y) {
this.check_for_ladder();
this.check_for_bridge();
}
// Handle landing on top of a ladder, and stopping immediately!
// Just landed on a ladder.
if(this.possible_land_on_entity && this.standing && this.over_ladder) this.pos.y = this.ladder.pos.y - this.size.y;
// Just landed on a bridge occupied by an enemy.
else if(this.possible_land_on_entity && this.standing && this.over_bridge && this.bridge_that_entity_is_over.enemy) this.pos.y = this.bridge_that_entity_is_over.pos.y - this.size.y;
// Flag possible ladder landing situation.
this.flag_possible_land_on_entity();
},
flag_possible_land_on_entity: function() {
this.possible_land_on_entity = !this.standing;
},
check_for_ladder: function() {
this.ladder = null;
this.over_ladder = false;
this.size.y += 1; // because 1px under still counts
var ladders = ig.game.getEntitiesByType(EntityLadder);
for(var i=0; i<ladders.length; i++) {
if(this.touches(ladders[i])) {
this.ladder = ladders[i];
this.over_ladder = true;
break;
}
}
this.size.y -= 1;
},
check_for_bridge: function() {
this.over_bridge = false;
this.size.y += 1; // because 1px under still counts
var bridges = ig.game.getEntitiesByType(EntityBridge);
for(var i=0; i<bridges.length; i++) {
// Touching bridge and an enemy is there and it's not this entity.
if(this.touches(bridges[i]) && bridges[i].enemy && bridges[i].enemy !== this) {
this.over_bridge = true;
this.bridge_that_entity_is_over = bridges[i];
break;
}
}
this.size.y -= 1;
},
at_top_of_ladder: function() {
return this.pos.y + this.size.y - 2 <= this.ladder.pos.y;
},
at_bottom_of_ladder: function() {
var velocity = { x: 0, y: 1 };
var result = ig.game.collisionMap.trace(this.pos.x, this.pos.y, velocity.x, velocity.y, this.size.x, this.size.y);
var stopped_by_floor = result.collision.y;
var out_of_ladder = this.pos.y >= this.ladder.pos.y + this.ladder.size.y;
return stopped_by_floor || out_of_ladder;
},
mount_ladder: function() {
this.pos.x = this.ladder.pos.x + this.ladder.size.x/2 - this.size.x/2; // align player over ladder
this.vel.x = 0; // prevents possible case of not being centered
this.climbing = true;
},
jump_off_ladder: function(side) {
this.stop();
if(!this.can_move_in_direction(side)) return;
this.pos.x += ig.game.collisionMap.tilesize * (side === 'left' ? -1 : 1);
this.climbing = false;
// Need to know there is no ladder to prevent walking on air.
this.check_for_ladder();
},
set_velocity_by_direction: function(direction) {
this.vel.x = 0;
this.vel.y = 0;
if(direction === 'left' || direction === 'right')
this.vel.x = ( direction === 'left' ? -1 : 1 ) * this.speed;
if(direction === 'up' || direction === 'down')
this.vel.y = ( direction === 'up' ? -1 : 1 ) * this.speed;
},
handle_movement_input: function(direction) {
// Getting off ladders.
if ((direction === 'left' || direction === 'right') && this.climbing) this.jump_off_ladder(direction);
// Running while atop ladders and on the ground.
else if ((direction === 'left' || direction === 'right') && (this.standing || this.over_ladder)) this.set_velocity_by_direction(direction);
// Prevent moving horizontally by walking over a ledge while holding key.
else if ((direction === 'left' || direction === 'right') && !this.standing) this.stop();
// Getting off at the top and the bottom of ladders.
else if (this.climbing && ((direction === 'up' && this.at_top_of_ladder()) || (direction === 'down' && this.at_bottom_of_ladder()))) this.climbing = false;
// Moving up and down ladders.
else if ((direction === 'up' || direction === 'down') && this.climbing) this.set_velocity_by_direction(direction);
// Getting on to ladders.
else if ((direction === 'up' || direction === 'down') && this.over_ladder) this.mount_ladder();
// Prevent moving horizontally by tapping left or right and then holding up or down.
else if ((direction === 'up' || direction === 'down') && this.standing) this.stop();
},
stop: function() {
this.vel.x = 0; // never move horizontally without input
if(this.standing) this.vel.y = 0; // prevent climbing but allow falling
},
is_facing_left: function() {
if(this.anims.running) return this.anims.running.flip.x === false;
else return false;
},
can_move_in_direction: function(direction) {
var velocity = { x: 0, y: 0 };
// Left and Right check a few pixels further than immediately beside,
// because when on a ladder, entity is a few pixels from edge of tile.
if (direction === 'left') velocity.x = -1 * (this.offset.x + 1);
else if(direction === 'right') velocity.x = 1 * (this.offset.x + 1);
else if(direction === 'up') velocity.y = -1;
else if(direction === 'down') velocity.y = 1;
var result = ig.game.collisionMap.trace(this.pos.x, this.pos.y, velocity.x, velocity.y, this.size.x, this.size.y);
if(direction === 'left' || direction === 'right') return !result.collision.x;
else return !result.collision.y;
}
});
});