I want to draw image sprite using canvas.
The code not working. How to improve my code.
I have some Error.
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var Game = {
draw_image: function(img, sourceX, sourceY, sourceW, sourceH, destX, destY, destW, destH){
var img = new Image(); // Create new img element
img.src = 'images/background.png'; // Set source path
img.onload = function(){
canvas.width = 1000;
canvas.height = 500;
ctx.drawImage(img, sourceX, sourceY, sourceW, sourceH, destX, destY, destW, destH);
};
}
var BACKGROUND = {
image_top: { x: 5, y: 5, w: 1280, h: 480 , dx:0 ,dy:0 ,dw:500 ,dh:500 },
image_body: { x: 5, y: 495, w: 1280, h: 480 , dx:0 ,dy:150 ,dw:500 ,dh:350},
image_bottom: { x: 5, y: 985, w: 1280, h: 480 , dx:0 ,dy:300 ,dw:500 ,dh:200 }
};
for(var n = 0 ; n < BACKGROUND.length ; n++) {
draw_image(nameImage, BACKGROUND[n].x,BACKGROUND[n].y, BACKGROUND[n].w, BACKGROUND[n].h, BACKGROUND[n].dx, BACKGROUND[n].dy, BACKGROUND[n].dw, BACKGROUND[n].dh );
}
};
To create a sprite animation it's important to know how it works.
You need your spritesheet make with pixel precision ( 1 pixel can mess up your animation ).
Like here, the character is always in the same size area, make it simple when you make your sprites.
With this you can make an object for each sprite you have like :
function Sprite(_position, _numberFrame, _framesize, _image, _duration){
this.position = _position; //Array like { x : 0, y : 0 }
this.rendersize = _rendersize; //Array like { width : 50, height : 80 }
this.framesize = _framesize; //Array like { width : 50, height : 80 }
this.image = _image; //Image object
this.chrono = new Chrono(_duration); //Explanation below
}
For more animation precision you can add a chrono who will manage the time of your animation :
function Chrono(_duration){
this.currentTime = 0;
this.lastTime = 0;
this.timeElapse = 0;
this.duration = _duration;
}
Chrono.prototype.countTime = function(){
this.currentTime = Date.now();
if(this.lastTime != 0)
this.timeElapse += this.currentTime - this.lastTime;
this.lastTime = Date.now();
if(this.timeElpase >= this.duration && this.lastTime != 0){
this.timeElapse = 0;
return TRUE;
} else {
return FALSE;
}
}
Then the function to animate your sprite may like :
Sprite.prototype.render = function(){
if(this.position.x <= this.image.width && this.chrono.countTime()){
this.position.x += this.framesize.x;
} else {
this.position.x = 0;
}
ctx.drawImage(this.image,
this.position.x, this.position.y,
this.framesize.width, this.framesize.height,
this.rendersize.width, this.rendersize.height
);
}
I hope I was clear and helpful,
Cheers
PS: Comments for question or optimisation ideas
You have to many problems with this code to make this sprite animation works. I wouldn't go to point any of the problems with your code, but I highly recommend to read a little bit about functions and variable scope before try to write this kind of code.
Another simple (and best for newbies) solution can be to use a canvas framework as EaselJS, with this you can do something like this to animate an sprite:
var data = {
images: ["images/background.png"],
frames: {width:50, height:50},
animations: {run:[0,4], jump:[5,8,"run"]}
};
var animation = new createjs.BitmapAnimation(data);
animation.gotoAndPlay("run");
Related
how to perform the movement of third image diagonally till the intersection of the two images
var pic1;
var pic2;
var pic3;
let posX=0
let posY=0
const rightwall=350;
function preload(){
pic1=loadImage("5.png")
pic2=loadImage("iron.jpg")
pic3=loadImage("slagmetal.jpg")
}
function setup() {
createCanvas(600, 600);
}
function draw() {
background(220);
text(mouseX + "," + mouseY, 20, 20);
img1=image(pic1, 300, 0, 150, 200)
img2=image(pic2, posX, 50, 100, 100)
img3=image(pic3, 0, 400, 200, 150)
posX=constrain(posX+1,0,rightwall-50)
posY+=1;
}
how can i move the third image vertically upwards at the point where the wall is
Well you could apply something like this for the collision:
this is how you could do it in your case:
let images = [pic1, pic2, pic3 ... ]
for(let img of images){ // of is a bit weird but it basically just loops thru an array by itself and throws back the array item,
// so for(let i = 0; i < array.length; i ++)
// array[i] = "yes" // array of i equals yes (i think)
// or for(let someString of array)
// someString = "yes" // someString equals yes
if (x < img.x + img.width &&
x + w > img.x &&
y < img.y + img.height &&
y + h > img.y) {
// cool when collided stuff yeah! ...
}
} // this is slightly changed, but still from the mdn page (rect w rect collision)
// also:
// since img(pic1, pic2 ... ) is an object/class it has a .width and a .height variable, same with canvases ...
class p6Image{
constructor(){
this.width = "Yeah!"
this.height = "idk"
this.pixels = ["r ed", "g reen", "b lue", ":( (a lpha)"]
// and some other stuff like this.pixelDensity ...
}
}
function loadp6Image(path){
// path stuff & blob stuff & so on
return new p6Image()
}
let cat = loadp6Image("_catzzzzzzzz/cats/cat.png")
I've tried a few different ways that I have seen on here, but I can't quite get my image to move. Whenever I try adapting code for arrow key presses, it just seems to make my canvas shrink and my player model (spaceperson) disappear.
here is the "drawing board" I keep returning to, and what I have so far.
// Get the canvas and context
var canvas = document.getElementById("space");
var ctx = canvas.getContext("2d");
canvas.width = 1920;
canvas.height = 700;
// Create the image object
var spaceperson = new Image();
// Add onload event handler
spaceperson.onload = function () {
// Done loading, now we can use the image
ctx.drawImage(spaceperson, 280, 300);
};
// artwork by Harrison Marley (using make8bitart.com)
spaceperson.src = "http://i.imgur.com/Eh9Dpq2.png";`
I am quite new to javascript, and I am just trying to work out how I can move the specperson image using arrow keys. I was trying to make a class for space person to access their x,y values, but I can't seem to draw the image without using .onload
here a more complete example:
//just a utility
function image(url, callback){
var img = new Image();
if(typeof callback === "function"){
img.onload = function(){
//just to ensure that the callback is executed async
setTimeout(function(){ callback(img, url) }, 0)
}
}
img.src = url;
return img;
}
//a utility to keep a value constrained between a min and a max
function clamp(v, min, max){
return v > min? v < max? v: max: min;
}
//returns a function that can be called with a keyCode or one of the known aliases
//and returns true||false wether the button is down
var isKeyDown = (function(aliases){
for(var i=256, keyDown=Array(i); i--; )keyDown[i]=false;
var handler = function(e){
keyDown[e.keyCode] = e.type === "keydown";
e.preventDefault(); //scrolling; if you have to suppress it
};
addEventListener("keydown", handler, false);
addEventListener("keyup", handler, false);
return function(key){
return(true === keyDown[ key in aliases? aliases[ key ]: key ])
}
})({
//some aliases, to be extended
up: 38,
down: 40,
left: 37,
right: 39
});
// Get the canvas and context
var canvas = document.getElementById("space");
canvas.width = 1920;
canvas.height = 700;
var ctx = canvas.getContext("2d");
//the acutal image is just a little-part of what defines your figue
var spaceperson = {
image: image("//i.imgur.com/Eh9Dpq2.png", function(img){
spaceperson.width = img.naturalWidth;
spaceperson.height = img.naturalHeight;
//start the rendering by calling update
update();
}),
//position
x: 60, y: 310,
width: 0, height: 0,
speed: 200 // 200px/s
};
var lastCall = 0; //to calculate the (real) time between two update-calls
//the render-fucntion
function update(){
//taking account for (sometimes changing) framerates
var now = Date.now(), time = lastCall|0 && (now-lastCall)/1000;
lastCall = now;
requestAnimationFrame(update);
var sp = spaceperson,
speed = sp.speed;
//checking the pressed buttons and calculates the direction
//two opposite buttons cancel out each other, like left and right
var dx = (isKeyDown('right') - isKeyDown('left')) * time,
dy = (isKeyDown('down') - isKeyDown('up')) * time;
//fix the speed for diagonals
if(dx && dy) speed *= 0.7071067811865475; // * 1 / Math.sqrt(2)
if(dx) { //there is some movement on the x-axes
sp.x = clamp(
//calculate the new x-Position
//currentPos + direction * speed
sp.x + dx * sp.speed,
//restraining the result to the bounds of the map
0, canvas.width - sp.width
);
}
//same for y
if(dy) sp.y = clamp(sp.y + dy * sp.speed, 0, canvas.height - sp.height);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(sp.image, sp.x, sp.y);
}
Edit:
A quick question (I hope); if I was to later add other objects, would I check for collisions in update()?
This is still just a very basic example. The main purpose of the update()-function should be to work as the main event-loop.
To trigger all Events that have to happen each frame in the order they have to happen.
var lastCall = 0;
function update(){
//I always want a next frame
requestAnimationFrame(update);
//handle timing
var now = Date.now(),
//time since the last call in seconds
//cause usually it's easier for us to think in
//tems like 50px/s than 0.05px/ms or 0.8333px/frame
time = lastCall|0 && (now-lastCall) / 1000;
lastCall = now;
movePlayer(time);
moveEnemies(time);
moveBullets(time);
collisionDetection();
render();
}
function render(){
ctx.clear(0, 0, canvas.width, canvas.height);
drawBackground(ctx);
for(var i=0; i<enemies.length; ++i)
enemies[i].render(ctx);
player.render(ctx);
}
Not saying that you have to implement all these functions now, but to give you an idea of a possible structure.
Don't be scared to break big tasks (functions) up into subtasks.
And it might make sense to give each enemy a move()-function so you can implement different movement-patterns per enemy,
or you say that the pattern is (and will be) all the same for each enemy, parameterized at the best, then you can handle that in a loop.
Same thing for rendering, as I'm showing in the last part of code.
Here's some slightly modified code from a game I was noodling around with a while back. If you want to see more code, check out the complete JS on GitHub. The game is incomplete but you should gather some helpful clues as to how to move an image around the canvas.
var spaceperson = {
speed: 256,
other_stuff: ''
},
keysDown = [],
update,
main;
addEventListener("keydown", function (e) {
keysDown[e.keyCode] = true;
}, false);
update = function (modifier) {
if (38 in keysDown && spaceperson.y > 0) { // UP
spaceperson.y -= spaceperson.speed * modifier;
}
if (40 in keysDown && spaceperson.y < CANVAS_HEIGHT - SPACEPERSON_HEIGHT) { // DOWN
spaceperson.y += spaceperson.speed * modifier;
}
if (37 in keysDown && spaceperson.x > 0) { // LEFT
spaceperson.x -= spaceperson.speed * modifier;
}
if (39 in keysDown && spaceperson.x < CANVAS_WIDTH - SPACEPERSON_WIDTH) { // RIGHT
spaceperson.x += spaceperson.speed * modifier;
}
}
I'm not sure but i think this can help.
// Get the canvas and context
var canvas = document.getElementById("space");
var ctx = canvas.getContext("2d");
canvas.width = 1920;
canvas.height = 700;
var x = 280;
var y = 300;
// Create the image object
var spaceperson = new Image();
spaceperson.addEventListener("keypress", press);
// Add onload event handler
spaceperson.onload = function () {
// Done loading, now we can use the image
ctx.drawImage(spaceperson, x, y);
};
function press(event) {
if(event.keyCode == 37) {//LEFT
x = x - 1;
} else if(event.keyCode == 38) {//UP
y = y - 1;
} else if(event.keyCode ==39) {//RIGHT
x = x + 1;
} else if(event.keyCode == 40) {//DOWN
y = y + 1;
}
draw();
}
function draw(){
ctx.drawImage(spaceperson,x,y);
}
// artwork by Harrison Marley (using make8bitart.com)
spaceperson.src = "http://i.imgur.com/Eh9Dpq2.png";
I found a solution!
// Get the canvas and context
var canvas = document.getElementById("space");
var ctx = canvas.getContext("2d");
canvas.width = 1920;
canvas.height = 700;
var xPos = 60;
var yPos = 310;
// Create the image object
var spaceperson = new Image();
// Add onload event handler
spaceperson.onload = function () {
// Done loading, now we can use the image
ctx.drawImage(spaceperson, xPos, yPos);
};
function move(e){
if(e.keyCode==39){
xPos+=10;
}
if(e.keyCode==37){
xPos-=10;
}
if(e.keyCode==38){
yPos-=10;
}
if(e.keyCode==40){
yPos+=10;
}
canvas.width=canvas.width;
ctx.drawImage(spaceperson, xPos, yPos);
}
document.onkeydown = move;
// artwork by Harrison Marley
spaceperson.src = "http://i.imgur.com/Eh9Dpq2.png";
I'm trying to understand how to use PixiJS with the GSAP library TweeMax.
For that, I used to look some code into project using the two library, like this one :
http://www.shanemielke.com/archives/usopen-sessions/
But, I've some trouble to understand why I can't scale.
When I try to scale, my ball goes to the top left of my window [0, 0].
And When I specify scaleX and scaleY, there is nothing.
In the both cases, my animation continue without any mistake...
Here is my code
var renderer,
stage;
var init = function() {
// We create the canvas element
stage = new PIXI.Stage(0x202020);
renderer = new PIXI.CanvasRenderer(800, 600, null, false, true);
document.getElementById("loader").appendChild(renderer.view);
$(window).resize(onResize);
onResize();
requestAnimFrame(animate);
drawElements();
};
var onResize = function() {
renderer.resize(window.innerWidth, window.innerHeight);
}
var drawElements = function() {
var ball = new PIXI.Sprite.fromImage("./img/ball.png");
ball.position.x = (window.innerWidth / 2) - 5;
ball.position.y = -10;
ball.scaleX = ball.scaleY = 1;
stage.addChild(ball);
var t1 = new TimelineMax({onUpdate:animate, onUpdateScope:stage});
t1.to(ball, 1.5, {y: (window.innerHeight / 2), ease: Bounce.easeOut})
.to(ball, 2, {scaleX: 10})
.to(ball, 2, {alpha: 0});
}
var animate = function() {
requestAnimFrame(animate);
renderer.render(stage);
}
window.onload = function() {
init();
}
Cheers guys for help !
The scale property of a PIXI Sprite is a Point with x and y properties, so instead of:
ball.scaleX = ball.scaleY = 1;
You need to do:
ball.scale.x = ball.scale.y = 1;
When you tween the scale you need to pass TweenLite the scale object, instead of the sprite itself, like so:
tween.to(ball.scale, 2, {x: 10});
I made a simple "animation" with PhysicsJS, where I have this body:
balon = Physics.body('circle', {
x: 50,
y: random(20, 350),
vx: 0.45,
angle: random(0,360),
angularVelocity:-0.005,
radius: 60,
mass: 1,
fixed: true
});
balon.view = new Image();
balon.view.src = 'ballon.png';
All works good but I need to add a shadow for the "ball", this means that I need to use two images the "ballon.png" and the second image (the shadow) need to be fixed over the first image (don't rotate with the body).
Any idea hot to do this ?
Thank you in advance !
If you need one of the images to have a different behavior, you'll need to handle the rendering yourself.
You can add another rendering layer for shadows. If you store the shadow image inside body.shadow, then you can do something like this.
var shd = renderer.addLayer('shadows');
var bodies = [balon];
// draw the provided shadow view
shd.drawShadow = function( body, view ){
var pos = body.state.pos
,v = body.state.vel
,t = renderer._interpolateTime || 0
,x
,y
,aabb
,ctx = shd.ctx;
;
// interpolate positions
x = pos.x + v.x * t;
y = pos.y + + v.y * t;
ctx.save();
ctx.translate( x, y );
ctx.drawImage(view, -view.width/2, -view.height/2, view.width, view.height);
ctx.restore();
}
shd.render = function(){
var body;
for (var i = 0, l = bodies.length; i < l; i++){
body = bodies[ i ];
if ( body.shadow ){
shd.drawShadow( body, body.shadow );
}
}
};
I'm trying to calculate the width of a sprite using the image width, but the number always comes out as 0, why is that?
function SpriteSheet(image, numFramesX, numFramesY, totalFrames) {
this.image = image;
this.numFramesX = numFramesX;
this.numFramesY = numFramesY;
this.totalFrames = totalFrames;
this.spriteWidth = this.image.width / this.numFramesX;
this.spriteHeight = this.image.height / this.numFramesY;
}
image.onload = function() {
console.log('Image has been loaded');
}
image.src = 'dance.png';
spritesheet = new SpriteSheet(image, 8, 10, 80);
spritesheet.spriteWidth and spritesheet.spriteHeight always yields 0. I cornered the problem to 'this.image.width' since it works if I put in the width of the image manually.
this.spriteWidth = 880 / this.numFramesX;
instead of
this.spriteWidth = this.image.width / this.numFramesX;
It also works if I calculate it using the object in the console:
spritesheet.image.width / spritesheet.numFramesX
yields 110
jsfiddle
How about that?
window.onload = function () {
console.log('Image has been loaded');
image.src = 'dance.png';
spritesheet = new SpriteSheet(image, 8, 10, 80);
}