PixiJS Random Rotation & Declining Speed - javascript

I am trying to get a simple random "rotation" based on the angle property, and would like to achieve the following.
Random Rotation, say "rotate" to 500 degrees
Start with a high speed and when getting nearer to the "rotated" degrees, lower the "rotating" speed so that the stop is not instant.
I put a basic concept of what I am trying to achieve on this link:
https://www.pixiplayground.com/#/edit/yalRPEN~6tg3seIHq5hbI
In the animate function, if I put the let degrees = 2000; as a Math.Random value it screws up the animation as it seems that this animate function is called numerous times?
Also, I tried using the speed property which would start off with a high value and starts to get lower with "rotations", but it seems to do nothing? Also tried using animationSpeed since I am using the angle property to change degrees, but I see no speed difference.
Any feedback would be appreciated.
Thanks

One approach is to change the angle and not the speed. Something like this:
var angleStep = 40;
let rotateSpeed = Math.floor(Math.random() * 300)
function animate() {
bunny.angle += angleStep;
angleStep = angleStep - angleStep/rotateSpeed;
if ((angleStep.toFixed(1) <= 0.0)) {
console.log("stopped rotation")
bunny.angle = bunny.angle;
return bunny.angle;
} else {
requestAnimationFrame(animate);
}
}

Related

Rotate wheel and stop at specific point in EaselJs

I am new to EaselJs.
I am rotating a wheel with 9x numbers and 3 (0x), the total of 12 numbers. I am able to rotate the wheel by calling function, but I want to stop it on predefined specific point/number of the wheel.
var _oContainer;
this._init = function(iXPos,iYPos){
_oWheel = s_oSpriteLibrary.getSprite("wheel_circle");
_oContainer = new createjs.Container;
_oContainer.x = CANVAS_WIDTH - 200;
_oContainer.y = CANVAS_HEIGHT - 350;
s_oStage.addChild(_oContainer);
img = createBitmap(_oWheel);
img.regX = _oWheel.width / 2;
img.regY = _oWheel.height / 2;
_oContainer.addChild(img);
}
this.spin = function(b, a){
//var h = new createjs.Bitmap(s_oSpriteLibrary.getSprite('wheel_circle'));
createjs.Tween.get(_oContainer).to({
rotation: _oContainer.rotation + a
}, 2600, createjs.Ease.quartOut).call(function() {
_oContainer.rotation %= 360;
})
}
I am calling the spin function as this.spin(5, 1131.7511808994204); on every time button is clicked.
Right now it is spinning and stopping randomly on every button click. How can stop it on a specific number/position on the wheel?
What value should I give in rotation:?
There are a lot of factors in play to do something like this. I made a quick demo to show how I would do it:
Draw the wheel (at center) with segments. It is important to know how many segments you have so you can choose a place to "end"
Start spinning. Just increment the rotation each tick depending on how fast you want it to go.
When "stopping", you have to do math to determine where to land
To get a realistic "slow down", make sure the remaining rotation in the tween is enough so it doesn't speed up or slow down too rapidly
Here is the fiddle: https://jsfiddle.net/lannymcnie/ych1qt8u/1/
// Choose an end number. In this case, its just a number between 0 and the number of segments.
var num = Math.random() * segments | 0,
// How many degrees is one segment?
// In my demo I use radians for `angle`, so I have to convert to degrees
angleR = angle * 180/Math.PI,
// Take the current rotation, add 360 to it to take it a bit further
// Note that my demo rotates backwards, so I subtract instead of add.
adjusted = c.rotation - 360,
// Determine how many rotations the wheel has already gone since it might spin for a while
// Then add the new angle to it (num*angleR)
// Then add a half-segment to center it.
numRotations = Math.ceil(adjusted/360)*360 - num*angleR - angleR/2;
Then I just run a tween to the new position. You can play with the duration and ease to get something you like.
createjs.Tween.get(c)
.to({rotation:numRotations}, 3000, createjs.Ease.cubicOut);
Technically, I should change the duration depending on the actual remaining spin, since depending on the result, it might not be super smooth. This came close enough, so I left it as-is.
Hope that helps! Let me know if I can clarify anything further.

Movement slower when canvas is bigger

