How to add an image to text that will show up randomly - c#

What it looks like in unity. I have also drawn a red arrow to show what I am trying to move
I am trying to make a quiz game that would show a random word with a corresponding image. I am able to show a random question and a random image at the same time. My problem is that the image that will show up will not always be the correct image for the word. Is it possible to move the random image up and place it with the random text?
I have tried attaching the image directly with the text and the problem is that the text will disappear and only the image will stay. What I did to get the image into the game object was by repeating everything for the text.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour
{
public Question[] questions;
public Image[] images;
private static List<Question> unansweredQuestions;
private static List<Image> unansweredImages;
private Question currentQuestion;
private Image currentImage;
[SerializeField]
private Text factText;
[SerializeField]
private Image factImage;
[SerializeField]
private Text trueAnswerText;
[SerializeField]
private Image trueAnswerImage;
[SerializeField]
private Text falseAnswerText;
[SerializeField]
private Image falseAnswerImage;
[SerializeField]
private Animator animator;
[SerializeField]
private float timeBetweenQuestions = 1f;
[SerializeField]
private float timeBetweenImages = 1f;
void Start()
{
if (unansweredQuestions == null || unansweredQuestions.Count == 0)
{
unansweredQuestions = questions.ToList<Question>();
}
if (unansweredImages == null || unansweredImages.Count == 0)
{
unansweredImages = images.ToList<Image>();
}
SetCurrentQuestion();
}
void SetCurrentQuestion()
{
int randomQuestionIndex = Random.Range(0, unansweredQuestions.Count);
currentQuestion = unansweredQuestions[randomQuestionIndex];
int randomImageIndex = Random.Range(0, unansweredQuestions.Count);
currentImage = unansweredImages[randomImageIndex];
factText.text = currentQuestion.fact;
if (currentQuestion.isTrue)
{
trueAnswerText.text = "CORRECT";
falseAnswerText.text = "WRONG";
}
else
{
trueAnswerText.text = "WRONG";
falseAnswerText.text = "CORRECT";
}
}
IEnumerator TransitionToNextQuestion()
{
unansweredQuestions.Remove(currentQuestion);
yield return new WaitForSeconds(timeBetweenQuestions);
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
unansweredImages.Remove(currentImage);
yield return new WaitForSeconds(timeBetweenQuestions);
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
I expect the image and correct text to show up together randomly.

Based on the small information I think you are trying to set a random question but with the correct image.
If this is the case:
The problem I see is you are using a list to access Question and Images. You can use Dictionaries to solve the issue.
public Question[] questions;
public Image[] images;
New:
Dictionary< int, Question> Questions;
Dictionary< int, Image> Images;
Integer here will be a random index that will be same for both dictionaries.
You can manually set the questions and images on runtime. then, whenever you want to assign an image to that random text, just get a random number using Random.Range function. it will return an integer that can be used as the index. Let me know if it helps.
PS: You can remove the space before int datatype.

Related

Game objects wrong positioning

The objects are being set to out of the canvas
The objective of setting them is to show the user inventory with only the items that the user have
It's setting them active normally, and in the order that the user got it, but in wrong positioning
No error messages were sent
Before setting the positions array, i checked what were the positions in the scene to put it right on the array
But the objects are setting in the wrong place
I put this debug logs to try to see the problem
But it says the positions that i set
This is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
public class Filters
: MonoBehaviour
{
[Header("Items")]
public GameObject doubleSpeed;
public GameObject doubleJump;
public GameObject superForce;
public GameObject noGravity;
public GameObject noHit;
public GameObject apple;
private GameObject[] items;
public int index = 0;
public float[] position = new float[6] { -125.8f, -78.6f, -24.1f, 23.1f, 80.69913f, 36.3375f };
private float x;
// Update is called once per frame
void Update()
{
Player player = FindObjectOfType<Player>();
Filter(doubleJump, player.doubleJumps);
Filter(doubleSpeed, player.doubleSpeeds);
Filter(superForce, player.superForces);
Filter(noGravity, player.noGravitys);
Filter(noHit, player.noHits);
Filter(apple, player.apples);
items = GameObject.FindGameObjectsWithTag("Have");
if(items.Length != 0)
{
for(int i = 0; i < items.Length; i++)
{
items[i].transform.position = new Vector3(position[i], 52.8f , 1f);
items[i].SetActive(true);
Debug.Log("Changed the position and set active new position:" + items[i].transform.position);
}
}
}
void Filter(GameObject item, int quantity)
{
if(quantity < 1)
{
item.SetActive(false);
Debug.Log("less than 1");
}
else
{
item.SetActive(true);
Debug.Log("set active");
item.tag = "Have";
Debug.Log("set the tag");
}
}
}
In general there is a difference between the localPosition - the position relative to the parent object and usually the one displayed in the Unity Inspector - and the absolute world space position you are setting in
items[i].transform.position = new Vector3(position[i], 52.8f , 1f);
Further there is an even bigger difference when dealing with a RectTransform. What you see and edit in the Inspector is the RectTransform.anchoredPosition which is relative to the parents RectTransform and additionally takes the Anchors and Pivot settings into account.
So try this instead
items[i].GetComponent<RectTransform>().anchoredPosition3D = new Vector3(position[i], 52.8f , 1f);
anchoredPosition3D is basically the same as anchoredPosition but additionally allows to set the delta in the Z axis
In general for your usecase I would recommend to use a HorizontalLayoutGroup and rather let the UI handle the placement itself. You would then simply use SetActive to hide and show items.

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]);
}

