Stopwatch cocos2d-x (Android & iOS) - android

I'm currently facing a problem.
I create a games where user can race within a level, and there's stopwatch to count the time user finished the level.
I use this code snippet for convert the counter to stopwatch
void update(float dt)
{
if (!paused)
{
fcheckbutton+=dt;
ftimer+=dt;
if (ftimer >= 0.01f)
{
this->timer();
ftimer = 0.0f;
}
}
}
void timer()
{
m_timer++;
int milliseconds = m_timer%60;
int seconds = (m_timer/60)%60;
int minutes = m_timer/3600;
CCString * P1Time = CCString::createWithFormat("%02d:%02d:%02d", minutes,seconds,milliseconds);
m_label->setString(P1Time->getCString());
}
I called this function in my update method...
The problem is in every device (iOS and Android) the stopwatch produce various result...
In my test case, if user doesn't make any input, he should be lost in about 32 secs....
iOS (iPhone 4) is the closest one, with stopwatch ~32 secs
But in Android device, The result is vary..
Google Nexus S 28 seccs
new Google Nexus 7 18 secs
Galaxy Note 30 secs
It's important that stopwatch must be sync in every device, because i have a leaderboard based on user's stopwatch result.
How do I supposed to do this?
EDIT: update to call timer method

Where do you update your m_timer variable? I think the problem is that some device has lower FPS.

Related

Android NDK Sensor strange report interval to event queue

I try to access the accelerometer from the NDK. So far it works. But the way events are written to the eventqueue seems a little bit strange.
See the following code:
ASensorManager* AcquireASensorManagerInstance(void) {
typedef ASensorManager *(*PF_GETINSTANCEFORPACKAGE)(const char *name);
void* androidHandle = dlopen("libandroid.so", RTLD_NOW);
PF_GETINSTANCEFORPACKAGE getInstanceForPackageFunc = (PF_GETINSTANCEFORPACKAGE) dlsym(androidHandle, "ASensorManager_getInstanceForPackage");
if (getInstanceForPackageFunc) {
return getInstanceForPackageFunc(kPackageName);
}
typedef ASensorManager *(*PF_GETINSTANCE)();
PF_GETINSTANCE getInstanceFunc = (PF_GETINSTANCE) dlsym(androidHandle, "ASensorManager_getInstance");
return getInstanceFunc();
}
void init() {
sensorManager = AcquireASensorManagerInstance();
accelerometer = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_ACCELEROMETER);
looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
accelerometerEventQueue = ASensorManager_createEventQueue(sensorManager, looper, LOOPER_ID_USER, NULL, NULL);
auto status = ASensorEventQueue_enableSensor(accelerometerEventQueue,
accelerometer);
status = ASensorEventQueue_setEventRate(accelerometerEventQueue,
accelerometer,
SENSOR_REFRESH_PERIOD_US);
}
That's how I initialize everything. My SENSOR_REFRESH_PERIOD_US is 100.000 - so 10 refreshs per second. Now I have the following method to receive the events of the event queue.
vector<sensorEvent> update() {
ALooper_pollAll(0, NULL, NULL, NULL);
vector<sensorEvent> listEvents;
ASensorEvent event;
while (ASensorEventQueue_getEvents(accelerometerEventQueue, &event, 1) > 0) {
listEvents.push_back(sensorEvent{event.acceleration.x, event.acceleration.y, event.acceleration.z, (long long) event.timestamp});
}
return listEvents;
}
sensorEvent at this point is a custom struct which I use. This update method gets called via JNI from Android every 10 seconds from an IntentService (to make sure it runs even when the app itself is killed). Now I would expect to receive 100 values (10 per second * 10 seconds). In different tests I received around 130 which is also completly fine for me even it's a bit off. Then I read in the documentation of ASensorEventQueue_setEventRate that it's not forced to follow the given refresh period. So if I would get more than I wanted it would be totally fine.
But now the problem: Sometimes I receive like 13 values in 10 seconds and when I continue to call update 10 secods later I get the 130 values + the missing 117 of the run before. This happens completly random and sometimes it's not the next run but the fourth following or something like that.
I am completly fine with being off from the refresh period by having more values. But can anyone explain why it happens that there are so many values missing and they appear 10 seconds later in the next run? Or is there maybe a way to make sure I receive them in their desired run?
Your code is correct and as i see only one reason can be cause such behaviour. It is android system, for avoid drain battery, decreases frequency of accelerometer stream of events in some time after app go to background or device fall asleep.
You need to revise all axelerometer related logic and optimize according
Doze and App Standby
Also you can try to work with axelerometer in foreground service.

