yield and WWWForm error - c#

I have been trying to convert the code at (the 2nd sample on the page): http://unity3d.com/support/documentation/ScriptReference/WWWForm.html
..to C# in Unity3D:
void Start ()
{
string dataUrl = "http://www.my-site.com/game/test.php";
string playName = "Player 1";
int score = -1;
// Create a form object for sending high score data to the server
var form = new WWWForm();
// Assuming the perl script manages high scores for different games
form.AddField( "game", "MyGameName" );
// The name of the player submitting the scores
form.AddField( "playerName", playName );
// The score
form.AddField( "score", score );
// Create a download object
WWW downloadW = new WWW( dataUrl, form );
// Wait until the download is done
yield return downloadW;
if(downloadW.error == null) {
print( "Error downloading: " + downloadW.error );
return false;
} else {
// show the highscores
Debug.Log(downloadW.text);
}
}
I get the following error:
error CS1624: The body of rr2game.Start()' cannot be an iterator block becausevoid' is not an iterator interface type
After doing some reading I have tried changing void Start() to IEnumerator Start()
..but it says IEnumerator is is not declared..?
If I comment out the yield command the errors go away, but of course the data doesn't load.
Please can someone help?
Thank you.

You need to change the return type of Start(), the Start callback supports both void and IEnumerator as it's return types.
IEnumerator Start ()
{
string dataUrl = "http://www.my-site.com/game/test.php";
string playName = "Player 1";
int score = -1;
// Create a form object for sending high score data to the server
var form = new WWWForm();
// Assuming the perl script manages high scores for different games
form.AddField( "game", "MyGameName" );
// The name of the player submitting the scores
form.AddField( "playerName", playName );
// The score
form.AddField( "score", score );
// Create a download object
WWW downloadW = new WWW( dataUrl, form );
// Wait until the download is done
yield return downloadW;
if(downloadW.error == null) {
print( "Error downloading: " + downloadW.error );
return false;
} else {
// show the highscores
Debug.Log(downloadW.text);
}
}
Once the return type is IEnumerator you are allowed to use the yield keyword.
Most callbacks let you return IEnumerator, some that can't are: Awake, Update, LateUpdate, FixedUpdate, OnGUI, OnEnable, OnDisable, OnDestroy. You will need to check the documentation of the event callback to see if it does not support being a co-routine.

yield can not be used in the Start() function, it needs to be called within its own thread, instead try this:
void Start()
{
StartCoroutine(SaveScore());
}
IEnumerator SaveScore()
{
string dataUrl = "http://www.my-site.com/game/test.php";
string playName = "Player 1";
int score = -1;
// Create a form object for sending high score data to the server
var form = new WWWForm();
// Assuming the perl script manages high scores for different games
form.AddField( "game", "MyGameName" );
// The name of the player submitting the scores
form.AddField( "playerName", playName );
// The score
form.AddField( "score", score );
// Create a download object
WWW downloadW = new WWW( dataUrl, form );
// Wait until the download is done
yield return downloadW;
if(!string.IsNullOrEmpty(downloadW.error)) {
print( "Error downloading: " + downloadW.error );
} else {
// show the highscores
Debug.Log(downloadW.text);
}
}

Related

Insert player name with new high score

