Select Random line from Text File and display on unity - c#

I was creating a form which contains contact details on unity for a game. I managed to connect text file with unity and write lines to it but I am not sure how to get a random person from text file and display it on unity. If someone has any idea about this please help me out..

If you link your file via e.g
public TextAsset file;
then you could e.g. do
private string GetRandomLine()
{
var lines = file.text.Split('/n');
var randomIndex = Random.Range(0, lines.Length);
return lines[randomIndex];
}
Or if you use system FileIo you can do
var lines = File.ReadAllLines(path);
var randomIndex = Random.Range(0, lines.Length);
return lines[randomIndex];
Of course you might want to cache the file content and lines somewhere etc but I hope the idea gets clear.

Related

Empty array if strings in c# for unity game

I am trying to empty and array of strings every-time a user clicks on load profiles so that the array doesn't get over populated with the same profiles over and over again every time they click load.
This is my array:
string[] files;
This is how i get the profiles but i need to empty it whenever getProfiles is called so it doesn't over populate with duplicate profiles
private void GetProfiles()
{
//Check if directory with saved profiles exists
if (Directory.Exists(filePath))
{
//Clear files array
//Get all of the file paths of each file in this directory
files = Directory.GetFiles(filePath);
//profileTileTemplate.SetActive(true);
//Go through each file and read the data and create a profile for each json file
for(int i = 1; i <= files.Length -1; i++)
{
string json = File.ReadAllText(files[i]);
Profile savedProfile = JsonUtility.FromJson<Profile>(json);
Instantiate(profileTileTemplate,LoadProfileTransform);
profileTileTemplate.SetActive(true);
profileTileTemplate.GetComponentInChildren<Text>().text = savedProfile.playerName;
Debug.Log(savedProfile.playerName);
}
}
}
how do i clear this array?
I have tried setting it to null but it doesn't work.
Question is not clear, but if you want to empty the array and stay with the same length then you can write this wherever you want to.
files = new string[files.Length];
As said I don't think this is related to the array at all .. GetFiles everytime returns a new array there are no duplicates.
However, you Instantiate a bunch of objects into the scene and never destroy them!
You could do this first
foreach(Transform child in LoadProfileTransform)
{
Destroy (child.gameObject);
}
and then you could simply do
foreach(var path in files)
{
var json = File.ReadAllText(path);
var savedProfile = JsonUtility.FromJson<Profile>(json);
var obj = Instantiate(profileTileTemplate,LoadProfileTransform);
obj.SetActive(true);
obj.GetComponentInChildren<Text>().text = savedProfile.playerName;
Debug.Log(savedProfile.playerName);
}
since you want to apply the text etc to the newly instantiated objects, not the original prefab.

Importing each line from text file from Resources in Unity to list in C#

