Drawn image not moving on canvas - javascript

I make the game with html canvas.I need to move the image sprite but my code only redraw the image on the same position.Where is problem?The code is here
class Duck{
constructor(x,y){
this.x = x;
this.y = y;
this.skin = 'img/path/';
}
draw() {
var img = new Image();
img.src = this.skin;
img.onload = function () {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img,this.x, this.y);
ctx.restore();
}
}
move(){
this.x+=10;
this.y+=10;
}
}
var canvas = document.getElementById("canv");
var ctx = canvas.getContext("2d");
var d = new Duck(0,0);
//this function called from another file and it works
function mainLoop() {
d.move();
d.draw();
requestAnimationFrame(mainLoop);
}

Here is your code fixed:
You don't need ctx.restore();
You need to store this context in the draw method, for reference in the img.onload callback
class Duck {
constructor(x, y) {
this.x = x;
this.y = y;
this.skin = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJDYXBhXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNTEyIDUxMjsiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPHBhdGggc3R5bGU9ImZpbGw6I0ZGREU3NjsiIGQ9Ik00MzMuNjYxLDIzNy44MzdjLTQuNDk3LTYuMjE0LTQuODgtMTQuNDQtMS4yMjUtMjEuMTg0YzExLjM2NS0yMC45NjcsMTcuNzczLTQ1LjAxNCwxNy42NTEtNzAuNTY2DQoJQzQ0OS43MDEsNjQuODY5LDM4Mi41NjQtMS4wMzcsMzAxLjM1MiwwLjAxMmMtODAuMTgzLDEuMDM2LTE0NC44NjQsNjYuMzU5LTE0NC44NjQsMTQ2Ljc4OGMwLDMyLjU1MywxMC41OTUsNjIuNjMsMjguNTI2LDg2Ljk3Mg0KCWM3Ljc1MywxMC41MjYsNy4yMTMsMjUuMS0xLjU0MywzNC44MDhjLTEzLjI5NywxNC43NDEtNDEuOTM1LDI0LjMwNi0xMDIuNTk1LTE2LjI3N2MtNi42NTItNC40NS0xNC40NjItNi44NjQtMjIuNDY1LTYuODY0bDAsMA0KCWMtMTkuOTQ3LDAtMzYuODMzLDE0LjYyOC0zOS43NzYsMzQuMzU3QzcuODg5LDM1MS44MTYsNi41Miw1MTIsMjA2Ljk2Niw1MTJoNzEuMDgzQzQ2Ni4wNSw1MTIsNTE2LjEyNywzNTEuODAxLDQzMy42NjEsMjM3LjgzN3oiLz4NCjxnPg0KCTxwYXRoIHN0eWxlPSJmaWxsOiNGRkI2NDE7IiBkPSJNMTgzLjQ3LDI2OC41ODJjLTMuOTMsNC4zNTctOS4yMDIsOC4yNjEtMTYuMjQ0LDEwLjU1MmMyNC40NjksNS44ODIsMzguODItMS4zMTksNDcuMTQ5LTEwLjU1Mg0KCQljOC43NTctOS43MDgsOS4yOTYtMjQuMjgxLDEuNTQzLTM0LjgwOGMtMTcuOTMtMjQuMzQyLTI4LjUyNi01NC40Mi0yOC41MjYtODYuOTczYzAtNzUuODMzLDU3LjUwMy0xMzguMjI2LDEzMS4yODEtMTQ1Ljk4DQoJCWMtNS42ODktMC42MDEtMTEuNDY3LTAuODg0LTE3LjMyMy0wLjgwOWMtODAuMTgzLDEuMDM2LTE0NC44NjQsNjYuMzU5LTE0NC44NjQsMTQ2Ljc4OGMwLDMyLjU1MywxMC41OTUsNjIuNjMsMjguNTI2LDg2Ljk3Mw0KCQlDMTkyLjc2NiwyNDQuMywxOTIuMjI2LDI1OC44NzMsMTgzLjQ3LDI2OC41ODJ6Ii8+DQoJPHBhdGggc3R5bGU9ImZpbGw6I0ZGQjY0MTsiIGQ9Ik00OS41MzksMjc5Ljc5NmMyLjEzNy0xNC4zMTcsMTEuNjE4LTI1Ljk0MiwyNC4yODItMzEuMjQ1Yy00Ljg2Ni0yLjAyMi0xMC4wOTEtMy4xMS0xNS40MTItMy4xMQ0KCQlsMCwwYy0xOS45NDcsMC0zNi44MzMsMTQuNjI4LTM5Ljc3NiwzNC4zNTdDNy44ODksMzUxLjgxNiw2LjUyLDUxMiwyMDYuOTY2LDUxMmgzMC45MDVDMzcuNDI1LDUxMiwzOC43OTQsMzUxLjgxNiw0OS41MzksMjc5Ljc5NnoNCgkJIi8+DQoJPHBhdGggc3R5bGU9ImZpbGw6I0ZGQjY0MTsiIGQ9Ik04MC41MTgsMzQ0LjMzNmMtOC43NjYsOC42NTYtMTAuMjc3LDIyLjI2OC0zLjU5OCwzMi42MTkNCgkJYzE5LjUwNCwzMC4yMjcsNjguMzUxLDg2LjI4MywxNjIuMzcyLDg2LjI4M2M1Ny4yNTYsMCwxMTcuNzkxLTM1LjgwOSwxMjkuMDY0LTk1LjA5N2M5LjMxLTQ4Ljk2Ni0xOS4yNDYtMTA4LjgyMS03NS4zMy0xMDYuMjQ3DQoJCWMtNDEuMDk3LDEuODg3LTY1LjEzNSwzNy40MTUtOTkuODY1LDUzLjg0MWMtMjQuMzk4LDExLjU0LTUwLjg0NCwxOC42NTEtNzcuNjg3LDIxLjMwNw0KCQlDMTAyLjY5OCwzMzguMzA2LDkwLjgwNSwzMzQuMTc4LDgwLjUxOCwzNDQuMzM2eiIvPg0KPC9nPg0KPHBhdGggc3R5bGU9ImZpbGw6IzM4NDg0QTsiIGQ9Ik0zODguMzk0LDExMC44MzNjLTMuNTAyLDAtNi42NzQtMi4zOTYtNy41MTMtNS45NTFsLTMuNzE1LTE1LjczDQoJYy0wLjk4MS00LjE1MywxLjU5MS04LjMxNSw1Ljc0My05LjI5NWM0LjE1Mi0wLjk3OSw4LjMxNSwxLjU5MSw5LjI5NSw1Ljc0M2wzLjcxNSwxNS43M2MwLjk4MSw0LjE1My0xLjU5MSw4LjMxNS01Ljc0Myw5LjI5NQ0KCUMzODkuNTgsMTEwLjc2NSwzODguOTgyLDExMC44MzMsMzg4LjM5NCwxMTAuODMzeiIvPg0KPHBhdGggc3R5bGU9ImZpbGw6I0ZGQjY0MTsiIGQ9Ik00MjcuNjE4LDY4Ljk5NGMwLDAsMy4xOTgsNDUuODMyLTE4LjAzMyw2Ni41OTFjLTIxLjIzMSwyMC43NTksMTQuMTU0LDUzLjMxNCw1Ni4xNDUsMjIuNjQ2DQoJYzYuMDMyLTQuNDA1LDEyLjE0My03LjIwNCwxOC4xODQtOC43NjhjNy43NzctMi4wMTIsMTMuMjQzLTguOTY3LDEzLjI0My0xNi45OTlsMCwwYzAtNy43MjQtNS4wMzEtMTQuNTk3LTEyLjQzOC0xNi43ODYNCgljLTQuOTI1LTEuNDU2LTExLjE4LTIuMzI1LTE4LjUxNi0xLjMyNWMwLDAsMjUuMzkzLTIyLjEzOCwxOS4xMTktNDcuNzUzYy0yLjAyNy04LjI4LTExLjg1Ni0xMS43MjYtMTguODM2LTYuODMyDQoJQzQ1Ny40NjEsNjYuMDk0LDQ0My40NTQsNzIuNzY0LDQyNy42MTgsNjguOTk0eiIvPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPC9zdmc+DQo=';
}
draw() {
var img = new Image();
img.src = this.skin;
const that = this;
img.onload = function () {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, that.x, that.y);
}
}
move() {
this.x += 10;
this.y += 10;
}
}
var canvas = document.getElementById("canv");
var ctx = canvas.getContext("2d");
var d = new Duck(0, 0);
//this function called from another file and it works
function mainLoop() {
d.move();
d.draw();
requestAnimationFrame(mainLoop);
}
mainLoop();
<canvas id="canv" height="600px" width="600px"></canvas>