I'm creating a game with a scoring system, but at the moment the players' names are not included with their high score. The idea is that the player is able to add their name once the game over screen appears and provided they have achieved a new high score.
Initially the system would only save one high score, but now 5 high scores are saved which will be called within a table elsewhere, which is where I would also like the player name to be displayed.
I'm not that familiar with C# so do not know how to incorporate this sort of user input, so I'm happy to hear the available options.
This is my code for the score system:
public class ScoreManager : MonoBehaviour
{
public Text scoreText;
public Text hiScoreText;
public Text gameOverScoreText;
public float scoreCount;
public float hiScoreCount;
public float distance;
public float pointsPerSecond;
public bool scoreIncreasing;
//create array for last 5 high scores
float[] highScores = new float[5];
//create list for scores
public List<float> ScoreHistory;
// Start is called before the first frame update
void Start()
{
//if there is a high score, the game will register it, otherwise it will be 0 - this is for one score
/*if (PlayerPrefs.HasKey("HighScore"))
{
hiScoreCount = PlayerPrefs.GetFloat("HighScore");
}*/
//obtain last 5 scores
ScoreHistory = LoadScoresFromPlayerPrefs(5);
// Set the current high score to be the highest score in the player history - if there is no high score saved, high score will be 0
if (ScoreHistory.Count > 0)
{
hiScoreCount = ScoreHistory[0];
}
else
{
hiScoreCount = 0;
}
}
// Update is called once per frame
void Update()
{
if (scoreIncreasing)
{
//adding points every frame/update => but shows decimals
scoreCount += pointsPerSecond * Time.deltaTime;
//scoreCount += Vector3.Distance(transform.position, camera.position);
}
if(scoreCount > hiScoreCount)
{
hiScoreCount = scoreCount;
//saves value called high score and the hiScoreCount value - not used if saving more than one score
//PlayerPrefs.SetFloat("HighScore", hiScoreCount);
}
//adding text to score
//Mathf.Round rounds scoreCount and hiScoreCount to nearest whole
scoreText.text = "Score: " + Mathf.Round(scoreCount);
hiScoreText.text = "High Score: " + Mathf.Round(hiScoreCount);
gameOverScoreText.text = "Your Score: " + Mathf.Round(scoreCount);
}
//function which needs a number value to take in - can be used more than once
public void AddScore(int pointsToAdd)
{
//adding points to score
scoreCount += pointsToAdd;
}
// Save the current score to the list of scores, and then write them to the player prefs
public void SaveCurrentScore()
{
ScoreHistory.Add(scoreCount);
//put scores in order
ScoreHistory.Sort();
for (int i = 0; i< ScoreHistory.Count; i++)
{
//key is the name of the value being stored
var key = "High Score " + i;
//value is what is being stored (i.e. the high scores) => ScoreHistory is being used as each score is being saved
var value = ScoreHistory[i];
//high scores are being saved using PlayerPrefs
PlayerPrefs.SetFloat(key, value);
}
}
// Loads the scores from the player prefs and returns them in a list of floats
private List<float> LoadScoresFromPlayerPrefs(int maximumNumberOfScoresToLoad)
{
//no visibility modifiers - this is a local variable
List<float> LoadScores = new List<float>();
//loop will run once per score
for (int i = 0; i < maximumNumberOfScoresToLoad; i++)
{
//key is the name of the value being stored
var key = "High Scores " + i;
//will return value of the key if there is one, otherwise will return default value of 0.0
//PlayerPrefs.GetFloat(key);
var score = PlayerPrefs.GetFloat(key);
LoadScores.Add(score);
}
return LoadScores;
}
}
If you want the user to enter a name you'll either have to use
Unity's UI system (e.g. input field) or
code something yourself (e.g. observing Input.inputString after finish), which I would only recommend if you have something like old arcades, allowing only 3 characters.
In both cases you need to be able to detect the end of your user's input with a detectable submit (e.g. return key, or a dedicated UI button). Afterwards you can just store it with the respective points.
To bind the points and name together just add a struct containing both
public struct ScoreData {
public float Score { get; set; }
public string Name { get; set; }
}
and use it for your ScoreHistory
public List<ScoreData> ScoreHistory;
private string playerName; // store the name input by player here
...
public void SaveCurrentScore()
{
ScoreHistory.Add(new ScoreData { Score = scoreCount, Name = playerName });
//put scores in order
ScoreHistory = ScoreHistory.OrderBy(s => s.Score).ToList();
for (int i = 0; i < ScoreHistory.Count; i++)
{
//key is the name of the value being stored
var scoreKey = "High Score " + i;
var nameKey = "High Score Playername " + i;
//value is what is being stored (i.e. the high scores) => ScoreHistory is being used as each score is being saved
var value = ScoreHistory[i];
//high scores are being saved using PlayerPrefs
PlayerPrefs.SetFloat(scoreKey, value.Score);
PlayerPrefs.SetString(nameKey, value.Name);
}
}