I have a text file in my Assets/Resources/Text, on Start() I want to import each line from the text file as a string in list. Using this code does it for me,
string[] AllWords = File.ReadAllLines(#"C:\Users\jamal\Downloads\English\english-words-master\New folder\AllWords.txt");
listOfWords = new List<string>(AllWords);
But how do I do the same when the file is in my Resources folder, I can't seem to use File.ReadAllLines.
Any help would be of great help, thank you!
The text file contains all the words in a dictionary, here's how the text file goes:
aahed
aahing
aahs
aal
aalii
aaliis
aals
aam
aani
aardvark
aardvarks
aardwolf
aardwolves
aargh
aaron
aaronic
aaronical
aaronite
aaronitic
To begin with Don't use Reources!
If against Unity's own recommendation you still want to do it for some reason then you have to load that resource using Resources.Load in your case as a TextAsset like e.g.
// assuming your path is e.g. "Assets/Resources/Text/AllWords.txt"
var file = Resources.Load<TextAsset>("Text/AllWords");
var content = file.text;
var AllWords = content.Split("\n");
listOfWords = new List<string>(AllWords);
The better approach though would probably be to listen to what Unity recommends and instead of using Resources at all rather place your file into the Assets/StreamingAssets folder and access it later via Application.streamingAssetsPath
either using as you did
string[] AllWords = File.ReadAllLines(Path.Combine(Application.streamingAssetsPath, "AllWords.txt");
listOfWords = new List<string>(AllWords);
Or - depending on the platform, e.g. in Android you can't directly access the StreamingAssets
StartCoroutine(LoadWords());
...
private IEnumerator GetRequest()
{
var url = Path.Combine(Application.streamingAssetsPath, "AllWords.txt");
using (var webRequest = UnityWebRequest.Get(url))
{
// Request and wait for result
yield return webRequest.SendWebRequest();
switch (webRequest.result)
{
case UnityWebRequest.Result.Success:
var content = webRequest.downloadHandler.text;
var AllWords = content.Split("\n");
listOfWords = new List<string>(AllWords);
break;
default:
Debug.LogError($"Failed loading file \"{url}\" - {webRequest.error}", this);
break;
}
}
}
You could actually also simply put your file into a "normal" folder like Assets/AllWords.txt and then directly reference it via the Inspector in a
public TextAsset file;
or
[SerializeField] private TextAsset file;
and then access the content via
var content = file.text;
var AllWords = content.Split("\n");
listOfWords = new List<string>(AllWords);

iPad can't read text file

In my Unity3D project I have several text fields. I saved my text in some text files.
When I test my project on the computer everything works fine, and my code reads the text files. But if I upload to my iPad it won't work and the text fields stay empty.
In the image you can see where I have saved my text files.
To read my text files I use the following code:
public Text infoText;
void Update()
{
readTextFile("FileName", "StepNumber")
}
public void readTextFile(string fileName, string stepNumber)
{
StreamReader txt_Reader = new StreamReader("Assets/Resources/Text_Files/" + fileName + ".txt");
while(!txt_Reader.EndOfStream)
{
string txt_String = txt_Reader.ReadLine();
if(txt_String.Contains(stepNumber))
{
string[] separator = { "_" };
string[] strList = txt_String.Split(separator, System.StringSplitOptions.RemoveEmptyEntries);
infoText.text = string.Join("\n", strList.Skip(1));
}
}
}
What do I have to change that my iPad can read from the text files?
EDIT:
My text files looks like this:
Step 1:
* Some Text
* Some Text
Step 2:
* Some Text
* Some Text
* Some Text
Step 3:
* Some Text
Step 4:
* Some Text
So each * should be a new line in my text field. With my old c# code this was no problem, but with
var lines = textFiles.text.Split(new char[] { `*` });
foreach(var line in lines)
{
...
}
i do not know how I can do that, that my text field shows all two lines for step one.
First of all from the Best Practices for the Resources folder
**Don't use it!
Please read the reasons there.
In general for system paths do never use simple string concatenation + "/" +!
Rather use Path.Combine which automatically uses the correct path separators according to the executing platform
Path.Combine(Application.dataPath, "Resources", "Text_Files", fileName + ".txt");
However, you don't/can't simply use a StreamReader to access the Resources folders (See Resources API since it is packed into the build so you have to go through Resources.Load like
// Here you can use / since this is how Unity stores internal paths
// for load you omit the suffix
TextAsset textFile = Resources.Load<TextAsset>("Text_Files/" + filename);
string fileContent = textFile.text;
Or also have a look at Resources.LoadAsync to not block the main thread meanwhile.
BUT
Speaking about blocking the main thread: What you definitely do not want to do is using any of these within Update thus doing heavy FileIO/Loading every frame!
Store the content of that file once as it won't change afterwards anyway!
Depending on your needs you could also simply put your file in any other folder inside the Assets and simply use a TextAsset field directly and drag it into according slot via the Inspector
public TextAsset textFile;
Finally you can then go through the lines one by one using e.g.
var lines = textFile.text.Split(new char[]{'/n'});
foreach(var line in lines)
{
...
}
Note that also that Split is a quite heavy operation since it has to parse every single character in the string and create new substrings so even store these results somewhere in a field of you need them multiple times during runtime!
Typed on smartphone but I hope the idea gets clear
In your case, StreamReader txt_Reader = new StreamReader("Assets/Resources/Text_Files/" + fileName + ".txt"); points to a file on your computer. Assets/Resources/Text_Files/ only exists on your computer.
You need to access a folder that exists on your iPad. It's likely you also didn't save your data to a folder existing on your IPad.
For other devices you could use : Application.persistentDataPath + "/" + fileName
Source: https://docs.unity3d.com/ScriptReference/Application-dataPath.html

Get Music files details only

Basically I am trying to get the details of a music file inside an android device (Ex. The music's title, artist, etc) and store them to a list<>. (SongData contains the list, and it contains a list of Song object.)
public void PopulateSongList(Context context) {
SongData songData = new SongData();
Android.Net.Uri musicUri = Android.Provider.MediaStore.Audio.Media.ExternalContentUri;
//Used to query the media files.
ICursor musicCursor = context.ContentResolver.Query(musicUri, null, null, null, null);
if (musicCursor != null && musicCursor.MoveToFirst())
{
int songID = 0;
//get columns.
int songTitleColumn = musicCursor.GetColumnIndex("title");
int songArtistColumn = musicCursor.GetColumnIndex("artist");
//add songs to list
do
{
String songTitle = musicCursor.GetString(songTitleColumn);
//Tried, but file name does not contain file extension.
if (songTitle.ToLower().Contains(".mp4") || songTitle.ToLower().Contains(".m4a"))
{
String songArtist = musicCursor.GetString(songArtistColumn);
songData.AddNewSong(new Song(++songID, songTitle, songArtist, null));
}
}
while (musicCursor.MoveToNext());
}
}
The code works well but however in the do..while loop, songTitle also contains other files that are not music files as well.
I tried checking for file extensions but it does not work, and after using the debugger again, the file name given does not contain the file extension.
So how do I make sure that it only grabs details from a music file, and not other kind of files?
(Also, I want to grab the name of the artist of a music file, but apparently int songArtistColumn = musicCursor.GetColumnIndex("artist"); does not seem to work.)
Finally, how do I get the image of a music file? (The song image).
You can try to use musicCursor.GetColumnNames() to see what the file is allowing you to work with.
Here's an image of the possible results you can get if you execute it.
musicCursor.GetColumnNames() will return the results in a string[] so you can use List<string> songInfo = new List<string>(string[]);
A problem you might get is a NullException, this happens when the data you're trying to work with have a value of null. You'll get this value directly from the file if the Artist or other values are unknown.
I don't know where the Image file is stored, but if it's stored with the music file it will most likely be stored in a byte[]. So you'll need to convert the byte[] to an image.

How to read data from Unity3D's prefab file?

So, I am trying to create an test application for online Unity game but to do what I need it to do, I must read datas from a hex offset located in a .prefab file.
And then, i will load prefabs on server-side from data. For an anti-collider hack from client-side.
I must read datas like unityVer, localScale, localPosition, localSize, collider size... etc.
Edit: I must make it on a simple console application, not in Unity.
My not working code :
try {
string[] prefabFiles = Directory.GetFiles(Path.Combine(Environment.CurrentDirectory, "data\\prefabs\\"));
foreach (var prefab in prefabFiles) {
if (prefab != null && prefab.Split('.')[1] == "prefab") {
try {
using (var reader = new BinaryReader(new FileStream(prefab, FileMode.Open, FileAccess.Read))) {
FileInfo info = new FileInfo(prefab);
Console.WriteLine("Analyzing File : " + info.Name);
reader.BaseStream.Position = 0xA;
//string unityVer = reader...
//float localPositionX = reader...
//float localPositionY = reader...
//float localPositionZ = reader...
//float localScaleX = reader...
//float localScaleY = reader...
//float localScaleZ = reader...
//float colliderRadius = reader...
}
Console.WriteLine("File parse success.");
} catch { Console.WriteLine("Parse error in the data file."); }
}
}
} catch (Exception e_Ex) {
Console.WriteLine(e_Ex.ToString());
}
My Prefab's Hex Tree:
HEX TREE IMAGE
I am new to reading and writing data located in a hex data location so any help would be awesome!
A partial answer would be to save assets as YAML text files instead of binary. That format is human readable, which makes it much easier to decode. Under Project Settings -> Editor, there's Asset Serialization, which should be set to Force Text. Of course all existing assets are going to be re-imported and existing builds will have to be re-deployed.
I think you are trying too hard or I misunderstood your point.
When you have a prefab that is referenced in your project, Unity will create an instance of it, it just won't show in the scene and is kept internally. Then when you use Instantiate with it, it will duplicate all info and data.
That means you can access info on prefab the same way you would access them on any game object:
public GameObject myPrefab;
void Start(){
Debug.Log(myPrefab.transform.position);
Collider col = myPrefab.GetComponent<Collider>();
// Use Collider
}

Categories

Resources