Canvas is flickering, img.src access - javascript

I got a game with falling pics
I push() the next func into an array
and my pics var bulletinare flickering, so I think it's probably I draw them a lot when use update() func
function rect () {
this.size = [rectSize.x, rectSize.y];
this.imagesSrc = rand(0, 1) ? 'bulletinYes' : 'bulletinNo';
this.position = [rand(0, w-rectSize.x), -rectSize.y];
this.bulletinValue = (this.imagesSrc === 'bulletinYes') ? 'bulletinYesValue' : 'bulletinNoValue';
}
rect.prototype = {
draw: function (){
var bulletin = new Image();
bulletin.src = imagesSrc[this.imagesSrc];
ctx.drawImage(bulletin, this.position[0], this.position[2], this.size[0], this.size[2]);
}
}
I've tried to put var bulletin outside the fuction like so
var bulletin = new Image();
bulletin.src = imagesSrc[this.imagesSrc]; <= ???
function rect () {
this.size = [rectSize.x, rectSize.y];
this.imagesSrc = rand(0, 1) ? 'bulletinYes' : 'bulletinNo';
this.position = [rand(0, w-rectSize.x), -rectSize.y];
this.bulletinValue = (this.imagesSrc === 'bulletinYes') ? 'bulletinYesValue' : 'bulletinNoValue';
}
rect.prototype = {
draw: function (){
ctx.drawImage(bulletin, this.position[0], this.position[1], this.size[0], this.size[1]);
}
}
but I have no idea how to change [this..imagesSrc] so it could work.
And also it is executed only once and pic are not randomizing for each pushed one.
Does anyone have any suggestion how to get rid of the flickering or change bulletin.src = imagesSrc[this.imagesSrc];
here's my github link if u want to see whole script
I just started my coding path, so thanks anyone who could answer this one:)

You create new image each time and trying to draw it before image is loaded.
Better way is prepare all images at start and just draw it.
Little changes in your code and all will work:
Prepare images:
var imagesSrc = {
ballotBoxImgSrc: 'img/ballotBox.png',
bulletinYes: 'img/yes.jpg',
bulletinNo: 'img/no.jpg'
};
var images = {
ballotBoxImgSrc: new Image(),
bulletinYes: new Image(),
bulletinNo: new Image()
}
for(let [name,value] of Object.entries(imagesSrc)) {
images[name].src = value;
}
Draw:
rect.prototype = {
draw: function (){
var bulletin = images[this.imagesSrc];
ctx.drawImage(bulletin, this.position[0], this.position[1], this.size[0], this.size[1]);
}
}

Related

How do I change only one image out of many onclick with appendChild?

