No Backtracking

Example source code


<!DOCTYPE html>
<html>
<head>

<script type="text/javascript">
var ctx				= null;
var gameCanvas		= null;
var gameTime		= 0;
var gameSpeed		= 1;
var mapW			= 20;
var mapH			= 15;
var lastFrameTime	= 0;

var map = [
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0,
	0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0,
	0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0,
	0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0,
	0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0,
	0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0,
	0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0,
	0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0,
	0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0,
	0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0,
	0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0,
	0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0,
	0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
];

var character = {
	from		: [0, 0],
	to			: [0, 0],
	realPos		: [0, 0],
	departed	: 0,
	moveSpeed	: 230,
	target		: [0, 0],
	history		: [],
	maxHistory	: 20,

	update		: function(t)
	{
		if(this.from[0]!=this.to[0] || this.from[1]!=this.to[1])
		{
			if((t - this.departed)>=this.moveSpeed) { this.setPos(this.to[0], this.to[1]); }
			else
			{
				var amt = ((40/this.moveSpeed) * (t-this.departed));
				var amtX = (this.from[0]==this.to[0] ? 0 : (this.to[0]<this.from[0] ? 0 - amt : amt));
				var amtY = (this.from[1]==this.to[1] ? 0 : (this.to[1]<this.from[1] ? 0 - amt : amt));

				this.realPos = [
					(this.from[0]*40) + 5 + amtX,
					(this.from[1]*40) + 5 + amtY
				];
			}
		}
		else
		{
			if(this.from[0]!=this.target[0] || this.from[1]!=this.target[1])
			{
				var n = new Array();

				if(this.from[0]>0 && map[((this.from[1]*mapW)+this.from[0]-1)]==1) { n.push([this.from[0]-1, this.from[1], 0]); }
				if(this.from[0]<(mapW-1) && map[((this.from[1]*mapW)+this.from[0]+1)]==1) { n.push([this.from[0]+1, this.from[1], 0]); }
				if(this.from[1]>0 && map[(((this.from[1]-1)*mapW)+this.from[0])]==1) { n.push([this.from[0], this.from[1]-1, 0]); }
				if(this.from[1]<(mapH-1) && map[(((this.from[1]+1)*mapW)+this.from[0])]==1) { n.push([this.from[0], this.from[1]+1, 0]); }

				for(i in n)
				{
					n[i][2] = getDistance(this.target[0], this.target[1], n[i][0], n[i][1]);

					for(h in this.history) { if(n[i][0]==this.history[h][0] && n[i][1]==this.history[h][1]) { n[i][2] = n[i][2] + 10 + (h*10); } }
				}

				if(n.length)
				{
					n.sort(function(v1, v2) { return v1[2]-v2[2]; });

					this.to[0] = n[0][0];
					this.to[1] = n[0][1];
					this.departed = t;

					this.history.push([n[0][0], n[0][1]]);
					if(this.history.length > this.maxHistory) { this.history.shift(); }
				}
			}
		}
	},
	setPos		: function(px, py)
	{
		this.from 			= [px, py];
		this.to				= [px, py];
		this.realPos		= [(px*40)+5, (py*40)+5];
		this.departed		= 0;
	},
	setTarget	: function(px, py)
	{
		this.history.length	= 0;
		this.target			= [px, py];
	}
};

function getDistance(x1, y1, x2, y2)
{
	return (Math.abs(Math.sqrt(((x1-x2) * (x1-x2)) +
		((y1-y2) * (y1-y2)))));
}

window.onload = function()
{
	gameCanvas = document.getElementById('game');
	ctx = document.getElementById('game').getContext('2d');
	character.setPos(1,1);
	character.setTarget(1, 1);

	gameCanvas.addEventListener('mouseup', function(e) {
		mouseX = e.pageX;
		mouseY = e.pageY;

		var p = game;
		do
		{
			mouseX-= p.offsetLeft;
			mouseY-= p.offsetTop;

			p = p.offsetParent;
		} while(p!=null);

		var tileX = Math.floor(mouseX / 40);
		var tileY = Math.floor(mouseY / 40);

		if(tileX < mapW && tileY < mapH && map[((tileY*mapW)+tileX)]==1)
		{
			character.setTarget(tileX, tileY);
		}
	});

	requestAnimationFrame(drawGame);
};

function drawGame()
{
	if(ctx==null) { return; }
	if(lastFrameTime==0)
	{
		lastFrameTime = Date.now();
		requestAnimationFrame(drawGame);
		return;
	}

	var timeElapsed = Date.now()-lastFrameTime;
	gameTime+= (timeElapsed * gameSpeed);

	character.update(gameTime);

	for(y = 0; y < mapH; ++y)
	{
		for(x = 0; x < mapW; ++x)
		{
			ctx.fillStyle = (map[((y*mapW)+x)]==0 ? "#000000" : "#ffffff");
			ctx.fillRect((x*40), (y*40), 40, 40);
		}
	}

	ctx.fillStyle = "#ff0000";
	for(i in character.history)
	{
		var pos = character.history[i];
		ctx.fillRect((pos[0] * 40)+15, (pos[1]*40)+15, 10, 10);
	}

	ctx.fillStyle = "#0000bb";
	ctx.fillRect(character.realPos[0], character.realPos[1], 30, 30);

	ctx.lineWidth = 2;
	ctx.strokeStyle = "#00bb00";
	ctx.setLineDash([5, 5]);

	ctx.strokeRect(character.target[0]*40, character.target[1]*40, 40, 40);

	lastFrameTime = Date.now();
	requestAnimationFrame(drawGame);
}

</script>

</head>
<body>
<p>Click anywhere on the maps paths (white tiles) to set the characters destination.</p>
<canvas id="game" width="800" height="600"></canvas>

</body>
</html>

Page loaded in 0.011 second(s).