I have been experimenting with creating interactive elements in a canvas using requestAnimationFrame. The issue I am facing is that the function to clear and create a 'blank' canvas space does not seem to be working properly within the loop. From previous tests, it seems like my code may be incomplete or not optimal as I am trying to improve it by following Object-Oriented Programming (OOP) and Model-View-Presenter (MV+) patterns. I am able to move a basic shape (a 'test square'), but the old drawing still remains on the screen. In a basic HTML structure like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>test action game</title>
<style type="text/css" rel="stylesheet" >
body{margin:0;padding:0;background-color:#000;overflow:hidden;}
</style>
</head>
<body>
<script>/* separated for better forum readability, see below */
</script></body></html>
Below is my JavaScript code:
/** global utility functions */
function isReal(val){ return val !== 'undefined' && val !== null ? true : false; }
/** animation loop */
window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
function animate(){
if(ctrls.input.states.up === true){ rc.y -= moveSpeed; }
if(ctrls.input.states.down === true){ rc.y += moveSpeed; }
if(ctrls.input.states.left === true){ rc.x -= moveSpeed; }
if(ctrls.input.states.right === true){ rc.x += moveSpeed; }
cnv.ctx.fillStyle = '#c0ffc0';
cnv.ctx.clearRect(0, 0, cnv.w, cnv.h);
drawRect(cnv.ctx, rc.x, rc.y, rc.w, rc.h, '#ff0000', '#0000ff');
requestAnimationFrame(animate);
}
/** Canvas drawing utilities */
function addCanvas(id, ancestor, w, h){
let canvas = document.createElement('canvas');
canvas.id = id;
canvas.setAttribute('WIDTH', w);
canvas.setAttribute('HEIGHT', h);
ancestor.appendChild(canvas);
return {tag: canvas, ctx: canvas.getContext('2d'), w: w, h: h};
}
function drawRect(ctx, x, y, w, h, stroke='#ffffff', fill='#ffffff'){
if(typeof ctx === typeof document.createElement('canvas').getContext('2d')){
ctx.rect(x, y, w, h);
if(isReal(stroke) && stroke !== false){
ctx.strokeStyle = stroke;
ctx.stroke();
console.log('drawRect stroke '+x+','+y+','+w+','+h+' '+stroke);
}
if(isReal(fill) && fill !== false){
ctx.fillStyle = fill;
ctx.fill();
console.log('drawRect fill '+x+','+y+','+w+','+h+' '+fill);
}
return ctx;
}
console.log('ERROR - Drawing Context: '+ctx+' should be CanvasRenderer2D');
return;
}
let cnv = addCanvas('cnv', document.body, window.innerWidth, window.innerHeight );
console.log('Canvas size: '+cnv.w+'X'+cnv.h);
function testItem(){ let tmp = Math.round(cnv.w/50); return {w: tmp, h: tmp, x: tmp, y: tmp}; }
let rc = testItem();
console.log('('+rc.x+' '+rc.y+')');
/** Input Management: Keyboard Controls */
function Controls(id){
return{
id: id,
input:{
states: {},
keys:{
up: 38,
down: 40,
right: 39,
left: 37
}
}
}
}
let moveSpeed = 2;
let controls = Controls('controller');
document.addEventListener('keydown', function(e){
switch(e.keyCode){
case controls.input.keys.up:
controls.input.states['up'] = true;
break;
case controls.input.keys.right:
controls.input.states['right'] = true;
break;
case controls.input.keys.down:
controls.input.states['down'] = true;
break;
case controls.input.keys.left:
controls.input.states['left'] = true;
break;
default: break;
}
console.log('States: up='+controls.input.states.up+'\tright='+controls.input.states.right+'\tdown='+controls.input.states.down+'\tleft='+controls.input.states.left);
});
document.addEventListener('keyup', function(e){
switch(e.keyCode){
case controls.input.keys.up: if(isReal(controls.input.states['up'])){ controls.input.states.up = false; }
break;
case controls.input.keys.right: if(isReal(controls.input.states['right'])){ controls.input.states.right = false; }
break;
case controls.input.keys.down: if(isReal(controls.input.states['down'])){ controls.input.states.down = false; }
break;
case controls.input.keys.left: if(isReal(controls.input.states['left'])){ controls.input.states.left = false; }
break;
default: break;
}
});
let animation = animate();
body{margin:0;padding:0;background-color:#000;overflow:hidden;}
I have attempted using .save() and .restore() methods during the initial draw without success, along with using .beginPath() and .closePath() while drawing shapes, but the results are not what I expected. Any advice on how to resolve this issue would be greatly appreciated.