<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<HTML>
<HEAD>
<TITLE>Canvascape – 3D walker</TITLE>
<!–
This game is copyright by Benjamin Joffe.
You may not reproduce or modify this without
written permission by the origional author.
Email him: CanvasGame@gmail.com for suggestions.
–>
<SCRIPT type="text/javascript" >
function G_VmlCanvasManager() {
this.init();
}
G_VmlCanvasManager.prototype = {
init: function (opt_doc) {
var doc = opt_doc || document;
if (/MSIE/.test(navigator.userAgent) && !window.opera) {
var self = this;
doc.attachEvent("onreadystatechange", function () {
self.init_(doc);
});
}
},
init_: function (doc, e) {
if (doc.readyState == "complete") {
// create xmlns
if (!doc.namespaces["g_vml_"]) {
doc.namespaces.add("g_vml_", "urn:schemas-microsoft-com:vml");
}
// setup default css
var ss = doc.createStyleSheet();
ss.cssText = "canvas{display:inline-block; overflow:hidden; text-align:left;}" +
"canvas *{behavior:url(#default#VML)}";
// find all canvas elements
var els = doc.getElementsByTagName("canvas");
for (var i = 0; i < els.length; i++) {
if (!els[i].getContext) {
this.initElement(els[i]);
}
}
}
},
fixElement_: function (el) {
// in IE before version 5.5 we would need to add HTML: to the tag name
// but we do not care about IE before version 6
var outerHTML = el.outerHTML;
var newEl = document.createElement(outerHTML);
// if the tag is still open IE has created the children as siblings and
// it has also created a tag with the name "/FOO"
if (outerHTML.slice(-2) != "/>") {
var tagName = "/" + el.tagName;
var ns;
// remove content
while ((ns = el.nextSibling) && ns.tagName != tagName) {
ns.removeNode();
}
// remove the incorrect closing tag
if (ns) {
ns.removeNode();
}
}
el.parentNode.replaceChild(newEl, el);
return newEl;
},
initElement: function (el) {
el = this.fixElement_(el);
el.getContext = function () {
if (this._context) {
return this._context;
}
return this._context = new G_VmlCanvas(this);
};
var self = this; //bind
el.attachEvent("onpropertychange", function (e) {
// we need to watch changes to width and height
switch (e.propertyName) {
case "width":
case "height":
// coord size changed?
break;
}
});
// if style.height is set
var attrs = el.attributes;
if (attrs.width && attrs.width.specified) {
// TOD use runtimeStyle and coordsize
// el.getContext().setWidth_(attrs.width.nodeValue);
el.style.width = attrs.width.nodeValue + "px";
}
if (attrs.height && attrs.height.specified) {
// TOD use runtimeStyle and coordsize
// el.getContext().setHeight_(attrs.height.nodeValue);
el.style.height = attrs.height.nodeValue + "px";
}
//el.getContext().setCoordsize_()
}
};
var G_vmlCanvasManager = new G_VmlCanvasManager;
function G_VmlCanvas(surface) {
this.m = G_VmlCanvas.MatrixIdentity();
this.element = surface;
this.mStack = [];
this.aStack = [];
this.currentPath = [];
// Canvas context properties
this.strokeStyle = "#000";
this.fillStyle = "#ccc";
this.lineWidth = 1;
this.lineJoin = ‘miter’;
this.lineCap = ‘butt’;
this.miterLimit = 10.0;
this.globalAlpha = 1.0;
};
G_VmlCanvas.dec2hex = [];
(function () {
for (var i = 0; i < 16; i++) {
for (var j = 0; j < 16; j++) {
G_VmlCanvas.dec2hex[i * 16 + j] = i.toString(16) + j.toString(16);
}
}
})();
G_VmlCanvas.MatrixIdentity = function() {
return [
[1,0,0],
[0,1,0],
[0,0,1]
];
}
G_VmlCanvas.MatrixMultiply = function(m1, m2) {
var result = G_VmlCanvas.MatrixIdentity();
for (var x = 0; x < 3; x++) {
for (var y = 0; y < 3; y++) {
var sum = 0;
for (var z = 0; z < 3; z++) {
sum += m1[x][z] * m2[z][y];
}
result[x][y] = sum;
}
}
return result;
}
G_VmlCanvas.CopyState = function(o1, o2) {
o2.fillStyle = o1.fillStyle;
o2.lineCap = o1.lineCap;
o2.lineJoin = o1.lineJoin;
o2.lineWidth = o1.lineWidth;
o2.miterLimit = o1.miterLimit;
o2.shadowBlur = o1.shadowBlur;
o2.shadowColor = o1.shadowColor;
o2.shadowOffsetX = o1.shadowOffsetX;
o2.shadowOffsetY = o1.shadowOffsetY;
o2.strokeStyle = o1.strokeStyle;
};
G_VmlCanvas.ProcessStyle = function(styleString) {
var str, alpha = 1.0;
styleString = String(styleString);
if (styleString.substring(0, 3) == "rgb") {
var start = styleString.indexOf("(", 3);
var end = styleString.indexOf(")", start + 1);
var guts = styleString.substring(start + 1, end).split(",");
str = "#";
for (var i = 0; i < 3; i++) {
str += G_VmlCanvas.dec2hex[parseInt(guts[i])];
}
if ((guts.length == 4) && (styleString.substr(3, 1) == "a")) {
alpha = guts[3];
}
} else {
str = styleString;
}
return [str, alpha];
}
G_VmlCanvas.ProcessLineCap = function(lineCap) {
switch (lineCap) {
case ‘butt’: return ‘flat’;
case ’round’: return ’round’;
case ‘square’: return ‘square’;
}
};
G_VmlCanvas.prototype.clearRect = function() {
this.element.innerHTML = "";
this.currentPath = [];
};
G_VmlCanvas.prototype.beginPath = function() {
// TODO(glen): Branch current matrix so that save/restore has no effect
// as per safari docs.
this.currentPath = [];
};
G_VmlCanvas.prototype.moveTo = function(aX, aY) {
this.currentPath.push({type: ‘moveTo’, x: aX, y:aY});
};
G_VmlCanvas.prototype.lineTo = function(aX, aY) {
this.currentPath.push({type: ‘lineTo’, x: aX, y:aY});
};
G_VmlCanvas.prototype.bezierCurveTo = function(aCP1x, aCP1y, aCP2x, aCP2y, aX, aY) {
this.currentPath.push({type: ‘bezierCurveTo’,
cp1x: aCP1x,
cp1y: aCP1y,
cp2x: aCP2x,
cp2y: aCP2y,
x: aX,
y: aY});
}
G_VmlCanvas.prototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
// VML’s qb produces different output to Firefox’s
this.bezierCurveTo(aCPx, aCPy, aCPx, aCPy, aX, aY);
}
G_VmlCanvas.prototype.arc = function(aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise) {
if (!aClockwise) {
var t = aStartAngle;
aStartAngle = aEndAngle;
aEndAngle = t;
}
var xStart = aX + (Math.cos(aStartAngle) * aRadius);
var yStart = aY + (Math.sin(aStartAngle) * aRadius);
var xEnd = aX + (Math.cos(aEndAngle) * aRadius);
var yEnd = aY + (Math.sin(aEndAngle) * aRadius);
this.currentPath.push({type: ‘arc’,
x: aX,
y: aY,
radius: aRadius,
xStart: xStart,
yStart: yStart,
xEnd: xEnd,
yEnd: yEnd});
}
G_VmlCanvas.prototype.strokeRect = function(aX, aY, aWidth, aHeight) {
// Will destroy any existing path (same as FF behaviour)
this.beginPath();
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
this.stroke();
}
G_VmlCanvas.prototype.fillRect = function(aX, aY, aWidth, aHeight) {
// Will destroy any existing path (same as FF behaviour)
this.beginPath();
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
this.fill();
}
// Gradient / Pattern Stubs
function G_VmlGradient(aType) {
this.type = aType;
this.radius1 = 0;
this.radius2 = 0;
this.colors = [];
this.focus = {x: 0, y:0};
}
G_VmlGradient.prototype.addColorStop = function(aOffset, aColor) {
aColor = G_VmlCanvas.ProcessStyle(aColor);
this.colors.push({offset: 1-aOffset, color: aColor});
}
G_VmlCanvas.prototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
var gradient = new G_VmlGradient("gradient");
return gradient;
}
G_VmlCanvas.prototype.createRadialGradient = function(aX0, aY0, aR0, aX1, aY1, aR1) {
var gradient = new G_VmlGradient("gradientradial");
gradient.radius1 = aR0;
gradient.radius2 = aR1;
gradient.focus.x = aX0;
gradient.focus.y = aY0;
return gradient;
}
G_VmlCanvas.prototype.drawImage = function (image, var_args) {
var dx, dy, dw, dh, sx, sy, sw, sh;
var w = image.width;
var h = image.height;
if (arguments.length == 3) {
dx = arguments[1];
dy = arguments[2];
sx = sy = 0;
sw = dw = w;
sh = dh = h;
} else if (arguments.length == 5) {
dx = arguments[1];
dy = arguments[2];
dw = arguments[3];
dh = arguments[4];
sx = sy = 0;
sw = w;
sh = h;
} else if (arguments.length == 9) {
sx = arguments[1];
sy = arguments[2];
sw = arguments[3];
sh = arguments[4];
dx = arguments[5];
dy = arguments[6];
dw = arguments[7];
dh = arguments[8];
} else {
throw "Invalid number of arguments";
}
var d = this.Coords(dx, dy);
var w2 = (sw / 2);
var h2 = (sh / 2);
var vmlStr = [];
// For some reason that I’ve now forgotten, using divs didn’t work
vmlStr.push(‘ <g_vml_:group’,
‘ coordsize="100,100"’,
‘ coordorigin="0, 0"’ ,
‘ style="width:100px; height:100px; position:absolute; ‘);
// If filters are necessary (rotation exists), create them
// filters are bog-slow, so only create them if abbsolutely necessary
// The following check doesn’t account for skews (which don’t exist
// in the canvas spec (yet) anyway.
if (this.m[0][0] != 1 || this.m[0][1]) {
var filter = [];
// Note the 12/21 reversal
filter.push("M11=’",this.m[0][0],"’,",
"M12=’",this.m[1][0],"’,",
"M21=’",this.m[0][1],"’,",
"M22=’",this.m[1][1],"’,",
"Dx=’",d.x,"’,",
"Dy=’",d.y,"’");
// Bounding box calculation (need to minimize displayed area so that filters
// don’t waste time on unused pixels.
var max = d;
var c2 = this.Coords(dx+dw, dy);
var c3 = this.Coords(dx, dy+dh);
var c4 = this.Coords(dx+dw, dy+dh);
max.x = Math.max(max.x, c2.x, c3.x, c4.x);
max.y = Math.max(max.y, c2.y, c3.y, c4.y);
vmlStr.push(‘ padding:0px ‘, Math.floor(max.x), ‘px ‘, Math.floor(max.y),
‘px 0px;filter:progid:DXImageTransform.Microsoft.Matrix(‘,
filter.join(""), ‘, sizingmethod=\’clip\’);’)
} else {
vmlStr.push(‘ top:’,d.y,’px; left:’,d.x,’px;’)
}
vmlStr.push(‘ ">’ ,
‘<g_vml_:image src="’, image.src, ‘"’,
‘ style="width:’, dw, ‘;’,
‘ height:’, dh, ‘;"’,
‘ cropleft="’, sx / w, ‘"’,
‘ croptop="’, sy / h, ‘"’,
‘ cropright="’, (w – sx – sw) / w, ‘"’,
‘ cropbottom="’, (h – sy – sh) / h, ‘"’,
‘ />’,
‘ </g_vml_:group>’);
//this.element.innerHTML += vmlStr.join("");
this.element.insertAdjacentHTML("BeforeEnd",
vmlStr.join(""));
};
G_VmlCanvas.prototype.stroke = function(aFill) {
var strokeColor, fillColor, opacity;
var lineStr = [];
var lineOpen = false;
if (aFill) {
var a = G_VmlCanvas.ProcessStyle(this.fillStyle);
fillColor = a[0];
opacity = a[1] * this.globalAlpha;
} else {
var a = G_VmlCanvas.ProcessStyle(this.strokeStyle);
strokeColor = a[0];
opacity = a[1] * this.globalAlpha;
}
lineStr.push(‘<g_vml_:shape’,
‘ fillcolor="’, fillColor, ‘"’,
‘ filled="’,(aFill) ? "true" : "false",’"’,
‘ style="position:absolute; width:10; height:10;"’,
‘ coordorigin="0 0" coordsize="10 10"’,
‘ stroked="’,(aFill) ? "false" : "true",’"’,
‘ strokeweight="’, this.lineWidth, ‘"’,
‘ strokecolor="’, strokeColor, ‘"’,
‘ path="’);
var newSeq = false;
var min = {x:null, y:null};
var max = {x:null, y:null};
for (var i = 0; i < this.currentPath.length; i++) {
var p = this.currentPath[i];
if (p.type == ‘moveTo’) {
lineStr.push(‘ m ‘);
var c = this.Coords(p.x, p.y);
lineStr.push(Math.floor(c.x), ‘,’, Math.floor(c.y));
} else if (p.type == ‘lineTo’) {
lineStr.push(‘ l ‘);
var c = this.Coords(p.x, p.y);
lineStr.push(Math.floor(c.x), ‘,’, Math.floor(c.y));
} else if (p.type == ‘close’) {
lineStr.push(‘ x ‘);
} else if (p.type == ‘bezierCurveTo’) {
lineStr.push(‘ c ‘);
var c = this.Coords(p.x, p.y);
var c1 = this.Coords(p.cp1x, p.cp1y);
var c2 = this.Coords(p.cp2x, p.cp2y);
lineStr.push(Math.floor(c1.x), ‘,’, Math.floor(c1.y), ‘,’,
Math.floor(c2.x), ‘,’, Math.floor(c2.y), ‘,’,
Math.floor(c.x), ‘,’, Math.floor(c.y));
} else if (p.type == ‘arc’) {
lineStr.push(‘ ar ‘);
var c = this.Coords(p.x, p.y);
var cStart = this.Coords(p.xStart, p.yStart);
var cEnd = this.Coords(p.xEnd, p.yEnd);
// TODO(glen): FIX (matricies (scale+rotation) now buggered this up)
// VML arc also doesn’t seem able to do rotated non-circular
// arcs without parent grouping.
var absXScale = this.m[0][0];
var absYScale = this.m[1][1];
lineStr.push(Math.floor(c.x – absXScale * p.radius), ‘,’, Math.floor(c.y – absYScale * p.radius), ‘ ‘,
Math.floor(c.x + absXScale * p.radius), ‘,’, Math.floor(c.y + absYScale * p.radius), ‘ ‘,
Math.floor(cStart.x), ‘,’, Math.floor(cStart.y), ‘ ‘,
Math.floor(cEnd.x), ‘,’, Math.floor(cEnd.y));
}
// TODO(glen): Following is broken for curves due to
// move to proper paths.
// Figure out dimensions so we can do gradient fills
// properly
if (min.x == null || c.x < min.x) {
min.x = c.x;
}
if (max.x == null || c.x > max.x) {
max.x = c.x;
}
if (min.y == null || c.y < min.y) {
min.y = c.y;
}
if (max.y == null || c.y > max.y) {
max.y = c.y;
}
}
lineStr.push(‘ ">’);
if (typeof this.fillStyle == ‘object’) {
var focus = {x:"50%", y:"50%"};
var width = (max.x – min.x);
var height = (max.y – min.y);
var dimension = (width > height) ? width : height;
focus.x = Math.floor((this.fillStyle.focus.x / width) * 100 + 50) + ‘%’;
focus.y = Math.floor((this.fillStyle.focus.y / height) * 100 + 50) + ‘%’;
var colors = [];
// inside radius (%)
if (this.fillStyle.type == ‘gradientradial’) {
var inside = (this.fillStyle.radius1 / dimension * 100);
// percentage that outside radius exceeds inside radius
var expansion = (this.fillStyle.radius2 / dimension * 100) – inside;
} else {
var inside = 0;
var expansion = 100;
}
var insidecolor = {offset:null, color:null};
var outsidecolor = {offset:null, color:null};
// We need to sort ‘colors’ by percentage, from 0 > 100 otherwise ie won’t
// interpret it correctly
this.fillStyle.colors.sort(function (cs1, cs2) {
return cs1.offset – cs2.offset;
});
for (var i = 0; i < this.fillStyle.colors.length; i++) {
var fs = this.fillStyle.colors[i];
colors.push( (fs.offset * expansion) + inside,’% ‘,fs.color,",");
if (fs.offset > insidecolor.offset || insidecolor.offset == null) {
insidecolor.offset = fs.offset;
insidecolor.color = fs.color;
}
if (fs.offset < outsidecolor.offset || outsidecolor.offset == null) {
outsidecolor.offset = fs.offset;
outsidecolor.color = fs.color;
}
}
colors.pop();
lineStr.push(‘<g_vml_:fill’,
‘ color="’,outsidecolor.color,’"’,
‘ color2="’,insidecolor.color,’"’,
‘ type="’, this.fillStyle.type, ‘"’,
‘ focusposition="’, focus.x, ‘, ‘, focus.y, ‘"’,
‘ colors="’, colors.join(”), ‘" />’);
}
if (aFill) {
lineStr.push(‘<g_vml_:fill opacity="’, opacity, ‘" />’);
} else {
lineStr.push(‘<g_vml_:stroke opacity="’, opacity, ‘" joinstyle="’, this.lineJoin, ‘" miterlimit="’, this.miterLimit, ‘" endcap="’, G_VmlCanvas.ProcessLineCap(this.lineCap) ,’" />’);
}
lineStr.push(‘</g_vml_:shape>’);
this.element.insertAdjacentHTML("beforeEnd", lineStr.join(""));
this.currentPath = [];
};
G_VmlCanvas.prototype.fill = function() {
this.stroke(true);
}
G_VmlCanvas.prototype.closePath = function() {
this.currentPath.push({type: ‘close’});
};
G_VmlCanvas.prototype.Coords = function(aX, aY) {
return {
x: (aX * this.m[0][0] + aY * this.m[1][0] + this.m[2][0]),
y: (aX * this.m[0][1] + aY * this.m[1][1] + this.m[2][1])
}
};
G_VmlCanvas.prototype.save = function() {
var o = {};
G_VmlCanvas.CopyState(this, o);
this.aStack.push(o);
this.mStack.push(this.m);
this.m = G_VmlCanvas.MatrixMultiply(G_VmlCanvas.MatrixIdentity(), this.m);//new G_VmlCanvas.Matrix(this.m.x, this.m.y, this.m.rot, this.m.xScale, this.m.yScale);
};
G_VmlCanvas.prototype.restore = function() {
G_VmlCanvas.CopyState(this.aStack.pop(), this);
this.m = this.mStack.pop();
};
G_VmlCanvas.prototype.translate = function(aX, aY) {
var m1 = [
[1, 0, 0],
[0, 1, 0],
[aX, aY, 1]
];
this.m = G_VmlCanvas.MatrixMultiply(m1, this.m);
};
G_VmlCanvas.prototype.rotate = function(aRot) {
var c = Math.cos(aRot);
var s = Math.sin(aRot);
var m1 = [
[c, s, 0],
[-s, c, 0],
[0, 0, 1]
];
this.m = G_VmlCanvas.MatrixMultiply(m1, this.m);
};
G_VmlCanvas.prototype.scale = function(aX, aY) {
var m1 = [
[aX, 0, 0],
[0, aY, 0],
[0, 0, 1]
];
this.m = G_VmlCanvas.MatrixMultiply(m1, this.m);
};
/******** STUBS ********/
G_VmlCanvas.prototype.clip = function() {;}
G_VmlCanvas.prototype.createPattern = function() {;}
</SCRIPT>
<STYLE type="text/css"><!–
H1 {
padding: 5px;
font-size: 14pt;
font-style: italic;
}
BODY {
font-family: arial;
font-size: 10pt;
background-color: #000;
color: #CCC;
}
#holder {
position: relative;
width: 400px;
height:300px;
top: 10px;
left: 120px;
border: 2px solid #333;
}
#sky {
position: absolute;
left: 0;
top: 0;
height: 150px;
width: 400px;
background-color: #CCD;
background-image: url(sky.jpg);
}
#floor {
position: absolute;
left: 0;
top: 150px;
height: 150px;
width: 400px;
background-color: #565;
background-image: url(floor.png);
}
#canvas {
position: absolute;
top: 0;
left: 0;
}
#overlay {
position: absolute;
top: 0;
left: 0;
width: 400px;
height: 300px;
background-image: url(overlay.gif);
}
#map, #underMap {
top: 70px;
left: 20px;
position: absolute;
}
#copyright {
position: absolute;
top: 170px;
left: 15px;
}
A {
color: #66AACC;
}
A:hover {
color: lime;
}
–></STYLE>
</HEAD>
<BODY>
<H1>Canvascape – "3D Walker"</H1>
<CANVAS id="underMap" width="80" height="80"></CANVAS>
<CANVAS id="map" width="80" height="80"></CANVAS>
<DIV id="copyright">
© Benjamin Joffe<BR>
<A href="mailtCanvasGame@gmail.com" style="font-size:7pt;">canvasGame@gmail.com</A>
</DIV>
<DIV id="holder" style="clear:both;">
<DIV id="sky"></DIV>
<DIV id="floor"></DIV>
<CANVAS id="canvas" width="400" height="300"></CANVAS>
<DIV id="overlay"></DIV>
</DIV>
<P>Use the arrow keys to walk around the map. Space bar = jump.</P>
<P>What you are seeing is a test using the new Canvas tag to demonstrate its capabilities, Internet Explorer support has recently been added thanks to Google’s workaround code. See als <A href="textures.htm">textured version</A>.</P>
<P><A href="Web’>http://www.studiocoast.com.au/">Web xiaoyebailong.coming provided by Studio Coast</A></P>
<SCRIPT type="text/javascript"><!–
/*
This code is copyright by Benjamin Joffe.
You may not reproduce or modify this without
written permission by the origional author.
Email him: CanvasGame@gmail.com for suggestions.
*/
var map;
var canvas;
var overlay;
//variables initiated at the bottom of the code…
var pi=Math.PI;
var total=0;
Number.prototype.range=function(){
return (this+2*pi)%(2*pi);
}
Number.prototype.roundC=function(){
return Math.round(this*100)/100;
}
var total=0;
var samples=200;
var arena=[];
arena[0]=[1,1,1,1,1,1,1,1,1,1]
arena[1]=[1,0,0,0,0,0,0,0,0,1]
arena[2]=[1,0,0,1,0,1,1,1,0,1]
arena[3]=[1,0,1,0,0,0,0,1,0,1]
arena[4]=[1,0,0,0,0,1,0,1,0,1]
arena[5]=[1,0,1,1,0,0,0,0,0,1]
arena[6]=[1,0,0,1,0,1,1,1,0,1]
arena[7]=[1,1,0,1,0,0,0,1,0,1]
arena[8]=[1,0,0,1,0,1,0,0,0,1]
arena[9]=[1,1,1,1,1,1,1,1,1,1]
var playerPos=[4,4]; // x,y (from top left)
var playerDir=0.4; // theta, facing right=0=2pi
var playerPosZ=1;
var key=[0,0,0,0,0]; // left, right, up, down
var playerVelY=0;
var face=[];
function wallDistance(theta){
var data=[];
face=[];
var x = playerPos[0], y = playerPos[1];
var deltaX, deltaY;
var distX, distY;
var stepX, stepY;
var mapX, mapY
var atX=Math.floor(x), atY=Math.floor(y);
var thisRow=-1;
var thisSide=-1;
var lastHeight=0;
for (var i=0; i<samples; i++) {
theta+=pi/(3*samples)+2*pi;
theta%=2*pi;
mapX = atX, mapY = atY;
deltaX=1/Math.cos(theta);
deltaY=1/Math.sin(theta);
if (deltaX>0) {
stepX = 1;
distX = (mapX + 1 – x) * deltaX;
}
else {
stepX = -1;
distX = (x – mapX) * (deltaX*=-1);
}
if (deltaY>0) {
stepY = 1;
distY = (mapY + 1 – y) * deltaY;
}
else {
stepY = -1;
distY = (y – mapY) * (deltaY*=-1);
}
for (var j=0; j<20; j++) {
if (distX < distY) {
mapX += stepX;
if (arena[mapX][mapY]) {
if (thisRow!=mapX || thisSide!=0) {
if (i>0) {
data.push(i);
data.push(lastHeight);
}
data.push(i);
data.push(distX);
thisSide=0;
thisRow=mapX;
face.push(1+stepX);
}
lastHeight=distX;
break;
}
distX += deltaX;
}
else {
mapY += stepY;
if (arena[mapX][mapY]) {
if (thisRow!=mapY || thisSide!=1) {
if (i>0) {
data.push(i);
data.push(lastHeight);
}
data.push(i);
data.push(distY);
thisSide=1;
thisRow=mapY;
face.push(2+stepY)
}
lastHeight=distY;
break;
}
distY += deltaY;
}
}
}
data.push(i);
data.push(lastHeight);
return data;
}
function drawCanvas(){
canvas.clearRect(0,0,400, 300);
var theta = playerDir-pi/6;
var wall=wallDistance(theta);
map.beginPath();
map.clearRect(0,0,80,80);
map.fillStyle="#3366CC";
map.arc(playerPos[0]*8, playerPos[1]*8, 3, 0, 2*pi, true);
map.fill();
map.beginPath();
map.moveTo(8*playerPos[0], 8*playerPos[1]);
var linGrad;
var tl,tr,bl,br;
var theta1,theta2,fix1,fix2;
for (var i=0; i<wall.length; i+=4) {
theta1=playerDir-pi/6 + pi*wall[i]/(3*samples);
theta2=playerDir-pi/6 + pi*wall[i+2]/(3*samples);
fix1 = Math.cos(theta1-playerDir);
fix2 = Math.cos(theta2-playerDir);
var h=2-playerPosZ;
var wallH1=100/(wall[i+1]*fix1);
var wallH2=100/(wall[i+3]*fix2);
tl=[wall[i]*2, 150-wallH1*h];
tr=[wall[i+2]*2, 150-wallH2*h]
br=[wall[i+2]*2, tr[1]+wallH2*2];
bl=[wall[i]*2, tl[1]+wallH1*2]
var shade1=Math.floor(wallH1*2+20); if (shade1>255) shade1=255;
var shade2=Math.floor(wallH2*2+20); if (shade2>255) shade2=255;
linGrad = canvas.createLinearGradient(tl[0],0,tr[0],0);
linGrad.addColorStop(0, ‘rgba(‘+(face[i/4]%2==0 ? shade1 : 0)+’,’+(face[i/4]==1 ? shade1 : 0)+’,’+(face[i/4]==2 ? 0 : shade1)+’,1.0)’);
linGrad.addColorStop(1, ‘rgba(‘+(face[i/4]%2==0 ? shade2 : 0)+’,’+(face[i/4]==1 ? shade2 : 0)+’,’+(face[i/4]==2 ? 0 : shade2)+’,1.0)’);
canvas.beginPath();
canvas.moveTo(tl[0], tl[1]);
canvas.lineTo(tr[0], tr[1]);
canvas.lineTo(br[0], br[1]);
canvas.lineTo(bl[0], bl[1]);
canvas.fillStyle = linGrad;
canvas.fill();
map.lineTo(playerPos[0]*8+Math.cos(theta1)*(wall[i+1])*8, playerPos[1]*8+Math.sin(theta1)*(wall[i+1])*8);
map.lineTo(playerPos[0]*8+Math.cos(theta2)*(wall[i+3])*8, playerPos[1]*8+Math.sin(theta2)*(wall[i+3])*8);
}
map.fillStyle="#FF0000"
map.fill();
}
function nearWall(x,y){
var xx,yy;
if (isNaN(x)) x=playerPos[0];
if (isNaN(y)) y=playerPos[1];
for (var i=-0.1; i<=0.1; i+=0.2) {
xx=Math.floor(x+i)
for (var j=-0.1; j<=0.1; j+=0.2) {
yy=Math.floor(y+j);
if (arena[xx][yy]) return true;
}
}
return false;
}
function wobbleGun(){
var mag=playerVelY;
overlay.style.backgroundPosition=(10+Math.cos(total/6.23)*mag*90)+"px "+(10+Math.cos(total/5)*mag*90)+"px";
}
var jumpCycle=0;
function update(){
total++;
var change=false;
if (jumpCycle) {
jumpCycle–;
change=true;
playerPosZ = 1 + jumpCycle*(20-jumpCycle)/110;
}
else if (key[4]) jumpCycle=20;
if (key[0]) {
if (!key[1]) {
playerDir-=0.07; //left
change=true;
}
}
else if (key[1]) {
playerDir+=0.07; //right
change=true;
}
if (change) {
playerDir+=2*pi;
playerDir%=2*pi;
document.getElementById("sky").style.backgroundPosition=Math.floor(1-playerDir/(2*pi)*2400)+"px 0";
}
if (key[2] && !key[3]) {
if (playerVelY<0.1) playerVelY += 0.02;
}
else if (key[3] && !key[2]) {
if (playerVelY>-0.1) playerVelY -= 0.02;
}
else {
if (playerVelY<-0.02) playerVelY += 0.015;
else if (playerVelY>0.02) playerVelY -= 0.015;
else playerVelY=0;
}
if (playerVelY!=0) {
var oldX=playerPos[0];;
var oldY=playerPos[1];
var newX=oldX+Math.cos(playerDir)*playerVelY;
var newY=oldY+Math.sin(playerDir)*playerVelY;
if (!nearWall(newX, oldY)) {
playerPos[0]=newX;
oldX=newX;
change=true;
}
if (!nearWall(oldX, newY)) {
playerPos[1]=newY;
change=true;
}
}
if (playerVelY) wobbleGun();
if (change) drawCanvas();
}
function changeKey(which, to){
switch (which){
case 65:case 37: key[0]=to; break; // left
case 87: case 38: key[2]=to; break; // up
case 68: case 39: key[1]=to; break; // right
case 83: case 40: key[3]=to; break;// down
case 32: key[4]=to; break; // space bar;
case 17: key[5]=to; break; // ctrl
}
}
document.onkeydown=function(e){changeKey((e||window.event).keyCode, 1);}
document.onkeyup=function(e){changeKey((e||window.event).keyCode, 0);}
function initUnderMap(){
var underMap=document.getElementById("underMap").getContext("2d");
underMap.fillStyle="#FFF";
underMap.fillRect(0,0, 200, 200);
underMap.fillStyle="#444";
for (var i=0; i<arena.length; i++) {
for (var j=0; j<arena[i].length; j++) {
if (arena[i][j]) underMap.fillRect(i*8, j*8, 8, 8);
}
}
}
window.onerror=function(){
alert(‘An error has occured, the most likely reason is because you are using an incompatible browser.\nYou must be using one of the following browsers or a newer version:\n\n- Internet Explorer 6\n- Firefox 1.5\n- Safari 1.3\n- Opera 9’);
window.onerror=function(){};
return true;
}
window.onload=function(){
map=document.getElementById("map").getContext("2d");
canvas=document.getElementById("canvas").getContext("2d");
overlay=document.getElementById("overlay");
document.getElementById("sky").style.backgroundPosition=Math.floor(-playerDir/(2*pi)*2400)+"px 0";
drawCanvas();
initUnderMap();
setInterval(update, 35);
}
//–></SCRIPT>
<!– Start of StatCounter Code –>
<script type="text/javascript" language="javascript">
var sc_project=1082313;
var sc_invisible=1;
var sc_partition=9;
var sc_security="adb52a92";
</script>
<!– End of StatCounter Code –>
</BODY>
</HTML>
评论前必须登录!
注册