I am trying to align bars which are synced to music (therefore moving) to a circle on a canvas. I already have the sync to music and make a round circle with it ready.
Right now I am trying to rotate them so it looks good, however since this is my first attempt with canvas I am failing miserably..
Here is the code Gist.
If i run it with the c.rotate(bar[i].rot); it gets all scrambled...
Please can you help me out with this.
Thank you very much.
First thing :
- Clear the whole canvas on each frame. It's too complicated, and performance-wise not worth the trouble to erase only what's required.
Second :
The Canvas's RenderingContext2D, is a context, meaning it's a state machine that will modify its state each time you perform a change on it.
This change might be a transform : translate, scale, rotate.
Or affect the rendering : globalAlpha, globalCompositeOperation, shadows.
Or be a strokeStyle/fillStyle/font change.
Any time you change the context's state, it is a very good practice to save it before, and restore it after :
context.save();
context.translate(.., ..);
context.beginPath();
context.move();
context.restore();
this way you end up with a context just as 'clean' after the call than before, no question asked.
For your code, you were quite close, for instance this code is quite ok (using random values) :
function animate() {
requestAnimationFrame(animate);
// clear whole screen
context.clearRect(0,0,600,600);
context.fillStyle = '#000';
// rotating step
var angle = 2*Math.PI/cnt ;
// save context
context.save();
context.translate(300,300);
for (var i=0; i<cnt; i++) {
context.rotate(angle);
var val = values[i];
context.fillRect(-10, 100, 20, 80*val );
values[i]+=(Math.random()-0.5)/20;
}
// restore now we're done.
context.restore();
}
you can try it here :
http://jsbin.com/haxeqaza/1/edit?js,output
do not hesitate to comment // animate() and to launch animate2() instead, with 2 nice little trick.
:-)
All transformations add up, unless you use the contexts .save() and .restore() methods. They save the current transformation and restore it afterwards, so transformations in beteeen will not affect the next draw.
But since you want to rotate each bar by a fixed amount, I suggest you do exactly that and set the rotation for each bar so a fixed amount instead of increasing it and let the rotations add up.
Related
I'm looking to have an algorithm that can randomly draw a "squiggly wiggly" pattern as per the picture.
It would be nice if it were progressively drawn as you would draw it with a pen and if it were based on speed, acceleration and forces like a double pendulum animation might be.
This would be for javascript in the p5 library.
Is there some way of producing this that a) looks hand drawn and b) fills a page, somewhat like a Hilbert curve?
Very interested to hear ideas of how this could be produced, regardless of whether there is some kind of formal algorithm, although a formal algorithm would be best.
Cheers
I can think of two solutions, but there could be more as I'm not very good at coding in general yet.
First of all, you can use perlin noise. With the code
var noiseSeeds = [];
//This changes the noise value over time
var noiseTime = 0;
var x = 0;
var y = 0;
function setup() {
createCanvas(400, 400);
//This will help for making two separate noise values later
noiseSeeds = [random(100), random(100)];
}
function draw() {
//Finding the x value
noiseSeed(noiseSeeds[0]);
x = noise(noiseTime)*400;
//Finding the y value
noiseSeed(noiseSeeds[1]);
y = noise(noiseTime)*400;
//Increasing the noise Time so the next value is slightly different
noiseTime += 0.01;
//Draw the point
stroke(0);
strokeWeight(10);
point(x, y);
}
You can create a scribble on screen. You would have to use createGraphics()in some way to make this more efficient. This method isn't the best because the values are generally closer to the center.
The second solution is to make a point that has two states - far away from an edge and close to an edge. While it is far away, the point would keep going in relatively the same direction with small velocity changes. However, the closer the point gets to the edges, the (exponentially) bigger the velocity changes so that the point curves away from the edge. I don't know exactly how you could implement this, but it could work.
So I'm using Three.js and I have some cubes inside of a box. I'm using the Transform Control to move the cubes around inside of the box with my mouse. I'd like to use raycasting in order to check for collisions. The question is how to I prevent the transform controller from moving the object if there is a collision? I'd like to stop it if it hits the wall. By the way, I'm on version r81 for Three.js.
UPDATE: I've used the size of the room to constrain the cubes from
moving outside of the room. This seems to work well. Is there a way
to use the cannon.js just for collisions? I don't want the momentum
or gravity or any other feature. JUST the collision check and to stop
it dead in its tracks when there is a collision.
I know this post is from a long time ago, but hopefully a googler finds this helpful. I wasn't able to stop the user from moving my object, but I was able to move it back to its proper position immediately afterward by adding some logic to the render method.
For the original poster's problem with collisions, you could attach an event listener to the transform controls and request the object to be repositioned if it is in an illegal state.
transformControls.addEventListener('objectChange', (e) => {
if (illegalPosition(this.obj.position)) {
needsReset = true;
}
lastPosition = attachedObject.position.clone();
});
and then in your render function
if (needsReset) {
attachedObject.position.set(lastPosition.x, lastPosition.y, lastPosition.z);
}
If this feels a little hacky, that's because it is. But for those of us who don't have the time or skill to read and modify TransformControls.js, I think it may prove helpful.
You could create helper raycaster and place all colliders in separate container. After movement is applied to object move raycaster to its position and test if ray intersects any of other objects in container. If yes: reset previous position for that object. In case of cube colliders you could want to raycast from cube center in multiple directions with half of side length as ray length.
Ben S does have the best and most painless way to implement collision detection with transform controls. Within a event listener.
But I don't know if the time of writing his answer he knew about or if there even was a function called "requestAnimationFrame". All you would have to do for collision detection instead of simply resetting the models position is to set up your render call within a loop (60 fps) by adding "requestAnimationFrame" to your render (I call it animate since that is more descriptive) function.
Since it is in a loop and is called when the every frame the scene is drawn it will just not allow the object to move past the point of collision.
function animate() {
// Called to draw onto screen every frame (60fps).
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
And your event listener would just look like this.
control.addEventListener('objectChange', (e) => {
// Collision detection code here. Set colliding model position here.
// No need to set it in render
});
Old post, I know. But here is a method that is still fairly simple but does not flicker or use ray casting. The biggest catch here is that you have a little bit of a bounce if you move the Transform control really quickly. But otherwise it seems to work fairly well. You can control the precision of the collision by adjusting the step value.
let transStart = null;
//capture objects position on start
control.addEventListener('mouseDown', function(){
transStart = control.object.position.clone();
})
//you'll have to provide your own collision function
control.addEventListener('objectChange', function(e){
if(collision(sphere, cube)){ stopControls() };
});
function stopControls(){
if(control.dragging && stopAt){
//calculate direction object was moving at time of collision
const s = transStart;
const e = control.object.position.clone();
const n = e.clone().sub(s).negate().normalize();
//janky hack nonsense that stops the transform control from
//continuing without making the camera controller go nuts.
control.pointerUp({button:0});
control.dragging = true;
//translate back the direction it came by the step amount and do not
//stop until the objects are no longer colliding.
//Increase the step size if you do not need super precise collision
//detection. It will save calculations.
let step = 0.00005;
while(colliding(sphere, cube)){
sphere.translateOnAxis( n, step ) ;
sphere.updateMatrix();
}
}
}
I'm think I'm having a similar issue as this in that I can not work out (or know if it exists) whereby I can get access to the scaling applied to a given object (in my instance, a raster).
I need to know this so I can animate the scaling via Tween.js.
Anyone have any ideas or know if indeed it is possible to find out the current scaling applied to a raster (or any) object?
I thought it was an issue with Rasters so I tried tweening the scale property of a Path and then a Group and I couldn't get access to the values in order to animate it.
Because I am using Tween.js I can not simply use the object.scale(value) function.
UPDATE
I even tried applying an arbitrary (animated) number to the scale function and it failed to work... i.e.:
object.scale( 0 );
object.arbitraryNumber = 0;
createjs.Tween.get( object )
.to( { arbitraryNumber:1 } , 1000, createjs.Ease.getPowInOut(2) )
.addEventListener( "change", function( event ) {
event.target.target.scale( event.target.target.arbitraryNumber);
} );
Although this did not work, when the same approach was applied to the x position of the object, it animated fine.
Is there anything that needs to be flagged in order to update scaling of an object?
When calling Item.scale() method on each frame with values from 0 to 1, you are actually scaling down item exponentially because each call scales the item relatively to the previous value.
What you want to do is animate the Item.scaling property instead.
You also have to know that by default, PaperJS use global coordinates system and apply every transformations directly to points.
You can change this behavior by setting Item.applyMatrix property to false.
Doing this, scale change will affect item matrix instead of affecting points coordinates and you will be able to animate it as you expect.
Here is simple Sketch of a scale animation:
var circle = new Path.Circle(view.center, 50);
circle.fillColor = 'orange';
circle.applyMatrix = false;
function onFrame(event)
{
circle.scaling = Math.sin(1 + event.count * 0.05);
}
You should be able to transpose this example to your Tween.js context easily.
For a university project I have been tasked with creating a Flappy Bird clone. It's being done using the HTML5 canvas.
The issue doesn't happen very often, but it seems that every 6 or so seconds, the grass will flicker. I'm not sure what's causing this, it could be a performance issue.
Here is a link so you may see the issue: http://canvas.pixcelstudios.uk
Here is the function I'm using to the draw the grass:
var drawGrass = function(cWidth, ctx, minusX)
{
var x = bg_grass.x;
var y = bg_grass.y;
var w = bg_grass.w;
var h = bg_grass.h;
var img = bg_grass.img;
if (minusX[0] >= cWidth)
{
bg_grass.x = 0;
minusX[0] = 0;
}
ctx.drawImage(img, x, y, w, h);
if (minusX[0] > 0)
{
ctx.drawImage(img, w-minusX[0], y, w, h);
}
};
Basically, I'm drawing two grass sprites, each taking up a canvas width. One starts with an X of 0 and the other starts at the end of the canvas. Both are decremented each frame, then one is completely off the screen, it's completely reset to keep it looping.
I don't think it's anything to do with my update loop which is as follows:
this.update = function()
{
clearScreen();
updateBackground();
updatePositions();
checkCollisions();
render();
requestAnimFrame(gameSpace.update);
};
I've done a little bit of reading and I've read about having a second canvas to act as a buffer. Apparently this can stop flickering and improve performance? But all of the examples I've seen show the parts being drawn into the canvas out of a loop and I can't really see how doing it within a game loop (moving parts and all) would increase performance rather than decrease it. Surely the same operations are being performed, except now you also have to draw the second canvas onto the first?
Please let me know if you need any more information (although you should be able to see the whole source from the web link).
Thanks!
Okay I found the issue! Was just a simple mistake in my drawGrass function.
Due to the ordering, there'd be just a single frame where I'd set my shorthand X variable to bg_grass.x and THEN set bg_grass.x to something else, therefore drawing the wrong value.
I've now set my shorthand variables after the first if-statement.
However, if anyone could provide any insight into the second part of the question regarding a buffer canvas, I'd still much appreciate that.
I'm making an HTML5 game engine, and I want my Camera object to have a zoom property. In the renderer, I thought that I could easily implement it, like this:
context.save();
context.scale(camera.zoom, camera.zoom);
draw();
context.restore();
There is a problem, though. When I first tested this, the camera seemed to zoom forever! I figured that context.save() and context.restore() probably aren't working as expected, and that the context's internal scaling factor is getting multiplied by camera's zoom ad infinitum.
This fixed the situation:
context.save();
context.scale(camera.zoom, camera.zoom);
draw();
context.scale(1/camera.zoom, camera.zoom);
context.restore();
This works now, but I'm afraid that this isn't the most elegant/fast solution. Also, I think it is possible that, because of the floating point calculation imprecision, the scaling factor always changes slightly. That is, 1/camera.zoom might not always produce the same results.
So, two questions:
Why wont the context.restore() set the scale of the context back to (1, 1)?
How can I manually manipulate the scaling of the context?
Edit:
It was pointed out that the number of context.save()'s and context.restore()'s might be different, but that is not the case.
Here is how I measured it:
renderer.context.save = (function()
{
var original = renderer.context.save;
return function()
{
renderer.saved ++;
original.call(renderer.context);
}
})();
renderer.context.restore = (function()
{
var original = renderer.context.restore;
return function()
{
renderer.saved --;
original.call(renderer.context);
}
})();
The renderer.saved value is 1 right before the context is restored one last time (after draw), and 0 after each rendering.
It seems like I have accidentally solved the problem. It works now.
The main suspect is this part of the code:
renderer.context.save();
//Erase everything.
renderer.context.globalAlpha = 1;
renderer.context.fillStyle = renderer.settings.fillStyle;
renderer.context.fillRect(0, 0, renderer.width, renderer.height);
//Zoom.
renderer.context.scale(camera.zoom, camera.zoom);
I believe that I used to zoom before actually saving the context, resulting in restoring having no effect on the zoom.