How to create a material picker option in unity?

I have created a floor where by gazing on it the material changes for every 2 seconds. Now I wanted to create a material picker on the scene. Where the user can choose from the given 3 options of the materials and by clicking on it the selected material should apply to the floor. How to do it?
The source code for gazing floor to change material:-
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//Make sure to change the class name (CCSphere) to whatever you called your
//script.
public class tochangematerial : MonoBehaviour
{
public float gazeTime = 2f;
private float timer;
private bool gazedAt;
public Material[] materials;//Allows input of material colors in a set size of array;
public Renderer Rend; //What are we rendering? Input object(Sphere,Cylinder,...) to render.
private int index = 1;//Initialize at 1, otherwise you have to press the ball twice to change colors at first.
// Use this for initialization
void Start()
{
Rend = GetComponent<Renderer>();//Gives functionality for the renderer
Rend.enabled = true;//Makes the rendered 3d object visable if enabled;
}
void Update()
{
if (gazedAt)
{
timer += Time.deltaTime;
if (timer >= gazeTime)
{
if (materials.Length == 0)//If there are no materials nothing happens.
return;
index += 1;//When mouse is pressed down we increment up to the next index location
if (index == materials.Length + 1)//When it reaches the end of the materials it starts over.
index = 1;
print(index);//used for debugging
Rend.sharedMaterial = materials[index - 1]; //This sets the material color values inside the index
timer = 0f;
}
}
}
public void pointerenter()
{
//Debug.Log("pointer enter");
gazedAt = true;
}
public void pointerexit()
{
//Debug.Log("pointer exit");
gazedAt = false;
}
}
Edited code:-
using UnityEngine;
using System.Collections;
// Change renderer's material each changeInterval
// seconds from the material array defined in the inspector.
public class color2 : MonoBehaviour
{
public Material[] materials;
public float changeInterval = 0.33F;
public Renderer rend;
void Start()
{
rend = GetComponent<Renderer>();
rend.enabled = true;
}
public void Update()
{
if (materials.Length == 0)
return;
// we want this material index now
int index = Mathf.FloorToInt(Time.time / changeInterval);
// take a modulo with materials count so that animation repeats
index = index % materials.Length;
// assign it to the renderer
rend.sharedMaterial = materials[index];
}
}
I used this code to change the color of a cube if i pressed a button. But it's not working. I have added this code to cube and in button I have attached this script and function. If I pressed the button the color of cube does not change.
I have added this script to cube and then in button I have dragged and dropped the gameobject(cube) and triggered the function void update()
Edited again:-
Now I can change the materials of the 3d model for eg:if it is a chair I am able to change the materials of chair by clicking on a button. How can I change the different models? eg:in chair there are different models if a user clicked on a button it should produce different models how to do it?
The simpliest way would be to create a function that takes an int index and in that function change Rend's material to materials[index], then create an UI canvas with three buttons, each of the buttons would trigger that function but pass different int.