Unity freezes for 2 seconds while Microsoft Azure Text-To-Speech processes input

I am using Microsoft Azure Text To Speech with Unity. How it works is when a button is pressed to produce a speech from text input, the whole app freezes for about 2 seconds then outputs the sound and the game resumes back to normal. I assume this freeze is due to Azure is processing TTS? Below is the code.
public void ButtonClick()
{
// Creates an instance of a speech config with specified subscription key and service region.
// Replace with your own subscription key and service region (e.g., "westus").
var config = SpeechConfig.FromSubscription("[redacted]", "westus");
// Creates a speech synthesizer.
// Make sure to dispose the synthesizer after use!
using (var synthsizer = new SpeechSynthesizer(config, null))
{
lock (threadLocker)
{
waitingForSpeak = true;
}
// Starts speech synthesis, and returns after a single utterance is synthesized.
var result = synthsizer.SpeakTextAsync(inputField.text).Result;
// Checks result.
string newMessage = string.Empty;
if (result.Reason == ResultReason.SynthesizingAudioCompleted)
{
// Since native playback is not yet supported on Unity yet (currently only supported on Windows/Linux Desktop),
// use the Unity API to play audio here as a short term solution.
// Native playback support will be added in the future release.
var sampleCount = result.AudioData.Length / 2;
var audioData = new float[sampleCount];
for (var i = 0; i < sampleCount; ++i)
{
audioData[i] = (short)(result.AudioData[i * 2 + 1] << 8 | result.AudioData[i * 2]) / 32768.0F;
}
// The default output audio format is 16K 16bit mono
var audioClip = AudioClip.Create("SynthesizedAudio", sampleCount, 1, 16000, false);
audioClip.SetData(audioData, 0);
audioSource.clip = audioClip;
audioSource.Play();
newMessage = "Speech synthesis succeeded!";
}
else if (result.Reason == ResultReason.Canceled)
{
var cancellation = SpeechSynthesisCancellationDetails.FromResult(result);
newMessage = $"CANCELED:\nReason=[{cancellation.Reason}]\nErrorDetails=[{cancellation.ErrorDetails}]\nDid you update the subscription info?";
}
lock (threadLocker)
{
message = newMessage;
waitingForSpeak = false;
}
}
}
void Start()
{
if (inputField == null)
{
message = "inputField property is null! Assign a UI InputField element to it.";
UnityEngine.Debug.LogError(message);
}
else if (speakButton == null)
{
message = "speakButton property is null! Assign a UI Button to it.";
UnityEngine.Debug.LogError(message);
}
else
{
// Continue with normal initialization, Text, InputField and Button objects are present.
inputField.text = "Enter text you wish spoken here.";
message = "Click button to synthesize speech";
speakButton.onClick.AddListener(ButtonClick);
//ButtonClick();
}
}
I'd like the TTS to ideally not freeze the whole app when the TTS button is pressed, so the app is useable when the TTS button is pressed. Any help would be greatly appreciated.
When you do synthesizer.SpeakTextAsync(inputField.text).Result; it blocks until the task is complete. Instead, try calling Task<SpeechSynthesisResult> task = synthesizer.SpeakTextAsync(inputField.text); then setting up a coroutine that yields until task.IsCompleted() is true then does the rest of the procedure you have in your code
Here's a partial (untested) solution to get you started. I changed the variable to synthesizer from synthsizer, and I removed all the locking because coroutines happen sequentially on the main thread so no locking is necessary:
public void ButtonClick()
{
if (waitingForSpeak) return;
waitingForSpeak = true;
// Creates an instance of a speech config with specified subscription
// key and service region.
// Replace with your own subscription key and service region (e.g., "westus").
SpeechConfig config = SpeechConfig.FromSubscription("[redacted]", "westus");
// Creates a speech synthesizer.
// Make sure to dispose the synthesizer after use!
SpeechSynthesizer synthesizer = new SpeechSynthesizer(config, null));
// Starts speech synthesis, and returns after a single utterance is synthesized.
Task<SpeechSynthesisResult> task = synthesizer.SpeakTextAsync(inputField.text);
StartCoroutine(CheckSynthesizer(task, config, synthesizer));
}
private IEnumerator CheckSynthesizer(Task<SpeechSynthesisResult> task,
SpeechConfig config,
SpeechSynthesizer synthesizer)
{
yield return new WaitUntil(() => task.IsCompleted());
var result = task.Result;
// Checks result.
string newMessage = string.Empty;
if (result.Reason == ResultReason.SynthesizingAudioCompleted)
{
// Since native playback is not yet supported on Unity yet (currently
// only supported on Windows/Linux Desktop),
// use the Unity API to play audio here as a short term solution.
// Native playback support will be added in the future release.
var sampleCount = result.AudioData.Length / 2;
var audioData = new float[sampleCount];
for (var i = 0; i < sampleCount; ++i)
{
audioData[i] = (short)(result.AudioData[i * 2 + 1] << 8
| result.AudioData[i * 2]) / 32768.0F;
}
// The default output audio format is 16K 16bit mono
var audioClip = AudioClip.Create("SynthesizedAudio", sampleCount,
1, 16000, false);
audioClip.SetData(audioData, 0);
audioSource.clip = audioClip;
audioSource.Play();
newMessage = "Speech synthesis succeeded!";
}
else if (result.Reason == ResultReason.Canceled)
{
var cancellation = SpeechSynthesisCancellationDetails.FromResult(result);
newMessage = $"CANCELED:\nReason=[{cancellation.Reason}]\n"+
$"ErrorDetails=[{cancellation.ErrorDetails}]\n"+"
"Did you update the subscription info?";
}
message = newMessage;
waitingForSpeak = false;
synthesizer.Dispose();
}
void Start()
{
if (inputField == null)
{
message = "inputField property is null! Assign a UI InputField element to it.";
UnityEngine.Debug.LogError(message);
}
else if (speakButton == null)
{
message = "speakButton property is null! Assign a UI Button to it.";
UnityEngine.Debug.LogError(message);
}
else
{
// Continue with normal initialization, Text, InputField and Button
// objects are present.
inputField.text = "Enter text you wish spoken here.";
message = "Click button to synthesize speech";
speakButton.onClick.AddListener(ButtonClick);
//ButtonClick();
}
}
In response to the comments, here's a start to an alternative method you could try that wraps the data copying in a task and yields until that task is complete:
private IEnumerator CheckSynthesizer(Task<SpeechSynthesisResult> task,
SpeechConfig config,
SpeechSynthesizer synthesizer)
{
yield return new WaitUntil(() => task.IsCompleted());
var result = task.Result;
// Checks result.
string newMessage = string.Empty;
if (result.Reason == ResultReason.SynthesizingAudioCompleted)
{
// Since native playback is not yet supported on Unity yet (currently
// only supported on Windows/Linux Desktop),
// use the Unity API to play audio here as a short term solution.
// Native playback support will be added in the future release.
Task copyTask = Task.Factory.StartNew( () =>
{
var sampleCount = result.AudioData.Length / 2;
var audioData = new float[sampleCount];
for (var i = 0; i < sampleCount; ++i)
{
audioData[i] = (short)(result.AudioData[i * 2 + 1] << 8
| result.AudioData[i * 2]) / 32768.0F;
}
// The default output audio format is 16K 16bit mono
var audioClip = AudioClip.Create("SynthesizedAudio", sampleCount,
1, 16000, false);
audioClip.SetData(audioData, 0);
audioSource.clip = audioClip;
audioSource.Play();
});
yield return new WaitUntil(() => copyTask.IsCompleted());
newMessage = "Speech synthesis succeeded!";
}
else if (result.Reason == ResultReason.Canceled)
{
var cancellation = SpeechSynthesisCancellationDetails.FromResult(result);
newMessage = $"CANCELED:\nReason=[{cancellation.Reason}]\n"+
$"ErrorDetails=[{cancellation.ErrorDetails}]\n"+"
"Did you update the subscription info?";
}
message = newMessage;
waitingForSpeak = false;
synthesizer.Dispose();
}