Related

How to use constructors and images in javascript?

I have the following segment of code intented to draw an image onto the canvas. This code works:
var ctx = canvas.getContext('2d');
class Rectangle {
constructor(x, y, scale, source) {
this.scale = scale;
this.source = source;
this.x = x;
this.y = y;
}
update() {
var sprite = new Image();
sprite.src = this.source;
sprite.onload = function () {
ctx.drawImage(sprite, this.x, this.y, sprite.width/3, sprite.height/3);
}
}
}
const rect = new Rectangle(0, 0, 1, 'circle.jpeg');
rect.update();
But, when I replace this line:
ctx.drawImage(sprite, this.x, this.y, sprite.width/3, sprite.height/3);
with this:
ctx.drawImage(sprite, this.x, this.y, sprite.width/this.scale, sprite.height/this.scale);
the canvas doesn't show anything at all. All this should be doing is replacing the 3 from before with the value from the constructor (which I set to 1 when I create a new instance). Why isn't it drawing anything?
I would move the sprite to the constructor that way when we call the update we don't have to create a new image, the idea behind that is the update function could be called multiple times efficiently.
See this sample below:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
class Rectangle {
constructor(x, y, scale, source) {
this.scale = scale;
this.x = x;
this.y = y;
this.sprite = new Image();
this.sprite.src = source;
this.sprite.onload = () => {
this.update()
};
}
update() {
if (this.sprite) {
ctx.drawImage(this.sprite, this.x, this.y, this.sprite.width / this.scale, this.sprite.height / this.scale);
}
}
}
const rect = new Rectangle(0, 0, 3, 'http://i.stack.imgur.com/UFBxY.png');
canvas.addEventListener("click", () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
rect.x += 5;
rect.update();
});
<canvas id="canvas"></canvas>
You can see that as suggested in the comments by #skara9 I'm using the () => instead of function() and I'm calling the update there.
On this sample I also added canvas.addEventListener("click" that shows how when the user clicks on the canvas the drawing move a little to the right, the logic is simple we increase the value of rect.x and then we call the rect.update(); that will draw the image on the new location.

Javascript Game: How to generate enemies (images) from an array

I was successful in generating enemies (out of one image) with an array, however, I'm stuck in trying to generate enemies out of more than one image (e. g. 5 different images, thus 5 different enemies)
Here is my code that works:
Enemies (enemyImg - one image) are generated
/** #type {HTMLCanvasElement} */
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const backgroundImg = document.getElementById("background");
const playerImg = document.getElementById("player");
const enemyImg = document.getElementById("enemy");
canvas.width = 800;
canvas.height = 500;
const enemies = [];
class Enemy {
constructor(x, y, w, h, speed) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.speed = speed;
}
draw() {
ctx.drawImage(enemyImg, this.x, this.y, this.w, this.h);
}
update() {
this.x = this.x - this.speed;
}
}
function spawnEnemies() {
setInterval(() => {
let w = 100;
let h = 40;
let x = canvas.width;
let y = Math.random() * Math.abs(canvas.height - h);
let speed = 5;
enemies.push(new Enemy(x, y, w, h, speed));
}, 1000);
}
function animate() {
requestAnimationFrame(animate);
ctx.clearRect(0, 0, canvas.width, canvas.height);
enemies.forEach((enemy) => {
enemy.draw();
enemy.update();
});
}
animate();
spawnEnemies();
Here is the code, that does not work. I do not get any error message at all:
I have 6 images in one folder, named enemy_1.png to enemy_6.png) and I want them to be generated;
/** #type {HTMLCanvasElement} */
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const backgroundImg = document.getElementById("background");
const playerImg = document.getElementById("player");
const enemyImg = document.getElementById("enemy");
canvas.width = 800;
canvas.height = 500;
let enemies = [];
class Enemy {
constructor(img, x, y, w, h, speed) {
this.img = img;
(this.x = x),
(this.y = y),
(this.w = w),
(this.h = h),
(this.speed = speed);
}
draw() {
ctx.drawImage(img, this.x, this.y, this.w, this.h);
}
move() {
this.x = this.x - this.speed;
}
}
function createEnemies() {
setInterval(() => {
let w = 40;
let h = 72;
let x = 300;
let y = Math.random() * Math.abs(canvas.height - h);
let speed = 5;
enemies.length = 6;
for (let i = 1; i < enemies.length; i++) {
enemies[i] = new Image();
enemies[i].src = "./images/enemy_" + i + ".png";
enemies.push(new Enemy(enemies[i], x, y, w, h, speed));
}
}, 2000);
}
function createGame() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
enemies.forEach((enemy) => {
enemy.draw();
enemy.move();
});
requestAnimationFrame(createGame);
}
createGame();
createEnemies();
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const backgroundImg = document.createElement('img');
const playerImg = document.createElement('img');
canvas.width = 500;
canvas.height = 200;
// load your images:
const imagesCount = 0; // I have not this images, so its zero for me
const enemyImages = [];
for (let i = 1; i < imagesCount; i++) {
const img = new Image();
img.src = "./images/enemy_" + i + ".png";
enemyImages.push(img);
}
// I have not your images so i take some random pictures:
const enemyImage1 = new Image();
enemyImage1.src = 'https://pngimg.com/uploads/birds/birds_PNG106.png';
const enemyImage2 = new Image();
enemyImage2.src = 'https://purepng.com/public/uploads/large/purepng.com-magpie-birdbirdsflyanimals-631522936729bqeju.png';
const enemyImage3 = new Image();
enemyImage3.src = 'https://www.nsbpictures.com/wp-content/uploads/2018/10/birds-png.png';
enemyImages.push(
enemyImage1,
enemyImage2,
enemyImage3,
);
const enemies = [];
class Enemy {
constructor(x, y, w, h, speed, img) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.speed = speed;
// Self image:
this.img = img;
}
draw() {
// Draw self image:
ctx.drawImage(this.img, this.x, this.y, this.w, this.h);
}
update() {
this.x = this.x - this.speed;
}
}
function spawnEnemies() {
setInterval(() => {
let w = 60;
let h = 50;
let x = canvas.width;
let y = Math.random() * Math.abs(canvas.height - h);
let speed = 5;
enemies.push(new Enemy(x, y, w, h, speed,
// Pick random image from array:
enemyImages[Math.floor(Math.random()*enemyImages.length)]
));
}, 1000);
}
function animate() {
requestAnimationFrame(animate);
ctx.clearRect(0, 0, canvas.width, canvas.height);
enemies.forEach((enemy) => {
enemy.draw();
enemy.update();
});
}
animate();
spawnEnemies();
<canvas id=canvas></canvas>

