beast.js
Version:
ANSI Beast for node
211 lines (166 loc) • 7.58 kB
JavaScript
/***************************************************************************************************************************************************************
*
* Hero
*
* Moving the hero and checking for collisions, blocks and deaths
*
**************************************************************************************************************************************************************/
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
// Dependencies
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
// Module
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
BEAST.hero = (() => {
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
// Private function
// _isOutOfBounds, Check that the move does not go outside the bounds of the board
//
// @param position {object} The position object: { x: 1, y: 1 }
//
// @return {boolean} True or false
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
const _isOutOfBounds = ( position ) => {
BEAST.debugging.report(`hero: _isOutOfBounds`, 1);
let outofbounds = false; //let's assume the best
if( position.x < 0 || position.y < 0 ) { //left and top bounds
outofbounds = true;
}
if( position.x > (BEAST.MINWIDTH - 3) || position.y > (BEAST.MINHEIGHT - 8) ) { //right and bottom bounds
outofbounds = true;
}
return outofbounds;
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
// Private function
// push, Check the environment and push blocks, return false if the move can't be done
//
// @param dir {string} The direction we are moving towards
// @param step {integer} The increment of the movement. 1 = move right, -1 = move left
//
// @return {boolean} True or false
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
const push = ( dir, step ) => {
BEAST.debugging.report(`hero: push`, 1);
let element = '';
let canMove = true;
let elements = [];
let pushBeast = false;
let beastPosition = {};
let position = { //our current position as clone
x: BEAST.HERO.x,
y: BEAST.HERO.y,
};
while( element !== undefined && !_isOutOfBounds( position ) ) { //stop when we encounter a space or the end of the frame
position[ dir ] += step; //go one step forward and see
if( BEAST.BOARD[ position.y ] === undefined ) { //if we're peaking beyond the bounds
canMove = false;
break
}
element = BEAST.BOARD[ position.y ][ position.x ]; //whats the element on the board on this step?
if( element === 'beast' && elements.length === 0 ) { //You just walked into a beast = you dead!
BEAST.hero.die(); //gone, done for, good bye
return false;
}
if(
element === 'solid' || //can't push no solid
element === 'beast' || //can't push the beast around. beast eats you
_isOutOfBounds( position ) //can't push past the bounds
) {
canMove = false;
}
if( element === 'beast' && !pushBeast ) { //if we got a beast by itself
pushBeast = true;
beastPosition = { //save the position of that beast for later squashing
x: position.x,
y: position.y,
};
}
if(
element === 'block' && pushBeast || //now we got a block right after a beast = squash it!
element === 'solid' && pushBeast //a solid after a beast = squash it too
) {
let previousSolids = false; //
for(let i = elements.length - 2; i >= 0; i--) { //have we got any solids in the elements we are pushing?
if( elements[i] === 'solid' ) {
previousSolids = true;
}
};
if( !previousSolids ) { //can't move this if you are trying to push solids
canMove = true; //even though there is a beast in the way we can totally squash it
}
elements.splice( (elements.length - 1), 1 ); //remove the beast from the things we will push
elements.push( element ); //move the block
BEAST.beasts.squash( beastPosition ); //squash that beast real good
break; //no other elements need to be pushed now
}
if( element !== undefined ) {
elements.push( element ); //save each element on the way to a free space
}
}
if( canMove ) { //if there is pushing
let i = 1;
while( position[ dir ] != BEAST.HERO[ dir ] ) { //stop when we're back where we started
element = elements[ elements.length - i ]; //get the saved element
BEAST.BOARD[ position.y ][ position.x ] = element; //place it on the board
position[ dir ] -= step; //step backwards
i ++; //count steps
}
}
return canMove;
}
return {
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
// Public function
// move, Move hero
//
// @param dir {string} The direction we are moving towards
// @param step {integer} The increment of the movement. 1 = move right, -1 = move left
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
move: ( dir, step ) => {
BEAST.debugging.report(`hero: move`, 1);
if( !BEAST.DEAD ) {
let position = { //our current position
x: BEAST.HERO.x,
y: BEAST.HERO.y,
};
position[ dir ] += step; //move
if( !_isOutOfBounds( position ) ) { //check to stay within bounds
let _isPushable = push( dir, step ); //can we even push?
if( _isPushable ) {
BEAST.BOARD[ BEAST.HERO.y ][ BEAST.HERO.x ] = undefined; //clear old position
BEAST.HERO = position; //update global position
BEAST.BOARD[ BEAST.HERO.y ][ BEAST.HERO.x ] = 'hero'; //set new position
BEAST.draw.board(); //now draw it up
}
}
}
},
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
// Public function
// die, Hero dies
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
die: ( ) => {
BEAST.debugging.report(`hero: die`, 1);
clearInterval( BEAST.INTERVAL );
BEAST.DEATHS ++;
BEAST.DEAD = true;
if( BEAST.DEATHS > BEAST.LIVES ) { //no more lives left
BEAST.draw.message('GAME OVER...'); //sorry :`(
setTimeout(() => {
process.exit(0); //exit without error
}, 2000);
}
else {
BEAST.draw.message('You were eaten by a beast :`(');
setTimeout(() => { //restart with level 1
BEAST.LEVEL = 1;
BEAST.DEAD = false;
BEAST.scaffolding.init();
BEAST.draw.init();
BEAST.beasts.init();
}, 3000);
}
},
}
})();