So far I have this:
a sprite sheet of w 5507px X H 2100px
the scenes are 550 x 700
and the png is named animation png or something
the image is on the background of the div, and it goes to the coordinates background position, but so far, the animation goes for a loop and I need it to stop, I've been trying some solutions but nothing...I will appreciate any idea, please check the code
<style>
#anim{
width:550px;
height:700px;
background-image:url(anim3.png);
}
</style>
<title>Untitled Document</title>
</head>
<body onload="init()">
<script>
var imageWidth=5500,
imageHeight=2100,
xpos=0,
ypos=0,
index=0,
numFrames= 30,
frameSize=550,
frameHeight=700,
div;
function init(){
div = document.getElementById('anim');
loop();
setInterval(loop, 1000 / 10);
}
function loop() {
//multiplying by -1 because we want to move the image to the left and up to reveal the area we want to see.
div.style.backgroundPosition = (-xpos)+"px "+(-ypos)+"px";
//each time around we add the frame size to our xpos, moving along the source image.
xpos += frameSize;
ypos +=frameHeight;
//increase the index so we know which frame of our animation we are currently on.
index += 1;
//if our index is higher than our total number of frames, we're at the end and better start over.
if (index == 30) {
div.style.backgroundPosition =(imageWidth)+"px"+(imageHeight)+"px";
//if we've gotten to the limit of our source image's width, we need to move down one row of frames.
} else if (xpos +frameSize > imageWidth){
xpos =0;
ypos += 700;
}
}
</script>
try this one, using clearInterval() to stop loop:
var result;
function init(){
div = document.getElementById('anim');
loop();
result = setInterval(loop, 1000 / 10);
}
function loop() {
//multiplying by -1 because we want to move the image to the left and up to reveal the area we want to see.
div.style.backgroundPosition = (-xpos)+"px "+(-ypos)+"px";
//each time around we add the frame size to our xpos, moving along the source image.
xpos += frameSize;
ypos +=frameHeight;
//increase the index so we know which frame of our animation we are currently on.
index += 1;
//if our index is higher than our total number of frames, we're at the end and better start over.
if (index == 30) {
div.style.backgroundPosition =(imageWidth)+"px"+(imageHeight)+"px";
//if we've gotten to the limit of our source image's width, we need to move down one row of frames.
clearInterval(result) ;
} else if (xpos +frameSize > imageWidth){
xpos =0;
ypos += 700;
}
}
Try this:
http://jsfiddle.net/BgSnL/3/
var div,
imageWidth = 427,
imageHeight = 140,
frameWidth = 61,
frameHeight = 70,
curFrame = { x: 0, y: 0 };
function init(){
div = document.getElementById('anim');
loop();
setInterval(loop, 1000 / 10);
}
function loop()
{
var xOffset = frameWidth * curFrame.x,
yOffset = frameHeight * curFrame.y;
div.style.backgroundPosition = -(xOffset) + "px " + -(yOffset) + "px";
// if we can, iterate to the next column
if ((xOffset + frameWidth) < imageWidth) {
curFrame.x += 1;
// else if we can, drop down a row
} else if ((yOffset + frameHeight) < imageHeight) {
curFrame.x = 0;
curFrame.y += 1;
// reset
} else {
curFrame.x = 0;
curFrame.y = 0;
}
}
init();
The current frame x/y offset is tracked via an object. Each iteration we want to do one of:
Move over to the next column
Reach the end of the row, drop down a row
Reach the end of the animation, restart
Related
I am trying to animate using a sprite sheet and use it in my website, however I am knew to animation and I am having some trouble fixing it, currently nothing shows up on my webpage when I use this. I am using a sprite sheet which is called Speech.png, is 18176 x 256 and each frame is 256x256. Here is my code so far.
<script language="javascript">
// screen size variables
var SCREEN_WIDTH = window.innerWidth,
SCREEN_HEIGHT = window.innerHeight;
var canvas = document.createElement('canvas');
var c = canvas.getContext('2d');
canvas.width = SCREEN_WIDTH;
canvas.height = SCREEN_HEIGHT;
var xpos=0,
ypos=0,
index=0,
numFrames = 70,
frameSize= 255;
// Add our drawing canvas
document.body.appendChild(canvas);
//load the image
image = new Image();
image.src = "Speech.png";
image.onload = function() {
//we're ready for the loop
setInterval(loop, 1000 / 30);
}
function loop() {
//clear the canvas!
c.clearRect(0,0, SCREEN_HEIGHT,SCREEN_WIDTH);
/*our big long list of arguments below equates to:
1: our image source
2 - 5: the rectangle in the source image of what we want to draw
6 - 9: the rectangle of our canvas that we are drawing into
the area of the source image we are drawing from will change each time loop() is called.
the rectangle of our canvas that we are drawing into however, will not.
tricky!
*/
c.drawImage(image,xpos,ypos,frameSize,frameSize,0,0,frameSize, frameSize);
//each time around we add the frame size to our xpos, moving along the source image
xpos += frameSize;
//increase the index so we know which frame of our animation we are currently on
index += 1;
//if our index is higher than our total number of frames, we're at the end and better start over
if (index >= numFrames) {
xpos = 0;
ypos = 0;
index = 0;
//if we've gotten to the limit of our source image's width, we need to move down one row of frames
} else if (xpos + frameSize > image.width){
xpos =0;
ypos += frameSize;
}
}
</script>
Here is My JS fiddle
I have a requirement like when user clicks on center circle, that should toggle outer circle and when user clicks on outer small circles that should change center circle value.
Here i am not getting how to Show/ hide part of Canvas when user clicks on center circle?
Any help on how to do this?
GenerateCanvas();
function GenerateCanvas() {
try {
var FlagCircleCenterCoordinates = new Array();
var FlagCircles = [];
var CenterX = document.getElementById('canvasFlag').width / 2;
var CenterY = document.getElementById('canvasFlag').height / 2;
var OuterTrackRadius = 98;
var InnerTrackRadius = 70;
var InnerCircleRadius = 20;
var FlagElement = document.getElementById("canvasFlag");
var ObjContext = FlagElement.getContext("2d");
// Outer track
ObjContext.fillStyle = "#FFF";
ObjContext.beginPath();
ObjContext.arc(CenterX, CenterY, OuterTrackRadius, 0, 2 * Math.PI);
ObjContext.strokeStyle = '#CCC';
ObjContext.stroke();
ObjContext.fill();
// Inner track
ObjContext.beginPath();
ObjContext.arc(CenterX, CenterY, InnerTrackRadius, 0, 2 * Math.PI);
ObjContext.strokeStyle = '#CCC';
ObjContext.stroke();
// Inner small circle
ObjContext.beginPath();
ObjContext.arc(CenterX, CenterY, InnerCircleRadius, 0, 2 * Math.PI);
ObjContext.strokeStyle = '#CCC';
ObjContext.stroke();
//Max 17...other wide need to change the Inner and Outer circle radius
var FlagImagesArray = [1, 2, 3,4,5];
if (FlagImagesArray.length > 0) {
var StepAngle = 2 * Math.PI / FlagImagesArray.length;
var FlagCircleRadius = (OuterTrackRadius - InnerTrackRadius) / 2;
var RadiusOfFlagCircleCenters = OuterTrackRadius - FlagCircleRadius;
for (var LoopCnt in FlagImagesArray) {
var CircleCenterCoordinates = new Object();
CircleCenterCoordinates.PostionX = CenterX + (Math.cos(StepAngle * (parseInt(LoopCnt) + 1)) * RadiusOfFlagCircleCenters);
CircleCenterCoordinates.PostionY = CenterY + (Math.sin(StepAngle * (parseInt(LoopCnt) + 1)) * RadiusOfFlagCircleCenters);
ObjContext.beginPath();
ObjContext.arc(CircleCenterCoordinates.PostionX, CircleCenterCoordinates.PostionY, FlagCircleRadius, 0, 2 * Math.PI);
ObjContext.strokeStyle = '#CCC';
ObjContext.stroke();
ObjContext.fillStyle = 'blue';
ObjContext.fillText(FlagImagesArray[LoopCnt], CircleCenterCoordinates.PostionX, CircleCenterCoordinates.PostionY);
FlagCircleCenterCoordinates[LoopCnt] = CircleCenterCoordinates;
var ObjFlagCircle = {
Left : CircleCenterCoordinates.PostionX - FlagCircleRadius,
Top : CircleCenterCoordinates.PostionY - FlagCircleRadius,
Right : CircleCenterCoordinates.PostionX + FlagCircleRadius,
Bottom : CircleCenterCoordinates.PostionY + FlagCircleRadius,
FlagName : FlagImagesArray[LoopCnt]
}
FlagCircles[LoopCnt] = ObjFlagCircle;
}
$('#canvasFlag').mousemove(function (Event) {
debugger;
$(this).css('cursor', 'auto');
var ClickedX = Event.pageX - $('#canvasFlag').offset().left;
var ClickedY = Event.pageY - $('#canvasFlag').offset().top;
for (var Count = 0; Count < FlagCircles.length; Count++) {
if (ClickedX < FlagCircles[Count].Right &&
ClickedX > FlagCircles[Count].Left &&
ClickedY > FlagCircles[Count].Top &&
ClickedY < FlagCircles[Count].Bottom) {
$(this).css('cursor', 'pointer');
break;
}
}
});
$('#canvasFlag').click(function (Event) {
debugger;
$(this).css('cursor', 'auto');
var ClickedX = Event.pageX - $('#canvasFlag').offset().left;
var ClickedY = Event.pageY - $('#canvasFlag').offset().top;
for (var Count = 0; Count < FlagCircles.length; Count++) {
if (ClickedX < FlagCircles[Count].Right &&
ClickedX > FlagCircles[Count].Left &&
ClickedY > FlagCircles[Count].Top &&
ClickedY < FlagCircles[Count].Bottom) {
ObjContext.fillStyle = "#FFF";
ObjContext.beginPath();
ObjContext.arc(CenterX, CenterY, InnerCircleRadius - 1, 0, Math.PI * 2);
ObjContext.closePath();
ObjContext.fill();
ObjContext.fillStyle = "blue";
ObjContext.fillText(FlagCircles[Count].FlagName, CenterX, CenterY);
break;
}
}
});
}
}
catch (E) {
alert(E);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<canvas id="canvasFlag" width="200" height="200">
Your browser does not support the canvas
</canvas>
Oh man. Ok so first off, you'll need to get rid of the try/catch statement, it isn't doing anything.
Next you'll need to make all those vars you have outside of the function body, we need to be able to access them from another function
It looks like you have all your click functionality done, and it's working too. That's good, just go ahead and move both of the lines that start with jquery outside of the generateCanvas function. They only need to run once, and we're going to need to call generate canvas again.
Fourth, make a variable to toggle the outer circle off and on somewhere, and only draw the outer ring in generateCanvas() when that variable is true. You should also set another Global variable that gets set to Count, right before you break, so that you can remember it when you regenerate the canvas.
Take all the code you have in your click function to draw the inner circle with the number, and put that inside of generate canvas. Make sure that code only calls if the variable you used to remember Count is set to something (ie you had already clicked an outer number)
Next, add a generateCanvas() call in your click function.Now your click function sets the variable you use to represent the center value, redraws the canvas, and returns. You'll need more logic in your mouse down function in order to figure out when you clicked the center, but based on the code you already have you can figure that out, your main problem is just that this was set up to run once, not multiple times. That makes the canvas a lot more like an image instead of an active drawing element
Don't forget to add FlagElement.width = FlagElement.width to clear the canvas! (or just draw a background over it)
How do I run a sprite animation when pressing the left or right arrow keys in JavaScript? Here's my code:
var avatarX = 0;
var avatarY = 240;
var avatarImage;
var counter = 1;
var XWIDTH = 0;
var WIDTH = 400;
var dx = 5;
var tt;
var gameCanvas;
var context;
var moving;
var animationCounter = 1;
window.addEventListener('keydown', KeyDown);
function setUpGame() { //This is the function that is called from the html document.
gameCanvas = document.getElementById("gameCanvas"); //Declare a new variable & assigns it the id of the CANVAS from the html document.
context=gameCanvas.getContext("2d");
context.font = "18px Iceland";
context.textBaseline = "top";
avatarImage = new Image(); //Declaring a new variable. This is so that we can store the image at a later date.
avatarImage.onload=function(){
// avatarImage is now fully loaded and ready to drawImage
context.drawImage(avatarImage, Math.random() * 100, avatarY);
// start the timer
tt = setInterval(function(){counTer()},1000);
setInterval(handleTick, 25);
}
avatarImage.addEventListener('load', startLoop, false);
avatarImage.src = "img/ships.png"; //Ditto from above.
}
function startLoop() {
console.log("Detecting whether moving to the right is: " + moving);
if(moving == 0) {
gameLoop();
}
}
function gameLoop() {
setTimeout(gameLoop, 100);
handleTick();
}
function KeyDown(evt) {
switch (evt.keyCode) {
case 39: /*Arrow to the right*/
if(avatarX + dx <WIDTH && avatarX + dx >XWIDTH) {
avatarX += dx;
moving = 0;
}
break;
case 37: /*Arrow to the left*/
if(avatarX - dx >XWIDTH) {
avatarX -= dx;
moving = 1;
}
break;
}
}
function counTer() {
if(counter == 60) {
clearInterval(tt);
} else {
counter++;
}
}
function handleTick() {
context.clearRect(0,0,gameCanvas.width,gameCanvas.height);
context.drawImage(avatarImage, 32*animationCounter, 0, 32,32, avatarX, avatarY, 64, 64);
context.fillText("Seconds: " + counter, 5, 5);
context.fillText("1 is Right, 2 is Left, 0 is idle: " + moving, 20, 20);
animationCounter++
if(animationCounter >1) {
animationCounter = 0;
}
}
There are many ways to implement animation. The one i use is pretty easy and looks something like this:
var player = {
x: 0,
y: 0,
width: 50,
height: 100,
sprite: {
column: 0,
row: 0,
height: 50,
width: 100
},
image: PlayerImage,
animation: {
active: true, //Determines if the animation is running or not.
counter: 0,
progress: 0,
sequence: []
}
}
//This functions fires when the left arrow is pressed.
var onLeft = function(){
player.animation.sequence = [{column: 0, row: 0, t: 12}, {column: 1, row: 0, t: 12}, {column: 2, row: 0, t: 12}];
player.animation.active = true;
}
//This functions fires when the right arrow is pressed.
var onRight = function(){
player.animation.sequence = [{column: 0, row: 1, t: 12}, {column: 1, row: 1, t: 12}, {column: 2, row: 1, t: 12}];
player.animation.active = true;
}
//This function fires when no arrow are pressed.
var standingStill = function(){
player.animation.active = false;
}
var handleTick = function(){
//Clear the canvas.
context.canvas.width = context.canvas.width;
//If the animation is active.
if(player.animation.active){
//If the counter >= tick in the sequence. If not, just keep on increasing the counter value.
if(player.animation.counter >= player.animation.sequence[player.animation.progress]){
player.animation.counter = 1;
if(player.animation.progress >= player.animation.sequence.length - 1){
player.animation.progress = 0;
}else{
player.animation.progress++;
}
var currentFrame = player.animation.sequence[player.animation.progress];
//Change player.sprite column and row.(new frame)
player.sprite.column = currentFrame.column;
player.sprite.row = currentFrame.row;
}else{
player.animation.counter++;
}
}
context.drawImage(player.image, player.sprite.column * player.sprite.width, player.sprite.row * player.sprite.height, player.sprite.width, player.sprite.height, player.x, player.y, player.width, player.height)
}
The sequence is an array that contains objects that look like that: {column: 0, row: 0, t: 12} Every object is a frame. The column value is the current x of the sprite, the row is the y of the sprite. The script automatically creates the x and the y value, so all you need to add is value like 0, 1, 3, 5, and so on.(Just which frame it is on either x or y axis.) So for example, if the column is 0 and the row is 0, this is the frame that is in the top-left corner(the first frame). The t value stands for tick, this determines how many ticks there has to happend before the animation goes to the next frame.
Player.sprite also has properties width and height, that's the width and the height of the frame, it is often the same value as the width and height of the player object.
You have to make your own player.animation.sequence in onLeft and onRight function so it animates how you want it to animate.
I hope you understood what i meant. This might seem complicated, but it really isn't and if you don't get it now, don't worry, you'll get it eventually. If you really have difficulties with understanding, just ask.
Edit: First of all i highly recommend using objects to store information about entities. It makes game making much easier and cleaner. Just look at the player object, it's much easier to get the x simply by writing player.x than PlayerX. It looks more professional too. :) And when you have to give a lot of information about your entity you don't have to pass many arguments, you pass the whole object. Example:
//Entity properties stored in separate variable.
function animate(EntityX, EntityY, EntitySpriteX, EntitySpriteY, ...){
var x = EntityX;
//And so on...
}
//Entity stored in an object.
function animate(Entity){
var x = Entity.x;
//And so on...
}
Anyway, back to your question. First, we have to add variables that store information about our sprite.
var avatarSpriteColumn = 0; //Sprite frame on the x axis.
var avatarSpriteRow = 0; //Sprite frame on the y axis.
var avatarSpriteWidth = 50; //The width of a frame.
var avatarSpriteHeight = 100; //The height of a frame.
We also have to add variables that store the information about the animation.
var animationActive = false; //A variable that controls if the animation is 'running'.
var animationCounter = 0; //How many frames(ticks) have passed since the last frame(animation frame) has changed. (I'm not good at describing variables. :P)
var animationProgress = 0; //Current animation frame.
var animationSequence = []; //Array that stores the sequence of animation, as i explained.
Then, in your handleTick function you have to add a code that will animate the sprite. You have to add this code before you draw your entity.
//If the animation is active.
if(animationActive){
//If the counter >= tick in the sequence. If not, just keep on increasing the counter value.
if(animationCounter >= animationSequence[animationProgress]){
animationCounter = 1;
//Reset the progress, so that next time another animation frame shows up.
if(animationProgress >= animationSequence.length - 1){
animationProgress = 0;
}else{
animationProgress++;
}
//Select information about the current animation frame and store it in a variable so it is easier to access.
var currentFrame = animationSequence[animationProgress];
//Change player.sprite column and row.(new frame);
avatarSpriteColumn = currentFrame.column;
avatarSpriteRow = currentFrame.row;
}else{
animationCounter.counter++;
}
}
Ok, now you have a code that animates the sprite, but how do we run it? Well, i see you have a variable called moving. It tells us in what direction the player is moving and if it is moving at all. It looks like you implemented it a little bit wrong. Right now your function that operates the keys looks like this:
function KeyDown(evt) {
switch (evt.keyCode) {
case 39: /*Arrow to the right*/
if(avatarX + dx <WIDTH && avatarX + dx >XWIDTH) {
avatarX += dx;
moving = 0;
}
break;
case 37: /*Arrow to the left*/
if(avatarX - dx >XWIDTH) {
avatarX -= dx;
moving = 1;
}
break;
}
}
The variable is supposed to return 1 if the entity is going to the right, 2 if it is going to the left and 0 if the entity is standing still, right? Right now it shows 0 when the entity is moving to the right and 1 when it is moving to the left. It also doesn't show us if the entity is idle. We have to fix it. Change it to something like this:
function KeyDown(evt) {
switch (evt.keyCode) {
case 39: /*Arrow to the right*/
if(avatarX + dx <WIDTH && avatarX + dx >XWIDTH) {
avatarX += dx;
moving = 1;
}
break;
case 37: /*Arrow to the left*/
if(avatarX - dx >XWIDTH) {
avatarX -= dx;
moving = 2;
}
break;
default:
moving = 0;
}
}
Ok, now we have to add this code to the handleTick function. This code starts the animation and changes the sequence.:
if(moving == 1){ //Moving in the right direction.
animationSequence = []; //Animation of moving in the right direction. Change the sequence to your own.
animationActive = true; //Run the animation.
}else if(moving == 2){ //Moving to the left.
animationSequence = []; //Animation of moving to the left. Change the sequence to your own.
animationActive = true; //Run the animation.
}else{
animationActive = false; //Stops the animation, but the last frame stays.
/*
Alternatively, if you want a separate frame or animation that is animating when the entity is standing, you run this code.
animationSequence = []; // Your sequence. If you want a single frame, with no animation just add one frame to the sequence.
animationActive = true;
*/
}
Now, the last thing we have to do is to draw the entity. In your case, this will look something like this:
context.drawImage(avatarImage, avatarSpriteColumn * avatarSpriteWidth, avatarSpriteRow * avatarSpriteHeight, avatarWidth, avatarHeight, avatarX, avatarY, 64, 64);
In the end your whole code will look something like this:
var avatarX = 0;
var avatarY = 240;
var avatarImage;
var counter = 1;
var XWIDTH = 0;
var WIDTH = 400;
var dx = 5;
var tt;
var gameCanvas;
var context;
var moving;
var animationCounter = 1;
var avatarSpriteColumn = 0; //Sprite frame on the x axis.
var avatarSpriteRow = 0; //Sprite frame on the y axis.
var avatarSpriteWidth = 50; //The width of a frame.
var avatarSpriteHeight = 100; //The height of a frame.
var animationActive = false; //A variable that controls if the animation is 'running'.
var animationCounter = 0; //How many frames(ticks) have passed since the last frame(animation frame) has changed. (I'm not good at describing variables. :P)
var animationProgress = 0; //Current animation frame.
var animationSequence = []; //Array that stores the sequence of animation, as i explained.
window.addEventListener('keydown', KeyDown);
function setUpGame() { //This is the function that is called from the html document.
gameCanvas = document.getElementById("gameCanvas"); //Declare a new variable & assigns it the id of the CANVAS from the html document.
context=gameCanvas.getContext("2d");
context.font = "18px Iceland";
context.textBaseline = "top";
avatarImage = new Image(); //Declaring a new variable. This is so that we can store the image at a later date.
avatarImage.onload=function(){
// avatarImage is now fully loaded and ready to drawImage
context.drawImage(avatarImage, Math.random() * 100, avatarY);
// start the timer
tt = setInterval(function(){counTer()},1000);
setInterval(handleTick, 25);
}
avatarImage.addEventListener('load', startLoop, false);
avatarImage.src = "img/ships.png"; //Ditto from above.
}
function startLoop() {
console.log("Detecting whether moving to the right is: " + moving);
if(moving == 0) {
gameLoop();
}
}
function gameLoop() {
setTimeout(gameLoop, 100);
handleTick();
}
function KeyDown(evt) {
switch (evt.keyCode) {
case 39: /*Arrow to the right*/
if(avatarX + dx <WIDTH && avatarX + dx >XWIDTH) {
avatarX += dx;
moving = 1;
}
break;
case 37: /*Arrow to the left*/
if(avatarX - dx >XWIDTH) {
avatarX -= dx;
moving = 2;
}
break;
default:
moving = 0;
}
}
function counTer() {
if(counter == 60) {
clearInterval(tt);
} else {
counter++;
}
}
function handleTick() {
context.clearRect(0,0,gameCanvas.width,gameCanvas.height);
if(moving == 1){ //Moving in the right direction.
animationSequence = []; //Animation of moving in the right direction. Change the sequence to your own.
animationActive = true; //Run the animation.
}else if(moving == 2){ //Moving to the left.
animationSequence = []; //Animation of moving to the left. Change the sequence to your own.
animationActive = true; //Run the animation.
}else{
animationActive = false; //Stops the animation, but the last frame stays.
/*
Alternatively, if you want a separate frame or animation that is animating when the entity is standing, you run this code.
animationSequence = []; // Your sequence. If you want a single frame, with no animation just add one frame to the sequence.
animationActive = true;
*/
}
//If the animation is active.
if(animationActive){
//If the counter >= tick in the sequence. If not, just keep on increasing the counter value.
if(animationCounter >= animationSequence[animationProgress]){
animationCounter = 1;
//Reset the progress, so that next time another animation frame shows up.
if(animationProgress >= animationSequence.length - 1){
animationProgress = 0;
}else{
animationProgress++;
}
//Select information about the current animation frame and store it in a variable so it is easier to access.
var currentFrame = animationSequence[animationProgress];
//Change player.sprite column and row.(new frame);
avatarSpriteColumn = currentFrame.column;
avatarSpriteRow = currentFrame.row;
}else{
animationCounter.counter++;
}
}
context.drawImage(avatarImage, avatarSpriteColumn * avatarSpriteWidth, avatarSpriteRow * avatarSpriteHeight, avatarWidth, avatarHeight, avatarX, avatarY, 64, 64);
context.fillText("Seconds: " + counter, 5, 5);
context.fillText("1 is Right, 2 is Left, 0 is idle: " + moving, 20, 20);
}
The only thing you have to do right now is to make your own animationSequences and check if it works, let me know if you have any problems with that.
Of course, the code i am using is more complicated and has more "abilities" and is easier to use(the code behind is more complicated), but hopefully this will help you.
I must also apoligize for making this thing seem so complicated, when it's not. I am bad at explaining.
I am attempting to use particlesDepthBlur() in place of the opacity for the "snowflakes" - which is located inside the step function, however it produces an undesired strobe effect - why? Consider the following code,
Edited for clarification:
<canvas id="canvas"></canvas>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var num = 2000;
var canvas = document.getElementById("canvas");
var width = canvas.width = 960;
var height = canvas.height = 500;
var ctx = canvas.getContext("2d");
var particles = d3.range(num).map(function(i) {
return [Math.round(width*Math.random()), Math.round(height*Math.random())];
});
function particlesDepthBlur(){
return Math.random();
console.log(Math.random());
}
function particlesDepthSize(){
return Math.floor((Math.random()*4)+1);
}
d3.timer(step);
function step() {
ctx.shadowBlur=0;
ctx.shadowColor="";
ctx.fillStyle = "rgba(0,0,0,"+particlesDepthBlur()+")";
ctx.fillRect(0,0,width,height);
ctx.shadowBlur=particlesDepthSize();
ctx.shadowColor="white";
ctx.fillStyle = "rgba(255,255,255,1)";
particles.forEach(function(p) {
p[0] += Math.round(2*Math.random()-1);
p[1] += Math.round(2*Math.random()-1) + 2;
if (p[0] < 0) p[0] = width;
if (p[0] > width) p[0] = 0;
if (p[1] < 0) p[1] = height;
if (p[1] > height) p[1] = 0;
drawPoint(p);
});
};
function drawPoint(p) {
ctx.fillRect(p[0],p[1],1,1);
};
</script>
<style>
html, body { margin: 0; padding: 0; }
</style>
Couple things:
Firstly you are calling ctx.fillStyle = "rgba(0,0,0,"+particlesDepthBlur()+")"; immediately before filling the background of the canvas.
Second, you are only calculating the blur and opacity once per frame, not per particle.
Thirdly, if you calculate it per particle (and continue to use Math.random()) then it bogs down my machine with several thousand operations per second.
Here is my
fiddle!
~Every frame I calculate 10 opacities and 10 sizes and iterate across the particles setting them per particle.~ << This was an
old version; now the opacities are all set up before step() is called, and the sizes are proportional to opacities.
edit: good job with the random falling-downward motion!
edit2: tweaking to set constant opacity and size per particle. this still runs very slowly for me, probably because you are running Math.random() 4000 times per frame. You might consider calculating a couple dozen positional vectors once per frame, and iterate across all your particles. This way every n snowflakes would be falling in the same pattern, at the benefit of much less computation needed.
Finally, perhaps consider making the 'close' snowflakes (big and bright) fall faster than the 'far' snowflakes.
<snip>
// Set up an opacity value for each particle, this will later be indexed with j
var particleOpacities = [];
particles.forEach(function(p){
particleOpacities.push(particlesDepthBlur());
});
d3.timer(step);
var j = 0;
// since j is used by both step and drawPoint, it has to be outside both functions
function step() {
ctx.shadowBlur=0;
ctx.shadowColor="";
ctx.fillStyle = "rgba(0,0,0,1)";
ctx.fillRect(0,0,width,height);
j = 0;
particles.forEach(function(p) {
p[0] += Math.round(2*Math.random()-1);
p[1] += Math.round(2*Math.random()-1) + 2;
if (p[0] < 0) p[0] = width;
if (p[0] > width) p[0] = 0;
if (p[1] < 0) p[1] = height;
if (p[1] > height) p[1] = 0;
drawPoint(p);
});
};
function drawPoint(p) {
j++; // iterate over points
var particleSize = particleOpacities[j] * 4;
ctx.shadowBlur=particleSize;
ctx.shadowColor="white";
ctx.fillStyle = "rgba(255,255,255," + particleOpacities[j] + ")";
ctx.fillRect(p[0],p[1],particleSize,particleSize);
};
The ctx.fillStyle = "rgba(0,0,0,"+particlesDepthBlur()+")"; randomly changes how much of the previous canvas is visible. It does so uniformly across the entire canvas. Sometimes if fills the screen completely with black wiping out the past views, other times it lets the last screen partially show. When it lets previous views be seen it can as much double the amount of white on the canvas, and when followed by a low opacity suddenly the quantity of white drops.
function particlesDepthBlur(){
return Math.random(0.5)+.5;
}
smooths this out
I have problem with this sprite animation.
sprite-sheet
The script don't change the correct animation, and the speed increases each time you click in the same direction.
<div id="coordinates">MOUSE XY</div>
<div id="map" style="width:960px; height:80px; background-color:black; ">
<div id="player"></div>
</div>
Javascript and Jquery
<style> #player{background-image:url('girl_60x60.png');
width:60px; height:60px; position:relative;
z-index:12; left:465px;}</style>
<script type="text/javascript">
// click event
$('#map').click(function(e) {
// take coordinates
var posX = e.pageX ;
var posY = e.pageY;
//print X e Y
$('#coordinates').html("X: " + posX + " Y: " + posY);
if (posX <= 480) { //Check the click relative to the center.
setInterval('ani_left()',100); //left animation
} else {
setInterval('ani_right()',100); //right animation
}
});
var frame = 1;
// Right animation
function ani_right() {
var left = 60 * frame; //next frame every 60px
var top = 0;
$('#player').css('backgroundPosition','-'+left+'px -'+top+'px');
frame++;
}
// left animation
function ani_left() {
var left = 60 * frame;
var top = 60; //second row of frames
$('#player').css('backgroundPosition','-'+left+'px -'+top+'px');
frame++;
}
</script>
You should stop the execution of previous setInterval with clearInterval(idInterval).
I reccomend you to use setInterval(funcName,100) and not setInterval('funcName()',100);
var idInt = -1; // add this
// click event
$('#map').click(function(e) {
if(idInt != -1)
clearInterval(idInt); // add this
/* .. CUT .. */
if (posX <= 480) { //Check the click relative to the center.
idInt = setInterval(ani_left,100); //left animation
} else {
idInt = setInterval(ani_right,100); //right animation
}
});
/* cut */
Fiddle here
You have to clear your old draw interval before you start a new one
var interval;
if (posX <= 480) { //Check the click relative to the center.
clearInterval(interval);
interval = 0;
interval = setInterval(ani_left,100); //left animation
} else {
clearInterval(interval);
interval = 0;
interval = setInterval(ani_right,100); //right animation
}