Why wont my image draw but it loads?

I'm starting to make a game and I'm putting together a little "game engine" to do stuff easily and not type so repetitively. I have a sprite function that loads the image and an update function which draws it. The problem is it won't draw, and no errors have been reported in the console.
jsfiddle
var canvas = document.createElement("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.position = "absolute";
canvas.style.right = "0px";
canvas.style.top = "0px";
document.body.appendChild(canvas);
var c = canvas.getContext("2d");
var Squares = [];
var Square = function(x,y,w,h,color="black") {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.color = color;
Squares.push(this);
return this
}
var Sprites = [];
var Sprite = function(x,y,w,h,src) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.src = src;
this.img = new Image();
this.img.onload = function() {
}
this.img.src = this.src;
this.img.width = this.w;
this.img.height = this.h;
return this
}
function Clear(x,y,w,h) {
c.clearRect(x,y,w,h);
}
function Update() {
Clear(0,0,canvas.width,canvas.height);
for(var square in Squares) {
c.fillStyle = Squares[square].color;
c.fillRect(Squares[square].x,Squares[square].y,Squares[square].w,Squares[square].h);
}
for(var sprite in Sprites) {
console.log(Sprites[sprite].img)
Sprites[sprite].img.onload = function() {
c.drawImage(Sprites[sprite].img);
}
}
}
var ground = new Square(0,0,canvas.width,canvas.height,color="forestgreen");
var player = new Square(10,10,6,6,color="red");
var Mtn = new Sprite(50,50,50,50,"mountain.png");
console.log(Mtn.img)
function Logic() {
}
function Main() {
Logic();
Update();
}
setInterval(Main,2);

