Unity Android: How to preload scenes in cache - android

When I load scenes the first time after app installation on my android phone, it takes time I.e. few seconds. Thereafter all the scenes load pretty fast. I am assuming the faster load times is because the scenes are loaded from cache.
So how can I preload all the scenes in cache or at least the 'heavy' scenes so that they get loaded fast even the first time?
Thanks.

Short answer is you can't, the first time your app runs it will create its own cache and that takes time, But you can create a loading screen and load your scenes asynchronously, there are a lot of tutorials about that
https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager.LoadSceneAsync.html
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Example : MonoBehaviour
{
void Update()
{
//Press the space key to start coroutine
if (Input.GetKeyDown(KeyCode.Space))
{
//Use a coroutine to load the Scene in the background
StartCoroutine(LoadYourAsyncScene());
}
}
IEnumerator LoadYourAsyncScene()
{
// The Application loads the Scene in the background at the same time as the current Scene.
//This is particularly good for creating loading screens. You could also load the Scene by build //number.
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync("Scene2");
//Wait until the last operation fully loads to return anything
while (!asyncLoad.isDone)
{
yield return null;
}
}
}
http://blog.teamtreehouse.com/make-loading-screen-unity
https://www.youtube.com/watch?v=YMj2qPq9CP8
https://en.wikipedia.org/wiki/Dalvik_%28software%29

Related

Glide inconsistent loading in for loop

I am writing an Android app where I want to display a consistent stream using the newest Glide 4.11.0. My idea was that I display every 100 ms a new image using a for loop where I call the Glide function. When I start my function loadImageFromURL() it runs through and afterwards display all the images as fast as possible after each other, but I want to get it displayed evenly with a time gap of around 100 ms.
What am I doing wrong? Is there a problem with an internal thread of Glide?
My Code:
public void loadImageFromURL() {
Glide.get(this).setMemoryCategory(MemoryCategory.HIGH); //use more RAM than normal
final long Start = System.currentTimeMillis();
for (int i = 0; i < 5; imageNumber++) { //for loop for displaying continuously stream
if (System.currentTimeMillis() > Start + i * 100) {
Glide.with(this).asBitmap().load(ImageURL).diskCacheStrategy(DiskCacheStrategy.NONE).override(ScreenSizeX, ScreenSizeY).into(new CustomTarget<Bitmap>(){
#Override
public void onResourceReady(#NonNull Bitmap resource, #Nullable Transition<? super Bitmap> transition) {
_imageView.setImageBitmap(resource);
imageNumber++;
}
#Override
public void onLoadCleared(#Nullable Drawable placeholder) {
}
});
i++;
}
}
Glide.get(this).setMemoryCategory(MemoryCategory.NORMAL); //RAM usage back to normal
}
There are multiple flaws with your code. Glide downloads the images in a separate thread, so it's running the download code independently from your loop. Some issues:
You are manipulating imageNumber from multiple threads. This will cause random time-sensitive issues. You should not increment imageNumber in onResourceReady
The loop will just infinitely loop until the desired time is reached. This will cause heavy CPU load and can be solved by using locks, waits or similar.
My suggestion: Try loading each image after another synchronously with the solution from this answer. When an image has loaded, calculate how much time remains for your "image load break" to pass and use Thread.sleep(milliSeconds) to wait out the remaining time. Then you can update the imageView.
Make sure you run this code in a separate thread and use runOnUIThread when updating the imageView.
You can probably further optimize this by using a ConcurrentQueue where the download of the images all happen at once and a separate consumer thread takes from the queue and waits in between. This will probably have higher memory usage though because the images will be also stored in the queue.

Unity App freezes when loading Multiple Videos on same Scene

When navigating from menu to a Scene that contains 8, 1-minutes MP4 videos, that are played using new VideoPlayer script on RawImage component. I am using Unity 5.6.0b11 beta version.
In the scene that I am trying to navigate has prefabs that loads videos in list thumbnails, previously I was loading Images instead of Videos and it was working fine, now when trying to load video it freezes for than 38 seconds on Axon 7 (4GB RAM) and 32 seconds on One Plus 3 (6 GB RAM) but does not lags at all when playing on Unity Player itself.
Script I used for VideoPlayer is from this StackOverflow Question.
button.onClick.AddListener(new UnityEngine.Events.UnityAction(() =>
{
SceneManager.LoadSceneAsync("SceneSponsors");
StartCoroutine(CloseMenu());
}));
Is there a way, I can work around with the Slow Loading Scenes or pre-load them in Background when mainScene is loaded on the App start and navigate in need.
I saw somewhere Resources.Load() also makes it slow on Android Devices, but I've tested by removing all Resources.Load() which I was using to load image sprites but the problem was still there.
Edit:
Here's my CloseMenu() functions it is only used to swipe and move the menu panel. P.S the App freezes only on loading that particular Scene, and works smoothly for other.
IEnumerator CloseMenu()
{
if (IsOpen)
{
Vector3 pos = MainMenuWindow.transform.position;
iTween.ColorUpdate(CloseArea, new Color(0, 0, 0, 0f), .6f);
iTween.MoveTo(MainMenuWindow.gameObject, new Vector3(Screen.width, pos.y, pos.z), .6f);
IsOpen = false;
yield return new WaitForSeconds(.3f);
CloseArea.transform.position = new Vector3(-240 * ScaleFact, CloseArea.transform.position.y, CloseArea.transform.position.z);
}
}
Edit 2
I am loading VideoPlayer on RawImage using Script. Here's what RawImage looks like in Play mode along with VideoPlayer, and in inactive mode.
For my case of problem. I had to make some changes on the VideoPlayer API Script I was using from this StackOverflow Question
In the script I was using from that link. The Co-routine was started inside the Start() function, that made the videos in 8 different prefab, to load at once even they were in pause mode.
So I added a new function PlayVideoOnClick() and attached it to the Click Event of the RawImage, so now the video will be loaded only if the RawImage is clicked.
Changed from
public void Start()
{
Application.runInBackground = true;
StartCoroutine(playVideo());
}
To
public void PlayVideoOnclick()
{
Application.runInBackground = true;
StartCoroutine(playVideo());
}
P.S: You can also see my YouTube Video Tutorial and Blog on Playing Videos smoothly in Unity.
It is a well known bug that loading big scenes using LoadSceneAsync may block the gpu completely several seconds (completely unnoticeable in the editor), i´ve also been following this for quite some time now,
From the forums:
https://forum.unity3d.com/threads/starting-async-load-causes-massive-lag-spike.288755/
Official unity Issue tracker:
https://issuetracker.unity3d.com/issues/loading-a-scene-async-creates-huge-performance-spikes-for-the-gpu

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.