How do I work with the system clock / time in xamarin forms?

for a school project i'm making an app. The app is supposed to keep track of the time that you spend working on something specific. For example when i'm going to start my work shift, I would press a (start)button so the timer starts off and counts how much I've worked until i press a stop button.
I've got the xaml ready with all the buttons and labels.
My main problem is the timer. I would like to have a stopwatch underneath my start button, that shows the elapsed time. I've been looking for many many hours on github, stackoverflow, google and youtube and haven't found a solution.
If it isn't easy/possible to implement a stopwatch, i would at least need the app to check for the system time when the start and stop buttons are clicked, to calculate the difference in time.
So far I haven't been able to get any of those functions working.
Thanks in advance! - MagSky
.NET has a built in Stopwatch class you can use
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
// do some work here
stopWatch.Stop();
// Get the elapsed time as a TimeSpan value.
TimeSpan ts = stopWatch.Elapsed;
to display a Timer in the UI, use System.Timers.Timer instead
int secs = 0;
// fire an event every 1000 ms
Timer timer = new Timer(1000);
// when event fires, update Label
timer.Elapsed += (sender, e) => { secs++; myLabel.Text = $"{secs} seconds"; };
// start the timer
timer.Start();

Android Sensor Data Collection is not working properly

I developed a Data collector which collects data from Accelerometer, Gyroscope, Magnetometer and it worked fine for a while. Then I added Linear Acceleration to it as well (After 4 months, this week). Now both the version are behaving very strangely. Sometime they log the data perfectly when I do some physical activities like walking etc. However, sometimes it doesn't update sensors values and just repeat old values i.e each sensor value is updated lets after 5 seconds, 2 sec etc randomly and I need a sampling rate of 50 samples per second. I experimented with 10-15 participants and all my data was invalid because of this. The strange things is that the same app has worked perfectly before. I can't find any problem in it. I am placing some of the snapshots here. May be if someone can point to any bug or something ?
The buffered Writter:
FileWriter fow;
BufferedWriter bow;
extfile = new File(extfilepath, message + ".csv");
fow = new FileWriter(extfile);
bow = new BufferedWriter(fow);
This bow.writer is then being used in timertask thread to log data every 20 milliseconds.
Can anyone please comment or help me with this ? This weird behavior of this app is beyond my understanding.
Check that you have a wake lock acquired if your application goes to background. I've used PowerManager.PARTIAL_WAKE_LOCK successfully in a data collection application.
When your display turns off, your application is at least paused (and system might even stop it). The partial wake lock "Ensures that the CPU is running; the screen and keyboard backlight will be allowed to go off." So reading between the lines it means that otherwise your CPU might go to sleep for small periods of time in order to save power.
Did you forget to paste in:
else if (event.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION){} ?
Are you using the accelerometer data, then subtracting gravity?
OK. What's your code look like to call the timer?? Something like this?
Timer updateTimer = new Timer("linear accel");
updateTimer.scheduleAtFixedRate(new TimerTask() {
public void run() {
updateGUI();
}
}, 0, 100);
}
private void updateGUI() {
runOnUiThread(new Runnable() {
public void run() {} } ?

Why does SystemClock.currentThreadTimeMillis() appear to be run half rate?

I'm trying to write a music app capable of playing MIDI files in sync with user input. I've got as far as creating a custom view, playing sounds, and reading MIDI data. I run the playback of MIDI data in the view's onDraw() method so I can apply user input to it. The note data is stored as an array of note pitches and times to play measured in ms from the start.
My test data plays a note of a different pitch every 500 ms (half a second). I log the currentThreadTimeMillis() alongside the time interval for each note, and it is as I expect. Every 500 ticks with a small variation, a note is played. However, this count in ms is about half real-world speed, taking a second to count 500 ms! I am running on a Galaxy Ace so this isn't an issue of a slow emulator.
How come SystemClock.currentThreadTimeMillis() is taking a good two seconds to count 1000ms?
public void onDraw(Canvas canvas) {
// TODO : Draw notes
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(aNote.img, aNote.x, aNote.y, null);
if (ready>0){
elapsed_time = SystemClock.currentThreadTimeMillis() - start_time;
midi_note_data = MIDI.track_data.get(current_note);
if (midi_note_data.start_time <= elapsed_time){
current_note++;
pitch = midi_note_data.pitch;
Log.d("MUSIC", "Note time " + midi_note_data.start_time + " ThreadTime "+ elapsed_time);
sounds.play(tone, 1.0f, 1.0f, 0, 0, notes[pitch]);
}
if (current_note > MIDI.track_data.size()-1){
ready = -2;
}
}else if (ready == 0){
start_time = SystemClock.currentThreadTimeMillis();
Log.d("MUSIC", "Start time "+start_time);
ready = 1;
}
}
You are using SystemClock.currentThreadTimeMillis(), which is the amount of time that the current thread has been running for. On Android, I'm guessing the UI thread is only actually running half of the time. (the other half is for the rest of the operating system!)
Switch to System.currentTimeMillis() and your problems will be solved.
You can read more about the different time measuring systems here.

Sensor manager not working as expected after Android 2.3.6 update

Couple of days back, I made my first app on Android. The basic concept is to monitor the proximity sensor, if there is an obstacle at the sensor I will increment a counter. If the counter crosses the threshold I will trigger an action.
I have implemented the sensor monitoring SW in a service, this service is called from an Activity in every 10 Min so as awake the cpu and start the service if it is stopped.
Everything was perfect, got few thousands of downloads in market with good ratings. This was fine until Android 2.3.3. Recently my mobile got upgraded to Android 2.3.6 and unfortunately the app is not working as expected.
Sensor listener does not trigger when the screen is OFF. Some times it works fine, most of the times it is not working. After giving several inputs at the sensor, after a while if I switch ON the screen, automatically all the triggers at the sensor are called at once and the counter increments and triggers the action.
To summarize, sensor listener does not work when screen goes OFF (in Android 2.3.6), this was working fine until Android 2.3.3. If I connect the debugger, phone does not go to sleep and everything works fine so I am not able to find the problem. Please help me .
Here is my code .
Calling the service at every 10 min ..
Thread trd = new Thread(){
public void run(){
int sec = 1000;
int min = 60 * sec;
Calendar cal = Calendar.getInstance();
alarmMngr.setRepeating(AlarmManager.RTC_WAKEUP,
cal.getTimeInMillis(),
10 * min,
PendInt);
}
};
trd.start();
In the service ..
// On sensor change
public void onSensorChanged(SensorEvent event){
if(event.sensor == SnsrProx){
if(event.values[0] <= 5){
IncProxCntr(1);
}else{
IncProxCntr(0);
}
}
}
private void IncProxCntr(int x){
if( x == 1){
FakeCall_SnsrCnt++;
vibrate(VIBRATE_SHORT);
}
if(FakeCall_SnsrCnt >= Settings.getMaxSnsrCnts(this)){
Trig_IncominCall();
}
}
Acquire wakelock in the service also

Categories

Resources