Created
January 21, 2015 06:28
-
-
Save evitolins/f4ba11a1d7e1772aa39b to your computer and use it in GitHub Desktop.
Canvas Snake: http://jsbin.com/ekiderO/28/edit?html,css,js,output
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*jslint | |
browser: true, devel: true, plusplus: true, unparam: true, todo: true, vars: true, white: true, nomen: true | |
*/ | |
/*global requestAnimationFrame */ | |
(function() { | |
var requestAnimationFrame = | |
window.requestAnimationFrame || | |
window.mozRequestAnimationFrame || | |
window.webkitRequestAnimationFrame || | |
window.msRequestAnimationFrame; | |
window.requestAnimationFrame = requestAnimationFrame; | |
})(); | |
/** | |
* Class providing a simple callback w/ refresh using requestAnimationFrame(). | |
* @param {Function} callback Executes at each refresh interval | |
* @param {Number} seconds Time between each refresh | |
* @param {Boolean} immediate Forces to execute refresh immediately upon init. | |
*/ | |
var RGBrefresher = function (callback, seconds, immediate) { "use strict"; | |
var self = this, | |
cb = callback, | |
freq = seconds || 0, | |
im = immediate || false, | |
first, prev, total, refreshing, mute, | |
runCallback = function () { | |
if (typeof cb === "function" && !mute) { | |
cb.apply(self); | |
} | |
}, | |
step = function (timestamp) { | |
var elapsed = timestamp - prev; | |
if (refreshing) { | |
requestAnimationFrame(step); | |
} | |
if (first === 0) { first = timestamp; } | |
if (elapsed >= freq * 1000) { | |
prev = timestamp; | |
total++; | |
runCallback(); | |
} | |
}, | |
start = function () { | |
refreshing = true; | |
if (im) { | |
runCallback(); | |
} | |
requestAnimationFrame(step); | |
}, | |
reset = function () { | |
first = 0; | |
prev = 0; | |
refreshing = false; | |
mute = false; | |
total = 0; | |
}; | |
// Init | |
reset(); | |
// API | |
return { | |
getTotal : function () { return total; }, | |
getFreq : function () { return freq; }, | |
setFreq : function (seconds) { freq = seconds; }, | |
getCallback : function () { return cb; }, | |
setCallback : function (func) { cb = func; }, | |
mute : function () { mute = true; }, | |
unmute : function () { mute = false; }, | |
reset : function () { reset(); }, | |
stop : function () { refreshing = false; }, | |
start : function () { start(); } | |
}; | |
}; | |
///////////////////////////////////////////////////////////////////////////// | |
//Snake Experiment | |
// Rules | |
// - continue in the same direction, until something obstructs the path | |
// - if an obstruction is found, try next direction clockwise | |
// - if no move is available, quit | |
var refresh = new RGBrefresher(); | |
var grid = | |
[ | |
[0,0,3,0,0,0,0,0,0,0], | |
[0,0,0,0,0,0,0,0,0,0], | |
[0,0,0,0,0,0,0,2,0,0], | |
[0,0,0,0,0,0,0,0,0,3], | |
[0,0,0,0,0,0,0,0,0,0], | |
[0,0,0,2,0,0,0,0,0,0], | |
[0,0,0,0,0,0,0,0,0,0], | |
[0,0,0,0,3,0,0,0,0,0], | |
[0,0,0,0,0,0,0,0,0,0], | |
[0,0,0,0,0,0,0,0,0,0] | |
]; | |
var dirs= [ | |
[0,-1], //n | |
[1,0], //e | |
[0,1], //s | |
[-1,0] //w | |
]; | |
var setCellValue = function(x,y,val){ | |
grid[y][x] = val; | |
}; | |
var getCellValue = function(x,y){ | |
if (grid[y] === undefined) return undefined; | |
if (grid[y][x] === undefined) return undefined; | |
return grid[y][x]; | |
}; | |
// Validate Proposed X & Y coords | |
var getValidDirs = function (x, y){ | |
var xMax = grid[0].length; | |
var yMax = grid.length; | |
var dirs = []; | |
// Validate N | |
if (y-1 >= 0 && getCellValue(x, y-1) === 0){ | |
dirs.push(0); | |
} | |
// Validate E | |
if (x+1 < xMax && getCellValue(x+1,y) === 0){ | |
dirs.push(1); | |
} | |
// Validate S | |
if (y+1 < yMax && getCellValue(x,y+1) === 0){ | |
dirs.push(2); | |
} | |
// Validate W | |
if (x-1 >= 0 && getCellValue(x-1,y) === 0){ | |
dirs.push(3); | |
} | |
return dirs; | |
}; | |
//Canvas Renderer | |
var canvas = document.getElementById('canvas'); | |
var context = canvas.getContext('2d'); | |
var pixel = 30; | |
var clear = function() { | |
context.clearRect ( 0 , 0 , canvas.width , canvas.height ); | |
}; | |
var render = function(pixels){ | |
var x,y,i,ii; | |
clear(); | |
for (i=0; i<pixels.length; i++) { | |
for (ii=0; ii<pixels[i].length; ii++) { | |
x = ii * pixel; | |
y = i * pixel; | |
if (!pixels[i][ii]) { | |
continue; | |
} | |
context.beginPath(); | |
// Pick color | |
if (pixels[i][ii] === 1) { | |
context.fillStyle = 'red'; | |
} | |
if (pixels[i][ii] === 2) { | |
context.fillStyle = 'green'; | |
} | |
if (pixels[i][ii] === 3) { | |
context.fillStyle = 'blue'; | |
} | |
context.rect(x, y, pixel, pixel); | |
context.fill(); | |
} | |
} | |
}; | |
var resetPosition = function(pos){ | |
if (Object.prototype.toString.call( pos ) !== '[object Array]' ) return; | |
//Reset given position | |
grid[pos[1]][pos[0]] = 0; | |
}; | |
var tailMaxLength = 10; | |
var speed = 1000; | |
// This example randomly chooses direction per choice | |
var snake_run = function (position, direction, random) { | |
var pos = position; | |
var dir = direction; | |
var v,i; | |
var da = 0; //direction attempts | |
var tries = 10000; | |
var lastdir = dir; | |
var snaketail = []; | |
var x = pos[0]; | |
var y = pos[1]; | |
var validDirs = getValidDirs(x, y); | |
i = 0; | |
var step = function () { | |
x = pos[0]; | |
y = pos[1]; | |
validDirs = getValidDirs(x, y); | |
// Quit | |
if (!validDirs.length){ | |
return; | |
} | |
// Maintain course | |
if (validDirs.indexOf(lastdir) >= 0 && !random) { | |
dir = lastdir; | |
} | |
// Choose new direction | |
else { | |
dir = validDirs[Math.floor(Math.random() * validDirs.length)]; | |
} | |
lastdir = dir; | |
pos = [ | |
x + dirs[dir][0], | |
y + dirs[dir][1] | |
]; | |
// Limit Tail Length | |
snaketail.unshift(pos); | |
if (snaketail.length > tailMaxLength) { | |
resetPosition(snaketail.pop()); | |
} | |
setCellValue(pos[0],pos[1],1); | |
render(grid); | |
i++; | |
}; | |
var next = function () { | |
if(i <= tries && validDirs.length){ | |
step(); | |
} else { | |
console.log("finished"); | |
refresh.stop(); | |
} | |
}; | |
refresh.setFreq(1/speed); | |
refresh.setCallback(next); | |
refresh.start(); | |
}; | |
var init = function(){ | |
grid = | |
[ | |
[0,0,3,0,0,0,0,0,0,0], | |
[0,0,0,0,0,0,0,0,0,0], | |
[0,0,0,0,0,0,0,2,0,0], | |
[0,0,0,0,0,0,0,0,0,3], | |
[0,0,0,0,0,0,0,0,0,0], | |
[0,0,0,2,0,0,0,0,0,0], | |
[0,0,0,0,0,0,0,0,0,0], | |
[0,0,0,0,3,0,0,0,0,0], | |
[0,0,0,0,0,0,0,0,0,0], | |
[0,0,0,0,0,0,0,0,0,0] | |
]; | |
render(grid); | |
snake_run([5,5], 0, false); | |
}; | |
// Bind Button | |
var btn = document.getElementById('play'); | |
btn.addEventListener('click', function(){refresh.start();}); | |
var btn1 = document.getElementById('pause'); | |
btn1.addEventListener('click', function(){refresh.reset();}); | |
var btn2 = document.getElementById('reset'); | |
btn2.addEventListener('click', function(){init();}); | |
var input_tail = document.getElementById('tail'); | |
input_tail.addEventListener('change', function(){tailMaxLength = parseInt(this.value, 10);clear();}); | |
var input_speed = document.getElementById('tail'); | |
init(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta name="description" content="Snake Experiment" /> | |
<meta charset=utf-8 /> | |
<title>JS Bin</title> | |
</head> | |
<body> | |
<canvas id="canvas" width="300" height="300"></canvas> | |
<br> | |
<button id="play">play</button> | |
<button id="pause">pause</button> | |
<button id="reset">reset</button> | |
<select id="tail"> | |
<option value=1>1</option> | |
<option value=2>2</option> | |
<option value=4>4</option> | |
<option value=6>6</option> | |
<option value=8>8</option> | |
<option value=10>10</option> | |
</select> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
canvas { | |
border: 1px solid #aaa; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment