Why is my sprite blurred when using requestAnimationFrame to move it? - javascript

I created a basic 2D game using pure JavaScript. My problem is when the sprite stops moving it is sometimes blurred sometimes not. I use requestAnimationFrame to move the sprite and keydown/keyup events trigger moving. When keyup is triggered the sprite stops moving and the default tile is set however sometimes it is showing blurred.
https://arpadvas.github.io/untitled_game_project/

Since you didn't posted an minimal code example, and that I don't want to go through the raw code you linked to, this will stay as a guess (an educated one).
Generally, this happens when you draw your sprites on floating coordinates.
Since there is no way to draw on half a pixel, the pixel being the smallest unit in canvas, to smoothen drawings, the browser will by default create antialias artifacts, turning some pixels less opaque so that your eyes think it is on half a pixel.
While this usually works well with realistic photographs, it doesn't at all with pixel-art.
The solution then is either to round all your coordinates, or if you are lazy, to set the imageSmoothingEnabled property of your context.
var img = new Image();
img.onload = draw;
function draw(){
i = .316252;
blurred.width = round.width = noAntiAlias.width = img.width +20;
blurred.height = round.height = noAntiAlias.height = img.height +20;
blurred.getContext('2d').drawImage(img, 10+i, 20+i);
round.getContext('2d').drawImage(img, 10, 20);
var nA = noAntiAlias.getContext('2d');
nA.mozImageSmoothingEnabled = nA.msImageSmoothingEnabled = nA.webkitImageSmoothingEnabled = nA.imageSmoothingEnabled = false;
noAntiAlias.getContext('2d').drawImage(img, 10+i, 20+i);
};
img.src = "https://dl.dropboxusercontent.com/s/4e90e48s5vtmfbd/aaa.png";
<canvas id="blurred"></canvas>
<canvas id="round"></canvas>
<canvas id="noAntiAlias"></canvas>
Ps : this made me realize that somehow my FF doesn't smooth this particular image I used... If someone can confirm in comments, I'd be glad to dig into this further if needed.

Related

HTML5 Canvas efficiency of panning image by Translate vs. Clipping

There's a bunch of questions on panning a background image in a canvas (i.e. to simulate a 'camera' in a game with the character in the center) - and most answers suggest using the canvas' translate method.
But since you have to re-draw the image in each frame anyway, why not just clip it? Does it matter in terms of efficiency?
In particular, is panning like this a bad idea? (This example shows a simplified pan of the camera moving in one direction)
let drawing = new Image();
drawing.src = "img_src";
drawing.onload = function () {
ctx.drawImage(drawing, 0, 0);
let pos = 0
setInterval(() => {
pos += 1
ctx.clearRect(0, 0, cnvs.width, cnvs.height);
ctx.drawImage(drawing, -pos, 0 ); // "pans" the image to the left using the option `drawImage` parameters `sx` and `sy`
}, 33);
};
Example result: fiddle
Thanks in advance!
The main advantage of using the transform matrix to control your camera is that you don't have to update all the elements in your world, you just move the world instead.
So yes, if you are willing to move only a single element (be it the background like in your case), moving only that one element might be a better choice.
But if you need several layers of elements to all move relatively to the camera, then using the transformation matrix is a better choice.
As for the perfs, I didn't ran any benchmarks on this, but I'd suspect it's exactly the same, though beware when messing with the cropping features of drawImage, at least Safari doesn't handle cropping from outside of a source canvas correctly.

Canvas - How to draw a growing trail

I want to draw a growing trail behind an moving object. I know this look quite easy :) But there are some constraints :
the trail must have some homogeneous transparency
and i can not use caching methods because of performance issues
I have tested 2 ways :
One with lineTo() and incrementing stroke width, but the alpha transparency is not homogenic...
https://jsfiddle.net/zOgs/9ntajsa1/
One with lineTo() and circles to fill the blank, transparency is OK but there is a strange behavior when drawing from left to right, negative space appears...
https://jsfiddle.net/zOgs/psa3x9y2/
I also try to use compositeOperation with something like this, but it's messing with my background...
trail.alpha = 0.5;
trail.compositeOperation = 'xor';
for(var i=nb; i>=0; i--) {
trail.graphics.drawCircle(points[i].x,points[i].y,size/2).closePath();
}
I can't find a valid solution to this problem and i am beginning to despair :(
There is probably a better way to do this, but here is an easy way: Use an off-screen canvas to draw the trails, then display that canvas as a bitmap child of the main stage.
Here is a fiddle based on your first one:
https://jsfiddle.net/lannymcnie/9ntajsa1/1/
// Canvas to draw to:
var offCanvas = document.getElementById("canvas2");
var offStage = new createjs.Stage(offCanvas);
// Add the offStage to the main stage.
var bmp = new createjs.Bitmap(offCanvas);
stage.addChild(bmp);
bmp.alpha = 0.1;
// Still get events from main stage
stage.addEventListener('stagemousemove',onMouseMove);

