/*jslint plusplus: true, white: true, indent: 2, maxlen: 90 */
/*global $wk$, $app$*/
/**
* @author Wolfgang Kowarschick
* @copyright 2013, Wolfgang Kowarschick
* <br/>
* Redistribution and use in source and binary forms, with or without
* modification, are permitted under the terms of the
* Creative Commons License Attribution-NonCommercial-ShareAlike 3.0 Unported
* (CC BY-NC-SA 3.0: http://creativecommons.org/licenses/by-nc-sa/3.0/).
*/
$wk$(
function()
{ "use strict";
////////////////////////////////////////////////////////////////////////////////
// Class "Snake"
////////////////////////////////////////////////////////////////////////////////
//import
var Body = $app$.game.snake.Body,
Food = $app$.game.snake.Food,
l_direction = null;
/**
* @class
* @name $app$.game.snake.Snake
*
* @param {Object} p_init
* Should contain three initialization objects to initialize the snake:
* <code>p_init.tail</code>,
* <code>p_init.length</code>, and
* <code>p_init.direction</code>.
* @param {$app$.game.snake.Plane} p_plane
* The plane where the snake is to be placed.
*/
$wk$.WKcClass(
{ name: "$app$.game.snake.Snake",
staticMethods:
{ /** @constant {Object} $app$.game.snake.Snake.NORTH */
NORTH: { x: 0, y: -1 },
/** @constant {Object} $app$.game.snake.Snake.EAST */
EAST: { x: +1, y: 0 },
/** @constant {Object} $app$.game.snake.Snake.SOUTH */
SOUTH: { x: 0, y: +1 },
/** @constant {Object} $app$.game.snake.Snake.WEST */
WEST: { x: -1, y: 0 },
/** @constant {String} $app$.game.snake.Snake.LEFT */
LEFT: "left",
/** @constant {String} $app$.game.snake.Snake.RIGHT */
RIGHT: "right" ,
init:
function()
{ this.NORTH.left = this.WEST;
this.NORTH.right = this.EAST;
this.EAST.left = this.NORTH;
this.EAST.right = this.SOUTH;
this.SOUTH.left = this.EAST;
this.SOUTH.right = this.WEST;
this.WEST.left = this.SOUTH;
this.WEST.right = this.NORTH;
l_direction =
{ north: this.NORTH, east: this.EAST,
south: this.SOUTH, west: this.WEST
};
}
},
methods:
{ init:
function (p_init, p_plane)
{ this.v_plane = p_plane;
this.v_init_tail = p_init.tail;
this.v_init_direction = l_direction[p_init.direction];
this.v_init_length = p_init.length;
},
/**
* The current length of the snake.
* @var {int} $app$.game.snake.Snake#length
*/
/**
* Resets the snake.
*
* @method
* @name $app$.game.snake.Snake#reset
*/
reset:
function()
{ var i, n,
l_tail = this.v_init_tail;
// Cleanup the plane
this.v_plane.reset();
// Place the initial snake on the plane.
this.v_head =
this.v_tail = new Body(l_tail.x, l_tail.y);
this.v_direction = this.v_init_direction;
this.v_plane.addItem(this.v_head);
for (i = 1, n = this.v_init_length; i < n; i++)
{ this.v_growing = true;
this.move();
}
this.length = n;
},
/**
* Moves the snake one field further. If it hits a food item, it grows.
* If it hits a wall or body item, it dies.
*
* @method
* @name $app$.game.snake.Snake#move
*
* @returns {Boolean}
* <code>true</code>, if and only if the snake is dead.
*/
move:
function()
{ var l_plane = this.v_plane,
l_head = this.v_head,
l_head_new,
l_tail = this.v_tail,
l_direction = this.v_direction,
l_x = l_head.x + l_direction.x,
l_y = l_head.y + l_direction.y,
l_item = l_plane.getItem(l_x, l_y);
if (!l_item || l_item instanceof Food)
{ l_head_new = new Body(l_x, l_y);
l_head.pred = l_head_new;
this.v_head = l_head_new;
l_plane.addItem(l_head_new);
// If food has been eaten, the snake is growing.
if (l_item)
{ this.v_growing = true;
this.length++;
l_plane.foodNr--;
}
}
else
{ return true; }
// If the snake is not growing, the current tail is removed.
if (!this.v_growing)
{ this.v_tail = l_tail.pred;
l_plane.removeItem(l_tail);
}
this.v_growing = false;
return false;
},
/**
* Turns the snake 90° to the left or to the right.
*
* @method
* @name $app$.game.snake.Snake#turnLeft
*
* @param {String} p_direction
* Either <code>Snake.LEFT</code> or <code>Snake.RIGHT</code>.
*/
turn:
function(p_direction)
{ this.v_direction = this.v_direction[p_direction]; }
}
});
////////////////////////////////////////////////////////////////////////////////
// End of Class "Snake"
////////////////////////////////////////////////////////////////////////////////
});