Improve Frame rate on too many UI Images - Unity UI - android

In my single page, there were so many textures those I require to render before I was just facing problem in just screen opening but this I was able to resolve this suggestion:
OnBecomeVisible for Canvas UI Objects
Here is the actual code that I used for this purpose:
public void OnValueChangeRefreshCards (Vector2 valueChange)
{
elapsedYDist += valueChange.y;
if (elapsedYDist > 3f) {
elapsedYDist = 0f;
for (int i = 0; i < GameConstants.TOTAL_ROSE_COUNT; i++) {
Card card = roseList [i].GetComponent<Card> ();
if (RendererExtensions.IsVisibleFrom (card.MyRectTransform, Camera.main))
card.roseImage.enabled = true;
else
card.roseImage.enabled = false;
}
}
}
But now I started too much framerate lose related issue so even scrolling of page become really difficult for me.
Please check the attached video for more clearance about the issue, I was facing.
NameThatRose - Low Frame Rate
Please give me some suggestions for next improvements.
EDIT: Here are my profiler output.
Detailed Deep Profiler
Overview Deep Profiler

You can try few things to find out whats causing the low fps.
Use profiler to deep profile to find out which UI call is taking more time. Like what I did here.
As Image inherits from UIMaskableGraphics, it calls MaskableGraphics.OnEnable() every frame for every image in your list. This takes up time which you can see here:
I believe your OnValueChanged method is called every frame this would only multiply the enable/disable iterations and its processing time. You can limit the call by some time, processing 4 times a second for example.
float timeSinceLastUpdate = 0;
void Update()
{
timeSinceLastUpdate += Time.deltaTime;
}
public void OnValueChangeRefreshCards (Vector2 valueChange)
{
if(timeSinceLastUpdate < 0.25f)
{
return;
}
timeSinceLastUpdate = 0;
// do your stuff here...
}
You have 250+ images to process every frame which is a big deal for older Android devices, again as MaskableGraphics.OnEnable() call can be the culprit. You can avoid changing the state if it is required:
if (RendererExtensions.IsVisibleFrom (card.MyRectTransform, Camera.main))
{
if(!card.roseImage.enalbed)
card.roseImage.enabled = true;
}
else
{
if(card.roseImage.enalbed)
card.roseImage.enabled = false;
}
Furthermore, following are some helpful links to optimize UI in Unity:
Some of the best optimization tips for Unity UI
Tantzy Games
Gemserk
Other UI Optimization Techniques and Tips
A guide to optimizing Unity UI
UPDATE:
The following blog provides more information about UI rendering:
Making the UI Backend Faster
Hope this helps :)

Related

how i can remove lagging in my unity android game?

