Synchronizing TWEEN, CCapture, and THREE.js rendering code to all be on the same clock - frame

I'm using a library called CCapture to capture equally time-spaced frames. This code seems to be able to hook the clock and control it so that is slows down my rendering loop when it is capturing. My code uses clock.getDelta() to get the time and it uses this time to calculate the positions of moving transit vehicles. When CCapture controls the rendering rate, the vehicles are correctly positioned.
I recently started using the TWEEN library in my code.
function animate() {
renderer.setAnimationLoop( renderFrame );
}
function renderFrame() {
const delta = clock.getDelta()
timeSinceStart += delta;
repositionTransitVehicles(timeSinceStart);
renderer.render(scene, camera);
if (capturer) {
capturer.capture( renderer.domElement );
}
orbitControls.enabled = false;
TWEEN.update();
orbitControls.enabled = true;
orbitControls.update();
},
With the no-arguments version of TWEEN.update(), tweening works but always proceeds at real time, which is too fast when I'm using CCapture. If I use...
TWEEN.update(timeSinceStart)
...then tweening does not work at all.
Does anyone know the secret to making TWEEN.update() operate using the same clock as the rest of the model?

The timer that TWEEN uses is a millisecond timer, an thus the units of the time that need to be passed into TWEEN.update() need to be in units of milliseconds. The units of THREE.Clock() are seconds. So use...
TWEEN.update(timeSinceStart*1000)
Wherever you use TWEEN's .start() method to initiate your tweens, you will also need to pass in the argument timeSinceStart*1000 as well.

Related

How to change the current time in the progress control?

Is it possible to manualy set the current time position on the timeline? I need this because I have several separated videos which represent one video and are playing in different players.
For example, the actual current time is marked as white dot, the desired current time that I want to show as red dot.
Can I do this somehow without creating completely new custom controlbar?
Middleware could be part of the solution, which allows you to intercept and modify what's sent to / received from the playback tech (video element).
var myMiddleware = function(player) {
return {
currentTime: function(ct) {
// When the video el says the currentTime is 60s, report 160s
return ct + 100;
},
setCurrentTime: function(time) {
// When the user / progress bar wants to seek to 220s, actually seek to 120s
return time - 100;
}
};
};
videojs.use('*', myMiddleware);

Titanium geolocation distanceFilter property is not working as expected

Need a help here for geolocation API - even after using Titanium.Geolocation.distanceFilter = 10; 10 in meter callback function is getting triggered randomly without moving here and there. Any idea what is wrong here ?
function Geolocate() {
var self = this;
// The callback function we should call when location is finally determined
this.locationReceivedCallback = function () {};
// Check if location event is already triggered or not
this.isLocationEventRegister = false;
// The function that unregisters the location event
this.unregisterLocationEvent = function () {
this.isLocationEventRegister = false;
Ti.Geolocation.removeEventListener('location', self.locationReceivedCallback);
};
}
Geolocate.prototype.init = function () {
// Setting up some preference values
Titanium.Geolocation.distanceFilter = 10; //The minimum change of position (in meters) before a 'location' event is fired.
if (deviceDetect.isIos()) {
Titanium.Geolocation.accuracy = Titanium.Geolocation.ACCURACY_BEST; // Using this value on Android enables legacy mode operation, which is not recommended.
} else {
Titanium.Geolocation.accuracy = Titanium.Geolocation.ACCURACY_LOW; //Using this value on Android enables simple mode operation.
}
};
Geolocate.prototype.getCurrentPosition = function (callback) {
this.isLocationEventRegister = true;
this.locationReceivedCallback = callback;
Titanium.Geolocation.addEventListener("location", this.locationReceivedCallback);
};
Geolocate.prototype.locationServicesAreAvailable = function () {
if (Titanium.Geolocation.locationServicesEnabled) {
return true;
} else {
return false;
}
};
Geolocate.prototype.cancelLocationRequest = function () {
this.unregisterLocationEvent();
};
module.exports = Geolocate;
Actual scenario is whenever I clicked on get location its gives me current location. then i tried to drag it map or image view for nearest place. Suddenly my view go current location. This is happening because of call back ? How to get rid off this ?
It's not a problem to do with your code, it is simply GPS in-accuracy.
GPS accuracy is (almost) never better than 10 meters, meaning it can be 10 meters off. When it recalculates your position it can be 10 meters down the line, so even if you're perfectly still with perfect GPS accuracy, you still might have differences of about 10 meters.
That said, you probably don't have best GPS accuracy when sitting behind a computer in a building, you probably have closer to 30-45 meters accuracy. Meaning every recalculation can easily be 10 meters differently.
Your solution would actually be rate-limit on top of using this property. The property will make sure it will not trigger multiple times per second, and then you can, in your own code, rate limit what you do with it.

