HTML5 Canvas blinking on drawing - javascript

I'm beginning with an isometric game, and my canvas is blinking(Not in IE) when draws all the parts of the ground. When I set fps to 20 or less, the blinking stops. How can I solve that? Any ideas?
var camerax = 300, cameray = 100;
var fps = 60;
function draw() {
clearCanvas();
drawGround();
}
function drawGround() {
var img = new Image();
img.onload = function() {
var width = img.width;
var height = img.height;
for (var x = 0; x < 3; x++) {
for (var y = 3; y >= 0; y--) {
mx = (x-y)*height + camerax;
my = (x+y)*height/2 + cameray;
ctx.drawImage(img, mx, my);
}
}
}
img.src = "ground.png";
}
var loop = setInterval(function() {
update();
draw();
}, 1000/fps);

Right now you're reloading the image every frame and unless the onload callback fires within the 16ms of the frame you're going to see a blank canvas.
You should only need to call the new Image, img.onload sequence once, to preload your images. The onload callback would then kick off your first frame, and the draw calls are free to use the image in memory.
Something like:
var camerax = 300, cameray = 100;
var fps = 60;
var img;
var loop;
function init() {
img = new Image();
img.onload = function() {
loop = setInterval(function() {
update();
draw();
}, 1000/fps);
};
img.src = "ground.png";
}
function draw() {
clearCanvas();
drawGround();
}
function drawGround() {
var width = img.width;
var height = img.height;
for (var x = 0; x < 3; x++) {
for (var y = 3; y >= 0; y--) {
mx = (x-y)*height + camerax;
my = (x+y)*height/2 + cameray;
ctx.drawImage(img, mx, my);
}
}
}
}
Of course, it gets more complex once you're waiting for multiple images to preload since you need to start the loop only once all of them are done.

Nice tip, freejosh! Thanks! My screen now is not blinking and the code result was that:
var canvas = document.getElementById("game");
var ctx = canvas.getContext("2d");
var camerax = 300, cameray = 100;
var fps = 60;
var img;
var loop;
function update() {
}
function draw() {
clearCanvas();
drawGround();
}
function clearCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
function drawGround() {
var width = img.width;
var height = img.height;
for (var x = 0; x < 3; x++) {
for (var y = 3; y >= 0; y--) {
mx = (x-y)*height + camerax;
my = (x+y)*height/2 + cameray;
ctx.drawImage(img, mx, my);
}
}
}
function init() {
img = new Image();
img.onload = function() {
drawGround();
};
img.src = "ground.png";
}
function keyListener(e){
e = e || window.event
if(e.keyCode==37){
camerax--;
}
else if(e.keyCode==39){
camerax++;
}
else if(e.keyCode==38){
cameray--;
}
else if(e.keyCode==40){
cameray++;
}
}
window.onkeypress = function(e) {
keyListener(e);
}
init();
var loop = setInterval(function() {
update();
draw();
}, 1000/fps);

Related

How to move the canvas backward in javascript?

I try to think how the box can move backward when it hit 1000px (canvas.width) ,but I don’t know how it solves after If condition, so there’s my script, anyone can help me ?
var canvas = document.querySelector("canvas");
var canvasCT = canvas.getContext("2d");
var x = 50;
function draw() {
canvas.width = canvas.width;
canvasCT.fillStyle = "blue";
canvasCT.fillRect(x, 50, 100, 100);
}
function run() {
draw();
x += 5 ;
if (x > 1000) {
......
}
}
setInterval(run, 10);
var canvas = document.querySelector("canvas");
var canvasCT = canvas.getContext("2d");
var x = 50;
var speed = 5;
function draw() {
canvas.width = canvas.width;
canvasCT.fillStyle = "blue";
canvasCT.fillRect(x, 50, 100, 100);
}
function run() {
draw();
x += speed;
if (x > 1000 || x < 0) {
speed = -speed;
}
}
setInterval(run, 10);
<canvas width=1000></canvas>

Moving multiple object together in canvas with respect to the current position

