How to create custom 3D name using c# script in Unity 3D - c#

I'm stuck on a c# scripting problem in Unity that I would like to solve.
This is what I want to achieve:
Enter a name on an InputField
Get Characters from the Input field
For each Character: set the 3D GameObject of the Character already created in the Hierarchy
SetCharacterPosition next to each other so they can create a name
SetMaterial in this order (Blue, Green,Red,Yellow) and start over
View the given input name in a 3D Colored way on the screen
This is what I have done so far:
Created 3D Prefabs of each Character and loaded into Hierarchy
Created the GUI with an InputField and a Button (+Script)
Create a Button Script (button_scr) in order to get the name and split into Characters
GUI
SCRIPT button_scr
public class button_scr : MonoBehaviour
{
public Button myButton;
public InputField un;
public GameObject go;
void Start ()
{
myButton = GetComponent<Button>();
myButton.onClick.AddListener(ProcessText);
}
void ProcessText()
{
Debug.Log("Your name is : "+un.text);
getCharacters(un.text);
}
void getCharacters(string text)
{
foreach (char c in text)
{
go = GameObject.Find(""+char.ToUpper(c));
go.SetActive (true);
// setPosicionNext2EachOther
// setColoredMaterial(Blue,Green,Red,Yellow) in this order
Debug.Log("GameObject name Log: "+go.name);
}
}
}
Some considerations:
Names can have some repeated Characters
Names can have accent marks on vowels (Á, É,Í,Ó,Ú)
Names can have "ñ" character
This is where I would like to get some orientation in order to solve the problem:
I have considered creating and filling a GameObject Array with all
the references of each character like so:
GameObject[0] = A 3D Character prefab
GameObject[1] = B 3D Character prefab
Then create a for loop to find the name character in the GameObject Array and make a copy in order to setup in the game
Set 3D character position
Set Material to 3D character in a sequential order (Blue,Green,Red,Yellow)
Is there any easier way to do this that I'm missing?
I would like to get some orientation/advice or some sample code where I can check similar issue solving.

this is a quick solution. not tested. i dont have unity installed. just for you to have an idea.
Yes. is better to assign all the letters in a array for optimization. Also deactivate all the letters in Awake()
public Material materials[]; // assign the materials in the order you want
public void getCharacters (string name)
{
int materialIndex = 0;
for (int i = 0; i < text.lenght; i++)
{
char c = char.ToUpper(text[i]);
GameObject go = GameObject.Find("" + c);
go.SetActive (true);
go.transform.position = new Vector3(i, 0, 0); // place the letters in the x axis separated by one meter
// change the material
go.GetCOmponent<Renderer>().sharedMaterial = materials[materialIndex];
materialIndex = (materialIndex + 1) % materials.length; // cycle the materials
// setPosicionNext2EachOther
// setColoredMaterial(Blue,Green,Red,Yellow) in this order
//Debug.Log("GameObject name Log: "+go.name);
}
}

Related

Spawn in 2 different prefabs over a network Unity PUN 2