Animating a missile in HTML5/WinJS

I'm writing a game using HTML5/WinJS on Windows 8. I'm trying to produce the effect of a bullet or missile firing at something; however, I can't seem to get the object to go through another image in the background without trailing a border. My working theory is that the border I'm seeing is caused by using clearRect. Here's my code:
var moveBullet = function(missile) {
if (missile.Image == undefined || missile.Image == null) {
var image = new Image();
image.src = "/images/missileImg.png";
image.onload = function () {
canvasContext.clearRect(missile.PointX - (image.width / 2), missile.PointY, image.width, image.height);
missile.PointY += BULLET_SPEED;
canvasContext.drawImage(image, missile.PointX - (image.width / 2), missile.PointY);
};
} else {
canvasContext.clearRect(missile.PointX - (missile.Image.width / 2), missile.PointY, missile.Image.width, missile.Image.height);
missile.PointY += BULLET_SPEED;
canvasContext.drawImage(missile.Image, missile.PointX - (missile.Image.width / 2), missile.PointY);
}
}
Is there a way to achieve this effect without using clearRect, or a more efficient way of restoring the background as it moves past?
Make your clearRect area a few pixels larger than the missile image. Drawing on a canvas in general has some built-in anti-aliasing. This means that if you draw a line with one color, then draw the same line with the background color, you'll not remove the original line. Something similar might be happening here, in which case a few extra pixels should help.
That said, there's a caveat to be aware of here.
First, I assume the background is separate element from the canvas? It looks like it as you're not redrawing that part on the canvas itself.
The reason I ask is that making repeated calls to clearRect on the same canvas will eventually show performance problems. What happens is that every call to clearRect accumulates into a complex region within the canvas--essentially its transparency mask. So every time the canvas has to be rendered, which happens any time you change it, it has to process that transparent area. Gradually, as you leave more and more small clearRect trails across the canvas, this region will become more and more complex and performance will drop.
I did this experiment with the Blizzard demo on the IE Test Drive site once, where I wondered why the demo was clearing the entire canvas with every animation frame. So I tried just clearing the trail behind each snowflake (and made each one a little bigger as I suggest above, because I had trails). Seemed like the right thing to do, but the performance plummeted by several orders of magnitude. Asking around within the IE team, they confirmed the region behavior I describe.
So the best thing to do, actually, is to do a clearRect on the entire canvas with every frame, then redraw the missile and any other bits that you're animating. This may seem counter intuitive, but ends up working best and avoids all these glitches with pixel trails.

What is causing my canvas drawing to break and skip at certain values (2^15, for one)?

I'm working on a 2d canvas-based app using EaselJS where the user can move indefinitely on the xy-plane by dragging the background. Think google maps, except the background is a repeating tile.
The code for the movement is very simple and looks something like this:
// container - the createjs.Container being panned
// background - a createjs.Shape child of container, on which the
// background is drawn
background.onPress = function(evt) {
var x = evt.stageX, y = evt.stageY;
evt.onMouseMove = function(evt) {
// the canvas is positioned in the center of the window, so the apparent
// movement works by changing the registration point of the container in
// the opposite direction.
container.regX -= evt.stageX - x;
container.regY -= evt.stageY - y;
x = evt.stageX;
y = evt.stageY;
stage.update();
};
evt.onMouseUp = function(evt) {
// Here the background would be redrawn based on the new container coords.
// However the issue occurs even before the mouse is released.
background.redraw();
stage.update();
};
};
All works as expected until reaching 32678px (2^15) on either axis. What occurs is different in different browsers, but the point where it first happens is the same.
In Firefox, it will suddenly shift a large chunk of pixels (~100) rather than 1. It will then happen again at 65538 (2^16+2), perhaps more after that, but I haven't witnessed it. After the trouble points, the drag will continue smoothly, as expected, but remaining shifted.
In Chrome, the effect is more dramatic. The drawing breaks and results in repeated ~100px wide "stripes" of the background across the page at 32768, and does not correct itself on redraw.
Oddly, the numbers in EaselJS don't reflect the issue. The only change in the container's transform matrix is the tx or ty incrementing by 1. No other matrices change. It seems as though EaselJS is getting all the numbers right.
Can anyone shed any light this issue?
Edit:
I worked around this problem by redrawing parts of the container using a calculated regX/regY, rather than attempting to translate very large regX/regY coords on the canvas.
This question may be related
What is the maximum size for an HTML canvas?
From what I gather browsers use short int to store canvas sizes with 32,767 being the maximum possible value.
Links possibly related to your issue,
Mozilla - HTML5 Canvas slow/out of memory
https://stackoverflow.com/a/12535564/149636