I have a canvas element with multiple images being displayed. I am trying to achieve is that when I click on a button it should move 200 position in X coordinates. I managed to move the second image, but the first image is not moving. And the images must move with respective to their current position. I am here by attaching my javascript for the same.
$(window).on('load', function () {
imageContent(200);
});
function imageContent(x) {
var posX = x;
var imgArray = ['http://via.placeholder.com/200x200?text=first', 'http://via.placeholder.com/200x200?text=second'];
$.each(imgArray, function (i, l) {
var img = new Image();
img.onload = function () {
var x = 0;
myCanvas(img, i * posX);
};
img.src = l;
});
}
function myCanvas(img, x) {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var last_ts = -1
var speed = 0.1
function renderScene() {
ctx.beginPath();
ctx.drawImage(img, x, 0);
}
function fly(ts) {
if (last_ts > 0) {
x += speed * (ts - last_ts)
}
last_ts = ts
if (x < 200) {
imageContent(x);
requestAnimationFrame(fly);
}
}
renderScene();
$('#movebutton').click(function () {
x = 0;
requestAnimationFrame(fly);
});
}
Here is the codepen. It would be greatful if anyone could help me.
Edit: Modified to achieve side by side movement
I modified your code a little, and removed jQuery. See if it is the effect you are trying to achieve:
var imgArr = [],
c = document.getElementById("myCanvas"),
ctx = c.getContext("2d"),
last_ts = -1,
speed = 0.1,
x = 0
window.onload = function() {
[
'http://via.placeholder.com/200x200?text=first',
'http://via.placeholder.com/200x200?text=second'
].forEach(function(obj, idx) {
var img = new Image()
img.onload = function() {
drawImage(img, idx * 200, 0)
}
img.src = obj
imgArr.push(img)
})
}
function drawImages(x) {
ctx.clearRect(0, 0, c.width, c.height)
imgArr.forEach(function(obj, idx) {
drawImage(obj, x + idx*200, 0)
})
}
function drawImage(img, x, y) {
ctx.beginPath()
ctx.drawImage(img, x, y)
}
function fly(ts) {
if (last_ts > 0) {
x += speed * (ts - last_ts)
}
last_ts = ts
if (x < 200) {
drawImages(x)
requestAnimationFrame(fly)
}
}
document
.getElementById('movebutton')
.addEventListener('click', function() {
x = 0
fly()
}, false)
canvas {
border: 1px solid red;
}
<canvas id="myCanvas" width="960" height="600"></canvas>
<button id="movebutton">Move</button>

Canvas rotation - fixed background, moving foreground

Goal
The stripes in the background remain fixed while the cones rotate about the center.
Current State
live demo:
https://codepen.io/WallyNally/pen/yamGYB
/*
The loop function is around line 79.
Uncomment it to start the animation.
*/
var c = document.getElementById('canv');
var ctx = c.getContext('2d');
var W = c.width = window.innerWidth;
var H = c.height = window.innerHeight;
var Line = function() {
this.ctx = ctx;
this.startX = 0;
this.startY = 0;
this.endX = 0;
this.endY = 0;
this.direction = 0;
this.color = 'blue';
this.draw = function() {
this.ctx.beginPath();
this.ctx.lineWidth = .1;
this.ctx.strokeStlye = this.color;
this.ctx.moveTo(this.startX, this.startY);
this.ctx.lineTo(this.endX, this.endY);
this.ctx.closePath();
this.ctx.stroke();
}
this.update = function() {
//for fun
if (this.direction == 1) {
this.ctx.translate(W/2, H/2);
this.ctx.rotate(-Math.PI/(180));
}
}//this.update()
}//Line();
objects=[];
function initLines() {
for (var i =0; i < 200; i++) {
var line = new Line();
line.direction = (i % 2);
if (line.direction == 0) {
line.startX = 0;
line.startY = -H + i * H/100;
line.endX = W + line.startX;
line.endY = H + line.startY;
}
if (line.direction == 1) {
line.startX = 0;
line.startY = H - i * H/100;
line.endX = W - line.startX;
line.endY = H - line.startY;
}
objects.push(line);
line.draw();
}
}
initLines();
function render(c) {
c.clearRect(0, 0, W, H);
for (var i = 0; i < objects.length; i++)
{
objects[i].update();
objects[i].draw();
}
}
function loop() {
render(ctx);
window.requestAnimationFrame(loop);
}
//loop();
What I have tried
The translate(W/2, H/2) should place the context at the center of the page, then this.ctx.rotate(-Math.PI/(180)) should rotate it one degree at a time. This is the part that is not working.
Using save()and restore() is the proper way to keep some parts of an animation static while others move. I placed the save and restore in different parts of the code to no avail. There are one of two types of result : Either a new entirely static image is produced, or some erratic animation happens (in the same vein of where it is now).
Here is the changed pen: http://codepen.io/samcarlinone/pen/LRwqNg
You needed a couple of changes:
var c = document.getElementById('canv');
var ctx = c.getContext('2d');
var W = c.width = window.innerWidth;
var H = c.height = window.innerHeight;
var angle = 0;
var Line = function() {
this.ctx = ctx;
this.startX = 0;
this.startY = 0;
this.endX = 0;
this.endY = 0;
this.direction = 0;
this.color = 'blue';
this.draw = function() {
this.ctx.beginPath();
this.ctx.lineWidth = .1;
this.ctx.strokeStlye = this.color;
this.ctx.moveTo(this.startX, this.startY);
this.ctx.lineTo(this.endX, this.endY);
this.ctx.closePath();
this.ctx.stroke();
}
this.update = function() {
//for fun
if (this.direction == 1) {
this.ctx.translate(W/2, H/2);
this.ctx.rotate(angle);
this.ctx.translate(-W/2, -H/2);
}
}//this.update()
}//Line();
objects=[];
function initLines() {
for (var i =0; i < 200; i++) {
var line = new Line();
line.direction = (i % 2);
if (line.direction == 0) {
line.startX = 0;
line.startY = -H + i * H/100;
line.endX = W + line.startX;
line.endY = H + line.startY;
}
if (line.direction == 1) {
line.startX = 0;
line.startY = H - i * H/100;
line.endX = W - line.startX;
line.endY = H - line.startY;
}
objects.push(line);
line.draw();
}
}
initLines();
function render(c) {
c.clearRect(0, 0, W, H);
for (var i = 0; i < objects.length; i++)
{
ctx.save();
objects[i].update();
objects[i].draw();
ctx.restore();
}
}
function loop() {
render(ctx);
window.requestAnimationFrame(loop);
angle += Math.PI/360;
}
loop();
First I added a variable to keep track of rotation and increment it in the loop
Second I save and restore for each individual line, alternatively if all lines were going to perform the same transformation you could move that code before and after the drawing loop
Third to get the desired affect I translate so the center point is in the middle of the screen, then I rotate so that the lines are rotated, then I translate back because all the lines have coordinates on the interval [0, H]. Instead of translating back before drawing another option would be to use coordinates on the interval [-(H/2), (H/2)] etc.

