I'm experimenting with Unity3d AssetBundles. I'm trying to load a scene with its objects. I have this simple code for creating my asset bundle :
[MenuItem ("Build/BuildAssetBundle")]
static void myBuild(){
string[] levels = {"Assets/main.unity"};
BuildPipeline.BuildStreamedSceneAssetBundle(levels,"Streamed-Level1.unity3d",BuildTarget.Android);
}
and I use above code to build asset bundle from a scene which in has a camera and a cube in center.
and I have this code to load it:
using UnityEngine;
using System.Collections;
public class loader : MonoBehaviour {
public GUIText debugger;
private string url = "http://www.myurl.com/Streamed-Level1.unity3d";
// Use this for initialization
IEnumerator Start () {
Debug.Log("starting");
WWW www = WWW.LoadFromCacheOrDownload(url,1);
if(www.error != null)
{
Debug.LogError(www.error);
}
yield return www;
Debug.Log("after yield");
AssetBundle bundle = www.assetBundle;
bundle.LoadAll();
Debug.Log("loaded all");
Application.LoadLevel("main");
}
// Update is called once per frame
void Update () {
}
}
The problem is seems to be when it gets to get to loadAll it stops.
I'll appreciate if anyone can help me with this.
Thanks very much
The problem is C# have iterators/generators and so on that looks like a function but they don't. So your code just create iterator but do not run it. Use StartCoroutine to load asset:
using UnityEngine;
using System.Collections;
public class BundleLoader : MonoBehaviour{
public string url;
public int version;
public IEnumerator LoadBundle(){
using(WWW www = WWW.LoadFromCacheOrDownload(url, version){
yield return www;
AssetBundle assetBundle = www.assetBundle;
GameObject gameObject = assetBundle.mainAsset as GameObject;
Instantiate(gameObject );
assetBundle.Unload(false);
}
}
void Start(){
StartCoroutine(LoadBundle());
}
}
Related
I'm trying to reproduce a stream audio in my unity app with a button in his onclick, i've already tried with some methods i found but it doesn't end the download... I post my class above:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
public class Audio_player : MonoBehaviour
{
AudioSource audioSource;
AudioClip myClip;
void Start()
{
audioSource = GetComponent<AudioSource>();
StartCoroutine(GetAudioClip());
Debug.Log("Starting to download the audio...");
}
IEnumerator GetAudioClip()
{
using (UnityWebRequest www =
UnityWebRequestMultimedia.GetAudioClip("url-sample",
AudioType.UNKNOWN))
{
yield return www.SendWebRequest();
if (www.isNetworkError)
{
Debug.Log(www.error);
}
else
{
myClip = DownloadHandlerAudioClip.GetContent(www);
audioSource.clip = myClip;
audioSource.Play();
Debug.Log("Audio is playing.");
}
}
}
public void pauseAudio(){
audioSource.Pause();
}
public void playAudio(){
audioSource.Play();
}
public void stopAudio(){
audioSource.Stop();
}
}
The console just pop up 2 messages after this onclick():
-[Adaptive Performance] No Provider was configured for use. Make sure you added at least one Provider in the Adaptive Performance Settings.
0x00007ff68171b5cd (Unity) StackWalker::GetCurrentCallstack
-Starting to download the audio...
0x00007ff68171b5cd (Unity) StackWalker::GetCurrentCallstack
My problem is that when all the enemies are killed the scene that should be loaded is not loading. I did add the scene to the Build setting (it has an index of 3) but it is still not loading. The script I created is attached to an empty object and not directly to the sprite (is that okay?). Can someone tell me why the scene isn't loading? Thank you.
This image is for to show you the EnemySpawner empty object inspector
EnemySpawner Script :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class EnemySpawner : MonoBehaviour {
[SerializeField] GameObject EnemyPreFab;
[SerializeField] int MaxEnemies = 30;
[SerializeField] float EnemySpawnTime = 1.00001f;
[SerializeField] GameObject FirstWaypoint;
int CurrentNumOfEnemies = 0;
public LevelManager myLevelManager;
public int maximumnumberofhits = 0;
int timesEnemyHit;
IEnumerator SpawningEnemies()
{
while(CurrentNumOfEnemies <= MaxEnemies)
{
GameObject Enemy = Instantiate(EnemyPreFab, this.transform.position, Quaternion.identity);
CurrentNumOfEnemies++;
yield return new WaitForSeconds(EnemySpawnTime);
}
}
void Start()
{
StartCoroutine(SpawningEnemies());
timesEnemyHit = 0;
if (this.gameObject.tag == "EnemyHit")
{
CurrentNumOfEnemies++;
}
}
void OnCollisionEnter2D()
{
timesEnemyHit++;
if (timesEnemyHit == maximumnumberofhits)
{
CurrentNumOfEnemies--;
Destroy(this.gameObject);
}
if (CurrentNumOfEnemies == 0)
{
myLevelManager.LoadLevel("NextLevelMenu");
Debug.Log("LevelLoaded");
}
}
}
LevelManger script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class LevelManager : MonoBehaviour {
public void LoadLevel(string name)
{
print("Level loading requested for" + name);
SceneManager.LoadScene(name);
}
}
EnemyShooting Script :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyShooting : MonoBehaviour {
[SerializeField] float EnemyLaserSpeed = 10f;
[SerializeField] float EnemyLaserFireTime;
[SerializeField] GameObject LaserBulletEnemyPreFab;
[SerializeField] int MaxNumberOfHits = 1;
int CurrentNumberOfHits = 0;
Coroutine FireCoroutine;
void OnTriggerEnter2D(Collider2D collider)
{
if(collider.gameObject.tag == "PlayerLaser")
{
if(CurrentNumberOfHits < MaxNumberOfHits)
{
CurrentNumberOfHits++;
Destroy(collider.gameObject);
Score.ScoreValue += 2;//The user will be rewarded 1 point
}
}
}
void DestroyEnemy()
{
if(CurrentNumberOfHits >= MaxNumberOfHits)
{
Destroy(gameObject);
}
}
private void Fire()
{
FireCoroutine = StartCoroutine(ShootContinuously());
}
void BecomeVisible()
{
Fire();
}
IEnumerator ShootContinuously()
{
while (true)
{
GameObject LaserBulletEnemy = Instantiate(LaserBulletEnemyPreFab, this.transform.position, Quaternion.identity) as GameObject;
LaserBulletEnemy.GetComponent<Rigidbody2D>().velocity = new Vector2(0, EnemyLaserSpeed);
EnemyLaserFireTime = Random.Range(0.5f, 0.9f);
yield return new WaitForSeconds(EnemyLaserFireTime);
}
}
// Use this for initialization
void Start () {
BecomeVisible();
}
// Update is called once per frame
void Update () {
DestroyEnemy();
}
}
EnemyPathing script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyPathing : MonoBehaviour {
[SerializeField] List<Transform> WayPoints;
[SerializeField] float EnemyMovingSpeed = 5f;
int WayPointIndex = 0;
void EnemyMoving()
{
if (WayPointIndex <= WayPoints.Count - 1)
{
var TargetedPosition = WayPoints[WayPointIndex].transform.position; //The position of where the enemy needs to go
TargetedPosition.z = 0f;
var MoveThisFrame = EnemyMovingSpeed * Time.deltaTime;
transform.position = Vector2.MoveTowards(this.transform.position, TargetedPosition, MoveThisFrame);
if(transform.position == TargetedPosition)
{
WayPointIndex++;
}
}
else
{
Destroy(gameObject);
}
}
// Use this for initialization
void Start () {
transform.position = WayPoints[WayPointIndex].transform.position;
}
// Update is called once per frame
void Update () {
EnemyMoving();
}
}
Problem
You're checking for collisions on the SPAWNER; when someone hits the Spawner it counts down enemies. But the Spawner doesn't have a collision box in the screenshot so it can never be hit. The Scene changing code can never be called.
So the game, based on the code, looks like this:
Spawn X enemies,
Hit the Spawner X times,
(Removed: Destroy the Spawner,)
Change scene.
I'm guessing this is conceptually incorrect and you actually want to check collisions on the spawned enemies, which will then count up the amount of destroyed enemies, and change the scene when they are all dead.
Solution
Conceptually, what you want is:
Spawn X enemies
Count up variable for every enemy
On Enemy death, count it down
When 0, change scene
So how do we code this?
Well, every enemy needs a reference to the object that holds the count. You can do this in several ways, when I personally do it I usually have just one spawner that is responsible for everyone so I make that one a Singleton, that can be references from anywhere:
EnemySpawner
public class EnemySpawner : MonoBehaviour
{
public static Spawner Instance = null;
int CurrentNumOfEnemies = 0;
// ... etc
void Start()
{
if (Instance == null)
Instance = this;
// Spawn enemies like you do already, CurrentNumOfEnemies++ for every spawned
}
public OnEnemyDeath() {
CurrentNumOfEnemies--;
if (CurrentNumOfEnemies < 1)
{
// You killed everyone, change scene:
LevelManager.LoadLevel("Your Level");
}
}
}
Enemy script (I don't know how your current code looks, but here's a minimal solution based on how I THINK your code looks):
void OnDestroy()
{
// This will run automatically when you run Destroy() on this gameObject
EnemySpawner.Instance.OnEnemyDeath(); // Tell the EnemySpawner that someone died
}
This will only work if you have exactly only ONE spawner. If you have multiple ones you will have to send a reference to the instance of its spawner to every spawned enemy. I can show you how to do ths too, if you wish.
Bonus content
LevelManager doesn't need to be on a GameObject, it can be static instead:
Remove the LevelManager script from any GameObject
Change your LevelManager code to this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public static class LevelManager
{
public static void LoadLevel(string name)
{
Debug.Log("Level loading requested for" + name);
SceneManager.LoadScene(name);
}
}
Now you can use it from ANYWHERE, without needing to initialize a reference to any script or GameObject:
LevelManager.LoadLevel("My Level");
myLevelManager.LoadLevel("NextLevelMenu"); is never executed, because you destroy the object in the if-test above.
[enter image description here][1]Originally, this was a null reference exception, which is a problem that occur when a variable is used/referenced but hasn't been initialized. I used an if statement that checks if an instance is NOT null it would instantiate. The Null reference exception problem is gone but it still wouldn't instantiate.
ScraptScript.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ScrapScript : MonoBehaviour
{
public GameObject[] ScrapSprite;
EnemyScript Es;
void Start ()
{
Es = GameObject.FindObjectOfType<EnemyScript> ();
foreach(GameObject SSprite in ScrapSprite)
{
print (SSprite);
}
}
void Update ()
{
}
public void SpawnScraps()
{
if(Es != null )
{
Instantiate (ScrapSprite[0], Es.transform.position, Es.transform.rotation);
}
}
}
EnemyDestroyed.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyDestroyed : MonoBehaviour {
BulletScript.BulletType theBulletType = 0;
ScrapScript SS;
void Start ()
{
SS = GameObject.FindObjectOfType<ScrapScript> ();
}
void Update ()
{
}
void OnTriggerEnter(Collider collider)
{
if(collider.tag == "PlayerBullet" && theBulletType == BulletScript.BulletType.PlayerBullet)
{
print ("ship destroyed");
Destroy(collider.gameObject);
Destroy(gameObject);
SS.SpawnScraps ();
}
if(collider.tag == "L.Collider Det")
{
Destroy(gameObject);
}
}
}
EnemyScript.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyScript : MonoBehaviour {
public int enemyHP;
public float enemySpeed;
public GameObject enemyBullet;
internal int enemyBulletCount = 0;
public int maxAllowableBulletCount;
public Transform enemyBulletSpawn;
public EnemyType ET;
public enum EnemyType
{
Grunt,
Boss,
}
void Awake()
{
StartCoroutine (MyShootCoroutine ());
}
void Start ()
{
}
void Update ()
{
if (ET == EnemyType.Grunt)
{
transform.Translate (-enemySpeed * Time.deltaTime, 0f, 0f);
}
}
IEnumerator MyShootCoroutine()
{
for(enemyBulletCount = 0; enemyBulletCount <= maxAllowableBulletCount; enemyBulletCount++)
{
yield return new WaitForSeconds (1.5f);
Instantiate (enemyBullet, enemyBulletSpawn.position, enemyBulletSpawn.rotation);
}
}
}
Expectation: What I expected of my code is to spawn a pickup currency called "Scraps" that the player will get upon contact when the enemy is destroyed. It spawns exactly where the enemy is destroyed through the player's bullets.
Screenshot link
[enter image description here][1][1]: https://i.stack.imgur.com/6iq11.png
Given that you had a null reference exception in SpawnScraps method on the Es object the only issue is that when your method is called the Es object has been destroyed.
Given that you kill your ennemy instance before trying to call a method on him, you get a null reference exception :
Destroy(collider.gameObject);
Destroy(gameObject);
SS.SpawnScraps ();
Just make call the SpawnScraps method before destroying the ennemy GameObject :
SS.SpawnScraps ();
Destroy(collider.gameObject);
Destroy(gameObject);
Within your scrap script, your Es is likely still null. This may because your script only finds the Enemyscript during Start().
You can remove this check and simplify things by passing the transform of the enemy into your SpawnScraps function.
within Enemydestroyed change your line to:
SS.SpawnScraps (transform);
within Scraptscript change existing function to:
public void SpawnScraps(Transform enemy)
{
Instantiate (ScrapSprite[0], enemy.position, enemy.rotation);
}
I have a very simple scene, a cube with a script that manages its rotation.
I generate a asset bundle from the entire scene, and when I load this scene, the cube appears in the screen, but the rotation does not work. The cube is static, like as the scene didn't load properly.
This is the code that i use to load the scene:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class TouchButton : MonoBehaviour {
public Button yourButton;
void Start()
{
Button btn = yourButton.GetComponent<Button>();
btn.onClick.AddListener(TaskOnClick);
}
void TaskOnClick()
{
string url = "https://dl.dropboxusercontent.com/s/0mm336mfxvh83gp/simple?dl=0";
WWW wwwObj = new WWW(url);
StartCoroutine(WaitForReq(wwwObj));
}
IEnumerator WaitForReq(WWW wwwObj)
{
yield return wwwObj;
AssetBundle bundle = wwwObj.assetBundle;
if (wwwObj.error == null) {
string[] scenePaths = bundle.GetAllScenePaths ();
SceneManager.LoadScene("Scene", LoadSceneMode.Single);
}
}
}
Like the title says I'm trying to get server time. I know there are many other question regarding this issue but none of them helped me. Here the code:
using UnityEngine;
using System.Collections;
public class ServerTime : MonoBehaviour{
public static ServerTime time;
void Awake(){
time = this;
}
public static void Get(){
time.StartCoroutine (time.ServerRequest ());
}
IEnumerator ServerRequest(){
WWW www = new WWW ("http://www.businesssecret.com/something/servertime.php");
yield return www;
Debug.Log(www.text);
}
}
And I call it from other script like this:
ServerTime.Get();
This should print the time from the server but instead I keep getting
"Object reference not set to an instance of an object" on line 13:
time.StartCoroutine (time.ServerRequest ());
What am I doing wrong? Please don't mark as duplicate because I tried all methods I found from Google and none helped.
That code should work as it is.
Possible reasons why you are getting that exception:
1.You forgot to attach ServerTime to an empty GameObject. You must attach it to a GameObject in order for its Awake() function to run. When Awake() is called, the time variable will be initialized.
2.You attached ServerTime to GameObject but then it got destroyed later on.
3.Script Execution order problems in Unity.
The script in which you are calling ServerTime.Get(); from is loaded before your ServerTime script is loaded. This is a know problem in Unity but you can change the order.
The code below should fix all 3 problems described above. If the time variable is null when ServerTime.Get() is called, a new GameObject is created and ServerTime script is attached to it. The time is then manually initialized.
public class ServerTime : MonoBehaviour
{
private static ServerTime localInstance;
public static ServerTime time { get { return localInstance; } }
private void Awake()
{
if (localInstance != null && localInstance != this)
{
Destroy(this.gameObject);
}
else
{
localInstance = this;
}
}
public static void Get()
{
if (time == null)
{
Debug.Log("Script not attached to anything");
GameObject obj = new GameObject("TimeHolder");
localInstance = obj.AddComponent<ServerTime>();
Debug.Log("Automatically Attached Script to a GameObject");
}
time.StartCoroutine(time.ServerRequest());
}
IEnumerator ServerRequest()
{
WWW www = new WWW("http://www.businesssecret.com/something/servertime.php");
yield return www;
Debug.Log(www.text);
}
}