Related
I have a 3D Render of moving cubes, they are different colors, so it's like a rainbow. But I want to know if there is a way to make the squares pulse colors.
https://repl.it/#AlexanderLuna/R-A-I-N-B-O-W#index.html
colorMode(HSB, nums.x * nums.y, 1, 1) Is your answere.
Apply it in the update function and play around with the colors by altering 'nums.x * nums.y' values.
Use a timer or a simple tick (you can simply do tick++ in the update function) as a modifier until it reaches a certain iteration and then reset (or jump the value). You should get the desired effect.
Okey.. apparently I'm procrastinating and spent the last hour playing around with your Repl..
This might not be exactly what you're after, but maybe it'll help some..
class Cube {
constructor(x_, y_, z_, size_, offset_) {
this.x = x_;
this.y = y_;
this.z = z_;
this.size = size_;
this.offset = offset_;
this.angle = 0;
this.tick = 1; // starting point
this.hueSpeed = 2; // tick modifier
}
update(f) {
this.y = map(f(this.angle + this.offset), -1, 1, this.size / 2, height - this.size / 2);
this.angle += 0.05;
colorMode(HSB, this.tick, 1, 1);
/**
* The request is there to simply regulate the frequency of the tick a bit..
* Though we do need to cancel the previous request if hadn't yet fired
* Which I'm apparently to lazy to do atm
*/
window.requestAnimationFrame((e)=>{
this.tick += this.hueSpeed;
(this.tick > 150 || this.tick < 2) && (this.hueSpeed *= -1);
});
}
render() {
push();
stroke(0);
translate(this.x, this.y, this.z);
box(this.size);
pop();
}
}
This is the cube.js script file, the only one altered.
I've been looking up on this for hours and hours but I couldn't figure out how to fit it to my needs.
I'm trying to make it so that an animation is played at a specific X and Y location, after being triggered. (For example, an explosion animation plays after a tank is destroyed)
I have a function like this:
var explosion = new Image();
explosion.src = "https://i.imgur.com/gWjqlKe.png";
function animate(img, x, y, width, height, steps){
steps = Math.floor(steps);
context.clearRect(x, y, width, height);
context.drawImage(img, width * step, 0, width, height);
step += .3;
requestAnimationFrame(animate(img, x, y, width, height, steps));
}
And then when I needed to call it, I did:
animate(explosions, tank.x, tank.y, 100, 100, 10);
But nothing happens when I destroy a tank.
I based my code off of this tutorial: https://www.youtube.com/watch?v=yna816VY8rg
Any help would be appreciated! Thanks so much!
EDIT:
I'm trying out setInterval now, but it still doesn't work...
var explosion = new Image();
explosion.src = "https://i.imgur.com/gWjqlKe.png";
// Animation Functions
function animate(img, x, y, width, height, endframe){
var frame = 0;
frame = setInterval(animation(frame, img, x, y, width, height), 1000);
if (frame >= endframe){
clearInterval(frame)
}
}
function animation(frame, img, x, y, width, height){
ctx = gameArea.context;
ctx.drawImage(img, x * frame, y, width, height);
frame ++;
return frame;
EDIT 2:
I realized from my Reddit that I made a mistake in the requestAnimationFrame and setInterval, so I edited again but it still does not work:
function animate(img, x, y, width, height, endframe){
var frame = 0;
frame = setInterval(function() {
animation(frame, img, x, y, width, height);
}, 1000);
if (frame >= endframe){
clearInterval(frame)
}
}
function animation(frame, img, x, y, width, height){
ctx = gameArea.context;
ctx.drawImage(img, x * frame, y, width, height);
frame ++;
return frame;
}
function animate(img, x, y, width, height, steps){
steps = Math.floor(steps);
context.clearRect(x, y, width, height);
context.drawImage(img, width * step, 0, width, height);
step += .3;
requestAnimationFrame(animate(img, x, y, width, height, steps));
}
One main loop to rule them all.
Using event timers to start animation loops via requestAnimationFrame will cause you all sort of problems. requestAnimationFrame will fire for the next frame in the same order as the last frame. If your timeout gets in during the frame before any other frames it will be the first function to draw to the canvas, then the other frames will draw over the top.
As nnnnnnn pointed out in the comment use only one game loop and save yourself a lot of unneeded complexity in getting the order of renders correct.
requestAnimationFrame time argument
requestAnimationFrame provides a timer in as the first argument. This timer is the current frame time, not the actual time. This lets you compute times from the V sync (display refresh)
Example of timing and animation
To animate some FX for a set time record the start time, set a duration and animate to the time given in the frames argument.
The example shows a simple explode timer used in a main loop. You begin the timer when needed supplying the current frame time. While it is active you give it the current time, It updates its own relative time, and when done the active flag is set to false. You render your animation via its current time which will be from 0 to length
This is only one animation, you would use a stack of such time objects, adding to the stack for each timed animation.
const explode = {
start : null,
length : 1000,
current : 0,
active : false,
begin(time,length = this.length){
this.start = time;
this.length = length;
this.active = true;
this.current = 0;
},
getCurrent(time){
this.current = time - this.start;
this.active = this.current <= this.length;
return this.current;
}
}
var tankDead = false;
function mainLoop(time){ // time is supplied by requestAnimationFrame
if(tankDead ) {
tankDead = false;
explode.begin(time,2000); // two seconds
}
if(explode.active){
explode.getCurrent(time);
if(explode.active){
// explode.current is the time
// draw the animation at time explode.current
} else {
// explosion is complete
}
}
requestAnimationFrame(mainLoop);
}
requestAnimationFrame(mainLoop);
Timing animations via a tick.
Though I prefer the fixed frame rate method and just count down a tick timer
var tankDead = false;
var explodeTick = 0;
function mainLoop(time){ // time is supplied by requestAnimationFrame
if(tankDead ) {
tankDead = false;
explodeTick = 60 * 2; // two seconds
}
if(explodeTick > 0){
explodeTick -= 1;
// draw the animation at time explosion
}
requestAnimationFrame(mainLoop);
}
requestAnimationFrame(mainLoop);
Much simpler to manage, and nobody will notice if you drop a frame or two and it takes a fraction of a second longer.
I've done this sort of programming before but It was a long while back, and despite trying for a while now, I am unable to get this working. I've tried loads of other similar codes that I've found on the internet but they don't work exactly the way I want it to! I basically want a 155x55 canvas, with a 50x50 image moving across it, simple! Despite how simple it sounds... I'm struggling... I've tried adapting my previous code but that was for bouncing balls and it was a long time ago. I'll appreciate any help. Thanks!
var myCanvas = document.getElementById("myCanvas");
var ctx = myCanvas.getContext("2d");
var speed = 1;
a = new Image();
a.src = "http://www.animated-gifs.eu/category_cartoons/avatars-100x100-cartoons-spongebob/0038.gif";
function frameRate(fps) {
timer = window.setInterval( updateCanvas, 1000/fps );
}
function updateCanvas() {
ctx.fillRect(0,0, myCanvas.width, myCanvas.height);
draw();
}
function draw() {
/* Add code here to randomly add or subtract small values
* from x and y, and then draw a circle centered on (x,y).
*/
var x = 0 + speed;
var y = 20;
if (x > 150) {
x == 1;
}
ctx.beginPath();
ctx.drawImage(a,x,y,100,100);
}
/* Begin animation */
frameRate(25);
Fiddle Link:
https://jsfiddle.net/th6fcdr1/
The problem you have is that your variable x and y are always reset to 0 and 20. Your speed is 1 so your x is always 1.
Since you never update the x position and always reset it to 0. What you could do is to increase the variable speed by 1 at the end of the frame.
speed += 1
At first, you'll have:
x = 0 + 1
then
x = 0 + 2
... and so on.
Then you'll have to check for speed being above 150 and reset speed to 1.
Then I suggest renaming speed by posX which is more accurate. Also, instead of using setInterval you should be using requestAnimationFrame(). And instead of incrementing the posX by 1, you should be incrementing the posX by speed * elapsedTime to get a fluent move and stable speed move which doesn't depend on the framerate.
In the end, you'd have this:
posX += speed * elapsedTime
var x = posX
I want to create a game where I need a animation: First should drawed a rectangle after 5 seconds, the second rect after 5 seconds, the third after 5 too, the fourth after 5 too, the 6-10 rects after 4s, the 10-15 rects after 3s, the 15-20 rects after 2s and the 20-25 rects after 1 second. The rectangles came from above and should run with a speed called recty to the bottom. Maybe will this help:jsfiddle.
var x = canvasWidth / 100;
var y = canvasHeight / 100;
b = 5000;
function init() {
recty = canvasHeight / 100 * 20;
rectx = (Math.random() *(x * 50)) + (x / 5);
rectb = (Math.random() * (x * 40)) + x * 20;
return setInterval(main_loop, 10);
}
function draw() {
rectheight = canvasHeight / 100 * 10;
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
// draw triangles
ctx.beginPath();
ctx.moveTo(x * 90, y * 50);
ctx.lineTo(x * 99, y * 60);
ctx.lineTo(x * 99, y * 40);
ctx.closePath();
ctx.stroke();
}
function drawrect() {
// draw rect
ctx.beginPath();
fillStyle = "#000000";
ctx.rect(rectx, recty, rectb, rectheight);
ctx.fill();
}
function update() {
recty += 1;
if (recty > canvasHeight) {
recty = -rectheight;
rectx = (Math.random() *(x * 50)) + (x / 5);
rectb = (Math.random() *(x * 50)) + (x / 5);
b -=1000;
}
if (recty > canvasHeight) {
recty -= 1;
}
}
function main_loop() {
draw();
update();
collisiondetection();
drawrect();
}
init();
setInterval ( drawrect, b );
Modern browsers have a built-in timer: requestAnimationFrame.
A requestAnimationFrame loop will fire about every 16ms and will be given a very precise currentTime argument. You start the timing loop with: requestAnimationFrame(Timer);. The loop will execute only once for each requestAnimationFrame you issue, so you put a requestAnimationFrame inside the loop itself to keep it running.
Here's an example timing loop that calculates the elapsed time since the timing loop started:
// variable used to calculate elapsed time
var lastTime;
// start the first timing loop
requestAnimationFrame(Timer);
function Timer(time){
// request another timing loop
// Note: requestAnimationFrame fires only once,
// so you must request another loop inside
// each current loop
requestAnimationFrame(Timer);
// if this is the very first loop, initialize `lastTime`
if(!lastTime){lastTime=time;}
// calculate elapsed time since the last loop
var elapsedTime=time-lastTime;
}
To make your rectangles "time aware" you can create a javascript object for each rectangle that defines all that's need to draw that rectangle at the desired timing interval. Then use this javascript object to draw the rectangle at the desired position after the desired time interval.
Example of rectangle object properties
position of the rect: x,y
the time interval to wait before next updating the rect's position: interval
the distance to move the rect during an update: moveByX, moveByY
Here's example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var rects=[]
rects.push({x:10,y:10,moveByX:5,interval:500,nextMoveTime:0});
rects.push({x:10,y:50,moveByX:5,interval:1000,nextMoveTime:0});
rects.push({x:10,y:110,moveByX:5,interval:2000,nextMoveTime:0});
var isFirstLoop=true;
// start the timing loop
requestAnimationFrame(Timer);
function Timer(currentTime){
// request another timing loop
// Note: requestAnimationFrame fires only once,
// so you must request another loop inside
// each current loop
requestAnimationFrame(Timer);
if(isFirstLoop){
isFirstLoop=false;
for(var i=0;i<rects.length;i++){
rects[i].nextMoveTime=time+rects[i].interval;
}
}
ctx.clearRect(0,0,cw,ch);
for(var i=0;i<rects.length;i++){
drawRect(rects[i],currentTime);
}
}
function drawRect(r,time){
if(time>r.nextMoveTime){
r.x+=r.moveByX;
r.nextMoveTime=parseInt(time+r.interval);
}
ctx.strokeRect(r.x,r.y,110,15);
ctx.fillText('I move every '+r.interval+'ms',r.x+5,r.y+10);
}
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=300></canvas>
Have you though about css animation?
It can come really handy, and has a better performance than javascript.
You can use transitions on position, and even delay if you don't care about IE9 and before. If you do, you should initiate the animations with javascript by adding a class to each boxes, and that would make it cross-browser.
Bassic css mockup for this would look something like this:
.box{
width:90px;height:90px;background:red;position:absolute;
-webkit-animation: mymove 5s; /* Chrome, Safari, Opera */
animation: mymove 5s;
animation-delay: 2s;
-webkit-animation-delay: 2s; /* Chrome, Safari, Opera */
}
And then you can add rules for specific boxes, and overrule the basic box style.
.box-1{animation-delay:10s; -webkit-animation-delay: 2s;}
See jsfiddle: http://jsfiddle.net/eyqtg9wp/
I am drawing an arc which increases gradually and turns in to a circle.On completion of animation(arc turning in to a circle) i want to draw another circle with increased radius with the previous circle persisting and the second animation continuing.
Arc to circle fiddle
After the circle is drawn,it gets washed out which is something that I dont want and continue the second animation.
Some unnecessary animation appears after the completion.
What should I do?
MyCode:
setInterval(function(){
context.save();
context.clearRect(0,0,500,400);
context.beginPath();
increase_end_angle=increase_end_angle+11/500;
dynamic_end_angle=end_angle+increase_end_angle;
context.arc(x,y,radius,start_angle,dynamic_end_angle,false);
context.lineWidth=6;
context.lineCap = "round";
context.stroke();
context.restore();
if(dynamic_end_angle>3.5*Math.PI){ //condition for if circle completion
draw(radius+10);//draw from same origin and increasd radius
}
},66);
window.onload=draw(30);
UPDATE:when should i clear the interval to save some cpu cycles and why does the animation slows down on third circle ??
First of all, about the flicker: you are using setInterval and not clearing it for the next draw(). So there’s that.
But I’d use a completely different approach; just check the time elapsed since the start, and draw an appropriate number of circles using a loop.
var start = new Date().getTime();
var timePerCircle = 2;
var x = 190, y = 140;
function draw() {
requestAnimationFrame(draw);
g.clearRect(0, 0, canvas.width, canvas.height);
var t = (new Date().getTime() - start) / 1000;
var circles = t / timePerCircle;
var r = 30;
do {
g.beginPath();
g.arc(x, y, r, 0, Math.PI * 2 * Math.min(circles, 1));
g.stroke();
r += 10;
circles--;
} while(circles > 0);
}
draw();
This snippet from your code has some flaw.
if(dynamic_end_angle>3.5*Math.PI){ //condition for if circle completion
draw(radius+10);//draw from same origin and increased radius
}
The recursive call to draw() will continue to run after the first circle was drawn completely. This is why the performance will be slow down immediately. You need to somehow block it.
I did a simple fix, you can polish it if you like. FIDDLE DEMO
My fix is to remove context.clearRect(0, 0, 500, 400); and change the new circle drawing logic to:
if (dynamic_end_angle > 3.5 * Math.PI) { //condition for if circle completion
increase_end_angle = 0; // this will prevent the draw() from triggering multiple times.
draw(radius + 10); //draw from same origin.
}
In this stackoverflow thread, it mentions how to make it more smooth. You'd better use some drawing framework since the optimization needs a lot of work.
When should I clear the interval to save some cpu cycles?
Better yet not use an interval at all for a couple of reasons:
Intervals are unable to sync to monitor's VBLANK gap so you will get jerks from time to time.
If you use setInterval you risk stacking calls (not high risk in this case though).
A much better approach is as you probably already know to use requestAnimationFrame. It's less CPU hungry, is able to sync to monitor and uses less resources in general even less if current tab/window is not active.
Why does the animation slows down on third circle ??
Your drawing calls are accumulating which slows everything down (setInterval is not cleared).
Here is a different approach to this. It's a simplified way and uses differential painting.
ONLINE DEMO
The main draw function here takes two arguments, circle index and current angle for that circle. The circles radius are stored in an array:
...,
sa = 0, // start angle
ea = 359, // end angle
angle = sa, // current angle
oldAngle = sa, // old angle
steps = 2, // number of degrees per step
current = 0, // current circle index
circles = [70, 80, 90], // the circle radius
numOfCircles = circles.length, ...
The function stores the old angle and only draws a new segment between old angle and new angle with 0.5 added to compensate for glitches due to anti-alias, rounding errors etc.
function drawCircle(circle, angle) {
angle *= deg2rad; // here: convert to radians
/// draw arc from old angle to new angle
ctx.beginPath();
ctx.arc(0, 0, circles[circle], oldAngle, angle + 0.5);
ctx.stroke();
/// store angle as old angle for next round
oldAngle = angle;
}
The loop increases the angle, if above or equal to end angle it will reset the angle and increase the current circle counter. When current counter has reach last circle the loop ends:
function loop() {
angle += steps;
/// check angle and reset, move to next circle
if (angle >= ea - steps) {
current++;
angle = sa;
oldAngle = angle;
}
drawCircle(current, angle);
if (current < numOfCircles)
requestAnimationFrame(loop);
}