Moving content of canvas with a specific framerate

So I have this sprite animation which goes fine when it's not in movement (I need it to go on 20 fps max because if not the animation would be too fast), but when I try to move it across the screen, the movement looks really choppy. Any ideas on how to make the movement smoothly? Increase the framerate works, but I'd like to see if there is another option aside of that.
var canvasA = document.createElement("canvas");
var canvasB = document.createElement("canvas");
var contextA = canvasA.getContext("2d");
var contextB = canvasB.getContext("2d");
canvasA.style.position = "absolute";
canvasB.style.position = "absolute";
var xpos = 0;
var ypos = 0;
var index = 0;
var frameSizeX = 140;
var frameSizeY = 395;
var numFrames = 20;
var drawing_character = false;
var xPosition = 0;
var now, then, elapsed, startTime, fps, fpsInterval;
var fpscounter = setInterval(updatefps, 1000);
var forw = true;
var cfps = 0;
// Pictures
var background = new Image();
background.src = "http://i.imgur.com/3FDB45h.png";
var character = new Image();
character.src = "http://i.imgur.com/tziJajG.png";
function redraw() {
contextB.clearRect(0, 0, canvasB.width, canvasB.height);
contextB.drawImage(background, 0, 0);
}
function drawchar() { // Input= fps max
requestAnimationFrame(drawchar);
now = Date.now();
elapsed = now - then;
if (elapsed > fpsInterval) {
then = now - (elapsed % fpsInterval);
contextA.clearRect(0, 0, 800, 600);
contextA.drawImage(character,
xpos,
ypos,
frameSizeX,
frameSizeY,
xPosition,
0,
frameSizeX,
frameSizeY);
xpos += frameSizeX;
index += 1;
if (index >= numFrames) {
xpos = 0;
ypos = 0;
index = 0;
} else if (xpos + frameSizeX > character.width) {
xpos = 0;
ypos += frameSizeY;
}
cfps++;
}
}
function updatefps() {
document.getElementById("fps").innerHTML = "FPS: " + cfps;
cfps = 0;
}
function aqui() {
prepareCanvas();
setInterval(redraw, 1000/60);
animarchar(20);
setInterval(move, 1);
}
function move() {
if (forw === true) {
xPosition += 1;
if (xPosition === 300){
forw = false;}
} else {
xPosition -= 1;
if (xPosition === 0){
forw = true;}
}
}
function prepareCanvas() {
canvasB.width = 800;
canvasB.height = 600;
canvasA.width = canvasB.width;
canvasA.height = canvasB.height;
//document.body.appendChild(canvasB);
document.body.appendChild(canvasA);
}
function animarchar(fps) {
fpsInterval = 1000 / fps;
then = Date.now();
startTime = then;
drawchar();
}
window.onload = function () {
aqui();
};
Here is a jsFiddle: https://jsfiddle.net/qb171ghf/