In React Native, how do you determine if an image is cached/prefetched?

I am caching a few images like:
Image.prefetch(`${remoteImageUrl}/100x100`)
Image.prefetch(`${remoteImageUrl}/800x800`)
Image.prefetch(`${remoteImageUrl}/1000x1000`)
While that is happening a component that wants to show the highest resolution version currently available may render.
if 1000 cached use 1000,
elseif 800 cached use 800,
elseif 100 cached use 100
How do I test "if 1000 is cached"?
I tried .complete this with no luck.
if (Image.prefetch(`${remoteImageUrl}/1000x1000`).complete) {}
How do you check the existence of a prefetched image in React Native?
It doesn't look like this is possible using the out of the box APIs.
First of all, Image.prefetch doesn't contain any other methods related to the prefetch cache.
Diving into the detail - on iOS, Image.prefetch calls the native RCTImageViewManager.prefetchImage method, which indirectly ends up loading the image and storing it in RCTImageCache. Since there are no bridged functions that access the image cache directly, you're somewhat out of luck.
However, you could work around it by wrapping your calls to Image.prefetch in a function that tracks which ones have completed:
// imagePrefetch.js
const prefetchedImages = {};
export function prefetchImage(url) {
return Image.prefetch(url)
.then(val => {
prefetchedImages[url] = true;
return val;
});
};
export function isPrefetched(url) {
return prefetchedImages[url] !== undefined;
}
Keep in mind that this is specifically a workaround for images you prefetch, not other images that happened to be cached from being loaded through other means.

Game loop on redux-saga

I'm playing with redux-saga to create a version of the snake game in react native, and I'm not sure how to go about the game loop implementation. So far I have a working version, but it feels clunky.. the snake moves at different speeds and the game is not very smooth.
Here is what I've got so far:
function *tickSaga() {
while (true) {
yield call(updateGameSaga)
const game = yield select(getGame)
if (game.crashed)
break
yield delay(1000)
}
}
The updateGameSaga basically gets the state from the store, process some logic (finds out if the snake next move will be a crash, move to an empty tile or move to a food tile and grow) and dispatches the corresponding action for it.
I'm slightly aware of things like requestAnimationFrame which I know I should be using, but I'm not sure how to make it work within the saga (maybe I don't need too do it in the saga, hence this question).
Any ideas on how to improve the smoothness of the game loop would be welcome.
UPDATE
I've included redux-saga-ticker, which internally uses setInterval (code here) to periodically send updates to the channel.
function *tickSaga() {
const channel = Ticker(1000); // game tick every 1000ms
while (true) {
yield take(channel);
yield call(updateGameSaga);
const game = yield select(getGame)
if (game.crashed)
break
}
}
It works better now and I like the channel aproach, but I still feel requestAnimationFrame is the way to go, although I'm not yet sure on how to implement it.
How about this.
let lastTime = 0;
function *tickSaga() {
while (true) {
var time = +new Date();
var delayTime = Math.max(0, 1000 - (time - lastTime));
lastTime = time + delayTime;
yield call(updateGameSaga)
const game = yield select(getGame)
if (game.crashed)
break
yield delay(delayTime)
}
}
If you need 60 fps, replace 1000 to 16 (1000/60).
For each tick you have a correction of the interval (time - lastTime) so the ticker interval should be uniform.

How to debounce a signal in QML?

I have a few properties that have change handlers that request a repaint of a canvas. This works fairly well, but I would like to debounce the signal because a user can only see a limited number of refreshes and some of the data items can change quite frequently. This causes far more refreshes than the user can see and reduces how responsive the UI is.
I have looked at debouncing the signal in javascript (there are examples on the web for how to do that) and tie it in to QML, but I haven't figured out how to get QML and javascript to work together in that way yet.
I would love to see something like the following:
function rateLimitedRefresh(){
// magic to limit to 30 frames per second
canvas.requestPaint()
}
onValueChanged: {
rateLimitedRefresh();
}
With the requestPaint method only being called on the canvas a maximum of 30 times per second.
I used a modification of Mertanian's answer. This modification enforces the frame rate limit at a per frame level as opposed to a per second level.
property var limitStartTime: new Date()
function rateLimitedRefresh(){
// magic to limit to 30 frames per second
var now = new Date();
if (now - limitStartTime >= 32) {
limitStartTime = now
canvas.requestPaint()
}
}
How about something like this:
property var limitStartTime: new Date()
property int refreshesThisSecond: 0
function rateLimitedRefresh(){
// magic to limit to 30 frames per second
if ((new Date()) - limitStartTime >= 33) {
limitStartTime = new Date(limitStartTime.getTime() + 33)
canvas.requestPaint()
}
}
onValueChanged: {
rateLimitedRefresh();
}