Unity c# Code working in one script but not in other?

Hey guys so I have this really strange problem, so basically what happens is the player runs into the box (OnTriggerEnter function) and a weapon will show on the character and the box will spawn to another location. Except I tried to make a separate script because the script that it works on is for spawning boxes. I didn't want it in the same script because not as neat.
So this is my code for the script where it doesn't work:
public class ChangeGun : MonoBehaviour {
public Sprite gunSprite;
private string[] weapons = { "Pistol", "Shotgun", "Ak47", "Bazooka" };
public GameObject currentGun;
public void AddGunToPlayer()
{
//int randomNumber = Random.Range(0, 4);
currentGun.GetComponent<SpriteRenderer>().sprite = gunSprite;
}
}
And this is the script where it works (keep in mind I used the EXACT same code, ignore all the code in this script except the for the 2 variables and the OnTriggerEnter Function.)
public class BoxGenerator : MonoBehaviour
{
public GameObject currentGun;
public Sprite gunSprite;
public Vector3[] boxPositions;
public GameObject box;
public GameObject startingBox;
int randomNumber;
// Use this for initialization
void Start()
{
//random number between 0-10 thats vector size
randomNumber = Random.Range(0, 10);
//instantiate the starting box
startingBox = Instantiate(box);
//set starting box to new location
startingBox.transform.position = boxPositions[randomNumber];
//set tag to box
startingBox.tag = "box";
}
void Update()
{
randomNumber = Random.Range(0, 10);
}
void OnTriggerEnter(Collider col)
{
if (col.GetComponent<Collider>().tag == "box")
{
startingBox.transform.position = boxPositions[randomNumber];
currentGun.GetComponent<SpriteRenderer>().sprite = gunSprite;
}
}
}
Keep in mind when I tried to use the old script under this line "currentGun.GetComponent().sprite = gunSprite;"
I pasted this code and got the null reference exception.
ChangeGun cg = new ChangeGun();
cg.AddGunToPlayer();
ChangeGun is null since you didn't set it. You said you set it in the inspector, but in your question you created in in the code so it will have the default values.
ChangeGun cg = new ChangeGun(); // cg.currentGun is null
cg.AddGunToPlayer(); // Trying to access cg.currentGun
I suppose you have set in in the inspector, so instead of creating new ChangeGun, you need to get the component you created in Inspector:
ChangeGun cg = GetComponent<ChangeGun>();
cg.AddGunToPlayer();

OnGui elements interacting with other OnGui elements