Using this code:
x = x + (canvas.height/250);
which happens every 1 millisecond should add an amount to x in proportion to the canvas size. x is then drawn so therefore x should move down the canvas at the same speed on different screen sizes (the canvas changes size according to the screen size). However the x moves down at different speeds on my ipod and my pc.
If you want to know the full source code and html file the html is here and the javascript file linked to it is here.
First, let's think about what this line does:
x += canvas.height / 250;
The speed of the object is canvas.height / 250. The distance is canvas.height. We can say that:
distance = speed * time
We already have distance and speed, so:
time = distance / speed = canvas.height / (canvas.height / 250) = 250 ms
So the object always reaches its destination in 2.5 seconds. In order to make that happen, you change the speed based on the screen size.
If you want the speed to be the same in all devices, it shouldn't depend on canvas.height.
The change in traversal time is due to a change in draw time.
If the device is, say, two times slower to draw, the increase
will get done two times less per second, and your object will be
in mid-screen in the slow device when it will have crossed screen in
the other.
To have consistent behavior you must handle your game time.
Then you just have to decide of your objects speed in pixels per milliseconds,
and use the classical equation :
pos = pos + speed * (time step)
the code looks like :
var x = 0;
var speed = canvas.width / 1000 ; // speed in pixels per milliseconds.
var lastTime = 0;
requestAnimationFrame(launchAnimate);
function animate() {
requestAnimationFrame(animate);
var now = Date.now();
var dt = now - lastTime ;
lastTime = now ;
// draw everything
draw();
// update everything with this frame time step.
update(dt);
}
function launchAnimate() {
lastTime = Date.now() ;
requestAnimationFrame(animate);
}
Edit : you can't draw faster than your screen, so on a 60Hz screen, you'll draw at best every 16.666 ms.
Don't be scared by RequestAnimationFrame, it just means : "when the screen is ready, draw the callback that i gave you.".
So you have to re-arm it every time to make your game live.
So for your game, it's time to organize a bit :
have an update function where you put all the code that updates all things.
have a draw function that draws everything.
do not draw in the update (remove the draw calls in moveTrees), and
do not update in the draw. SEPARATION OF CONCERNS, :-)
have each update depend on frame time (dt) for all that's related to time (position, speed, acceleration, forces).
function update( dt ) {
x = x + speed * dt ;
moveTrees(dt);
}
function draw () {
drawTrees();
drawHangGlider();
drawTrees();
}
You'll notice i changed the animate function to call draw and update, still you have a bit of work to re-organize things.
Edit 2 : RequestAnimationFrame is widely ok now :
http://caniuse.com/requestanimationframe
(Chrome for Android is ok).
Rq :
// to use rAF, call this function before your game launches
polyFillRAFNow();
// insert the function in your code.
function polyFillRAFNow() {
// requestAnimationFrame polyfill
var w = window;
var foundRequestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame || w.mozRequestAnimationFrame || w.oRequestAnimationFrame || function (cb) { setTimeout(cb, 1000 / 60); };
window.requestAnimationFrame = foundRequestAnimationFrame;
}
Rq2 : you might be interested in this article i wrote on the game loop http://gamealchemist.wordpress.com/2013/03/16/thoughts-on-the-javascript-game-loop/
So basically you want a relative absolute speed depending on the screen size, which would then appear to be the same on different displays. In order to do this you should use percentages, for example:
var pixels_in_1_percent = canvas.height/100;
x += pixels_in_1_percent
That will increase the speed by 1% of canvas height, if you want more speed then you have to multiply it
x += pixels_in_1_percent * <number_of_percent_to_increase>
Hope that helps.
You said in your question that you are calling the function every 1 millisecond. However, some browsers limit the speed of window.setInterval so if you made the function call once every 50 milliseconds it would be the same on all devices.
window.setInterval(function(){
/// call your function here e.g. add1toxfunction();
}, 50);

Maths and Easing For Javascript/Canvas Preload Animation