HTML5 drawImage - Not working in Chrome while dragging

Im trying to drag and drop an image in canvas. But when dragging in chrome the image disapears but in Mozilla it works fine. Any help on this would be really appreciated.
HTML File
<head>
<script>
var canvasImages = [];
function imageProp() {
this.imgName = ' ';
this.imgX = 0;
this.imgY = 0;
this.ImgWidth = 1;
this.ImgHeight = 1;
}
function GetFilename(url) {
if (url) {
var m = url.toString().match(/.*\/(.+?)\./);
if (m && m.length > 1) {
return m[1];
}
}
return "";
}
function load(source) {
var canvas = document.getElementById("mycanvas");
var ctx = canvas.getContext('2d');
var imageObj = new Image();
//Loading image to Canvas
imageObj.onload = function () {
ctx.drawImage(imageObj, 0, 0);
};
imageObj.src = source;
//Inserting properties of image loaded in canvas to an array
var Property = new imageProp;
//Property.imgName = GetFilename(source);
Property.imgName = source;
Property.imgX = 0;
Property.imgY = 0;
Property.ImgWidth = imageObj.width;
Property.ImgHeight = imageObj.height;
canvasImages.push(Property);
}
</script>
</head>
<body>
<img id = "imgID" onclick=" load(this.src)" src = 'download.png'/>
<canvas id="mycanvas" width="1000" height="1000">HTML5 Not Supported</canvas>
<script src="Canvas_js.js"></script>
</body>
Javascript file
(function () {
"use strict";
/*global document*/
/*global clear*/
/*global canvasImages*/
/*jslint devel: true */
/*jslint browser: true */
var canvas, ctx, ghostcanvas, gctx, RedrawInterval = 20, canvasValid = false, clickLoc = {}, isDragging = false, index = 0, selectedIndex = 0;
clickLoc.x = 0;
clickLoc.y = 0;
function drawCanv() {
var i = 0, imageObj;
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (i = 0; i < canvasImages.length; i += 1) {
imageObj = new Image();
imageObj = document.createElement('img');
imageObj.src = canvasImages[i].imgName;
imageObj.onload = function () {
ctx.drawImage(imageObj, canvasImages[i].imgX, canvasImages[i].imgY);
};
}
}
function resizeHandler(index) {
ctx.beginPath();
ctx.strokeRect(canvasImages[index].imgX, canvasImages[index].imgY, canvasImages[index].ImgWidth + 5, canvasImages[index].ImgHeight + 5);
}
function canvasOnClick(e) {
var rect, i = 0;
isDragging = true;
//Get X and Y coordinates of the click
rect = canvas.getBoundingClientRect();
clickLoc.x = e.clientX - rect.left;
clickLoc.y = e.clientY - rect.top;
//Check whether any image is clicked
for (i = 0; i < canvasImages.length; i += 1) {
if (clickLoc.x >= canvasImages[i].imgX && clickLoc.x <= canvasImages[i].imgX + canvasImages[i].ImgWidth && clickLoc.y >= canvasImages[i].imgY && clickLoc.y <= canvasImages[i].imgY + canvasImages[i].ImgHeight) {
selectedIndex = i;
resizeHandler(i);
}
}
}
function canvasMouseUp(e) {
isDragging = false;
}
function canvasMouseMove(e) {
if (isDragging === true) {
canvasImages[selectedIndex].imgX += 5;
drawCanv();
}
}
function init() {
// Defining Canvas and fake canvas
canvas = document.getElementById('mycanvas');
ctx = canvas.getContext('2d');
ghostcanvas = document.createElement('canvas');
ghostcanvas.height = canvas.height;
ghostcanvas.width = canvas.width;
gctx = ghostcanvas.getContext('2d');
// Redrawing canvas for the interval
//setInterval(draw, RedrawInterval);
// Adding Eventlisteners
canvas.addEventListener("mousedown", canvasOnClick, false);
canvas.addEventListener("mouseup", canvasMouseUp, false);
canvas.addEventListener("mousemove", canvasMouseMove, false);
}
init();
}());
Start messing around with
user-select: none;
-webkit-user-select: none;
in your css.

Categories

Resources