HTML5 rotate method skewing image - javascript

I am writing a game engine for Javascript and am attempting to allow my sprites to be rotated.
However, when I rotate my sprites, the image gets skewed. It rotates, but it is not the correct dimensions.
I am following the same basic logic that I use when programming in Java with the Image object and 2d libraries but getting different results. (Image skewed and shouldn't be... just needs to be rotated)
function Sprite(imgg,w,h)
{
this.img = imgg;
this.x = 350;//Math.random()*700;
this.y = 350;//Math.random()*700;
this.vx = 0;//Math.random()*8-4;
this.vy = 0;//Math.random()*8-4;
this.width = w;
this.height = h;
this.rotatespeed = 0;//0.01;
this.rotate = 40;
}
function drawSprite(sprite, ctx)
{
ctx.save();
ctx.translate(sprite.x,sprite.y);
ctx.rotate(sprite.rotate);
ctx.drawImage(sprite.img,0,0,sprite.img.width,sprite.img.height,-sprite.width/2,-sprite.height,sprite.width,sprite.height);
ctx.restore();
}
function drawGame(g)
{
var gameLoop = setInterval(function(){
g.context.clearRect(0,0,g.canvas.width, g.canvas.height);
g.context.save();
g.context.translate(g.canvas.width/2, g.canvas.height/2);
g.context.scale(g.camera.scale,g.camera.scale);
g.context.rotate(g.camera.rotate);
g.context.translate(g.camera.x,g.camera.y);
for(var i=0;i<g.objects.length;i++)
{
updateSprite(g.objects[i]);
drawSprite(g.objects[i], g.context);
}
g.context.restore();
},setIntervalAmount);
}

Turns out that everything was okay, but the web browser was very stretched in one dimension because I had the developer console up, so it was all an optical illusion.

Related

Fix position for tranlate() while rotate() only in p5js?

Have a class with methods that draws rectangular shapes with random lengths.
However, is unable to only do rotate() on the shapes without translating ( translate() ), which translate will make the shapes draw off the canvas.
So are there anyways to make it so no translation occurs while rotating?
The code:
class rect {
constructor(range) {
this.boundary = 100;
this.x = random(this.boundary, width - this.boundary);
this.y = random(this.boundary, height - this.boundary);
this.xu = this.x + random(50, 200);
this.yu = this.y + random(50, 200);
this.range = range;
this.limit = random(-range, range);
this.rand_color1 = random(255);
this.rand_color2 = random(255);
this.rand_color3 = random(255);
}
custom_shapes() {
// how to make no translations occur while only perform rotation on shapes?
translate(this.x-this.margin,this.y-this.margin);
rotate(30);
fill(this.rand_color1, this.rand_color2, this.rand_color3)
quad(this.x, this.y, this.xu + this.limit, this.y, this.xu, this.yu, this.x, this.yu + this.limit);
}
}
If you mean that your rectangular is going of the screen when rotating, it's rotating around x = 0, y= 0 point, so i guess you could do something like:
push() //push and pop acts as a way to "seperate" any style and translate and so on...
rectMode(CENTER) // basically the middle of the rect = x , y
translate(this.x,this.y) // **OR** translate(this.x - this.rectSizeX / 2, this.y - this.rectSizeY / 2)
//quad() // if you're not using the rectMode()
pop() // also you'll have to fill() and so on in here i believe, not too sure
also if you know it's allways going to be a long or tall square, you can just use rect(x,y,xSize,ySize) // if think it's the size anyways
If you just want to separate translate() in general, just put push() and pop() around it...
Oh yeah and translate() basically just makes whatever x and y you give it into 0,0... Dunno if i said that already i'm just editing this the next day.

html canvas animation flickering

I'm in the middle of creating this simple animation using HTML5 Canvas and JavaScript and I'm experiencing a problem with flickering objects.
I was trying to find the solution on the internet before I asked this question and all I found was basically:
avoid loading new image , object at each new frame
use requestAnimationFrame()
I think I've done that all and the flickering is still happening.
(blue rectangles (obstacles) in my case.
The only solution that works is reducing the number of pixels in method responsible for moving the object, here:
obstacle.prototype.moveObstacle = function(){
this.x -=3
}
but the the animation is too slow.
Is there any way around it?
JSFiddle: https://jsfiddle.net/wojmjaq6/
Code:
var cnv = document.getElementById("gameField");
var ctx = cnv.getContext("2d");
var speedY = 1
var obst1 = new obstacle(cnv.width + 50);
var myBird = new bird(100, 1);
function bird(x, y) {
this.x = x;
this.y = y;
this.gravity = 0.3
this.gravitySpeed = 0
}
bird.prototype.drawbird = function() {
ctx.fillStyle = "red"
ctx.fillRect(this.x, this.y, 20, 20);
}
bird.prototype.animate = function() {
this.gravitySpeed += this.gravity
this.y += speedY + this.gravitySpeed
}
function obstacle(x) {
this.x = x;
this.y = 0;
this.obstLen = Math.floor(Math.random() * 400)
}
obstacle.prototype.drawobstacle = function() {
ctx.fillStyle = "blue";
ctx.fillRect(this.x, this.y, 15, this.obstLen)
ctx.fillRect(this.x, cnv.height, 15, -(cnv.height - this.obstLen - 100))
}
obstacle.prototype.moveObstacle = function() {
this.x -= 3
}
function myFun() {
ctx.clearRect(0, 0, cnv.width, cnv.height);
myBird.animate();
myBird.drawbird();
obst1.moveObstacle();
obst1.drawobstacle();
if (obst1.x < 0) {
obst1 = new obstacle(cnv.width + 50);
}
window.requestAnimationFrame(myFun)
};
function test() {
if (myBird.gravity > 0) {
myBird.gravity = -1
} else {
myBird.gravity = 0.3
}
}
document.getElementById("gameField").onmousedown = test
document.getElementById("gameField").onmouseup = test
window.requestAnimationFrame(myFun)
I do see some stuttering with the blue obstacle - the animation is not smooth.
Changing the x position of the obstacle based on the raw requestAnimationFrame loop will not necessarily result in a smooth operation as requestAnimationFrame just requests that the browser re-draws when it can.
The time between calls to requestAnimationFrame can vary depending on the power of the device the animation is on and how much there is to do each frame. There is no guarantee that requestAnimationFrame will give you 60 FPS.
The solutions are to decouple the changing of objects positions with the actual drawing of them, or factor it the elapsed time between frames and calculate the new position based on that to give a smooth animation.
Normally in my canvas animations I just use a library like GreenSock's Animation Platform (GSAP) https://greensock.com/get-started-js which can animate any numeric property over time, then I only have to write code for the drawing part.
It is possible to compute a time based animation in your own requestAnimationFrame, though there is a bit of complexity involved. This looks like a good tutorial on it http://www.javascriptkit.com/javatutors/requestanimationframe.shtml
Cheers,
DouG

Slitting HTML5 canvas (video) element into pieces

I am new with canvas and I've been Googling for a couple of hours, but I am stuck.
What I would like to do is to render a video on a canvas element, divide it and animate the pieces. I am halfway there (see: http://jsbin.com/riduxadazi/edit?html,css,js,console,output ) but I have a couple of questions:
Am I doing things right, or is this extremly inefficient?
I would like to use the video fullscreen. Whatever I try, the canvas grid + video don't seem to match size.
I would like to animate the pieces of the video, but I have no clue how I should address them. Can I get some sort of array and animate the pieces one by one?
My JS looks like this. I tried to add comments to the most important parts. At least what I think were the most important parts ;)
var video = document.getElementById('video'); // Get the video
var ctx = canvas.getContext('2d'),
columns = 6,
rows = 4,
w, h, tileWidth, tileHeight;
// Start video and add it to canvas
video.addEventListener('play', function() {
var $this = this; //cache
(function loop() {
if (!$this.paused && !$this.ended) {
ctx.drawImage($this, 0, 0,window.innerWidth,window.innerHeight);
calcSize(); // Divide video
setTimeout(loop, 1000 / 30); // drawing at 30fps
}
})();
}, 0);
function calcSize() {
video.width = w = window.innerWidth;
video.height = h = window.innerHeight;
tileWidth = w / columns;
tileHeight = h / rows;
ctx.strokeStyle = '#000';
render();
}
function render() {
for(var x = 0; x < columns; x++) {
ctx.moveTo(x * tileWidth, 0);
ctx.lineTo(x * tileWidth, h);
}
for(var y = 0; y < rows; y++) {
ctx.moveTo(0, y * tileHeight);
ctx.lineTo(w, y * tileHeight);
}
ctx.stroke();
}
You would perhaps consider:
Using requestAnimationFrame to update the loop. This allows for perfect synchronization with the monitor update rate as well as being more efficient than setTimeout/setInterval You could throttle it so you only update per 1/30 frame to match video rate by using a simple boolean flag that alternates.
The video element does not need to be inserted into DOM. Also, the actual video bitmap size is read through the properties videoWidth and videoHeight, though, in the provided code you should use canvas' properties width and height as this determine the destination size. To draw proportional you can for example use this answer.
Using drawImage() using the clipping parameters would be the more efficient way to draw video onto canvas if you want to split the content.
You could split your video using a mathematical approach (see this answer) or using objects which allows you to define source regions and have individual properties on it such as position, rotation, scale and so forth. In case you would have to consider destination position to adopt to the current size of canvas.

Canvas mouse coords after rotation

Im drawing lines from the center of a shape on mouse clicks. This works fine, until I perform a rotation on the div element holding the canvas element.
Below is the basic Javascript. rotateWrapper gets called by a button elsewhere on the page
var p;
var rot = 0;
var canvas;
var ctx;
function rotateWrapper() {
if (rot == 0) rot = 180;
else rot = 0;
$("#wCanvas").rotate({ animateTo:rot,duration:2500});
}
function draw() {
ctx.save();
ctx.moveTo(p[0], p[1]);
ctx.lineTo(p[2], p[3]);
ctx.closePath();
ctx.stroke();
ctx.restore();
}
$(document).ready(function () {
canvas = $("#imgCanvas").get(0);
ctx = canvas.getContext("2d");
$("#imgCanvas").bind({
mouseup: function(ev) {
p[2] = ev.pageX;
p[3] = ev.pageY;
},
mousedown: function(ev) {
p = new Array(4);
p[0] = $("#wCanvas").width() / 2;
p[1] = $("#wCanvas").height() / 2;
}
});
}
Im sure Im missing something basic but this is driving me up the wall. Ive tried rotating the context in the draw method, both the amount of rot, as well as the inverse of it. Because Im rotating the container element Im thinking this has something to do with the CSS change interfering with things but not certain on that.
Any insights would be highly appreciated
"rotate" will rotate the canvas for elements drawn after the rotation. Without seeing how rotateWrapper and draw are called, it's difficult to tell how you should structure the code. But essentially, you should redraw after you want to apply the rotation. You probably want to store the rotation value, and call a central redraw routine that will apply the rotation first, then redraw.

Canvas animation stutters in FireFox but is perfect in Chrome

I recently got about doing some HTML5/Canvas stuff and was going about my business quite happily, testing stuff in Chrome, until I decided to try what I have been working on in Firefox... doesn't work so good.
This is a bare bones example of the kind of stuff I'm doing. Setting up the basic requestAnimationFrame shim, the main loop clears the canvas and then updates and draws my objects. Easy enough, examples about this stuff are every where to be found.
function loop() {
canvas.width = canvas.width;
requestAnimFrame(loop);
rR.update();
rG.update();
rB.update();
rY.update();
rR.draw();
rG.draw();
rB.draw();
rY.draw();
}
function Rect(color, x, y, speedX, speedY) {
this.x = x;
this.y = y;
this.color = color;
this.speedX = speedX;
this.speedY = speedY;
}
Rect.prototype.draw = function () {
context.fillStyle = this.color;
context.beginPath();
context.rect(this.x, this.y, 10, 10);
context.closePath();
context.fill();
};
Rect.prototype.update = function () {
if (this.x < 0 || this.x > canvas.width) this.speedX = -this.speedX;
if (this.y < 0 || this.y > canvas.height) this.speedY = -this.speedY;
this.x += this.speedX;
this.y += this.speedY;
};
var rR = new Rect("#FF0000", canvas.width/2, canvas.height/2, 2, 2);
var rG = new Rect("#00FF00", canvas.width/2, canvas.height/2, -2, -2);
var rB = new Rect("#0000FF", canvas.width/2, canvas.height/2, 2, -2);
var rY = new Rect("#FFFF00", canvas.width/2, canvas.height/2, -2, 2);
http://jsfiddle.net/Polaris666/psDM9/3/
When I test that in Chrome it looks great, but Firefox has a lot of stuttering and tearing, for what seems a rather simple task.
I have found similar questions but none with a good clear solution. Is this a Firefox thing? Are Webkit browsers just better at doing this? Should I just give up on it and hope it is fixed in future versions of the browser? Or maybe it is my particular set up? I'm using Windows 7 64bit with FireFox 17.0.1.
Any help is appreciated.
The solution #HakanEnsari provided seems to work. I was curious about the reason and found that it's because his version of the code doesn't clear the entire canvas. It only clears the individual 10x10 Rects and leaves the rest of the canvas alone.
This goes into it a bit, and also has a lot of other useful canvas performance tips:
http://www.html5rocks.com/en/tutorials/canvas/performance/#toc-render-diff
So you want this:
function loop() {
// get rid of this
//canvas.width = canvas.width;
requestAnimFrame(loop);
Just clear the individual rects
Rect.prototype.update = function () {
if (this.x < 0 || this.x > canvas.width) this.speedX = -this.speedX;
if (this.y < 0 || this.y > canvas.height) this.speedY = -this.speedY;
// clear just the rect
context.clearRect(this.x, this.y, 10, 10);
this.x += this.speedX;
this.y += this.speedY;
};
(tweaked fiddle: http://jsfiddle.net/shaunwest/B7z2d/1/)
Apparently, clearing the canvas with canvas.width = canvas.width; caused the lag on Safari (I'm browsing with version 5.1.9).
I've never used that way of clearing the screen: instead, I use this one:
context.clearRect(0,0, canvas.width, canvas.height);
If you try it out, it shouldn't lag anymore. See jsfiddle.
This is the fastest way to clear the canvas: on the contrary, clearing each individual element requires you to:
keep track of every element position
perform a clearRect call for every element you want to redraw
and also wouldn't work for shapes other than a rectangle (as there is no clearSphere or clearPath method).
Another reason of the stutters is that until FireFox24, the animations of FireFox was not fully synchronized to the refresh rate (VSYNC), especially if the refresh rate was not exactly 60Hz.
It has to do with the end of section 5 of W3C recommendation, http://www.w3.org/TR/animation-timing/ for the browsers to synchronize animations to the refresh rate. It now runs almost equally as smoothly in both Chrome and FireFox on Windows, since FireFox 24.
TestUFO lists all the supported browsers (that can sync requestAnimationFrame() to the refresh rate) at http://www.testufo.com/browser.html

Categories

Resources