Within my 2d game i wsih to have a number of OnGui elements there for the user to select, however, the cursor that im using is another ongui element(using kinect to navigate) is this possible by any chance, at the moment im using planes but i will be zooming in and out of the camera so ill essentially need them attatched to the screen. Any ideas, suggestions or workarounds.
THis is currently my cursor.
using UnityEngine;
using System;
using System.Collections;
public class PillarAgent : MonoBehaviour {
public SkeletonWrapper sw;
public Vector3 distance;
public float progress =0f;
public Texture2D cursor;
public Texture2D load;
public Camera mainCam;
public float startTime;
private int roundedRestSecounds;
// Use this for initialization
float differencex = 0;
float differencey = 0;
void Start () {
distance =new Vector3(0f,0f,0f);
}
float translate(float value, float leftMin, float leftMax,
float rightMin,float rightMax)
{
float leftSpan = leftMax - leftMin;
float rightSpan= rightMax - rightMin;
float valueScaled = (value-leftMin)/(leftSpan);
return rightMin+(valueScaled * rightSpan);
}
// Update is called once per frame
void Update () {
if (sw.pollSkeleton())
{
distance.x=sw.bonePos[0,0].x - sw.bonePos[0,7].x;//5 is left shoulder
distance.y=sw.bonePos[0,0].y -sw.bonePos[0,7].y;
differencex=translate(distance.x,.6f,0,0,Screen.width);
differencey=translate(distance.y,-.5f,0,0,Screen.height);
//Debug.Log();
float width = sw.bonePos[0,5].x+ sw.bonePos[0,9].x;
float height =sw.bonePos[0,4].y- sw.bonePos[0,0].y;
float heightdiv= (height/2)+sw.bonePos[0,0].y;
}
}
void OnGUI() {
//left top width height
Rect r = new Rect(differencex,differencey,80,50);
GUI.Label(r,cursor);
GUI.BeginGroup(new Rect(differencex,differencey+50,50*Mathf.Clamp01(progress),15));
//Debug.Log(progress);
GUI.DrawTexture(new Rect(0,0,50,50),load);
GUI.EndGroup();
transform.position =mainCam.ScreenToWorldPoint(new Vector3(differencex,Screen.height-differencey,50));
//mainCam.fieldOfView()
}
void OnCollisionStay(Collision Other)
{
startTime+=Time.deltaTime;
if(Other.gameObject.GetComponent(typeof(TextControl)))
{
roundedRestSecounds=Mathf.CeilToInt(Time.time);
progress = Time.time *0.2f;
CurrentState=true;
}
else if(Other.gameObject.tag==("Scalpal")){
progress = startTime *0.5f;
//scallpall activated
//
}
}
void OnCollisionExit(Collision Other){
startTime =0f;
progress =0f;
}
public Boolean CurrentState{get;set;}
}
The next class is essentially the class in which i pick up my tools, currently this code doesnt work(not sure why), but what i wish to do is select some tools which show up on the screen so that i can use them,for e.g pick up paint brush start painting bricks or what not. at the moment i have my tools on a plane, i wish to always have them on the screen at all times when the camera moves.
using UnityEngine;
using System.Collections;
public class SelectTool : MonoBehaviour {
public Tools tools;
public float startTime;
public bool ScalpalSelected;
public GameObject selectedTool;
void Start()
{
tools = this.GetComponent<Tools>(); //in order to use this tools muyst be attached to the game object
//this is essentially saying with regards to this game object get the component named tools
}
void update()
{
}
void OnCollisionStay(Collision Other)
{
startTime +=Time.deltaTime;
if(startTime >5f){
if(Other.collider.tag==("Scalpal"))
{
selectedTool = Other.collider.gameObject;
Debug.Log(selectedTool+" What in gods good name is:" +tools.utilities[0]);
}
else {
selectedTool=null;
}
if(selectedTool){
for(int i=0;i<tools.utilities.Length;i++)
{
}
}
ScalpalSelected=true;
renderer.material.color = Color.yellow;
}
}
void OncollisionStay(Collision other){
startTime = 0f;
}
}
From the comment section to the question I will assume that you want to know how to do this:
"... you want your plane objects to move together with the camera ..." - Steven Mills
"thank you #StevenMills Do you have any example of how this can be done?" j bel
While the answer provided in the comments is to just manually add the planes as children of the camera (a very straightforward, manual approach), I will give another way to do this through scripting (in light of maybe this will help someone else out disregarding the likeliness of someone using this solution).
The idea of this is to create a script (thus following being attached to the MainCamera) that will search through all of the GameObject in the Object Hierarchy with the method GameObject.FindGameObjectsWithTag. Once we have all our GameObject with the associated Tag, we can then loop through the array and parent the attached script's GameObject to each.
public class ParentGameObjects : MonoBehaviour {
//The tag to search for on all game objects in the hierarchy
public String objectTag;
//The game objects that we will parent the main camera to
private GameObject[] children;
//It's not necessary to store references to the children but if you want to modify them at some point you will be able to
void Start() {
//Find all game objects with the tag we want
children = GameObject.FindGameObjectsWithTag(objectTag);
//Loop through all of the game objects found and parent this object's transform
for(int i = 0; i < children.Length; i++) {
children[i].transform.parent = transform;
}
}
}
Now, there are a few things you have to do for this script to work:
Attach this script to any GameObject that you want to parent other objects to.
In the Inspector of the GameObject that the script is attached to, enter in the name of the Tag you want to use.
For all GameObject(s) in the Hierarchy that should be added as children, assign the same Tag.
Of course there are other things you can do like, for example, instead of only searching for one Tag be able to search for multiple but that requires a bit (not exactly much) more work. Nonetheless, I hope this will at least be useful information to someone on how parenting works via scripting.

Categories