how to create loading screen in libgdx?

I have a GameScreen class that renders my game.
but before starting to render the game, it needs to reading files and initializing that is time consuming.
So I need to show/render another Screen class called LoadingScreen in order to spending some time and concurrently read my files and do initializing process for my GameScreen, and after initializing completed changing the screen by calling setScreen(gameScreen).
I need to use thread for making this concurrent work, now the problem is that if I use a thread to read files and initializing; When switching to the GameScreen the openGl gives me this error:
javax.media.opengl.GLException: Error: no OpenGL buffer object appears to be bound to target 0x8892
at com.sun.opengl.impl.GLBufferSizeTracker.setBufferSize(GLBufferSizeTracker.java:118)
I am aware of not both of threads use the graphic resources simultaneously.
I have found that the problem causes with Meshes. Initializing a Mesh in initializer thread and rendering in main thread causes this error. But I don't know how to solve it.
Do you have any ideas to solve this problem?
As suggested in the comments, the AssetManager is the way to load most libGDX resources (audio, textures, etc) asynchronously while showing a splash or loading screen.
For other operations, running them in a background thread (or using one of the other Android or Java background task execution facilities) should be sufficient. To invoke libGDX routines like setScreen or others that need to be executed on the libGDX render thread, use Gdx.app.postRunnable, like this:
Gdx.app.postRunnable(new Runnable() {
#Override
public void run() {
// Do something on the main thread
myGame.setScreen(postSplashGameScreen);
}
});
Depending on the visibility of myGame and postSplashGameScreen it may be easier to construct the Runnable in a different context and then pass it over to the background thread to post when its done.
My workouround is using Actions in my loading screen method:
#Override
public void show() {
stage.addAction(Actions.sequence(Actions.delay(0.5f), action_loading_assets_and_other_stuff, Actions.delay(0.5f), action_setScreen));
}
Actions.delay(0.5f) makes the magic - game not freezing
The action delay did it for me, too. I just sequence a delayaction with 0.2f and a runnable action on the stage in the loading screens show() method. Now the loading screens render method is called a few time while while the 0.2 sec delay which draws the screen and i can proceed stuff in the runnable action.

Progress bar while loading Textures in AndEngine

when I start my game black screen comes for a while because resources are being loaded.
I went thorough a tutorial which show how to show progress bar while leading resources I followed it and now I can see progress bar. But the problem is this when progress bar is visible every thing else is stopped. And nothing happens. Only a black screen and a progress bar on it. Can any one tell me why every thing is paused and why loadresources and loadscene methods are not working? Please provide a solution.
You need to load your resources in a worker thread. A nice utility for doing this is AsyncTask. The guide topic Processes and Threads has an explanation of why you need something like this, as well as sample code showing how to do a simple AsyncTask that might be just what you need.
From Engine.java:
public void onDrawFrame(final GLState pGLState) throws InterruptedException {
final EngineLock engineLock = this.mEngineLock;
engineLock.lock();
try {
engineLock.waitUntilCanDraw();
this.mVertexBufferObjectManager.updateVertexBufferObjects(pGLState);
this.mTextureManager.updateTextures(pGLState);
this.mFontManager.updateFonts(pGLState);
this.onUpdateDrawHandlers(pGLState, this.mCamera);
this.onDrawScene(pGLState, this.mCamera);
engineLock.notifyCanUpdate();
} finally {
engineLock.unlock();
}
}
And that's why the engine hangs and the UI gets stuck. It's possible to display a loading screen while the textures are being loaded into hardware, without freezing, let's say, a ProgressBar. It's not easy and requires a lot of code, but it's possible and doesn't require crazy hacks, just some logic.
You need to have a Resources Manager (RM) and a Scene Manager (SM) who work together (with AsyncTasks) and are responsible for loading the textures for the current scene. Since you've a BaseGameActivity you can use this Activity instance to show a fullscreen Dialog with the progress bar. The logic is:
SM is asked to show Scene A
SM shows the loading Dialog
SM asynchronously tells the RM to load all Scene A resources into hardware (for each texture for Scene A, texture.load)
RM "onSceneTexturesLoadComplete" tells SM that all textures are loaded
Since texture.load doesn't guarantee the texture is actually loaded you'll need to have a TryToDismissDialog that extends TimerTask. This TryToDismissDialog from time to time will query the Scene A textures and check if they are actually loaded:
if (texturePack.getTexture().isLoadedToHardware()) {
texturesLoaded++;
}
If all textures are loaded you dismiss the Dialog and voilá you'll see the Scene ready.
Hope it helps
ps: this actually involves some lines of code, I've just posted here a quick steps/guide/pseudo-code. I'll not post the final solution because it's quite heavy and "project related".

Categories

Resources