I'm building an image preload animation, that is a circle/pie that gets drawn. Each 'slice' is totalImages / imagesLoaded. So if there are four images and 2 have loaded, it should draw to 180 over time.
I'm using requestAnimFrame, which is working great, and I've got a deltaTime setup to restrict animation to time, however I'm having trouble getting my head around the maths. The closest I can get is that it animates and eases to near where it's supposed to be, but then the value increments become smaller and smaller. Essentially it will never reach the completed value. (90 degrees, if one image has loaded, as an example).
var totalImages = 4;
var imagesLoaded = 1;
var currentArc = 0;
function drawPie(){
var newArc = 360 / totalImages * this.imagesLoaded // Get the value in degrees that we should animate to
var percentage = (isNaN(currentArc / newArc) || !isFinite(currentArc / newArc)) || (currentArc / newArc) > 1 ? 1 : (currentArc / newArc); // Dividing these two numbers sometimes returned NaN or Infinity/-Infinity, so this is a fallback
var easeValue = easeInOutExpo(percentage, 0, newArc, 1);
//This animates continuously (Obviously), because it's just constantly adding to itself:
currentArc += easedValue * this.time.delta;
OR
//This never reaches the full amount, as increments get infinitely smaller
currentArc += (newArc - easedValue) * this.time.delta;
}
function easeInOutExpo(t, b, c, d){
return c*((t=t/d-1)*t*t + 1) + b;
}
I feel like I've got all the right elements and values. I'm just putting them together incorrectly.
Any and all help appreciated.
You've got the idea of easing. The reality is that at some point you cap the value.
If you're up for a little learning, you can brush up on Zeno's paradoxes (the appropriate one here being Achilles and the Tortoise) -- it's really short... The Dichotomy Paradox is the other side of the same coin.
Basically, you're only ever half-way there, regardless of where "here" or "there" may be, and thus you can never take a "final"-step.
And when dealing with fractions, such as with easing, that's very true. You can always get smaller.
So the solution is just to clamp it. Set a minimum amount that you can move in an update (2px or 1px, or 0.5px... or play around).
The alternative (which ends up being similar, but perhaps a bit jumpier), is to set a threshold distance. To say "As soon as it's within 4px of home, snap to the end", or switch to a linear model, rather than continuing the easing.

Create smooth rotation in given time interval (+- x%)