I'm currently learning JavaScript at my university, so I apologize if my code is terrible. I'm new to it.
I'm having an issue only changing one image onclick using appendChild. What I want to happen is that if the person clicks on the image whose rng is <= 0.89, then only that image is changed to a different image. Every thing I've tried has changed all of the images whose rng was <=0.89.
Example: I click the first image (img1) which has rolled a number greater than 0.9. If (img2) has rolled the same (greater than 0.9), then it also changes. I'd only want img1 to change. Here is only some of my code as the whole thing is about 150 lines and I think this bit gets my point across somewhat well:
function myFunction() {
var rng=Math.random();
var rng2=Math.random();
if (rng <= 0.89){
var img1=document.createElement('img');
img1.src='card2.gif';
img1.id="bad1";
img1.onclick = goodbye;
document.getElementById('card').appendChild(img1);
}
if (rng2 <= 0.89){
var img2=document.createElement('img');
img2.src='card2.gif';
img2.onclick= goodbye;
img2.id="bad2";
document.getElementById('card2').appendChild(img2);
}
if (rng >= 0.9) {
var img1=document.createElement('img');
img1.src='card3.gif';
img1.id="good1";
img1.onclick = hello;
document.getElementById('card').appendChild(img1);
}
if (rng2 >= 0.9){
var img2=document.createElement('img');
img2.src='card3.gif';
img2.onclick= hello;
img2.id="good2";
document.getElementById('card2').appendChild(img2);
}
}
Like I said, every thing I've tried to only change the image that was clicked has changed all images whose rng is <=0.89. The answer's probably really obvious, but I'm new to this, like I said.
Based on the comments, the only change that your code needs is to make .onclick set to a function instead of a string. This way we also pass this the element reference to your functions goodbye and hello. You can also use this to read the element properties if you wanted to. If this is not what your looking for let us know.
img1.onclick = function(){goodbye(this)};
Script
function goodbye(e) {
e.src = 'https://www.youtube.com/yt/brand/media/image/YouTube-logo-full_color.png'
}
function hello(e) {
e.src = 'https://pbs.twimg.com/profile_images/767879603977191425/29zfZY6I.jpg'
}
function myFunction() {
var rng = Math.random();
var rng2 = Math.random();
if (rng <= 0.89) {
var img1 = document.createElement('img');
img1.src = 'card2.gif';
img1.id = "bad1";
img1.onclick = function () {
goodbye(this)
};
document.getElementById('card').appendChild(img1);
}
if (rng2 <= 0.89) {
var img2 = document.createElement('img');
img2.src = 'card2.gif';
img2.onclick = function () {
goodbye(this)
};
img2.id = "bad2";
document.getElementById('card2').appendChild(img2);
}
if (rng >= 0.9) {
var img1 = document.createElement('img');
img1.src = 'card3.gif';
img1.id = "good1";
img1.onclick = function () {
hello(this)
};
document.getElementById('card').appendChild(img1);
}
if (rng2 >= 0.9) {
var img2 = document.createElement('img');
img2.src = 'card3.gif';
img2.onclick = function () {
hello(this)
};
img2.id = "good2";
document.getElementById('card2').appendChild(img2);
}
}
jsfiddle if required

tick method in javascript for canvas

I'm trying to make a tick method for this code.
When I try to put a while loop or time interval it just goes blank.
I want the tick method to call this function without the canvas going blank.
How would i make that tick method
function setup(){
var canvas = document.getElementById('my_canvas');
var ctx = canvas.getContext('2d');
canvas.width = 800;
canvas.height = 600;
var gun = new Image();
var badguy = new Image();
var wall1 = 200;
var ground = new Image();
var back = new Image();
var back2 = new Image();
var back3 = new Image();
var wall = new Image();
var wall2 = new Image();
back.onload = function() {
ctx.drawImage(back, 0, 0, 800, 300);
};
back2.onload = function() {
ctx.drawImage(back2, mountainplace, 0, mtnsize1, 300);
};
back3.onload = function() {
ctx.drawImage(back3, mountainplace2, 0, mtnsize2, 300);
};
ground.onload = function() {
ctx.drawImage(ground, groundplace, 300, 1980, 200);
};
wall.onload = function() {
ctx.drawImage(wall, place2, 250, size2, 100);
};
wall2.onload = function() {
ctx.drawImage(wall2, place, 250, size, 100);
};
badguy.onload = function() {
ctx.drawImage(badguy, badguyplace, 250, 100, 100);
};
gun.onload = function() {
ctx.drawImage(gun, 0, 100, 400, 400);
};
back2.src = "moutain1.png";
back3.src = "moutain2.png";
back.src = "backing.png";
ground.src = "ground1.jpg";
wall.src = "wall.png";
wall2.src = "wall2.png";
badguy.src = "santa2.png";
gun.src = "gun1.png";
};
You need to clarify the question because I'm not sure what exactly you are trying to achieve.
I assume you put some code at the end of your setup() function that performs some operations on the images. But before you can do it you need to wait for the images to load.
BTW: another problem with your code is that the images will be drawn on the canvas in the order in which they load, which may be unpredictable. You probably want to avoid this too.
A solution to your problem (or at least to what I think your problem is) is to first start loading the images and then only perform further operations after they have all been loaded.
You can use the following code to do this:
function makeAllLoadedHandler(image_files_count, on_all_loaded) {
return function() {
--image_files_count;
if (image_files_count == 0) {
// All images loaded, call the function.
on_all_loaded();
}
}
}
function loadAllImages(image_files, on_all_loaded) {
var images = {};
var callback = makeAllLoadedHandler(image_files.length, function() { on_all_loaded(images); } );
for (var i = 0; i < image_files.length; ++i) {
var image = new Image;
image.src = image_files[i];
image.onload = callback;
images[image_files[i]] = image;
}
}
The loadAllImages() function takes an array of image file names and a function to call when all the images have been loaded.
You can use it like this in your code:
function setup() {
var image_files = [
"mountain1.png",
"mountain2.png",
"backing.png",
"ground1.jpg",
"wall.png",
"wall2.png",
"santa2.png",
"gun1.png" ];
loadAllImages(image_files, onAllImagesLoaded);
}
function onAllImagesLoaded(images) {
// Draw your images and perform all the other tasks on them.
// The 'images' object stores each of the Image object under a key that is
// its file name.
ctx.drawImage(images['backing.png'], 0, 0, 800, 300);
// ...
// Do other stuff with the images.
}
You just call the setup() function like you used to and then the onAllImagesLoaded function will be called some time later when all the images are available. You continue your processing in there.
I hope this helps. Although it's possible that your problem is completely different ;)