How to optimize animation on canvas? HTML 5

I am faced with a problem that slows down animation on a canvas, as various pictures move left, right, up and down. I need advice on how to optimize the animation.
It is important that the animation works on all main browsers, in particular: Chrome, Firefox and Internet Explorer.
Is it possible to optimize the animation? Maybe put a delay on the drawing? Thank you in advance.
In javascript you can use the setInterval and setTimeout functions to create delays and throttle the frame rate.
for instance if you wanted to make your drawing loop approximately 30 FPS you could have some code that looks like this:
function draw(){
var canvas = document.getElementById('myCanvas');
//create the image object
var img = new Image();
//set the image object's image file path
var img.src = "images/myImage.png"
//check to see that our canvas exists
if( canvas.getContext )
{
//grab the context to draw to.
var ctx = cvs.getContext('2d');
//clear the screen to a white background first
//NOTE to make this faster you can clear just the parts
//of the canvas that are moving instead of the whole thing
//every time. Check out 'Improving HTML5 Canvas Performance'
//link mention in other post
ctx.fillStyle="rgb(255,255,255)";
ctx.fillRect (0, 0,512, 512);
//DO ALL YOUR DRAWING HERE....
//draw animation
ctx.drawImage(img, 0, 0);
}
//Recalls this draw update 30 times per second
setTimeout(draw,1000/30);
}
This will help you control how much processing time the animation is taking. Thus if you find that your animation is going too slow you can increase the frame rate by changing the denominator '30' to something like '60' fps or anything that really works well for your program.
As far as optimizing goes in addition to setTimeout() the way you draw your animations is critical too. Try to load all your images before you render them this is called "Preloading". That is if you have a bunch of different images for each animated cell then before you call your draw function load all the images into an array of images like so:
var loadedImages = new Array();
loadedImages[0] = new Image();
loadedImages[0].src = "images/animationFrame1.png";
loadedImages[1] = new Image();
loadedImages[1].src = "images/animationFrame2.png";
loadedImages[2] = new Image();
loadedImages[2].src = "images/animationFrame3.png";
loadedImages[3] = new Image();
loadedImages[3].src = "images/animationFrame4.png";
you could even put them in a hash if it makes sense for you app where instead of
loadedImages[0] = new Image();
loadedImages[0].src = "images/animationFrame1.png";
you do this
loadedImages['frame1'] = new Image();
loadedImages['frame1'].src = "images/animationFrame1.png";
once you have all your images loaded you references them for drawing by doing calling them like so:
//Using the integer array
ctx.drawImage(loadedImages[0], 0, 0);
//OR
//Using the stringed hash
ctx.drawImage(loadedImages['frame1'], 0, 0);
You want to separate your loading process from your rendering process because loading images is process intensive thus will slow your animations down if you are loading things while rendering.
That is not to say that you can't ever load anything while rendering, but instead just be conscience that this will slow animation speed down.
Here is an article on preloading images.
There is another post on here which talks about consistent animation speed on all browsers here
Note the link posted by the green checked answer
Other things to be noted are making sure to only clearing and redrawing bounding boxes as mentioned in the post with HTML 5 canvas optimization. That link has some really good techniques to be conscience of while developing canvas animations.
Here are some frame works as well which might come in handy to cross compare what you are doing to what other engines are doing.
Hope some of this helps. I am new to javascript (only started coding with it about 2 weeks ago) and so there could be better ways to do things but these are the things I have found thus far.
window.requestAnimationFrame() is one sure way to make your animation run smoother.
https://developer.mozilla.org/en/DOM/window.mozRequestAnimationFrame
(cross browser http://paulirish.com/2011/requestanimationframe-for-smart-animating/ )
However it doesn't fix the possible problems with your drawing code which was missing from the question.

Categories

Resources