assigning and moving instances in a array

void InsertScoreAndLeaderBoard(int pointageCurrent, string nameCurrent)
{
int savePosition;
string saveName;
if (IsBetterScore(pointageCurrent))
{
for (int i = 0; i < leaderBoardNum.Length; i++)
{
if (pointageCurrent > leaderBoardNum[i])
{
savePosition = leaderBoardNum[i] ;
saveName = leaderBoardName[i];
leaderBoardNum[i] = pointageCurrent;
leaderBoardName[i] = nameCurrent;
for (int j = leaderBoardNum.Length; j > 0; j--)
{
}
}
}
}
}
so i am kinda stuck in this code i am trying to write. I have to put a username and his score to this leader board. The thing is that i never modified an array in a way so, for example, if i replace the 2nd place with the current numbers and name, the ancient score and name is transferred to 3rd place and the old score of the 3rd place moves to 4th place and so on. The only data that has to be destroyed while moving the arrays is the last place (or position 0).
As in the comments, using arrays for this purpose is probably not a correct choice. It will make your code unreadable/complex.
There may be a valid case of using an array for this purpose: when you are trying to be very memory efficient and performance is crucial.
Suggested solutions (Lists, LINQ) allow clean (easy to read and maintain) code, but add some overhead.
Here's a sample console app, which shows how it could be done with an array, to be memory efficient (first) and also fast (second):
using System;
namespace ScoreBoardApp
{
// How a single scoreboard entry looks like.
struct ScoreboardEntry
{
public ushort scoredPoints;
public string playerName;
public ScoreboardEntry( ushort points, string name )
{
scoredPoints = points;
playerName = name;
}
}
public class Program
{
// This is our scoreboard array. Most games start with fake entries,
// to set some expectations, so are we. (Make sure you order them
// correctly here and the data is clean and neat.)
// To start empty use:
// scoreboard = new ScoreboardEntry[10];
private readonly ScoreboardEntry[] scoreboard = new [] {
new ScoreboardEntry( 7777, "Winner" ),
new ScoreboardEntry( 6666, "Hans" ),
new ScoreboardEntry( 5555, "Anna" ),
new ScoreboardEntry( 4444, "Sven" ),
new ScoreboardEntry( 3333, "Elsa" ),
new ScoreboardEntry( 2222, "Kurt" ),
new ScoreboardEntry( 1111, "Ollie" ),
new ScoreboardEntry( 999, "Bertha" ),
new ScoreboardEntry( 888, "Joana" ),
new ScoreboardEntry( 777, "Javaid" )
};
// What to show, when no player name given.
private const string playerNamePlaceholder = "<none>";
// In case we need to start from scratch.
public void ClearBoard()
{
// We could just do (after we strip "readonly" from our field):
// scoreboard = new ScoreboardEntry[scoreboard.Length];
// But this way we're re-using memory, and are still relatvely
// fast:
for (var i = 0; i < scoreboard.Length; i++)
scoreboard[i] = new ScoreboardEntry();
}
// This shows current state of the scoreboard (not very fast
// nor efficient).
public void PrintScoreboard()
{
Console.WriteLine("---+-----------------+-------");
Console.WriteLine("{0,2} | {1,-15} | {2,6}", "#", "Name", "Score");
Console.WriteLine("---+-----------------+-------");
var len = scoreboard.Length;
for (var i = 0; i < len; i++)
Console.WriteLine(
"{0,2:N0} | {1,-15} | {2,6:N0}",
i + 1,
scoreboard[i].playerName ?? playerNamePlaceholder,
scoreboard[i].scoredPoints
);
Console.WriteLine("---+-----------------+-------");
}
// This checks if the player's score reached the scoreboard
// tells us so, and if yes, then places his entry on the board.
// Should be quite efficient & fast (apart from console output).
public void RecordScore(ushort playerScore, string playerName)
{
// Cleaning the input data.
if (playerName != null)
{
// TODO: Deal with pesky control characters inside!
playerName = playerName.TrimStart();
playerName = playerName.Substring(0, Math.Min(15, playerName.Length)).TrimEnd();
}
if (string.IsNullOrWhiteSpace(playerName))
playerName = null;
// Let's compare to the last scoreboard entry.
var place = scoreboard.Length - 1;
if (playerScore <= scoreboard[place].scoredPoints)
{
Console.WriteLine(
"{0} did not make it with score {1:N0}",
playerName ?? playerNamePlaceholder,
playerScore
);
return;
}
// We'll go from bottom, to the top, to find correct landing
// spot, and at the same time, move the beaten entries down.
while (place > 0 && playerScore > scoreboard[place - 1].scoredPoints)
{
place--;
scoreboard[place + 1] = scoreboard[place];
}
// Let's record our winner.
scoreboard[place].scoredPoints = playerScore;
scoreboard[place].playerName = playerName;
Console.WriteLine(
"{0} is #{1:N0} with score {2:N0}",
playerName ?? playerNamePlaceholder,
place + 1,
playerScore
);
}
// Let's play.
public static void Main(string[] args)
{
var p = new Program();
// Initial state.
p.PrintScoreboard();
// This player should not reach the board.
p.RecordScore(666, null);
p.PrintScoreboard();
// This one scored same as the #10, which is not enough.
p.RecordScore(777, "Almost there");
p.PrintScoreboard();
// This one should land as #5.
p.RecordScore(4000, " Fifth ");
p.PrintScoreboard();
// This is the #1.
p.RecordScore(ushort.MaxValue, "Best !!!!!!!!!!!!!!!!!!!!!!!");
p.PrintScoreboard();
// No app is considered worthy, without accepting some user
// input. This one uses execution parameters.
if (args.Length >= 1 && args.Length <= 2)
{
ushort score = 0;
string name = null;
if (ushort.TryParse(args[0], out score))
{
if (args.Length > 1)
name = args[1];
p.RecordScore(score, name);
p.PrintScoreboard();
}
else
Console.Error.WriteLine("Give <score> and <name> as parameters.");
}
// Let's sweep everything before we go to sleep.
p.ClearBoard();
p.PrintScoreboard();
}
}
}
To make it faster, but a bit less efficient, we could use a class instead of a struct (and adjust code accordingly).