I am adroid proggrammer,because of many object in scene my game has lagging
i have theory for remove lagging in my game.
if i can control rendering in unity i can remove lagging.
using UnityEngine;
using System.Collections;
public class Enemy : MonoBehaviour {
void Update(){
void Start(){
GetComponent<Renderer>().enabled = false;
}
object2 = GameObject.Find("TR");
var distance = Vector3.Distance(gameObject.transform.position, object2.transform.position);
print (distance);
if(distance <= 80){
GetComponent<Renderer>().enabled = true;
}
}
}
Don't work.how can i have boolean render that when have collision will render
else remove.
i want have zone that all object in my zone rendered and allthing outside do not render.
void OnTriggerEnter(Collider collision)
{
if(collision.gameObject.tag == "zone")
{
GetComponent<Renderer>().enabled = true;
}
else{
GetComponent<Renderer>().enabled = false;
}
don't work
void OnTriggerEnter(Collider collision)
{
if(collision.gameObject.tag == "zone")
{
gameObject.SetActive(false);
}
else{
gameObject.SetActive(true);
}
This is either implemented in Unity or implementing it is a bad idea because raycasts are expensive and you need a lot of them. Try finding other problems which cause lagging in your game, disable feature by feature and write how many frames you have, this will get you best overview of what's the problem. Look online which methods are expensive (Instantiating, Destroy, try merging all models you have, smaller amount of shaders, fast shaders, less textures to load, FindGameObjectByName (or tag...)).
Here you will find a great document about optimization. It's preapared for mobile devices but i hope you will find what you need: Unity Optimization Guide for x86 Android
I would recommend having your blue blobs in an object pool, and the ones leaving your screen getting disabled.
You know your position and you know the position of the objects in the pool, you can math your distance in one direction, for instance behind you and disable after x amount.
Raycasting or collisions are abundant.
On your terrain generation scripts, check for disabled pool objects and if one exist, it should be put ahead in the level and repositioned or w/e logic you have there.
Don't instantiate and destroy unless you really need it, do it on level-load instead of on the fly.
(It's expensive.)
There's some really good tutorials on the unity page, have a look there.
They cover things like endless-runners.

Position interpolation not working properly

I am developing an android game with box2d and use a fixed timestep system for advancing the physics.
However as I use this system it requires the box2d positions to be interpolates. I read this article
and have implemented an interpolation method very much like the one in the article.
The method seems to work nicely on the computer but on my phone the positions of objects are very jumpy. There is of course a big frame rate difference between PC and phone, but I think this algorithm should not mind that.
Here is the just of the code if you don't feel like looking at the article :
void PhysicsSystem::smoothStates_ ()
{
const float oneMinusRatio = 1.f - fixedTimestepAccumulatorRatio_;
for (b2Body * b = world_->GetBodyList (); b != NULL; b = b->GetNext ())
{
if (b->GetType () == b2_staticBody)
{
continue;
}
PhysicsComponent & c = PhysicsComponent::b2BodyToPhysicsComponent (* b);
c.smoothedPosition_ =
fixedTimestepAccumulatorRatio_ * b->GetPosition () +
oneMinusRatio * c.previousPosition_;
c.smoothedAngle_ =
fixedTimestepAccumulatorRatio_ * b->GetAngle () +
oneMinusRatio * c.previousAngle_;
}
}
Does anyone know why my game is acting like this?
Thanks for the help
That code in and of itself doesn't appear to have any issues as compared to the article. You might want to try posting this on https://gamedev.stackexchange.com/ and see if they have any recommendations.
Alternatively, here is a very well written article about having a semi-fixed time step, and decoupling physics and frame rate, which I imagine could be the problem. It isn't for Box2D, but reading over it might help you pinpoint the issue with your physics.

Android: How to find the frame rate of a device?

Frame rate: I'm referring to the rate at which display changes. i.e. Ondraw() is called and the canvas is redrawn.
Is there a default rate for all android devices ? As this rate depends on the processing power of the device , How to find out the frame rate of a device , before starting to program for that mobile device ?
This may be a follow-up to this question, where I suggested that having a redraw loop that just kept drawing over and over again might be a bit excessive. There may be an api to find out the capabilities of the devices display, but if there is I'm not aware of it. When you're writing your own event loop / thread function you can control the framerate by how often you call your 'draw' method. Typically, I think for most purposes, you would be ok with a refresh rate of 30 or so. If you're writing a fast action game, that needs rapid animation then you may want to run as fast as you can, the more fps, the smoother it will be.
A typical event loop (thread run function) might look something like this:
// define the target fps
private static final int UPDATE_RATE = 30; // Frames per second (fps)
public void run() {
while(running) { // volatile flag, set somewhere else to shutdown
long beginTimeMillis, timeTakenMillis, timeLeftMillis;
// get the time before updates/draw
beginTimeMillis = System.currentTimeMillis();
// do the thread processing / draw
performUpdates(); // move things if required
draw(); // draw them on the screen
// get the time after processing and calculate the difference
timeTakenMillis = System.currentTimeMillis() - beginTimeMillis;
// check how long there is until we reach the desired refresh rate
timeLeftMillis = (1000L / UPDATE_RATE) - timeTakenMillis;
// set some kind of minimum to prevent spinning
if (timeLeftMillis < 5) {
timeLeftMillis = 5; // Set a minimum
}
// sleep until the end of the current frame
try {
TimeUnit.MILLISECONDS.sleep(timeLeftMillis);
} catch (InterruptedException ie) {
}
}
}
You can use the dumpsys tool provided by Android. To obtain information about the display of the device execute the command:
adb shell dumpsys display
The information about the frame rate of the device is provided in the attribute "mPhys".
You will find something like:
mPhys=PhysicalDisplayInfo{1080x1920, 60.000004 fps, densitiy 3.0,
480.0x480.0 dpi, secure true}
The frame rate of the device is in the second field, in my case is 60.000004 fps
You can't rely on a certain framerate. Android is a using multitasking operating system. If there are some threads running in the background that do some heavy lifting, you might not be able to reach the framerate you want. Even if you're the only active process, the framerate depends on your GPU and CPU, and the clock of each. Maybe the user has a hacked ROM that changes the clock to a custom value.
Some phones might be locked to a certain framerate. The HTC EVO was locked to 30fps for the longest time, until custom ROMs came out that removed that limitation. Newer EVO ROMs also removed that limitation.
I don't know what you're trying to do, but your best bet is to measure the time after each frame and use that delta for your animations. If you're trying to display the FPS, then use a smoothed average.
There is a simple tricky way to find device FPS during runtime.
Just call the following method:
long oneSecondLater=0;
int FPS=0;
int counter=0;
ValueAnimator v_animator;
private void logFPS()
{
oneSecondLater = System.currentTimeMillis()+1000;
v_animator = ValueAnimator.ofFloat(0.0f, 1.0f);
v_animator.setRepeatCount(ValueAnimator.INFINITE);
v_animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
FPS++;
if(System.currentTimeMillis() > oneSecondLater)
{
counter++;
if(counter>1)//ignore the first onAnimationUpdate call (it is not correct)
Log.i("checkFPS","FPS:" + FPS);
FPS=0;
oneSecondLater = System.currentTimeMillis()+1000;
}
}
});
v_animator.start();
}
I log FPS every second, The output of my Logcat was as follows
It works because for ValueAnimator, onAnimationUpdate() method will call according to device FPS;
This might be an old question, but for future reference, I found this library named Takt
https://github.com/wasabeef/Takt.
Takt is Android library for measuring the FPS using Choreographer.

