I have a video being used as a background of a mobile device to show a reactive animation for when the phone is rotated its works (sort of) but when the rotation requires it to loop from start to end or end to start it does not loop and I have no clue why as the value it's trying to be set as should work.
this is the function that subscribes to the gyroscope and updates the angle with some maths
this.gyroscope.watch(this.options)
.subscribe((orientation: GyroscopeOrientation) => {
// need delta time to correctly calculate angle per update
this.time.now = new Date().getTime();
this.time.delta = this.time.now - this.time.last;
if (this.videoLoaded) {
// convert radians/sec to degree/sec and times by deltaTime
const degree = 180 / Math.PI * orientation.z;
this.targetAngle -= (this.time.delta / 1000) * degree;
// lerp target angle no clipping applied
this.angle = (1 - .1) * this.angle + .1 * this.targetAngle;
// convert lerped angle into clipped 0-360
let displayAngle = this.angle % 360;
if (displayAngle < 0) { displayAngle = 360 + displayAngle; }
// convert angle to time of video round to tenths dec
this.frame = Math.round((displayAngle * this.axeVideo.duration / 360) * 10) / 10;
// set video time
this.axeVideo.currentTime = this.frame;
} else {
// clear angle as gyro spits out large values at first
this.angle = this.targetAngle = 0;
}
// update last time for deltaTime calc
this.time.last = this.time.now;
});
this is all correct maths and logically works however when testing the video is going to either edge and locking up no matter how many rotations the phone does and to "unlock" it i must rotate the phone back the same amount.
Screen Capture of issue recording is a little laggy but normally super smooth (hence why i use this solution).
It is the ion-range that has [(ngModel)] on it overriding the set time.
Related
I'm trying to create a realistic slot machine animation, where the "spin" (actually a looped translation) gradually slows to a stop at a specified slot image. With my current implementation, it does actually stop at the right image, but it does so by spinning past it, then reversing direction and finally landing at the correct spot.
displacement = initial_velocity*delta_time + 1/2*acceleration*delta_time^2
to derive
acceleration = (2*total_displacement - 2*initial_velocity*delta_time) / delta_time^2.
private getAnimationDisplacement(): number {
if(!this.spinInProgress) return 0
// Time
const totalDuration = this.machine.spinDuration // ms
const curTime = new Date()
const dt = curTime.getTime() - (this.lastFrameTime || this.spinInProgress.startTime).getTime() // ms
this.lastFrameTime = curTime
// Calculate total (final) displacement for current spin
const spinCount = 1
const spinOffset = spinCount * this.spinInProgress.slotFaces // number of faces
const faceOffset = this.spinInProgress.getFaceOffset().offset // pixels
const totalOffset = new FaceOffset(spinOffset + faceOffset) // pixels
const totalDisplacement = totalOffset.offset * this.getFaceHeight() // pixels
// Acceleration
const acceleration = (2*totalDisplacement - 2*INIT_VELOCITY * totalDuration) / Math.pow(totalDuration, 2) // pixels / ms^2
// Diplacement
this.displacement += this.velocity * dt
// Velocity
this.velocity += acceleration * dt
// Modulo by max displacement causes animation to loop
return this.displacement % this.maxDisplacement
}
I can't figure out how this standard equation of motion is somehow going the right direction, then reversing direction, to finally land at the correct spot. I'm trying to avoid the weird reverse animation. Any insights would be greatly appreciated.
Using three.js, I'm creating a game with cars that move in a specific direction, depending on their y-rotation. An example would be 90 degrees. I use object.translateZ() to move them forward but I've run into a problem.
I'm using physijs to simulate the cars. Cars that run into each other may change their y-rotation (because of the crash) and I want to find a way for the cars to slowly change their rotation back to the original rotation like they are turning to get back on the road. Without this my city is very chaotic.
Here's the code that I'm already using (this is just part of it):
var targetRotation = 90
var rotation = car.mesh.rotation.y * 180 / Math.PI //to convert to degrees
I want to find a way to slowly change the car's rotation so it's the same as the target rotation.
Any help is appreciated! (but some sort of function would be perfect)
I've done stuff like this before in other systems (2D, not Three.js), and essentially all you want to do is gradually increment the angle until you reach something close enough to the target angle. Usually this means the float is less than the turning speed you're incrementing by (so you don't "overshoot" the value).
The amount of the increment depends on how quickly you want them to turn.
You also want to check if it's better to increase the angle or decrease (do you turn clockwise or counterclockwise) depending on if you're closer to 360 or 0. This prevents the car from turning the "long way" around. You can find this out by seeing if the difference is greater/less than 180.
We can use the modulus operator to get the "real" angle between -360/360.
var currentAngle = car.mesh.rotation.y * 180 / Math.PI; //car's angle in degrees
var targetAngle = 90; //preferred angle *this time* ;)
var turningSpeed = 1; //one degree per update (wayyy to high for real stuff, usually)
currentAngle = currentAngle % 360; //get the 0-360 remainder
if ( Math.abs(targetAngle - currentAngle) >= turningSpeed) {
var addto = 0
if (targetAngle - currentAngle < 0) {
addto = 360
}
if ( targetAngle - currentAngle + addto <= 180 ) {
currentAngle += turningSpeed;
}
else {
currentAngle -= turningSpeed;
}
}
else { currentAngle = targetAngle; } //we're close enough to just set it
car.mesh.rotation.y = ( currentAngle * Math.PI ) / 180; // back to radians!
I'm trying to create a wheel of fortune type animation using jquery but for some reason the code that i am using always displays the wrong number!
here is the jsfiddle: http://jsfiddle.net/wf49mqaa/2/
click on the WHITE AREA in the wheel to see the animation and you will see a wrong number will be shown!
at the moment I only have 4 columns and 4 segments in my jquery code but in the future i am will pull the amount of segments from a database and I need this to work correctly at all times and display the correct number.
I tried everything from changing the segment = Math.ceil(((percent/100) * 4)), to segment = Math.ceil(((percent/100) * 4) -1), and also segment = Math.ceil(((percent/100) * 5)),
and it still display wrong number!
could someone please advise on this?
Thanks
Part of the Code you use I found in a Non-working demo from sitepoint., digging a bit deeper there are two different errors/ problems to solve the fortune-wheel behavior:
First: How to define the degree:
// existing code fragment (wrong)
var deg = 1500 + Math.round(Math.random() * 1500);
This would cause the wheel to stop at a totally random position, but that is not what you need. The wheel should always stop at the marker position, it should just turn around by a random number of segments.
// supposing you have a wheel with 4 segments (here the items array):
var deg = 0, /* basic degree */
spinbase = 1080, /* basic spinning of the wheel, here 3 times full turn */
items = [1,2,3,4];
// your spinning function...
spin: function () {
var min = 1,
max = 10,
rand = Math.floor(min + Math.random()*(max+1-min));
[...]
// like this you'll stop at the same position,
// but the wheel moved by a random number of segments
deg = deg + ( Math.round( 360 / items.length ) * rand) + spinbase;
[...]
}
Second: How to get the correct segment:
In short:
// where deg is the current degree, and items the array from above.
var segmentIndex = Math.ceil(
(deg - (360 * parseInt(deg / 360))) /
Math.round(360/items.length)
);
And when filling the algorithm..
// e.g. deg is (degree of each segment) * random (here 5) + 1080
// deg = 1530 (1080 + ( (360/4) * 5) )
// (1530 - (360 * parseInt( 1530 / 360))) / Math.round(360 / 4);
// (1530 - (360 * 4)) / 90;
// 90 / 90 = 1
// since we have 4 segments only and the random number is higher,
// the wheel did another full turn + 1 (from the starting number)
// so we get items[ 1 ] = (result: 2);
// due to the ceil/floor/round methods in calculation it can happen
// that you reach the extrem values segments.length or less than 0,
// to fix this:
var segmentIndex = Math.ceil(
(deg - (360 * parseInt(deg / 360))) /
Math.round(360/items.length)
);
if(target < 0 ) { target = segment.length - 1; }
if(target === segments.length ) { target = 0; }
alert( 'Winning: ' + items[target] );
Putting this together you'll get a working fortune-wheel. I allowed myself to create a new variant of the fortune wheel, which is able to handle different amounts of segments to make it easier to prove the algorithm.
this is my first question after having relied on this site for years!
Anyway, I'd like to accomplish something similar to this effect:
http://www.flashmonkey.co.uk/html5/wave-physics/
But on a circular path, instead of a horizon. Essentially, a floating circle/blob in the center of the screen that would react to mouse interaction. What I'm not looking for is gravity, or for the circle to bounce around the screen - only surface ripples.
If at all possible I'd like to apply a static texture to the shape, is this a possibility? I'm completely new to Canvas!
I've already tried replacing some code from the above example with circular code from the following link, to very limited success:
http://www.html5canvastutorials.com/tutorials/html5-canvas-circles/
If only it were that easy :)
Any ideas?
Thanks in advance!
I tried to figure out how wave simulation works using View Source and JavaScript console. It's working fine but threw some JS errors. Also, it seems physics update is entangled with rendering in the render() method.
Here is what I found about the code:
The mouseMove() method creates disturbances on the wave based on mouse position, creating a peak around the mouse. The target variable is the index of the particle that needs to be updated, it's calculated from mouse pos.
if (particle && mouseY > particle.y) {
var speed = mouseY - storeY;
particles[target - 2].vy = speed / 6;
particles[target - 1].vy = speed / 5;
particles[target].vy = speed / 3;
particles[target + 1].vy = speed / 5;
particles[target + 2].vy = speed / 6;
storeY = mouseY;
}
Then, the particles around target are updated. The problem I found is that it does no bounds checking, i.e. it can potentially particles[-1] when target == 0. If that happens, an exception is thrown, the method call ends, but the code does not stop.
The render() method first updates the particle positions, then renders the wave.
Here is its physics code:
for (var u = particles.length - 1; u >= 0; --u) {
var fExtensionY = 0;
var fForceY = 0;
if (u > 0) {
fExtensionY = particles[u - 1].y - particles[u].y - springs[u - 1].iLengthY;
fForceY += -fK * fExtensionY;
}
if (u < particles.length - 1) {
fExtensionY = particles[u].y - particles[u + 1].y - springs[u].iLengthY;
fForceY += fK * fExtensionY;
}
fExtensionY = particles[u].y - particles[u].origY;
fForceY += fK / 15 * fExtensionY;
particles[u].ay = -fForceY / particles[u].mass;
particles[u].vy += particles[u].ay;
particles[u].ypos += particles[u].vy;
particles[u].vy /= 1.04;
}
Basically, it's Hooke's Law for a chain of particles linked by springs between them. For each particle u, it adds the attraction to the previous and next particles (the if statements check if they are available), to the variable fForceY. I don't fully understand the purpose of the springs array.
In the last four lines, it calculates the acceleration (force / mass), updates the velocity (add acceleration), then position (add velocity), and finally, reduce velocity by 1.04 (friction).
After the physics update, the code renders the wave:
context.clearRect(0, 0, stageWidth, stageHeight);
context.fillStyle = color;
context.beginPath();
for (u = 0; u < particles.length; u++) {
...
}
...
context.closePath();
context.fill();
I'm not explaining that, you need to read a canvas tutorial to understand it.
Here are some ideas to get started, note that I didn't test these code.
To modify the code to draw a circular wave, we need introduce a polar coordinate system, where the particle's x-position is the angle in the circle and y-position the distance from center. We should use theta and r here but it requires a large amount of refactoring. We will talk about transforming later.
mouseMove(): Compute particle index from mouse position on screen to polar coordinates, and make sure the disturbance wrap around:
Define the function (outside mouseMove(), we need this again later)
function wrapAround(i, a) { return (i + a.length) % a.length; }
Then change
particles[target - 2] --> particles[wrapAround(target - 2, particles)]
particles[target - 1] --> particles[wrapAround(target - 1, particles)]
...
The modulo operator does the job but I added particles.length so I don't modulo a negative number.
render(): Make sure the force calculation wrap around, so we need to wrapAround function again. We can strip away the two if statements:
fExtensionY = particles[wrapAround(u - 1, particles)].y - particles[u].y - springs[wrapAround(u - 1, springs)].iLengthY;
fForceY += -fK * fExtensionY;
fExtensionY = particles[u].y - particles[wrapAround(u + 1, particles)].y - springs[warpAround(u, springs)].iLengthY;
fForceY += fK * fExtensionY;
Here is the result so far in jsfiddle: Notice the wave propagate from the other side. http://jsfiddle.net/DM68M/
After that's done, the hardest part is rendering them on a circle. To do that, we need coordinate transform functions that treat particle's (x, y) as (angle in the circle, distance from center), and we also need inverse transforms for mouse interaction in mouseMove().
function particleCoordsToScreenCoords(particleX, particleY) {
return [ radiusFactor * particleY * Math.cos(particleX / angleFactor),
radiusFactor * particleY * Math.sin(particleX / angleFactor) ];
}
function screenCoordsToParticleCoords(screenX, screenY) {
// something involving Math.atan2 and Math.sqrt
}
Where the ...Factor variables needed to be determined separately. The angleFactor is two pi over the highest x-position found among particles array
Then, in the coordinates supplied to the context.lineTo, context.arc, use the particleCoordsToScreenCoords to transform the coordinates.
I've seen this kinda structure inside the update function in HTML5, Canvas games, with a "modifier" variable:
function update(modifier) {
obj.x += obj.speed * modifier
obj.y += obj.speed * modifier
}
function main() {
var thisLoop = new Date
var delta = thisLoop - lastLoop
update(delta / 1000)
render()
var lastLoop = new Date
}
var lastLoop = new Date
setInterval(main, 1)
Now I use myself this structure:
function update() {
obj.x += obj.speed
obj.y += obj.speed
render()
window.requestAnimationFrame(update)
}
What is the "modifier" supposed to do in the first structure?
And which one of them is the best to use, or is there maybe structure with both "modifier" and "requestAnimationFrame" too?
If you need your animation to be locked to time then you need a way to compensate for for example variable frame rates which of course then also have variable time between each frame.
A modifier could (as it's not shown how it is calculated) be used to fine-tune the speed/movement by compensating for this variation.
A couple of things though: don't use such as short time interval (1) as this could have an overall negative effect - you won't be able to update anything faster than the frame rate anyways so use nothing less than 16 ms.
Try to use requestAnimationFrame (rAF) instead as this is the only mechanism able to actually synchronize to the monitor update. rAF also passes a high-resolution timestamp which you can use for the compensator.
For example:
At 60 FPS you would expect a frame to last about 16.67ms.
So a modifier could be set as:
modifier = timeElapsed / 16.67;
If frame was able to run on time the value would be 1 in theory.
modifier = 16.67 / 16.67 = 1;
Now, if a frame iteration for some reason took more time, for example the double, you would get 2 as value for modifier.
modifier = 33.34 / 16.67 = 2;
How does this manifest in practical terms?
If you needed to move 100 pixels per frame then in the first situation when we were on time:
modifier = 16.67 / 16.67 = 1;
vx = 100 * modifier = 100; // # 1 frame = 100 pixels / frame
In the second case we spent two frames which means we needed it to move 200 pixels but since we didn't get that frame in between we need to use the modifier to compensate:
modifier = 33.34 / 16.67 = 2;
vx = 100 * modifier = 200; // # 2 frames = 100 pixels / frame
So here you see even if the frame rate was variant we moved what we expected to move anyways.
To calculate time elapsed simply use the rAF argument:
var oldTime = 0 // old time
frameTime = 1000 / 60; // frame time, based on 60 FPS, in ms
function loop(time) {
var timeElapsed = time - oldTime; // get difference
oldTime = time; // store current time as old time
var modifier = timeElapsed / frameTime; // get modifier based on FPS
...
requestAnimationFrame(loop);
}
Now, all that being said - modifier could also be just a value used to control speed... :-)
The newer version of requestAnimationFrame will return an elapsed time since the animation began.
You can use this elapsed time to determine where your animated objects should be redrawn.
For example, assume you have a ball object with an x property indicating it's x-coordinate.
If you want the ball to move 10 pixels right every 1000ms you can do this (untested!):
// set the starting x-coordinate of the ball
var ballStartingX=50;
ball.x=ballStartingX;
// get the time when the animation is started
var startingTime = performance.now();
// start the animation
requestAnimationFrame(update);
// update() is the animation loop function
function update(timestamp){
// request another frame
requestAnimationFrame(update);
// reposition the ball
// (timestamp-startTime) is the milliseconds elapsed
ball.x = ballStartingX + 10 * (timestamp-startTime)/1000;
}