Make classes in javascript with arrays

I want to make a Rain drop efect on Javascript
var canvas = document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");
function Drop(x,y,larg,alt){
this.x=x;
this.y=y;
this.larg=larg;
this.alt=alt;
}
var a = new Drop(canvas.width/4,0,2,25);
function draw(){
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.fillStyle="blue";
ctx.fillRect(a.x,a.y,a.larg,a.alt)
a.y++;
}
setInterval(draw, 5);
With this code i can make just one drop, by this i think in make this "var a" a array.
How can i declare this array in code to work?
var canvas = document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");
function Drop(x,y,larg,alt){
this.x=x;
this.y=y;
this.larg=larg;
this.alt=alt;
}
var a = [];
a = push(new Drop(canvas.width/4,0,2,25));
function draw(){
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.fillStyle="blue";
ctx.fillRect(a.x,a.y,a.larg,a.alt)
a.y++;
}
setInterval(draw, 5);
or with es6 classes:
var canvas = document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");
class Drop {
constructor (x,y,larg,alt) => {
this.x=x;
this.y=y;
this.larg=larg;
this.alt=alt;
}
}
var a = [new Drop(canvas.width/4,0,2,25)];
function draw(){
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.fillStyle="blue";
ctx.fillRect(a.x,a.y,a.larg,a.alt)
a.y++;
}
setInterval(draw, 5);