I am making an online multiplayer game. Once both players are ready, 2 DIFFERENT character prefabs are spawned into a room. The problem is that each player's device can't seem to read information about the other player's character.
They're spawned using the following code:
public class GameplayManager : MonoBehaviour
{
public PhotonView view;
public string BlueName;
public string GreenName;
public GameObject BluePlayer;
public GameObject GreenPlayer;
public Vector2 BlueSpawnPos = new Vector2(4.07f, 0.02f);
public Vector2 GreenSpawnPos = new Vector2(3.97f, -0.02f);
public void Start()
{
InstantiatePlayers();
BluePlayer = GameObject.Find("blue soldier(Clone)");
BlueName = PhotonNetwork.LocalPlayer.NickName;
GreenPlayer = GameObject.Find("green soldier(Clone)");
GreenName = PhotonNetwork.LocalPlayer.NickName;
VictoryText = GameObject.Find("VictoryText").GetComponent<Text>();
}
public void InstantiatePlayers()
{
//If player 1:
if (PhotonNetwork.LocalPlayer.ActorNumber == 1)
{
BluePlayer = PhotonNetwork.Instantiate(BlueSoldier.name, BlueSpawnPos, Quaternion.identity);
Debug.Log("bname" + BlueName);
}
//if player 2:
if (PhotonNetwork.LocalPlayer.ActorNumber == 2)
{
GreenPlayer = PhotonNetwork.Instantiate(GreenSoldier.name, GreenSpawnPos, Quaternion.identity);
Debug.Log("gname" + GreenName);
}
}
I run this using the Unity Editor and a build to test. When I check the inspector in the editor, the 'Player' and 'Name' variables for the colour character in the editor have been updated correctly, but that of the other copy of the game are empty (i.e. if the editor is blue, 'BlueName' and 'BluePlayer' will be updated but 'GreenName' will be empty and 'GreenPlayer' will be 'None').
I suspect it's to do with my using if statements to spawn in characters, but I don't know if there's another way of spawning in multiple prefabs for multiple players.

How can I change one material texture in an array?

How can I change one material in an array?
I've imported a Daz figure into unity, all of the materials are stored in an array for the figure.
I'm trying to change the texture of the Irises with the click of a button.
The code below does change the material but only on the first material in the array. I've attempted to alter the code to change the Irises, but I have been unable to.
{
//Component
private Renderer _rendereyes;
//Game Object
public GameObject eyes;
//etc
public Object[] texEyes;
public int texID;
// Start is called before the first frame update
void Start()
{
//Get Component
_rendereyes = eyes.GetComponent<Renderer>();
//Change eye tex
string texPath = "Textures";
texEyes = Resources.LoadAll(texPath, typeof(Texture2D));
}
public void SetEyeTexture()
{
if (texID < texEyes.Length - 1)
{
texID++;
}
else
{
texID = 0;
}
_rendereyes.material.SetTexture("_DiffuseMap",(Texture2D)texEyes[texID]);
}
Here is the 2nd iteration of the code which is my attempt to alter the Irises texture.
{
//Component
private Renderer[] _rendereyes;
//Game Object
public GameObject eyes;
//etc
public Object[] texEyes;
public int texID;
// Start is called before the first frame update
void Start()
{
//Get Component
_rendereyes = eyes.GetComponent<Renderer[]>();
//Change eye tex
string texPath = "Textures";
texEyes = Resources.LoadAll(texPath, typeof(Texture2D));
}
public void SetEyeTexture()
{
if (texID < texEyes.Length - 1)
{
texID++;
}
else
{
texID = 0;
}
_rendereyes[15].material.SetTexture("_DiffuseMap",(Texture2D)texEyes[texID]);
}
What is the best way to change the Irises texture?
First of all in general avoid using Resources at all. (See Best practices -> Resources)
Don't use it!
Then if you use it and in general I would be more specific and do
public Texture2D[] texEyes;
and then
texEyes = Resources.LoadAll<Texture2D>(texPath);
or rather simply drag and drop them into the slots via the Inspector
And finally
GetComponent<Renderer[]>
makes no sense. You always want to either get a single component or use GetComponents.
However, it sounds like you actually have only one single object with one single Renderer and want to stick to
_rendereyes = eyes.GetComponent<Renderer>();
or directly make it
[SerializeField] private Renderer _rendereyes;
and drag the object into the slot in the Inspector.
And then rather access the according index from Renderer.materials.
And then you have a little logical mistake in your SetEyeTexture method.
You do
if (texID < texEyes.Length - 1)
{
texID++;
}
which might result in texID = texEyes.Length which will be out o bounds since in c# all indices go from 0 to array.Length - 1.
Your code should rather look like
public void SetEyeTexture()
{
// Simple modulo trick to get a wrap around index
texID = (++texID) % texEyes.Length;
// Note that according to your screenshot the Material "Irises" is at index 14 not 15!
_rendereyes.materials[14].SetTexture("_DiffuseMap", texEyes[texID]);
}

Different game objects with their respective collider that comes with different score

I have a Game Manager script with a Ball Class attached in it that consists of different information of balls and another script that attached to the ball (game object) to detect collision. (Two scripts in total) So when the player collides with the balls, their respective scores will be counted.
public string[] ballColor;
public int[] score;
Assume there are three balls at the beginning and here are the inputs:
Green Ball - 2 pts
Red Ball - 3 pts
Yellow Ball - 5 pts
Here is the collision script attached to the game object:
public void Start()
{
GameObject gameManager = GameObject.Find("GameManager");
GameManager Ball = gameManager.GetComponent<GameManager>();
ball_color = Ball.ballColor[count];
ball_score = Ball.score[count];
}
public void OnPointerClick(PointerEventData eventData)
{
if (ball_color.Contains(gameObject.tag))
{
//Debug.Log("Yes");
score = ball_score;
GameManager.instance.PlayerScore += score;
Destroy(gameObject);
count = 0;
}
else
{
//Debug.Log("No");
count++;
}
}
Game Manager script:
private int playerScore;
public string[] animalName;
public int[] animalScore;
public int PlayerScore
{
get
{
return playerScore;
}
set
{
playerScore = value;
scoreText.SetText("Score: " + playerScore);
}
}
I realize there is a communication problem between these two scripts.
The game manager script is only passing the first value in the string array to the collision script and not updating afterwards, which means the point is always stuck on the first one.
The same goes for the ball_color information, only the first value in the string array is passed to the collision script and not updating afterwards, which means the color is always stuck on the first one.
As I would like to keep changing the points and colors of the balls whenever I want in the Unity editor without entering the visual studio afterwards.
How do I make the collision script gets the correct points of their respective balls without attaching individual scoring script onto each single game object and also without repeating the same if(gameobject.tag == "Green") comparison?

Attach Custom Class To A Newly Instantiated Object

I'm trying to instantiate multiple objects called Stars. In my Simulation class, I have a method where I am creating an object called newStar and attaching the class Star.
Here is my GameObject hierarchy:
The Simulation script, which has the Simulation class is attached to the Simulation gameobject. The Star script which has the Star class is attached to the StarObject gameobject. Within the Star script, I've attached both the prefab of the star to prefabStar and the StarObject gameobject has been attached to the StarObject variable through the Unity editor.
Here is my Simulation class: (ObjectStar is a GameObject which is the parent of the prefabStar.
void listStars()
{
int i = 0;
while (i < (StarDataBank.Instance.NumOfStars))
{
int primaryID = int.Parse(StarDataBank.Instance.StarIDID[i]);
string properName = StarDataBank.Instance.StarName[i];
string HIPID = StarDataBank.Instance.StarIDHIP[i];
string HDID = StarDataBank.Instance.StarIDHD[i];
string HRID = StarDataBank.Instance.StarIDHR[i];
string GLID = StarDataBank.Instance.StarIDGL[i];
string BFID = StarDataBank.Instance.StarIDBF[i];
decimal rightAscension = Convert.ToDecimal(StarDataBank.Instance.StarRA[i]);
decimal declination = Convert.ToDecimal(StarDataBank.Instance.StarDec[i]);
decimal Mag = Convert.ToDecimal(StarDataBank.Instance.StarMag[i]);
decimal CI = Convert.ToDecimal(StarDataBank.Instance.StarCI[i]);
int scale = 0;
int r = 0;
int g = 0;
int b = 0;
Star newStar = ObjectStar.AddComponent<Star>();
newStar.Instantiate(primaryID, properName, HIPID, HDID, HRID, GLID, BFID, rightAscension, declination, Mag, CI);
i++;
}
}
Here is the Star class:
public void Instantiate(int primaryID, string properName, string HIPID, string HDID, string HRID, string GLID, string BFID, decimal rightAscension, decimal declination, decimal magnitude, decimal colourIndex)
{
this.primaryID = primaryID;
this.properName = properName;
this.HIPID = HIPID;
this.HDID = HDID;
this.HRID = HRID;
this.GLID = GLID;
this.BFID = BFID;
this.rightAscension = rightAscension;
this.declination = declination;
this.magnitude = magnitude;
this.colourIndex = colourIndex;
var newStar = Instantiate(prefabStar, transform.position + getVector(Convert.ToDecimal(rightAscension), Convert.ToDecimal(declination)), Quaternion.identity);
newStar.name = (primaryID).ToString();
newStar.transform.parent = StarObject.transform;
newStar.transform.localScale = new Vector3(20, 20, 20);
}
My desired intention is to create a clone of the prefabStar, with each clone attached to the Star class, so I can retrieve the variables of each clone of the prefabStar.
Instead, what's happening is I'm getting an error that reads "The Object you want to instantiate is null." and there are no new gameobjects (prefabStar isn't being cloned.)
EDIT: I have added a screengrab of the Star prefab in the editor,
Notice how the Star class is attached to this prefab. (Please ignore the name Star Manager, I was doing a few tests, the problem still persists with it called Star)
Check the editor again and try to look if the prefab you've attached is still visible in the game editor upon starting the game. Maybe mistakenly you've attach it in the editor while being in game-mode.
Also if you've made your change in the edit mode to your object that is also a prefab you need to apply the changes to your prefab by clicking on Apply button, that will be located most probably in the upper right corner of your editor.
From the screenshot that you've posted I would choose the prefab that is in question from the bottom part of your screen. Upon selection the right side panel should change to show your prefab data. Then I would lock the right side panel by clicking on little lock icon that is visible at the top. While locked just press and drag your prefabs from the bottom panel to appropriate places in your right side panel.

Acquiring Text of a label from scene1 to scene2 Unity

I have created a simple 2d card game in Unity , While the user is playing the game , certain information is getting captured like (score,tries,time), When the user wins or loses the game then the appropriate scene (game over or Win scene) is getting triggered, in these 2 scenes id like to copy the info from the score, tries, time fields of the game to the appropriate labels of gameOver or Win, But it seems I'm doing something wrong..
I tried to find similar questions on StackOverflow, Youtube, the web; I checked the documentation and I tried different approaches.
Here is the code I'm working with at the moment, which seems totally correct to me, I don't get any errors, just nothings appears in the labels.
'''
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class win_results : MonoBehaviour
{
// public options script;
public Text score_final_text;
public Text tries_final_text;
public Text time_final_text;
public void player_win_results()
{
// script = a.getComponent<options>();
if (options.user_lvl_choice=="easy")
{
GameObject tries_final = GameObject.Find("tries_text_lvl1"); //finds the object named score_results
tries_final_text.text = tries_final.GetComponent<Text>().text + "a"; //gets the Text property of it.
GameObject time_final = GameObject.Find("TimeCounter_lvl1"); //finds the object named score_results
time_final_text.text = time_final.GetComponent<Text>().text + "a"; //gets the Text property of it.
GameObject score_final = GameObject.Find("score_lvl1"); //finds the object named score_results
score_final_text.text = score_final.GetComponent<Text>().text + "a"; //gets the Text property of it.
}
else if (options.user_lvl_choice == "hard")
{
GameObject tries_final = GameObject.Find("tries_text_lvl2"); //finds the object named score_results
tries_final_text.text = tries_final.GetComponent<Text>().text + "a"; //gets the Text property of it.
GameObject time_final = GameObject.Find("TimeCounter_lvl2"); //finds the object named score_results
time_final_text.text = time_final.GetComponent<Text>().text + "a"; //gets the Text property of it.
GameObject score_final = GameObject.Find("score_lvl2"); //finds the object named score_results
score_final_text.text = score_final.GetComponent<Text>().text + "a"; //gets the Text property of it.
}
}
As the code above shows I'm using GameObject.Find as the documentation states, I have double checked the names and typos, the scripts are correctly attached, I get no errors in the output, just nothing happens.
As you can see above I have added an extra "a" character at the end for debugging purposes, the "a" character also doesn't appear in the output, meaning that the gameObject find doesn't work correctly in my example.
What am I doing wrong?
Thanks in advance.
When you load a scene without the second parameter
SceneManager.LoadScene("scene2");
The old scene will be destroyed, all the GameObjects in that scene will also be destroyed except you've called DontDestroyOnLoad on it.
So if you haven't done this job yet, what you get in the new scene are empty data. You can print the values to check.
The easiest way to pass data through scenes is use static field. Create a class and add some static fields:
class Global
{
public static string user_lvl_choice;
public static string tries_final;
....
}
Then you can set or get these values from any scene.
Global.user_lvl_choice = "easy"
print(Global.user_lvl_choice);
Read more:
static
SceneManager.LoadScene
Object.DontDestroyOnLoad

Categories