How to make coroutines run in order?

This is using Unity3D. I have three coroutines: GetJSONFromSelectedSubreddit(), LoadMoreMemes(), and a function in a separate script that needs to be able to access the array of memes through the GetNewMemes() function (must return type Meme[]). LoadNewMemes() produces. The thing is, LoadMoreMemes() requires the json to work, so they have to run in the mentioned order. If you need the functions, here they are:
public void GetNewMemes(string subReddit, int count)
{
SetSelectedSubreddit(subReddit);
memesAtATime = count;
subJSON = null;
StartCoroutine(GetJSONFromSelectedSubreddit());
StartCoroutine(LoadMoreMemes());
}
IEnumerator GetJSONFromSelectedSubreddit()
{
gettingJSON = true;
WWW requester = new WWW("https://www.reddit.com/r/" + selectedSub + "/new.json?sort=new&count=25&after=" + postIndex);
yield return requester;
subJSON = requester.text;
json = new JSONObject(subJSON);
gettingJSON = false;
}
IEnumerator LoadMoreMemes()
{
while (gettingJSON)
yield return new WaitForSeconds(0.1f);
for (int i = 0; i < memesAtATime; i++)
{
yield return StartCoroutine(GetUserPostKarma(json["data"]["children"][i]["data"]["author"].str));
string sourceURL = json["data"]["children"][i]["data"]["preview"]["images"][0]["source"]["url"].str;
sourceURL = sourceURL.Replace("&", "&");
yield return StartCoroutine(GrabImage(sourceURL));
Meme currentMeme = new Meme(
json["data"]["children"][i]["data"]["preview"]["images"][0]["source"]["url"].str,
authorPostKarma,
(int) json["data"]["children"][i]["data"]["score"].i,
json["data"]["children"][i]["data"]["permalink"].str,
json["data"]["children"][i]["data"]["title"].str,
currentBitmap
);
Debug.Log(currentMeme.cost);
memes[i] = currentMeme;
}
}
Here's the other script:
void Start ()
{
RedditCommunicator redditCommunicator = GetComponent<RedditCommunicator>();
redditCommunicator.GetNewMemes("me_irl", 1);
Meme[] memes = redditCommunicator.GetCurrentMemes();
Debug.Log(memes[0].currentScore);
redditCommunicator.SpawnOneMeme(memes[0]);
}
Each function works fine on its own, but they need to wait for each other to finish, as well as run in the correct order to work. I'd like the functions to stay separate so I can call them individually in the future. memes is a private variable, and the one I'd like to pass to the other script calling these functions. If you don't think I've tried my options Googling and solving this on my own, just believe me, I've done my best. Thanks for your help in advance. If you need more information, just ask me for it. The current state of this code is it returns memes to early, before the coroutines can finish, resulting in empty memes.
You can yield a Coroutine in an IEnumerator which will halt the progression of that Coroutine until that Coroutine is done. Like this:
void Start()
{
StartCoroutine(DoThings((text) => {
Debug.Log("Dothings told me: " + text);
}));
}
IEnumerator DoThings(Action<string>() callback)
{
yield return StartCoroutine(DoThisFirst());
callback("Returning a value mid-method!");
yield return StartCoroutine(ThenThis());
Debug.Log(3);
}
IEnumerator DoThisFirst()
{
yield return new WaitForSeconds(1);
Debug.Log(1);
}
IEnumerator ThenThis()
{
yield return new WaitForSeconds(1);
Debug.Log(2);
}
Problem is that GetJSONFromSelectedSubreddit and LoadNewMemes methods are called as two "parallel" coroutines in GetNewMemes method.
If you do not need to run a coroutine "asynchronously", you can just enumerate through it:
public void GetNewMemes(string subReddit, int count)
{
SetSelectedSubreddit(subReddit);
memesAtATime = count;
subJSON = null;
var enumerator = GetJSONFromSelectedSubreddit();
while (enumerator.MoveNext());
enumerator = LoadNewMemes();
while (enumerator.MoveNext());
}

Wait while file load in Unity

How I can load and return file from another method(use WWW)?
I want to do next:
Method GetSettings(). Download file text, parse json and
return result.
Call method from Start() and wait while GetSettings() return result.
How I can do this?
Looks like you want to downloaded data then wait then wait for the download to finish then download another data. If this is true the you can the code below will download data 2 times. You can increase the number of times by increasing the REQ_AMOUNT value.
It uses yield return StartCoroutine to wait for the current coroutine function to return before running again.
IEnumerator Start()
{
int REQ_AMOUNT = 2;
for (int i = 0; i < REQ_AMOUNT; i++)
{
yield return StartCoroutine(GetSettings());
}
}
IEnumerator GetSettings()
{
string url = RoomSettings.AbsoluteFilenamePath;
if (Application.isEditor)
{
url = "file:///" + url;
}
var www = new WWW(url);
yield return www;
// Do some code, when file loaded
}

Categories

Resources