Picture background for canvas particle

I'm trying to create background for every created particle.
Canvas pattern is not working properly. I'm getting this error >> "SyntaxError: An invalid or illegal string was specified"
HTML
<canvas id="canvas"></canvas>
JS
(function(){
window.onload = function(){
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d'),
particles = {},
particleIndex = 0,
particleNum = 1;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, canvas.width, canvas.width);
function Particle(){
this.x = canvas.width / 2;
this.y = 0;
this.vx = Math.random() * 10 - 5;
this.vy = Math.random() * 10 - 5;
this.gravity = 0.2;
particleIndex++;
particles[particleIndex] = this;
this.id = particleIndex;
this.test = 0;
this.maxLife = 100;
}
Particle.prototype.draw = function(){
this.x += this.vx;
this.y += this.vy;
this.vy += this.gravity;
this.test++;
if ( this.test >= this.maxLife ) {
delete particles[this.id];
};
var img = new Image();
img.src = 'img/aaa.png';
var pattern = ctx.createPattern(img,'repeat');
ctx.fillStyle = pattern;
ctx.fillRect(this.x, this.y, 20, 20);
};
setInterval(function(){
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < particleNum; i++) {
new Particle();
};
for(var i in particles) {
particles[i].draw();
}
},30)
}})();
I was trying to do this also with ctx.drawImage(), but picture was displayed one time only.
Any tips?:)
Fiddle
I think the issue is the image being loaded later than its used.
Inside your draw() you have:
var img = new Image();
img.src = 'img/aaa.png';
var pattern = ctx.createPattern(img,20,20);
It is a bad idea to create new images everytime you want to draw. I strongly suggest you create the img variable outside of the draw loop. Once you set the .src of an image, you have to wait until it is loaded to use it. There is an onload event you can use to let you know when its ready.
Here is an example:
var imgLoaded = false;
var img = new Image();
img.src = 'img/aaa.png';
img.onload = function() { imgLoaded = true; };
function draw() {
...
if (imgLoaded) {
var pattern = ctx.createPattern(img, 'repeat');
...
}
...
}

Categories

Resources