I am trying to change an element of a 2d character at runtime. I've used the code below and it doesn't seem to change the sprite of the character at all. No errors or anyhting but the physical sprite doesn't change. I have used Debug.Log to see if the methods are being called (which they are). I've also included some screenshots of how it is inside of inspector.
Here is what I have so far.
InventoryPanel.cs
public CharacterAppeance ca;
if (item.location == ItemLocation.Boot)//This is set in ItemData.ca
{
ca.SetBoot(item.appaerance[0], item.appaerance[1]);
}
CharacterApperance.cs
public SpriteRenderer leg1ArmorRenderer;
public SpriteRenderer leg2ArmorRenderer;
public SpriteRenderer pelvisArmorRenderer;
public SpriteRenderer shin1ArmorRenderer;
public SpriteRenderer shin2ArmorRenderer;
public void SetBoot(Sprite leg, Sprite shin)
{
leg1ArmorRenderer.sprite = leg;
leg2ArmorRenderer.sprite = leg;
shin1ArmorRenderer.sprite = shin;
shin2ArmorRenderer.sprite = shin;
}
ItemData.cs
public Sprite[] appaerance;
Itemdata in Inspector: http://prntscr.com/nbvgj9
CharacterApperance in Inspector: http://prntscr.com/nbvh7w
InventoryPanel in Inspector: http://prntscr.com/nbvhlr
Thank you all who help :)
Related
So I am able to Instantiate new objects at runtime and they spawn in with the correct scripts attached however the scripts do now spawn in with the variables fixed in their slots.
I need a way to spawn prefabs with the scripts attached AND the variable slots in the script are all filled in.
Deploy capsule script (linked to main camera)
public class deployCapsule : MonoBehaviour
{
public GameObject CapsulePrefab;
public Path path;
public float respawnTime = 1.0f;
void Start()
{
StartCoroutine(capsuleWave());
}
private void spawnCap()
{
GameObject a = Instantiate(CapsulePrefab) as GameObject;
a.transform.position = new Vector2(1.0f, 1.0f);
path.followers.Add(a);
Debug.Log("1");
}
IEnumerator capsuleWave()
{
while (true)
{
yield return new WaitForSeconds(respawnTime);
spawnCap();
}
}
}
Path Follower script
public class PathFollower : MonoBehaviour
{
public float movementSpeed;
//private float pathProgress = 0;
public GameObject objectToSpawn;
public Transform[] positionPoint;
[Range(0,1)]
public float value;
void Start()
{
Debug.Log(iTween.PathLength(positionPoint));
}
void Update()
{
movementSpeed = 10f;
if (value < 1)
{
value += Time.deltaTime / movementSpeed;
}
iTween.PutOnPath(objectToSpawn, positionPoint, value);
}
private void OnDrawGizmos()
{
iTween.DrawPath(positionPoint,Color.green);
}
}
I KNOW THIS IS NOT TECHNICALLY POSSIBLE.
But I need a method to get this done one way or another.
I am quite new to unity and would appreciate any help given.
Thank you in advance.
in deployCapsule, store a reference to the array of points
public Transform[] positionPoint;
assign the values in the inspector.
and then once you've instantiated the prefab, give it the array like this
//this is in the SpawnCap function
//GameObject a = Instantiate(CapsulePrefab) as GameObject;
a.GetComponent<PathFollower>().positionPoint = positionPoint;
//rest of your function
alternatively, set the values in the Awake() or Start() function of the newly instantiated Capsule by getting a reference to a class that has the data.
void Start()
{
positionPoint = GameObject.Find("Spawner").GetComponent<deployCapsule>().positionPoint;
}
After instantiating your capsule prefab and assigning a reference to it named a (I suggest you change this naming to something more logical)
GameObject a = Instantiate(CapsulePrefab);
Assuming your prefab already has the PathFollower component attached, you could use the GameObject.GetComponent<T> method to access it.
var pathFollowerComponent = a.GetComponent<PathFollower>();
After which, you could populate the positionPoint[] Transform's array (assuming that's what you're after) with references to the "Points" GameObjects located in the hierarchy and the scene.
It's up to you how to go about this:
You could create a tag on each point, use GameObject.FindGameObjectsWithTag("Point");
Obtain the children from the "PathFollower" GameObject and add its child transforms to your array
Create a singleton instance or a "GameManager" class which stores the points located in a scene
If you create new points dynamically, create a listener and invoke events to add the new points to the array whenever they're instantiated.
Note that the mentioned above may not return the points in the order you placed them, so you may need to sort them! In general, there are many other ways which you can find by searching the forums, or on Google!
The issue here is that your prefab is in project while the path nodes are in scene. You have two approaches to fix that.
First, your path nodes are under a parent object, that parent holds a container script:
public class PathNodes : MonoBehaviour
{
[SerializeField] private Transform m_nodes;
public Transform [] Nodes => m_nodes;
}
Either you use the singleton pattern (yes it is fine when used properly) or have the newly created object use FindObjectOfType then you can access the nodes.
The second solution is to have the prefab of your object to create in the scene as an inactive object. Being in the scene, you can then drag and drop all you need from the scene into it. The prefab is dragged in place of the original project prefab (CapsulePrefab) and when creating a clone of it, you just need to set it active.
I have a homework assigned and I need the make a sound and music volume thing and I want it to be used in other scripts too.
What I mean is :
enter image description here
So when I drag the slider value to 0.2 for example I want the audio source on the other scene to have volume 0.2, but I have no idea how thats made.
Thanks.
(I only have a plan but no code)
Also does anyone know why does it take forever to load when you save a script and go to unity:
enter image description here
A great way to do this is to use static variables that are actually defined for the class And can hold variables between scenes.
public class AudioManager
{
public static float MusicVolume = 1f;
public static float SoundVolume = .5f;
public void SetVolume(float value) => MusicVolume = value;
}
To call them, you just need to write the full name of the class before the variable name.
public class Player : MonoBehaviour
{
public AudioClip AudioClip;
public void Shot()
{
AudioSource.PlayClipAtPoint(AudioClip, transform.position, AudioManager.SoundVolume);
}
}
Remember that these are class variables will set in all instances of the same class. Also if you want your variables to be loaded after re-running the game. I suggest using PlayerPrefs for saving them.
To do this you would write a singleton script AudioManager that is set to DontDestroyOnLoad
It's just a script holding your AudioSources and that doesn't get destroy when you switch scenes.
Something like this
public class AudioManager : MonoBehaviour
{
private static AudioManager instance;
[Header("AudioSources")]
[SerializeField] private AudioSource musicSource;
[SerializeField] private AudioSource soundSource;
private void Awake()
{
// If you have AudioManager in every scene, you want to only keep the main one (the first one)
if (instance != null && instance != this)
{
Destroy(gameObject);
}
else
{
instance = this;
DontDestroyOnLoad(this); // This line will tell Unity to keep this gameobject when switching scenes
}
}
}
Then you can alter your audio sources as you wish, they won't get destroy after switching scene.
Okay Its nice that I have a lot of things to do but okay the script that you guys sent me, so if I put it on the audio Gameobject and I still don't get how I can change parameters from 1 scene to other (I'm a beginner and I'm 13 years old so I might not get what audio ATM's are but yes.)
For short I need this:
Scene1.findgameobject.name = blah blah = audiogameobject in menu
I have a Player script. I have the variables on there
public class Player : MonoBehaviour
{
float horimove;
Rigidbody rb;
public float speed;
public GameObject thrown;
public bool win;
On my other script (I'm making a game where you instantiate spheres into a hole and win.)
public class spheresciprt : MonoBehaviour
{
public Player pscript;
public GameObject player;
// Start is called before the first frame update
void Start()
{
player = GameObject.Find("Player");
pscript = player.GetComponent<Player>();
}
private void OnTriggerEnter(Collider other)
{
if (gameObject.CompareTag("win"))
{
pscript.win = true;
}
}
However pscript.win doesn't change. The bool always stays false but I want the player to win after the sphere hits the trigger in the hole I want it to go to. I tried different computers. The same thing happened in different games I think so I'm probably just missing something.
First of all, make sure that the collision is detected. You can easily do something like
void OnTriggerEnter()
{
Debug.Log("Pass1");
if (gameObject.CompareTag("win"))
{
Debug.Log("Hey, it worked!");
}
}
in the OnTriggerEnter to check that.
If the collision is NOT detected, make sure there are colliders on all the affected GameObjects, as well as a RigidBody component on the sphere. Also, make sure that the collider is marked as Trigger. If you still have an issue with that, we will need to see your inspector to figure it out.
If the collision IS detected... Well, start by making sure that you have assigned the proper tag on the hole. Then, make sure that the player GameObject is actually called "Player" (since you are trying to find it by name) and that it has the script you are trying to get on the object you actually find (and not on one of its children). I hope that works, because I can't see anything else seriously flawed at your code.
Have you tried to change
if (gameObject.CompareTag("win"))
to
if (collider.gameObject.CompareTag("win"))
or just add the rigidbody to both player and other object.
does the other object have "win" tag?
Here is your script:
public class spheresciprt : MonoBehaviour
{
public Player pscript;
public GameObject player;
// Start is called before the first frame update
void Start()
{
player = GameObject.Find("Player");
pscript = player.GetComponent<Player>();
}
private void OnTriggerEnter(Collider other)
{
if (gameObject.CompareTag("win"))
{
pscript.win = true;
}
}
}
It sets pscript to the current values in Player script. This is the problem, because it is setting a variable to the current values, and you want access to the component. You could change this by, just replace all of the pscript variables with player.GetComponent<Player>(). There are other ways of doing this. You could, at the end of OnTriggerEnter, add this:
void OnTriggerEnter(Collider other)
{
...
player.GetComponent<Player>() = pscript;
}
In both of these solutions you fix it. In one, you re-apply the variable. In the other, you are changing the component directly. Which is what you want, because you have pscript as an instance of player script, not the player script that is attached to player.
I'm trying to make my elements referenced in Unity by making private variables using Serializable Fields and then using a {get {return }} underneath in order to access it. I'm a complete beginner at C# and Unity so I'd appreciate a simple explanation. Every one of these Serializable Fields has this same error and doesn't appear in my Unity inspector.
public struct UIElements
{
[SerializeField] RectTransform answerContentArea;
public RectTransform AnswerContentArea { get { return answerContentArea; } }
[SerializeField] TextMeshProUGUI questionInfoTextObject;
public TextMeshProUGUI QuestionInfoTextObject { get { return questionInfoTextObject; } }
[SerializeField] TextMeshProUGUI scoreText;
public TextMeshProUGUI ScoreText { get { return scoreText; } }
[Space]
[SerializeField] Image resolutionBG;
public Image ResolutionBG { get { return resolutionBG; } }
[SerializeField] TextMeshProUGUI resolutionStateInfoText;
public TextMeshProUGUI ResolutionStateInfoText { get { return resolutionStateInfoText; } }
[SerializeField] TextMeshProUGUI resolutionScoreText;
public TextMeshProUGUI ResolutionScoreText { get { return resolutionScoreText; } }
[Space]
[SerializeField] TextMeshProUGUI highScoreText;
public TextMeshProUGUI HighScoreText { get { return highScoreText; } }
[SerializeField] CanvasGroup mainCanvasGroup;
public CanvasGroup MainCanvasGroup { get { return mainCanvasGroup; } }
[SerializeField] RectTransform finishUIElements;
public RectTransform FinishUIElements { get { return finishUIElements; } }
}
You need to mark the struct as Serializable in order to show it in the Unity Inspector, like so:
[Serializable]
public struct UIElements
{
// ...
}
As for the warning, it is normal, so you can ignore it.
Just make sure to set those respective values in the inspector.
Unity provides serialization system for MonoBehaviour's fields which you can use to set fields links in editor and later use it from code.
In you case you need to make UIElements as class which inherits from MonoBehaviour, attach it to some GameObject at scene and set up needed links - after this you can use links for objects in scene.
All of your fields seem to be defined as property. Someone correct me if I'm wrong but in order to display property in the inspector you have to "create" your own inspector because Unity cannot safely serialize/deserialize properties since getters and setters can have different effects based on what code they encapsulate.
I hope this post sheds more light for you.
Edit
This might also be useful
Using the Unity 3D editor. I have an object which changes colour when it collides with other objects, this all works, but when changing scene the ball reverts back to its default colour. So i need the ball when changing colour to update the prefab through the script so the other instances of the object in other scenes will also change colour.
here is the code i have written for the colour changing:
using UnityEngine;
using System.Collections;
public class colourpicker : MonoBehaviour {
public GameObject whiteblock;
public GameObject limegreentintblock;
public GameObject cyantintblock;
public GameObject redtintblock;
public GameObject yellowtintblock;
public GameObject player;
public Material limegreentint;
public Material redtint;
public Material cyantint;
public Material yellowtint;
public Material white;
void OnTriggerEnter(Collider other)
{
if (other.gameObject == whiteblock)
{
renderer.material = white;
}
else if (other.gameObject == redtintblock)
{
renderer.material = redtint;
}
else if (other.gameObject == limegreentintblock)
{
renderer.material = limegreentint;
}
else if (other.gameObject == cyantintblock)
{
renderer.material = cyantint;
}
else if (other.gameObject == yellowtintblock)
{
renderer.material = yellowtint;
}
}
}
thanks for any help in advance :)
If I were you I'd make a static class with an Empty Game Object where you can save the state of your object colour. In the Initialize part of you Ball you should check if a variable (that must be static as well) of this static class is different from an Initial state and then assign the colour of the static variable to the Ball object. This LINK teaches you how to implement it (you have to change some stuff to make what you want achieve)
EDIT
In the static class you create something like
public static Material BallMaterial = null; // or you can assign a Material that will act as InitialState
After that, in your piece of code, when you assign the new Material to the ball, you also assign the new material to BallMaterial and then when you load the new scene you check if the BallMaterial has a different value from its InitialState (or null).