Drawing application undo button

i have problem with undo button for my drawing application
<input id="undo" type="image" src="images/undo.ico" onclick="cUndo()" width="25" height="25">
var cPushArray = new Array();
var cStep = -1;
var ctx;
// ctx = document.getElementById('myCanvas').getContext("2d");
function cPush() {
cStep++;
if (cStep < cPushArray.length) { cPushArray.length = cStep; }
cPushArray.push(document.getElementById('myCanvas').toDataURL());
}
function cUndo() {
if (cStep > 0) {
cStep--;
var canvasPic = new Image();
canvasPic.src = cPushArray[cStep];
canvasPic.onload = function () { ctx.drawImage(canvasPic, 0, 0); }
}
}
But this doesn't work.Please help
First remark : As #markE underlines, saving with DataURL has a high memory cost. You might consider saving the draw commands + their arguments within an array instead.
Seek for tuts/Stack Overflow post on the topic, out of a few posts you should get some nice ideas.
Anyway, you can go with the dataURL solution in a first time to get your application working (with a limit of 20 undos or like to avoid memory explosion), then you can later improve the undo to reach a higher limit.
I updated my code to handle such a stack limit.
For your issue : onload should be hooked prior to setting the src, but anyway with a DataURL you are not async : the image is built at once, so no need to hook unload.
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext("2d");
var historic = [];
var maxHistoricLength = 20; // might be more or less, depending on canvas size...
function saveForUndo() {
historic.push(canvas.toDataURL());
if (historic.length === maxHistoricLength +1) historic.shift();
}
function canUndo() {
return (historic.length !== 0 );
}
function undo() {
if (!canUndo()) return;
var lastDataURL = historic.pop();
var tmpImage = new Image();
tmpImage.src = lastDataURL;
ctx.drawImage(tmpImage, 0, 0);
}

Animating canvas with a javascript constructor