I have got a cube in my scene which I want to rotate at a specific start velocity and in a given time interval.
In addition, the cube's end angle should be the same as the start angle.
Therefore, I thought of allowing +- 5% deviation of the time interval.
Here is my current status: http://jsfiddle.net/5NWab/1/.
Don't wonder that is currently working. The problem occurs if I change the time interval, e.g. by '3000': http://jsfiddle.net/5NWab/2/.
The essential move() method of my cube:
Reel.prototype.move = function (delta) {
if (this.velocity < 0 && this.mesh.rotation.x == 0) {
return false;
}
// Create smooth end rotation
if (this.velocity < 0 && this.mesh.rotation.x != 0) {
this.mesh.rotation.x += Math.abs(delta * this.speedUp * 0.5 * this.timeSpan);
if (Math.abs(this.mesh.rotation.x - 2 * Math.PI) < 0.1) {
this.mesh.rotation.x = 0;
}
}
else {
this.mesh.rotation.x += delta * this.velocity;
this.time -= delta;
this.velocity = this.speedUp * this.time;
}
}
The problem is that I cannot think of a solution or method in order to accomplish my topic.
It would not be so complex if I the variable delta would be constant.
It should be around 60fps = 1000/60 because I'm using requestAnimationFrame().
I have also found this question which could help finding the solution.
I think the code should either
slow down the velocity before the actual end is reached.
That should be the case if the final angle is a little bit greater than the desired (start) angle.
or should speed up the rotation speed after the actual end is reached.
That should be the case if the final angle is a little bit smaller than the desired (start) angle.
But what is when the angle is a hemicycle away from the desired one (i.e. 180° or PI)?
In order to clarify my question, here are my knowns and unknowns:
Known:
Start velocity
Time interval
Start angle (usually 0)
I want the cube to have the same start angle/position at the end of the rotation.
Because the FPS count is not constant, I have to shorten or lengthen the time interval in order to get the cube into the desired position.
If you want the rotation to end at a particular angle at a particular time, then I would suggest that instead of continually decrementing the rotation as your current code (2012-09-27) does, set the target time and rotation when you initialise the animation and calculate the correct rotation for the time of the frame recalculation.
So if you were doing a sine-shaped speed curve (eases in and out, linearish in the middle, nice native functions to calculate it), then (pseudocode not using your variables):
//in init
var targetTime = now + animationTime;
// normalize the length of the sine curve
var timeFactor = pi/animationTime;
var startAngle = ...
var endAngle = ...
var angleChange = endAngle - startAngle;
// inside the animation, at some time t
var remainingT = targetTime - t;
if(remainingT <= 0) {
var angle = endAngle;
} else {
var angle = startAngle + cos(remainingT * timefactor) * angleChange;
}
[Edited to add startAngle into andle calculation]
Because the cos function is odd (i.e. symmetric about the origin), as t approaches targetTime, the remainingT approaches zero and we move backward from pi to 0 on the curve. The curve of the sin shape flattens toward zero (and pi) so it will ease out at the end (and in at the beginning. There is an explicit zeroing of the angle at or past the targetTime, so that any jitter in the framerate doesn't just push it into an endless loop.
Here's one possible method, although it's not quite as good as I'd like: http://jsfiddle.net/5NWab/8/
The idea is to decrease the speed gradually, as you were doing, based on the amount of time left, until you get to a point where the amount of distance that the cube has to rotate to reach it's starting rotation (0) becomes greater than or equal to the amount of rotation that can possibly be made given the current velocity and the current amount of time left. After that point, ignore the time left, and slow down the velocity in proportion to the amount of rotation left.
This works fairly well for certain timeSpans, but for others the ending slowdown animation takes a little long.

How can I make Raphael.js elements "wiggle" on the canvas?

I'm working on a project that uses SVG with Raphael.js. One component is a group of circles, each of which "wiggles" around randomly - that is, slowly moves along the x and y axes a small amount, and in random directions. Think of it like putting a marble on your palm and shaking your palm around slowly.
Is anyone aware of a Raphael.js plugin or code example that already accomplishes something like this? I'm not terribly particular about the effect - it just needs to be subtle/smooth and continuous.
If I need to create something on my own, do you have any suggestions for how I might go about it? My initial idea is along these lines:
Draw a circle on the canvas.
Start a loop that:
Randomly finds x and y coordinates within some circular boundary anchored on the circle's center point.
Animates the circle from its current location to those coordinates over a random time interval, using in/out easing to smooth the effect.
My concern is that this might look too mechanical - i.e., I assume it will look more like the circle is tracing a star pattern, or having a a seizure, or something like that. Ideally it would curve smoothly through the random points that it generates, but that seems far more complex.
If you can recommend any other code (preferably JavaScript) that I could adapt, that would be great too - e.g., a jQuery plugin or the like. I found one named jquery-wiggle, but that seems to only work along one axis.
Thanks in advance for any advice!
Something like the following could do it:
var paper = Raphael('canvas', 300, 300);
var circle_count = 40;
var wbound = 10; // how far an element can wiggle.
var circleholder = paper.set();
function rdm(from, to){
return Math.floor(Math.random() * (to - from + 1) + from);
}
// add a wiggle method to elements
Raphael.el.wiggle = function() {
var newcx = this.attrs.origCx + rdm(-wbound, wbound);
var newcy = this.attrs.origCy + rdm(-wbound, wbound);
this.animate({cx: newcx, cy: newcy}, 500, '<');
}
// draw our circles
// hackish: setting circle.attrs.origCx
for (var i=0;i<circle_count;i++) {
var cx = rdm(0, 280);
var cy = rdm(0, 280);
var rad = rdm(0, 15);
var circle = paper.circle(cx, cy, rad);
circle.attrs.origCx = cx;
circle.attrs.origCy = cy;
circleholder.push(circle);
}
// loop over all circles and wiggle
function wiggleall() {
for (var i=0;i<circleholder.length;i++) {
circleholder[i].wiggle();
}
}
// call wiggleAll every second
setInterval(function() {wiggleall()}, 1000);
http://jsfiddle.net/UDWW6/1/
Changing the easing, and delays between certain things happening should at least help in making things look a little more natural. Hope that helps.
You can accomplish a similar effect by extending Raphael's default easing formulas:
Raphael.easing_formulas["wiggle"] = function(n) { return Math.random() * 5 };
[shape].animate({transform:"T1,1"}, 500, "wiggle", function(e) {
this.transform("T0,0");
});
Easing functions take a ratio of time elapsed to total time and manipulate it. The returned value is applied to the properties being animated.
This easing function ignores n and returns a random value. You can create any wiggle you like by playing with the return formula.
A callback function is necessary if you want the shape to end up back where it began, since applying a transformation that does not move the shape does not produce an animation. You'll probably have to alter the transformation values.
Hope this is useful!
There is a very good set of easing effects available in Raphael.
Here's a random set of circles that are "given" bounce easing.
Dynamically add animation to objects
The full range of easing effects can be found here. You can play around with them and reference the latest documentation at the same time.
Putting calls in a loop is not the thing to do, though. Use callbacks, which are readily available.

Categories