<pre id="maze"></pre>
<script>
//Why a roguelike?
//A RL is a sweetspot between effort vs. new features
//You get something awesome every 5 LoC or even just by tweaking a single variable, and this makes it fun to program
//What's exciting about JS is that you can make something you can see in a browser, fast, and then share it with everyone
//JS being a simple to understand, practical, and easy to share language has helped it develop an awesome community
//Things to tweak
//Try adding a ghost trail to the player by not replacing their last position with a .
//Try making an AI that moves randomly, that moves towards the player, that runs away from the player (like tag)
// pacman AI have some great examples of these behaviours: http://gameinternals.com/post/2072558330/understanding-pac-man-ghost-behavior
//Try writing code to generate a map, ideas here: http://ondras.github.io/rot.js/manual/#map
//Try tweaking the visibility code, you can make the whole maze invisible, make only certain items always visible,
// give the player a direction and let them only see that way
// or even try and implement a better algorithm: http://journal.stuffwithstuff.com/2015/09/07/what-the-hero-sees/
//Try adding more items, doors that you can stand on but not see through, different treasure, keys, stairs to different levels, go crazy!
const maze = [
'##########',
'#@.......#',
'#........#',
'#..###...#',
'#....##..#',
'#..T...R.|',
'##########',
]
let map = maze.map(line => line.split(''))
let player = {x: 1, y: 1, char: '@'}
let robot = {x: 7, y: 5, char: 'R'}
const keyCodeToDirection = {
37: {x: -1, y: 0},
38: {x: 0, y: -1},
39: {x: 1, y: 0},
40: {x: 0, y: 1}
}
function addPoint(point1, point2) {
return { x: point1.x + point2.x, y: point1.y + point2.y }
}
function render(map) {
document.getElementById('maze').innerHTML =
filterMap(map, player).map(characters => characters.join('')).join('\n')
}
function filterMap (map, player) {
return map.map((line, y) =>
line.map((character, x) =>
canSee(player, x, y) ? character : ' '
)
)
}
function canSee (player, x, y) {
return rectAroundPlayer(player, 5)
.some(point => point.x === x && point.y === y)
}
document.onkeydown = function(e) {
const direction = keyCodeToDirection[e.keyCode]
if (direction) {
e.preventDefault()
player = move(player, direction)
robot = move(robot, direction)
render(map)
}
}
function move(entity, direction) {
const newPosition = addPoint(entity, direction)
const newCharacter = map[newPosition.y][newPosition.x]
if (newCharacter === '.') {
return teleportEntity(entity, newPosition)
} else if (newCharacter === 'T') {
if (entity.char === 'R')
alert("Oh No! The robot wins!")
else
alert("Congrats! You win!")
}
return entity
}
function teleportEntity(entity, {x,y}) {
map[entity.y][entity.x] = '.'
map[y][x] = entity.char
return {x, y, char: entity.char}
}
render(map)
// Util Functions
function rectAroundPlayer (point, diameter) {
const radius = Math.floor(diameter / 2)
return getRect({x: point.x -radius, y: point.y -radius}, {x: point.x +radius, y: point.y +radius})
}
function getRect(topLeft, bottomRight) {
const line = range(topLeft.x, bottomRight.x + 1)
const column = range(topLeft.y, bottomRight.y + 1)
const box = line.map(x => column.map(y => ({x,y})))
return flatten(box)
}
// General utils
function flatten (arr) {
return [].concat.apply([], arr)
}
function range(a, b, step) {
if (arguments.length === 1) {
b = a;
a = 0;
}
step = step || 1;
var x, r = [];
for (x = a; (b - x) * step > 0; x += step) {
r.push(x);
}
return r;
}
</script>