Hello stackoverflow community!
First I must say that I dont have much experience with constructors.
So. What I am trying to do, is to animate a parachutist to fly from top to bottom of the screen.
I thought I could use a constructor to set up a parachutist:
var parachute = function() {
this.height = 35;
this.width = 30;
this.speed = 50;
this.xPos = Math.round(Math.random() * (window.width - this.width));
this.animate = function() {
this.img = new Image();
this.yPos = 0;
this.img.onload = function() {
ctxPara.globalCompositeOperation = 'copy';
ctxPara.translate(0, this.yPos);
ctxPara.drawImage(this.img, this.xPos, 0);
};
this.img.src = 'para.png';
this.yPos++;
};
};
This constructor is used in a function called 'fly':
var fly = function() {
var newParachute = new parachute();
setInterval(newParachute.animate, newParachute.speed);
};
And this 'fly' function is triggered when the window loads:
window.onload = function() {
var canvasBg = document.getElementById('canvasBg');
// I splitt the Background and the parachutists in two canvas elements
// handling the problem (to erase content and draw new content) with
// the canvas animation.
var canvasPara = document.getElementById('canvasPara');
ctxPara = canvasPara.getContext('2d');
canvasPara.width = window.width;
canvasPara.height = window.height;
canvasBg.width = window.width;
canvasBg.height = window.height;
fly();
clouds(); // background is loading here
};
What you should see, is a Parachutist flying down the screen. But unfortunately you don't...
Now, after that Long text. (Iam very sorry that it is so long :-( ) My question is: Do you know what I am doing wrong? Is my constuctor correct? Is, what i am trying to do, supposed to be written like this? Any advices or suggestions for a succesfull opportunity? (I hope my english isn't that terrible I think it is :-) )
Oh i forgot to mention the error. It's a TypeMissMatchError.
That means 'this.img' is not an img element at this line:
ctxPara.drawImage(this.img, this.xPos, 0);
Now, I followed the example of markE.
Instead of showing me a parachutist. It shows me an error in this line: ctxPara.drawImage(this.img, this.xPos, this.yPos);
var fly = function () {
var newParachute = new parachute();
newParachute.img.load.call(newParachute);
setInterval(newParachute.animate.call(newParachute), newParachute.speed);
};
var parachute = function () {
this.height = 35;
this.width = 30;
this.speed = 25;
this.xPos = Math.round(Math.random() * (window.innerWidth - this.width));
this.img = new Image();
this.yPos = 0;
this.img.isLoaded = false;
this.img.load = function () {
this.img.isLoaded = true;
};
this.img.src = 'parachute.png';
this.animate = function () {
if (this.img.isLoaded) {
ctxPara.clearRect(0, 0, canvasPara.width, canvasPara.height);
ctxPara.drawImage(this.img, this.xPos, this.yPos); // ERROR: 'Unknown Error'.
this.yPos++;
console.log('animating');
}
};
};
I am stuck again. But now i don't even know the reason... Please help!?
Demo: http://jsfiddle.net/m1erickson/ym55y/
A couple of issues:
(1) To get the window width you can use:
window.innerWidth
(2) setInterval calls newParachute.animate.
setInterval(newParachute.animate, newParachute.speed);
But this inside animate the window object--not the Parachute object.
To give the correct this to animate you can use the call method like this:
var newParachute = new parachute();
setInterval(function(){newParachute.animate.call(newParachute);}, newParachute.speed);
(3) You need to deal with clearing previously drawn images or they will still show on your canvas.

html5 canvas code blanking out

I am in desperate need to fix a problem I have in html5 canvas. I am making an educational game, but after adding another photo and making the necessary code changes, but the canvas blanked out. I reverted the changes, but the problem persisted. I spent the past week or so trying to fix it, but I've run out of ideas :( Here is the relevent code (if anyone needs another part, just say so):
// Create the canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = 1041;
canvas.height = 550;
document.body.appendChild(canvas);
// Background image
var bgReady = false;
var bgImage = new Image();
bgImage.onload = function () {
bgReady = true;
};
bgImage.src = "images/introbackground.png";
//.... rest of the photos load like this so I won't put it...
// Level 1 background 1 image
var bbg1Ready = false;
var bbg1Image = new Image();
bbg1Image.onload = function () {
bbg1Ready = false; //Exception since it shouldn't load at the beginning
};
bbg1Image.src = "images/pollutedbeach1.png";
// Game objects
var hero = {
speed: 200 // movement in pixels per second
};
var level1;
var level2;
var biolevel = false;
//...Code to make the hero picture move with arrow keys and to reset the game are skipped...
if (hero.x <= (level1.x + 345)
&& level1.x <= (hero.x + 32)
&& hero.y <= (level1.y +50)
&& level1.y <= (hero.y + 32)){
biolevel = true;
return biolevel;
}
var render = function () {
if (bgReady) {
ctx.drawImage(bgImage, 0, 0);
}
//...The same for all photos previously loaded...
if (biolevel == true){
level1Ready = false;
level2Ready = false;
bbg1Ready = true;
hero.speed = 125;
}
};
//...Then the main game loop to animate it...
Sorry It's kind of long, but I really need a solution. Thanks!

Categories

Resources