Android: Touch seriously slowing my application

I've been raking my brains on this one for a while.
when I'm running my application (opengl game) eveyrthing goes fine but when I touch the screen my application slows down quite seriously (not noticeable on powerful phones like the nexus one, but on the htc magic it gets quite annoying).
I did a trace and found out that the touch events seem to be handled in a different thread and even if it doesn't take so much processing time I think androids ability to switch between threads is not so good...
What is the best way to handle touch when speed is an issue ?
Currently I'm using :
in the GLSurfaceView
#Override
public boolean onTouchEvent(MotionEvent event) {
GameHandler.onTouchEvent(event);
return true;
}
Any ideas are welcome
I have a feeling the bug report below may be relevant. Sadly in seems its only going to be fixed in gingerbread.
Bug report
Have just seen that SO prefers details in the answers in case links vanish etc. the above refers to a google accepted bug in Adnroid 2.1 targetted for a fix in the gingerbread release.
Issue 7836: system_server consumes excessive CPU processing touch events
I can't vouch for this myself, but my research has shown that touching the screen fires so many events that it floods the events queue and therefore lags the CPU taking your resources.
Try putting: -
try {
Thread.sleep(16);
} catch (InterruptedException e) {} //ignore
before any returns that you have in the onTouch method (usually there's only the one at the end - but just making sure). I know sleep is usually a very bad thing to do, but its not in the UI thread so it should be ok. Sleep 16 should cap the FPS to 60.
Don't put heavy computation to your onTouchEvent(). The OnTouchEvent can be fired tens or hundred of times per second per finger, you should defer the heavy computation to the other part of your game (e.g. the physics engine or the graphic engine). In particular avoid drawing in your onTouchEvent.
You should preferrably use onClickEvent or other less intensive mouse event and only use onTouchEvent when you really need to track the motion of the touch.
#Jason:
This was going to be a comment, but it grew too big and it is a different [better] answer to the one I just gave.
I have changed my implementation using this method as described here
http://obviam.net/index.php/the-android-game-loop/
By employing the method described above means you should not need to sleep the OnTouch events.
Also don't forget to protect your game loop thread as mentioned here http://wonton-games.blogspot.com/2010/06/lunar-lander-resume-game-workaround.html
Also also keep in mind that Chris Pruett when writing Replica Island said he used 2 threads, one for the update() and the other for render() - both will have to be protected.
Chris does sleep his OnTouch with 16 milliseconds (60 fps) to cut back the events - so I would say its best to experiment if you still need to cut the events down - you need only touch the screen whilst stuff is happening to see if it lags and thus subsequently speeds up when let go.
For my needs currently I am using the same thread as I haven't progressed into OpenGL, I still use the canvas. But when I go OpenGL, it will be 2 threads, and each will be a complete class of its own.
Finally, I don't time my sprites by counting frames, I've wrapped them with a timer. I'll share my Class and show you how I call it. Bear in mind I am still new to Java so apologies for poor code.
package com.yourname.yourapplication;
//Used for doing something after a set time
public class TimeDo {
private int mRepeat = 0; //Stores the last wait period for the reset() later
private long mTime = 0; //The goal time of when its due
private boolean mFlagged = false; //Stop them getting a second true on a subsequent check
public TimeDo(int milliseconds) {
reset(milliseconds);
}
public TimeDo() {
this(0);
}
public void reset(int milliseconds) {
mRepeat = milliseconds;
mTime = System.currentTimeMillis() + milliseconds;
mFlagged = mRepeat==0; //ignore if zero
}
public void reset() { //Set it back to the delay used last time
reset(mRepeat);
}
public boolean check() {
if (mFlagged) //Assert: shouldn't really happen
return false;
mFlagged = System.currentTimeMillis() > mTime;
return mFlagged;
}
public boolean checkAndReset() {
if (check()) {
reset();
return true;
}
return false; //note mFlagged could be true here, so don't use it
}
}
And it is implemented thusly: -
public class Gem {
private TimeDo mMoveGem = new TimeDo(100); //move 10 times a second, 100ms
private int mX = 0;
private int mY = 0;
private int mMoveX = 3;
private int mMoveY = 4;
.
.
.
public void update() {
if (mMoveGem.checkAndReset()) {
mX += mMoveX;
mY += mMoveY;
.
.
}
}
public void render(Canvas canvas) {
//etc etc
.
.
}
}
Hope any of that helps!
Sorry if you have to rewrite lots of your application - I did.
Edit: That TimeDo class is not a postDelayed runnable, like an automatic alarm. If you don't check it no "event" will fire. You could get excited and have it create a runnable and pass it a callback method that resides within your class (think of an OnClick method) - but defeats the purpose of running an exclusive time-able update() thread that updates all your components.

Android loading and showing a lot of images in ImageView(frame by frame animation) hangs in certain moments

I've created an application that show around 250 images in ImageView. Images are loaded one after another, 15-30 images per second. Basically the whole thing gives an illusion of a rotating 3D object, at least it should.
The problem is next, app hangs when loading certain images(i.e. I see a few seconds of fluid animation and then animation hangs, jump 10-15 frames(images) ahead and continues. It always happens at the same places in animation cycle.
I though that Android might not have enough resources to handle something like this, so I've resized images to half their size, but it did't help. I've tried buffering images but that did't help either(actually, maybe a little, I think that animation looks a little bit smoother).
And now the weirdest thing. I use the touch screen to allow users to "rotate" the 3D object on those images, and while rotating I again experience those hangs at exactly the same places as with the animation.
All images are in .png format and their size vary from 15kB to 40kB.
I use the following code for the animation:
new Thread(new Runnable() {
#Override
public void run() {
while (!stopStartupAnimation && li < images_360.length) {
final int fli = li;
handler.post(new Runnable() {
#Override
public void run() {
//Bitmap b = BitmapFactory.decodeResource(getResources(), R.drawable.icon);
//imageCanvas.setImageResource(images_360[fli]);
imageCanvas.setImageBitmap(imageStackNext.pop());
System.out.println("rawX = " + fli);
}
});
int ti = fli +25;
if(ti > images_360.length-1){
ti = ti - images_360.length;
}
imageStackNext.push(BitmapFactory.decodeResource(getResources(), images_360[ti]));
synchronized (this) {
try {
wait(1000 / 25);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
li++;
li++;
if (li >= images_360.length) {
li = 0;
}
}
}
}).start();
First, 15-40KB is their compressed form. Uncompressed, as Bitmaps, they are probably substantially larger. 250 of them may be using many MB of RAM, which is not a good idea.
Second, given a choice between using OpenGL for 3D (which is its purpose), or the 2D drawing primitives on the Canvas, or using ImageView, you chose the worst-performing option.
Third, postRunnable() does not take effect immediately, but rather puts things on a message queue for the main application thread to process when it gets a chance. If it gets tied up -- say, handling touch events -- it may well skip over some seemingly redundant ImageView redraws, or have them go by so fast they appear to not happen. All your 40ms wait() does is ensure that you are only raising events every 40ms, not that they will paint every 40ms. Besides, you could have more easily just used postDelayed() for your 40ms timing.
Bitmaps should be loaded efficiently.
Refer example on official page: https://developer.android.com/training/displaying-bitmaps/index.html

Categories

Resources