Note that there are some explanatory texts on larger screens.

plurals
  1. POHow do I fix shocking/lagging movement in this ajax based multiplayer example?
    primarykey
    data
    text
    <p>EDIT: important, examples must be used in firefox 3+ due to html5 elements.</p> <p>Hi there,</p> <p>I'm trying to find out more about the potential of AJAX in a browser based multiplayer game. To do so, I'm testing out movement with AJAX and a space shuttle as a character. This space shuttle is rendered with canvas (html5).</p> <p>My first version is ready, you can test it out here: [<a href="http://ajax.uptowar.com/test3/][1]" rel="nofollow noreferrer">http://ajax.uptowar.com/test3/][1]</a></p> <p>Source code:</p> <pre><code>&lt;?php header('Content-Type: text/html;charset=utf-8'); header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); header("Cache-Control: no-store, no-cache, must-revalidate"); header("Cache-Control: post-check=0, pre-check=0", false); header("Pragma: no-cache"); session_start(); $_SESSION['playerid'] = ""; echo("&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\n"); ?&gt; &lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt; &lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"&gt; &lt;head&gt; &lt;title&gt;ajax test&lt;/title&gt; &lt;meta http-equiv="pragma" content="no-cache" /&gt; &lt;meta http-equiv="expires" content="-1" /&gt; &lt;meta name="robots" content="index, follow" /&gt; &lt;meta name="audience" content="all" /&gt; &lt;meta http-equiv="content-language" content="en" /&gt; &lt;meta http-equiv="content-type" content="text/html; charset=utf-8" /&gt; &lt;script type="text/javascript"&gt; //vars var presstime = 300; //howlong a button should be hold down for 1 event fire var ajaxivtime = 500; //interval at which doAjax is executed, unless a manual request has been send within this time var keypressivtime = 50; //interval at which the keypress fire event is fired //init vars var keysdown = []; //array for what keys are down at a specific moment var cobjects = []; //array for all canvas objects var oldpress = 0; var ajaxrestime = 0; var latency = 0; //functions function isset() { var a = arguments; var l = a.length; var i = 0; if (l === 0) { return false; } while (i != l) { if (typeof(a[i]) == 'undefined' || a[i] === null) { return false; } else { i++; } } return true; } function keycheck(e) { var keynum; if (window.event) { //IE keynum = e.keyCode; } else if (e.which) { // Netscape // FireFox // Opera keynum = e.which; } if (keysdown.indexOf(keynum) == -1) { keysdown.push(keynum); } return true; } function updateLatency(oldLatencyTime) { var curtime = new Date(); curtime = curtime.getTime(); if (oldLatencyTime !== 0) { latency = curtime - oldLatencyTime; document.title = "Latency: " + latency + "ms"; } return true; } function setAjaxResTime() { var curtime = new Date(); ajaxrestime = curtime.getTime(); return true; } function getAjaxResTimeDiff() { var curtime = new Date(); curtime = curtime.getTime(); return curtime - ajaxrestime; } function setOldPress() { var curtime = new Date(); oldpress = curtime.getTime(); return true; } function getPressTimeDiff() { var curtime = new Date(); curtime = curtime.getTime(); return curtime - oldpress; } function searchcobjects(canvasid) { indexes = cobjects.length - 1; i = 0; while (i &lt;= indexes) { if (cobjects[i][0] == canvasid) { return i; } i++; } return -1; } function getCurX(canvasid) { var key = searchcobjects(canvasid); if (key == -1) { return -1; } return cobjects[key][2]; } function getCurY(canvasid) { var key = searchcobjects(canvasid); if (key == -1) { return -1; } return cobjects[key][3]; } function getTarX(canvasid) { var key = searchcobjects(canvasid); if (key == -1) { return -1; } return cobjects[key][4]; } function getTarY(canvasid) { var key = searchcobjects(canvasid); if (key == -1) { return -1; } return cobjects[key][5]; } function getStepCoords(cur, tar, step) { var curX = cur[0]; var curY = cur[1]; var tarX = tar[0]; var tarY = tar[1]; var xmultiplier; var ymultiplier; var xdiff; var ydiff; if ((tarX &gt; curX)&amp;&amp;(tarY == curY)) { xmultiplier = 1; ymultiplier = 0; } else if ((tarX &lt; curX)&amp;&amp;(tarY == curY)) { xmultiplier = -1; ymultiplier = 0; } else if ((tarY &gt; curY)&amp;&amp;(tarX == curX)) { xmultiplier = 0; ymultiplier = 1; } else if ((tarY &lt; curY)&amp;&amp;(tarX == curX)) { xmultiplier = 0; ymultiplier = -1; } else if ((tarX &gt; curX)&amp;&amp;(tarY &gt; curY)) { xdiff = tarX - curX; ydiff = tarY - curY; xmultiplier = xdiff / (xdiff + ydiff); ymultiplier = ydiff / (xdiff + ydiff); } else if ((tarX &lt; curX)&amp;&amp;(tarY &lt; curY)) { xdiff = curX - tarX; ydiff = curY - tarY; xmultiplier = -(xdiff / (xdiff + ydiff)); ymultiplier = -(ydiff / (xdiff + ydiff)); } else if ((tarX &gt; curX)&amp;&amp;(tarY &lt; curY)) { xdiff = tarX - curX; ydiff = curY - tarY; xmultiplier = xdiff / (xdiff + ydiff); ymultiplier = -(ydiff / (xdiff + ydiff)); } else if ((tarX &lt; curX)&amp;&amp;(tarY &gt; curY)) { xdiff = curX - tarX; ydiff = tarY - curY; xmultiplier = -(xdiff / (xdiff + ydiff)); ymultiplier = ydiff / (xdiff + ydiff); } var newx = curX + Math.round(step * xmultiplier); var newy = curY + Math.round(step * ymultiplier); return [newx, newy]; } function updateTarX(canvasid, x) { var key = searchcobjects(canvasid); if (key == -1) { return false; } else { cobjects[key][4] = x; } return true; } function updateTarY(canvasid, y) { var key = searchcobjects(canvasid); if (key == -1) { return false; } else { cobjects[key][5] = y; } return true; } function updateCurX(canvasid, x) { var key = searchcobjects(canvasid); if (key == -1) { return false; } else { cobjects[key][2] = x; } return true; } function updateCurY(canvasid, y) { var key = searchcobjects(canvasid); if (key == -1) { return false; } else { cobjects[key][3] = y; } return true; } function updateTarAngle(canvasid, angle) { var key = searchcobjects(canvasid); if (key == -1) { return false; } else { cobjects[key][8] = angle; } return true; } function updateCurAngle(canvasid, angle) { var key = searchcobjects(canvasid); if (key == -1) { return false; } else { cobjects[key][7] = angle; } return true; } function getCurAngle(canvasid) { var key = searchcobjects(canvasid); if (key == -1) { return -1; } return cobjects[key][7]; } function getTarAngle(canvasid) { var key = searchcobjects(canvasid); if (key == -1) { return -1; } return cobjects[key][8]; } function isMoving(canvasid) { var key = searchcobjects(canvasid); if (key == -1) { return false; } else if (cobjects[key][2] == 1) { return true; } return false; } function isRotating(canvasid) { var key = searchcobjects(canvasid); if (key == -1) { return false; } else if (cobjects[key][6] == 1) { return true; } return false; } function startRotating(canvasid) { var key = searchcobjects(canvasid); if (key == -1) { return false; } else { cobjects[key][6] = 1; } return true; } function stopRotating(canvasid) { var key = searchcobjects(canvasid); if (key == -1) { return false; } else { cobjects[key][6] = 0; } return true; } function startMoving(canvasid) { var key = searchcobjects(canvasid); if (key == -1) { return false; } else { cobjects[key][3] = 1; } return true; } function stopMoving(canvasid) { var key = searchcobjects(canvasid); if (key == -1) { return false; } else { cobjects[key][4] = 0; } return true; } function drawSprite(ctx, angle, img, centerX, centerY) { ctx.save(); ctx.translate(centerX, centerY); ctx.rotate(angle); ctx.drawImage(img, -(img.width / 2), -(img.height / 2)); ctx.restore(); return true; } function rotate(ctx, canvas, angle, img) { var rotation = Math.PI * angle / 180; var max = Math.max(img.width, img.height); ctx.clearRect(0, 0, max, max); drawSprite(ctx, rotation, img, max / 2, max / 2); return true; } function draw(canvasid, imgfile, angle, left, top) { var canvas = document.createElement('canvas'); document.body.appendChild(canvas); canvas.id = canvasid; var ctx = canvas.getContext('2d'); var img = new Image(); canvas.appendChild(img); img.id = canvas.id + "imgid"; img.onload = function() { var max = Math.max(img.width, img.height); canvas.width = canvas.height = max; canvas.style.width = canvas.style.height = max + "px"; canvas.style.position = "absolute"; canvas.style.left = left + "px"; canvas.style.top = top + "px"; drawSprite(ctx, 0, img, max / 2, max / 2); if ((isset(angle))&amp;&amp;(angle !== 0)) { rotate(ctx, canvas, angle, img); } }; img.src = imgfile; return true; } function execMoving(canvasid) { var el = typeof canvasid == 'string' ? document.getElementById(canvasid) : canvasid; var curX = getCurX(canvasid); var curY = getCurY(canvasid); var tarX = getTarX(canvasid); var tarY = getTarY(canvasid); //calculate how often we have to do this in order to determine delay and step later var i = 0; var loopdone = false; var step = 5; var loopcurX = curX; var loopcurY = curY; var loopcoords; var loopxdiff; var loopydiff; while (!(loopdone)) { i++; loopcoords = getStepCoords([loopcurX, loopcurY], [tarX, tarY], step); loopxdiff = Math.max(tarX, loopcoords[0]) - Math.min(tarX, loopcoords[0]); loopydiff = Math.max(tarY, loopcoords[1]) - Math.min(tarY, loopcoords[1]); if ((loopxdiff &lt;= step)&amp;&amp;(loopydiff &lt;= step)) { loopdone = true; } else { loopcurX = loopcoords[0]; loopcurY = loopcoords[1]; } } var delay = 0; step = 0; var multiplier = 0; var stepextra = 5; var time; if (presstime &gt; latency) { time = presstime - latency; } else { time = presstime; } while (delay &lt; 1) { multiplier++; step = stepextra * multiplier; delay = Math.round((time) / (i / multiplier)); } if (delay &gt; 10) { delay = 10; } //ceil delay var coords = getStepCoords([curX, curY], [tarX, tarY], step); var xPos = coords[0]; var yPos = coords[1]; el.style.left = xPos + 'px'; el.style.top = yPos + 'px'; updateCurX(canvasid, xPos); updateCurY(canvasid, yPos); var xdiff = Math.max(tarX, xPos) - Math.min(tarX, xPos); var ydiff = Math.max(tarY, yPos) - Math.min(tarY, yPos); if ((xdiff &lt;= step)&amp;&amp;(ydiff &lt;= step)) { stopMoving(canvasid); } else { setTimeout(function() { execMoving(canvasid); }, delay); } return true; } function execRotation(canvasid) { var curAngle = getCurAngle(canvasid); var tarAngle = getTarAngle(canvasid); //calcAngles var tarAngleCalc; var curAngleCalc; var calcDiff; if (tarAngle &gt; 360) { tarAngleCalc = tarAngle - 360; } else if (tarAngle &lt; 0) { tarAngleCalc = tarAngle + 360; } else { tarAngleCalc = tarAngle; } if (curAngle &gt; 360) { curAngleCalc = curAngle - 360; } else if (curAngle &lt; 0) { curAngleCalc = curAngle + 360; } else { curAngleCalc = curAngle; } //calcDiff if ((tarAngleCalc &gt; 180)&amp;&amp;(curAngleCalc &lt; 180)&amp;&amp;(Math.max(tarAngleCalc, curAngleCalc) - Math.min(tarAngleCalc, curAngleCalc) &gt; 180)) { tarAngleCalc = tarAngleCalc - 360; calcDiff = Math.max(tarAngleCalc, curAngleCalc) - Math.min(tarAngleCalc, curAngleCalc); } else if ((curAngleCalc &gt; 180)&amp;&amp;(tarAngleCalc &lt; 180)&amp;&amp;(Math.max(tarAngleCalc, curAngleCalc) - Math.min(tarAngleCalc, curAngleCalc) &gt; 180)) { curAngleCalc = curAngleCalc - 360; calcDiff = Math.max(tarAngleCalc, curAngleCalc) - Math.min(tarAngleCalc, curAngleCalc); } else { calcDiff = Math.max(tarAngleCalc, curAngleCalc) - Math.min(tarAngleCalc, curAngleCalc); } //calculate rotation speed var changeAngle = 0; var rotspeed = 0; var time; if (presstime &gt; latency) { time = presstime - latency; } else { time = presstime; } while (rotspeed &lt; 1) { changeAngle++; rotspeed = Math.round(time / (calcDiff / changeAngle)); } //rotate var angle; if ((tarAngle &gt; curAngle)&amp;&amp;(tarAngle - curAngle &gt; 180)) { angle = curAngle - changeAngle; } else if (tarAngle &gt; curAngle) { angle = curAngle + changeAngle; } else if ((tarAngle &lt; curAngle)&amp;&amp;(curAngle - tarAngle &gt; 180)) { angle = curAngle + changeAngle; } else if (tarAngle &lt; curAngle) { angle = curAngle - changeAngle; } if (angle &gt; 360) { angle = angle - 360; } else if (angle &lt; 0) { angle = angle + 360; } var canvas = document.getElementById(canvasid); var ctx = canvas.getContext('2d'); var img = document.getElementById(canvasid + "imgid"); rotate(ctx, canvas, angle, img); updateCurAngle(canvasid, angle); if (getCurAngle(canvasid) != getTarAngle(canvasid)) { setTimeout(function() { execRotation(canvasid); }, rotspeed); } else { stopRotating(canvasid); } return true; } function keydown(e) { var keynum; if (window.event) { // Internet Explorer keynum = window.event.keyCode; } else if (e.which) { // Netscape, Firefox and Opera keynum = e.which; } if (keysdown.indexOf(keynum) == -1) { keysdown.push(keynum); } return true; } function keyup(e) { var keynum; if (window.event) { // Internet Explorer keynum = window.event.keyCode; } else if (e.which) { // Netscape, Firefox and Opera keynum = e.which; } key = keysdown.indexOf(keynum); if (key != -1) { keysdown.splice(key); } return true; } function isDown(keynum) { if (keysdown.indexOf(keynum) == -1) { return false; } return true; } function ajaxHandle1(explode) { //move existing canvas object var canvasid = explode[1]; var x = parseFloat(explode[2]); var y = parseFloat(explode[3]); if ((getCurX(canvasid) != x)||(getCurY(canvasid) != y)) { if (isMoving(canvasid)) { updateTarX(canvasid, x); updateTarY(canvasid, y); } else { updateTarX(canvasid, x); updateTarY(canvasid, y); startMoving(canvasid); execMoving(canvasid); } } return true; } function ajaxHandle2(explode) { //create new canvas object var canvasid = explode[1]; var imgfile = explode[2]; var x = parseFloat(explode[3]); var y = parseFloat(explode[4]); var angle = parseFloat(explode[5]); var rotation = Math.PI * angle / 180; draw(canvasid, imgfile, rotation); cobjects.push([canvasid, 0, x, y, x, y, 0, angle, angle]); //register canvas object - [canvasid, moving, curX, curY, tarX, tarY, rotating, curAngle, tarAngle] } function ajaxHandle3(explode) { //rotate existing canvas object var canvasid = explode[1]; var angle = parseFloat(explode[2]); if (getCurAngle(canvasid) != angle) { //if the new angle is different if (isRotating(canvasid)) { updateTarAngle(canvasid, angle); } else { updateTarAngle(canvasid, angle); startRotating(canvasid); execRotation(canvasid); } } } function handleAjaxResponse(response) { var commands = response.split("@"); var command; var explode; var type; for (var i = 0; i &lt; commands.length; i++) { // loop every handler command to execute it's type of action, commands are separated by an @ character command = commands[i]; explode = command.split("#"); // explode the attributes of this command, separated by an # character type = parseFloat(explode[0]); if (type == 1) { //move existing canvas object ajaxHandle1(explode); } else if (type == 2) { //create new canvas object ajaxHandle2(explode); } else if (type == 3) { //rotate existing canvas object ajaxHandle3(explode); } } return true; } function doAjax(get) { var oldLatencyTime = new Date(); oldLatencyTime = oldLatencyTime.getTime(); if (!(isset(get))) { get = ""; } if ((getAjaxResTimeDiff() &lt; ajaxivtime)&amp;&amp;(get === "")) { return false; } var xmlHttpReq = false; try { // Firefox, Opera 8.0+ and Safari xmlHttpReq = new XMLHttpRequest(); } catch (e) { // Internet Explorer try { xmlHttpReq = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { alert("Your browser does not support AJAX. Please use an AJAX compatible browser."); return false; } } } xmlHttpReq.open('GET', 'handler.php' + get, true); xmlHttpReq.onreadystatechange = function() { if (xmlHttpReq.readyState == 4) { updateLatency(oldLatencyTime); var response = xmlHttpReq.responseText; if ((isset(response))&amp;&amp;(response !== "")) { handleAjaxResponse(response); } } }; xmlHttpReq.send(null); return true; } function keyinput() { //keycodes: 87 = w, 68 = d, 65 = a if (getPressTimeDiff() &gt; presstime) { if ((isDown(87))&amp;&amp;(isDown(68))&amp;&amp;(!(isDown(65)))) { setOldPress(); doAjax("?move=f&amp;rotate=r"); } else if ((isDown(87))&amp;&amp;(isDown(65))&amp;&amp;(!(isDown(68)))) { setOldPress(); doAjax("?move=f&amp;rotate=l"); } else if ((isDown(87))&amp;&amp;(!(isDown(68)))&amp;&amp;(!(isDown(65)))) { setOldPress(); doAjax("?move=f"); } else if ((isDown(68))&amp;&amp;(!(isDown(65)))) { setOldPress(); doAjax("?rotate=r"); } else if ((isDown(65))&amp;&amp;(!(isDown(68)))) { setOldPress(); doAjax("?rotate=l"); } } return true; } //init intervals var iv_ajax = setInterval(function() { doAjax(); }, ajaxivtime); //ajax handler interval var iv_keypress = setInterval(function() { keyinput(); }, keypressivtime); //keypress fire interval //register event handlers document.onkeydown = function(event) { keydown(event); }; document.onkeyup = function(event) { keyup(event); }; document.onkeypress = function(event) { keycheck(event); }; &lt;/script&gt; &lt;/head&gt; &lt;body style="background-color: white;"&gt;&lt;div style="position: absolute; top: 300px; left: 300px;"&gt;W: accelerate.&lt;br /&gt;A: rotate left.&lt;br /&gt;D: rotate right.&lt;/div&gt;&lt;/body&gt; &lt;/html&gt; </code></pre> <p>As you can probably notice, even if your latency (see title) is lower then 50ms, the shuttle will now and then "shock" or lag while moving/rotating. Because I wanted to find out what is causing the problem, I remade the whole thing to a client side version (without ajax).</p> <p>You can check it out here: [<a href="http://ajax.uptowar.com/test5/index.php][2]" rel="nofollow noreferrer">http://ajax.uptowar.com/test5/index.php][2]</a></p> <p>This is the source of the client side remake:</p> <pre><code>&lt;?php header('Content-Type: text/html;charset=utf-8'); header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); header("Cache-Control: no-store, no-cache, must-revalidate"); header("Cache-Control: post-check=0, pre-check=0", false); header("Pragma: no-cache"); session_start(); $_SESSION['playerid'] = ""; echo("&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\n"); ?&gt; &lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt; &lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"&gt; &lt;head&gt; &lt;title&gt;ajax test&lt;/title&gt; &lt;meta http-equiv="pragma" content="no-cache" /&gt; &lt;meta http-equiv="expires" content="-1" /&gt; &lt;meta name="robots" content="index, follow" /&gt; &lt;meta name="audience" content="all" /&gt; &lt;meta http-equiv="content-language" content="en" /&gt; &lt;meta http-equiv="content-type" content="text/html; charset=utf-8" /&gt; &lt;script type="text/javascript"&gt; //vars var keypressivtime = 50; //interval at which keyinput is handled var presstime = 150; //howlong a button should be hold down for 1 event fire //init var cobjects = []; //array for all canvas objects var keysdown = []; //array for what keys are down at a specific moment var oldpress = 0; //press init var latency = 0; //client side //functions function isset() { var a = arguments; var l = a.length; var i = 0; if (l === 0) { return false; } while (i != l) { if (typeof(a[i]) == 'undefined' || a[i] === null) { return false; } else { i++; } } return true; } function getStepCoords(cur, tar, step) { var curX = cur[0]; var curY = cur[1]; var tarX = tar[0]; var tarY = tar[1]; var xmultiplier; var ymultiplier; var xdiff; var ydiff; if ((tarX &gt; curX)&amp;&amp;(tarY == curY)) { xmultiplier = 1; ymultiplier = 0; } else if ((tarX &lt; curX)&amp;&amp;(tarY == curY)) { xmultiplier = -1; ymultiplier = 0; } else if ((tarY &gt; curY)&amp;&amp;(tarX == curX)) { xmultiplier = 0; ymultiplier = 1; } else if ((tarY &lt; curY)&amp;&amp;(tarX == curX)) { xmultiplier = 0; ymultiplier = -1; } else if ((tarX &gt; curX)&amp;&amp;(tarY &gt; curY)) { xdiff = tarX - curX; ydiff = tarY - curY; xmultiplier = xdiff / (xdiff + ydiff); ymultiplier = ydiff / (xdiff + ydiff); } else if ((tarX &lt; curX)&amp;&amp;(tarY &lt; curY)) { xdiff = curX - tarX; ydiff = curY - tarY; xmultiplier = -(xdiff / (xdiff + ydiff)); ymultiplier = -(ydiff / (xdiff + ydiff)); } else if ((tarX &gt; curX)&amp;&amp;(tarY &lt; curY)) { xdiff = tarX - curX; ydiff = curY - tarY; xmultiplier = xdiff / (xdiff + ydiff); ymultiplier = -(ydiff / (xdiff + ydiff)); } else if ((tarX &lt; curX)&amp;&amp;(tarY &gt; curY)) { xdiff = curX - tarX; ydiff = tarY - curY; xmultiplier = -(xdiff / (xdiff + ydiff)); ymultiplier = ydiff / (xdiff + ydiff); } var newx = curX + Math.round(step * xmultiplier); var newy = curY + Math.round(step * ymultiplier); return [newx, newy]; } function drawSprite(ctx, angle, img, centerX, centerY) { ctx.save(); ctx.translate(centerX, centerY); ctx.rotate(angle); ctx.drawImage(img, -(img.width / 2), -(img.height / 2)); ctx.restore(); return true; } function rotate(ctx, canvas, angle, img) { var rotation = Math.PI * angle / 180; var max = Math.max(img.width, img.height); ctx.clearRect(0, 0, max, max); drawSprite(ctx, rotation, img, max / 2, max / 2); return true; } function searchcobjects(canvasid) { indexes = cobjects.length - 1; i = 0; while (i &lt;= indexes) { if (cobjects[i][0] == canvasid) { return i; } i++; } return -1; } function isMoving(canvasid) { var key = searchcobjects(canvasid); if (key == -1) { return false; } else if (cobjects[key][1] == 1) { return true; } return false; } function isRotating(canvasid) { var key = searchcobjects(canvasid); if (key == -1) { return false; } else if (cobjects[key][6] == 1) { return true; } return false; } function startRotating(canvasid) { var key = searchcobjects(canvasid); if (key == -1) { return false; } else { cobjects[key][6] = 1; } return true; } function stopRotating(canvasid) { var key = searchcobjects(canvasid); if (key == -1) { return false; } else { cobjects[key][6] = 0; } return true; } function startMoving(canvasid) { var key = searchcobjects(canvasid); if (key == -1) { return false; } else { cobjects[key][1] = 1; } return true; } function stopMoving(canvasid) { var key = searchcobjects(canvasid); if (key == -1) { return false; } else { cobjects[key][1] = 0; } return true; } function stepxy(steppixels, angle) { //steppixels is the total amount of pixels to be shared between x and y depending on the angle var xmultiplier; if ((angle &lt; 0)||(angle &gt; 360)) { return false; } else if ((angle === 0)||(angle == 360)) { xmultiplier = 0; ymultiplier = -1; } else if ((angle &gt; 0)&amp;&amp;(angle &lt; 91)) { xmultiplier = angle / 90; ymultiplier = -(1 - (angle / 90)); } else if ((angle &gt; 90)&amp;&amp;(angle &lt; 181)) { xmultiplier = 1 - ((angle - 90) / 90); ymultiplier = (angle - 90) / 90; } else if ((angle &gt; 180)&amp;&amp;(angle &lt; 271)) { xmultiplier = -((angle - 180) / 90); ymultiplier = 1 - ((angle - 180) / 90); } else if ((angle &gt; 270)&amp;&amp;(angle &lt; 361)) { xmultiplier = -(1 - ((angle - 270) / 90)); ymultiplier = -((angle - 270) / 90); } else { return false; } var xstep = Math.round(steppixels * xmultiplier); var ystep = Math.round(steppixels * ymultiplier); var arr = [xstep, ystep]; return arr; } function getPressTimeDiff() { var curtime = new Date(); curtime = curtime.getTime(); return curtime - oldpress; } function setOldPress() { var curtime = new Date(); oldpress = curtime.getTime(); return true; } function isDown(keynum) { if (keysdown.indexOf(keynum) == -1) { return false; } return true; </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload