Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>One possibility (as you're clearing the canvas each frame) would be to draw ball paths onto a secondary canvas, which would not be cleared each frame. Then, when you come to clear the first frame, render the second frame after clearing, and before rendering the balls.</p> <p>The second canvas would of course have to be the same dimensions as the first, so that all of the ball points line up correctly. The second canvas should also have a z-index lower than the first, so that it is only shown when you specifically render it to the first canvas (i.e. when the radio button is checked).</p> <p>To decrease any lag while the radio is not checked, you could skip drawing the ball paths to the second canvas, although I don't think you would see any great increase in performance.</p> <p>On each frame update, you would mark the position of each ball with a pixel, or line (from the previous position to the current) on the second canvas.</p> <p>Looking at your code, you seem pretty competent, so I've skipped writing an example as I think this would be good experience for you :)</p> <p><strong>Modified 'script.js' source demonstrating solution</strong></p> <pre><code>window.onload = function(){ $("#canvas").hide(); var howManyPaths = 0; var showPath=false; // SLIDERS var gravitySlider = document.getElementById('gravitySlider'); var gravityVal = document.getElementById('gravityValue'); gravitySlider.onchange = function(){ gravityVal.value = gravitySlider.value; } gravityVal.onkeyup = function(){ gravitySlider.value = gravityVal.value; } var forceSlider = document.getElementById('forceSlider'); var forceValue = document.getElementById('forceValue'); forceSlider.onchange = function(){ forceValue.value = forceSlider.value; } forceValue.onkeyup = function(){ forceSlider.value = forceValue.value; } // GLOBAL VARIABLES var test = false; var gravityCount = $("#gravity").val(); var forceCount = $("#rectangles").val(); // CSS : var playCSS = document.getElementById("play"); var restartCSS = document.getElementById("restart"); var clickableCSS = document.getElementById("setup"); var clickableBG = document.getElementById("img"); //restartCSS.style.visibility="hidden"; var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); var canvas2 = document.getElementById("canvas2"); var ctx2 = canvas2.getContext("2d"); //var ctx; var gravity = 9.86; var forceFactor = 0.5; var mouseDown = false; var balls = new Array(); var mousePos = new Array(); // EVENT HANDLER function onMouseDown(evt){ mouseDown = true; mousePos['downX'] = evt.pageX; mousePos['downY'] = evt.pageY; } function onMouseUp(evt){ mouseDown = false; setup.style.visibility="visible"; if(test == true &amp;&amp; !( mousePos['downX'] &lt; 200 &amp;&amp; mousePos['downY'] &lt; 150) ){ restartCSS.style.visibility="visible"; forceFactor = forceCount; balls.push(new ball(mousePos["downX"], mousePos["downY"], (evt.pageX - mousePos["downX"]) * forceFactor, (evt.pageY - mousePos["downY"]) * forceFactor, 10 + (Math.random() * 10), 0.8, randomColor() )); } ctx2.clearRect(0, 0, canvas2.width, canvas2.height); } function onMouseMove(evt){ mousePos['currentX'] = evt.pageX; mousePos['currentY'] = evt.pageY; } function resizeWindow(evt){ //canvas.height = 960; //canvas.width = 720; canvas.height = $(window).height()-6; canvas.width = $(window).width(); canvas2.height = $(window).height()-6; canvas2.width = $(window).width(); } $(document).mousedown(onMouseDown); $(document).mouseup(onMouseUp); $(document).mousemove(onMouseMove); $(window).bind("resize", resizeWindow); // GRAPHICS CODE function circle(x, y, r, col){ ctx.beginPath(); ctx.arc(x, y, r, 0, Math.PI*2, true); ctx.closePath; // fill ctx.fillStyle = col; ctx.fill(); // stroke ctx.lineWidth = r * 0.1; ctx.strokeStyle = "#000000"; ctx.stroke(); } function circlePath(x, y) { ctx2.clearRect(0, 0, canvas2.width, canvas2.height); ctx2.fillStyle = '#3f4043'; ctx2.fillRect(x, y, 5, 5); ctx2.strokeStyle = "black"; ctx2.strokeRect(x, y, 5, 5); } function randomColor(){ var letter = "0123456789ABCDEF".split(""); var color = "#"; for(var i=0; i&lt;6; i++){ color += letter[Math.round(Math.random()*15)]; } return color; } function arrow(fromX, fromY, toX, toY, color){ // path ctx.beginPath(); var headLen = 10; var angle = Math.atan2(toY - fromY, toX - fromX); ctx.moveTo(fromX, fromY); ctx.lineTo(toX, toY); ctx.lineTo(toX - headLen * Math.cos(angle - Math.PI/6), toY - headLen * Math.sin(angle - Math.PI/6)); ctx.moveTo(toX, toY); ctx.lineTo(toX - headLen * Math.cos(angle + Math.PI/6), toY - headLen * Math.sin(angle + Math.PI/6)); // style ctx.lineWith = 1; ctx.strokeStyle = color; ctx.lineCap = "butt"; ctx.stroke(); } function drawBall(){ // Gravity gravity = gravityCount; this.speedY += gravity * 0.5; // v = a * t this.x += this.speedX * 0.05; // s = v * t this.y += this.speedY * 0.05; // prawa ściana if(this.x + this.r &gt; canvas.width){ this.x = canvas.width - this.r; this.speedX *= -1 * this.bounce; } // lewa ściana if(this.x - this.r &lt; 0){ this.x = this.r; this.speedX *= -1 * this.bounce; } // dolna ściana if(this.y + this.r &gt; canvas.height){ this.y = canvas.height - this.r; this.speedY *= -1 * this.bounce; } // górna ściana if(this.y - this.r &lt; 0){ this.y = this.r; this.speedY *= -1 * this.bounce; } // zwalnianie na ziemi if (this.speedX &gt; 0.25){ this.speedX -= 0.25; if (this.speedY &gt; 0.25) this.speedY -= 0.25; } if (this.speedX &lt; -0.25){ this.speedX += 0.25; //if (this.speedY &lt; -0.25) // this.speedY += 0.25; } circle(this.x, this.y, this.r, this.col);; } // OBJECTS function ball(positionX, positionY, sX, sY, radius, b, color){ this.x = positionX; this.y = positionY; this.speedX = sX; this.speedY = sY; this.r = radius; this.bounce = b; this.col = color; this.draw = drawBall; } //GAME LOOP function gameLoop(){ ctx.clearRect(0, 0, canvas.width, canvas.height); //grab the context from your destination canvas //if path drawing is enabled, first draw the path canvas to the display canvas if (showPath) ctx.drawImage(canvas2,0,0); if(mouseDown == true){ // ctx.clearRect(0, 0, canvas.width, canvas.height); /* !important !!!!!!!!!!!!!!! */ arrow(mousePos['downX'], mousePos['downY'], mousePos['currentX'], mousePos['currentY'], "red"); } for(var i=0; i&lt;balls.length; i++){ balls[i].draw(); if (i==balls.length-1) { //draw path ctx2.fillStyle = '#3f4043'; ctx2.fillRect(balls[i].x, balls[i].y, 5, 5); ctx2.strokeStyle = "black"; ctx2.strokeRect(balls[i].x, balls[i].y, 5, 5); } } ctx.fillStyle = "#000000"; ctx.font = "15px Arial"; ctx.fillText("Balls: " + balls.length + " " + gravityCount + " " + forceCount + " " + howManyPaths, 10, canvas.height -10); } // START THE GAME function init(){ //$("#setup").hide(); $("#canvas").show(); $("#canvas2").hide(); ctx = $('canvas')[0].getContext("2d"); canvas.height = $(window).height()-6; canvas.width = $(window).width(); //canvas.width = 960; //canvas.height = 720; canvas2.height = $(window).height()-6; canvas2.width = $(window).width(); return setInterval(gameLoop, 10); } $("#play").click(function() { test = true; playCSS.style.visibility="hidden"; gravityCount = $("#gravitySlider").val(); forceCount = $("#forceSlider").val(); init(); }); $("#restart").click(function() { window.location.href="index.html"; }); $("#refresh").click(function() { gravityCount = $("#gravitySlider").val(); forceCount = $("#forceSlider").val(); }); $("#showPath").click(function() { showPath=true; }); $("#hidePath").click(function() { showPath=false; }); } </code></pre>
    singulars
    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.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      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