I'm working on a 2D UI application with Unity and i have a problem.
I was working on the script to instantiate my popup window (i made a prefab). And i succeed but later Unity crashed and i had to redo my scene (forgot to ctrl+s)
Since this crash, my popup isn't instantiate as a child of my canvas and i've got this message:
"Setting the parent of a transform which resides in a prefab is disabled to prevent data corruption"
Here is my script :
using UnityEngine;
using System.Collections;
public class Popup : MonoBehaviour
{
public RectTransform popupPrefab;
private Animator anim;
// Use this for initialization
void Start()
{
//get the animator component
anim = popupPrefab.GetComponent<Animator>();
//disable it on start to stop it from playing the default animation
anim.enabled = false;
}
public void CreatePopup()
{
// Copie du prefab
RectTransform newPopup = Instantiate(popupPrefab, popupPrefab.transform.position, popupPrefab.transform.rotation) as RectTransform;
newPopup.transform.SetParent(transform, false);
//anim = newPopup.GetComponent<Animator>();
//anim.enabled = true;
//anim.Play("Popup");
}
public void ClosePopup()
{
anim.enabled = true;
anim.Play("ClosePopup");
}
}
I don't understand why i have this error since it was working fine before crash...
if you have any idea
Thanks
I solved the problem by re-doing my project from the beginning...
Related
I was creating a flappy bird game in Unity and while I was trying to add touch inputs it gave me this error
InvalidOperationException: You are trying to read Input using the
UnityEngine.Input class, but you have switched active Input handling
to Input System package in Player Settings.
I think it's because I downloaded the new Input system from the package manager, but i removed it
playerScript Code:
using UnityEngine;
public class playerScript : MonoBehaviour
{
Rigidbody2D rb;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
private void Update()
{
if (Input.GetMouseButtonDown(0) || Input.touchCount > 0)
{
rb.velocity = new Vector2(0f, 7f);
}
}
}
Solved it!
You need to go to the Player settings Build settings/Player settings/Other settings/Configuration and search for:
and set Input manager old
Try change code to this
using UnityEngine;
public class playerScript : MonoBehaviour
{
Rigidbody2D rb;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
Jump();
}
}
public void Jump()
{
rb.velocity = new Vector2(0f , 7f);
}
}
Then add UI button and on the on click drag the gameobject this script is attacked to into it, click the script and then click 'Jump()'
You could add Giant UI button and add function jump and make it work when button is pressed. I had similar problem for visual novel game. And I added screen sized button :)
I'm developing a 2D mobile game where the player should tap on the screen to go up. I just added a pause button recently and I've noticed that when I click the button it counts as a tap on the screen, so the player goes up. Basically, in the same exact moment that I press the pause button, the player jumps and then the game freezes while he is in mid-air. Is there a way I could make so the button wouldn't count as a tap?
Here's the part of the player script that makes him move:
if (Input.GetMouseButtonDown (0) && isDead == false && isKnifeDead == false && UiStartScript.uiInstance.firstClickUi == true) {
rb.velocity = Vector2.up * velocity;
}
Heres's the part of the UI script for the pause button:
public void PauseGame()
{
Time.timeScale = 0;
}
My EventSystem:
EventSystem
My Button:
Button
An easy with no code required is to remove the code about detecting tap on screen and instead place a button that covers the whole screen (invisible button).
That button event would trigger the screen movement.
You can add extra buttons on top and Unity will automatically discard the tap from any other button below.
This way you can start adding UI all over without checking in code which should be considered.
In U. I script add
public GameObject PlayerConrtollerScript;
In your U.I Script, under the class Pausgame()
Add this code.
GameObject.PlayerControllerScript.SetActive = false;
When unpaused you need to add to your script that has the
Time. timeScale =1;
Add this code.
GameObject.PlayerControllerScript.SetActive = true;
After you have added the code mentioned above. Don't forget to add the player game object from your hierarchy into the Inspector with the U. I script, the space will be available to add a game object when you scroll down to your U. I script.
That will stop your player from moving around during pause.
This is the approach that I been done. I create a cople of tricks using Event System and Canvas for take advantage of the Mouse Input, you don't need the use of Updates functions for do the basic gameplay.
Here's my example project: TapAndJump on Github
Check the GameObjects called "Click Panel" and "Pause Button" and
respective linked methods.
JumpWithTap.cs
using UnityEngine;
public class JumpWithTap : MonoBehaviour
{
[SerializeField] private UIHandler uiHandler;
[SerializeField] private float jumpPower = 5f;
private Rigidbody2D rb2D;
private int counter;
#region Class Logic
public void Jump()
{
rb2D.velocity = Vector2.up * jumpPower;
uiHandler.SetNumberToCounter(++counter);
}
#endregion
#region MonoBehaviour API
private void Awake()
{
rb2D = GetComponent<Rigidbody2D>();
}
#endregion
}
UIHandler.cs
using UnityEngine;
using UnityEngine.UI;
public class UIHandler : MonoBehaviour
{
[SerializeField] private Text counterText;
[SerializeField] private Text pauseText;
[SerializeField] private Image clickPanel;
private bool isPaused = false;
public bool IsPaused
{
get { return isPaused; }
set
{
pauseText.gameObject.SetActive(value);
isPaused = value;
}
}
#region Class Logic
public void SetNumberToCounter(int number) => counterText.text = number.ToString();
public void DisableClickPanel() => clickPanel.raycastTarget = !clickPanel.raycastTarget;
public void PauseGame()
{
IsPaused = !IsPaused;
DisableClickPanel();
// Time.timeScale = IsPaused == true ? 0 : 1; // If you want keep the Physics (ball fall) don't stop the time.
}
#endregion
}
I guided by your code example and so on; be free that modify and request any issue.
I have problems accessing the enabled variable in children of my Player GameObject.
-Human holds Rigidbody2D, BoxCollider, PlayerController script and Animator
-body and range_attack_body only hold SpriteRenderer
What I want to do:
I want to change the SpriteRenderer of my Player Object when mouse button is on hold. There are SpriteRenderers in body and range_attack_body. Both GameObjects are part of animations.
body.SpriteRenderer is active and range_attack_body.SpriteRenderer inactive during normal motion.
In my PlayerController script I wrote a routine that will trigger an attack animation when mouse button is on hold. In this routine I wanted to change the enabled states of the SpriteRenderers. However nothing is happening, meaning the varibales are not changing during runtime. I already checked if the GameObjects and SpriteRenderers are accessed correctly during Awake() and I can find both renderers in my SpriteRenderer array using debug messages.
On top of that I checked what happens if I add a SpriteRenderer to my Human GameObject. It will appear in my SpriteRenderer array and I have full access to enabled variable meaning I can change them in my routine. So I figured there might be a conflict with body and range_attack_body due to their SpriteRenderers being part of animations. I added Human.SpriteRenderer to an animation and can still change variables.
I have no clue what is going on, please help. Here is some code:
public class PlayerController2D : PhysicsObject {
public float maxSpeed = 7f;
public float jumpTakeOffSpeed = 7f;
public float posOffset = 1;
protected bool flipSprite = false;
protected bool flipState = true;
private Animator animator;
private SpriteRenderer[] spriteRenderers;
void Awake ()
{
animator = GetComponent<Animator> ();
GameObject human = GameObject.Find("Human");
spriteRenderers = human.GetComponentsInChildren<SpriteRenderer> ();
}
protected override void Attack ()
{
if(Input.GetMouseButton(0))
{
spriteRenderers[0].enabled = false;
spriteRenderers[1].enabled = true;
Debug.LogError("Inhalt:" + spriteRenderers[0].ToString());
Debug.LogError("Inhalt:" + spriteRenderers[1].ToString());
animator.SetBool("attack", true); // boolean to start hold animation
}
else if(!Input.GetMouseButton(0))
{
spriteRenderers[0].enabled = true;
spriteRenderers[1].enabled = false;
animator.SetBool("attack", false);
}
}
}
Your script code is ok, the problem should be elsewhere.
First of all, disable the Animator component and run the script: if enabling/disabling the sprite renderers work, than you must look in the animation clips if you have the Sprite Renderer.Enabled property anywhere, most probably you'll have it - remove it so you can enable/disable the renderers only via script.
If the script still doesn't work, then the problem is elsewhere (another script which is accessing the enabled property of the renderers).
But I'd bet that you're changing the enabled property from the animation clips, which supercedes the script due to how the Unity execution order works (animations are always updated after the scripts and before rendering).
I've been working on a simple 2D game in unity and it just has three scenes, the start scene, the game scene, and the game over scene. I want to display the score from the game in the game over screen. I created a score manager game object in the game scene that uses the DontDestroyOnLoad() function to carry it over into the game over screen and I gave it access to the score which is managed by the game manager. I've been debugging my code and the score is translated over into the score manager and is maintained when the game over screen loads, but for some reason it won't let me update the score text object. Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ScoreManager : MonoBehaviour {
public static ScoreManager Instance;
private GameController gameController;
private int scoreInstance;
private Text scoreText;
// When scene is first loaded
void Awake() {
this.InstantiateController();
}
// Use this for initialization
void Start () {
GameObject gameControllerObject = GameObject.FindWithTag("GameController");
if (gameControllerObject != null)
{
gameController = gameControllerObject.GetComponent<GameController>();
}
GameObject scoreTextObject = GameObject.FindWithTag("ScoreText");
if (scoreTextObject != null)
{
scoreText = scoreTextObject.GetComponent<Text>();
}
scoreInstance = 0;
scoreText.text = "";
}
// Update is called once per frame
void Update () {
scoreInstance = gameController.score;
Debug.Log("Score: " + scoreInstance.ToString());
scoreText.text = scoreInstance.ToString();
}
private void InstantiateController ()
{
if (Instance == null)
{
Instance = this;
DontDestroyOnLoad(this);
}
else if (this != Instance)
{
Destroy(this.gameObject);
}
}
}
So I tried to programmatically gather the "score text" ui component in the start function because I figured I can't just make it public and drag in the text component because the score manager is actually in a different scene than the score text object. I also tried adding this whole bit of code to gather the text component into the update function so that it can do that when the score manager is actually a part of game over screen. Nothing seems to work and I have no idea why. Can anybody please help me with this? Also I keep getting a "NullReferenceException: Object reference not set to an instance of an object" error. Thanks in advance for any help.
Unity Start function is only called the first time the script is enabled, i.e. not every time the scene changes for a DontDestroyOnLoad object.
So if you need to wire up some changes after a scene change, you need to either detect the scene change, or have an object that starts in that scene trigger the code you want to run.
Having another object on the new scene trigger things is easy and pretty fool-proof, but there's a builtin function you can add to your other objects:
void OnLevelWasLoaded(int currentLevel)
{
}
This will be called on level changes, and give you the level's number (not name sadly). However, the above is deprecated and they want you to use Unity's SceneManager, so the proper way to set this up is now:
Unity 5 OnLevelWasLoaded?
Start()
{
SceneManager.sceneLoaded += this.OnLoadCallback;
}
void OnLoadCallback(Scene scene, LoadSceneMode sceneMode)
{
// you can query the name of the loaded scene here
}
I'm having an issue where I can't disable a script from the other script - they are both public and within the same package (I think).
Here is my code for the script I'm trying to disable from:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
#if UNITY_EDITOR
using UnityEditor;
#endif
using RTS;
public class PauseMenu : MonoBehaviour {
Canvas canvas;
private Player player;
public Button Button2;
void Start()
{
Debug.Log ("asdf");
player = transform.root.GetComponent< Player >();
canvas = GetComponent<Canvas>();
canvas.enabled = false;
ResourceManager.MenuOpen = false;
Button2.GetComponent<Button>().onClick.AddListener(() => { Resume();});
if(player) player.GetComponent< UserInput >().enabled = false;
}
And the code for the other script:
//sets up what resources we are using
using UnityEngine;
using System.Collections;
using RTS;
public class UserInput : MonoBehaviour {
//sets up a private variable for only this class - our player
private Player player;
// Use this for initialization
void Start () {
//this goes to the root of the player ie the object player and allows us to
player = transform.root.GetComponent< Player > ();
}//end Start()
So the part that is not working is:
if(player) player.GetComponent< UserInput >().enabled = false;
And the code runs and then causes the runtime error:
NullReferenceException: Object reference not set to an instance of an object
PauseMenu.Pause () (at Assets/Menu/PauseMenu.cs:40)
PauseMenu.Update () (at Assets/Menu/PauseMenu.cs:29)
Here is a picture showing my scene hierarchy and components:
The issue here is that you try to execute transform.root.GetComponent< Player >(); from within PauseMenu, which is on the "Canvas" object.
The problem with that is that the topmost transform in the hierarchy of your "Canvas" object (which is what transform.root returns) is, well, the transform of the "Canvas" object - which is in no way related to the UserInput script you are trying to access. For this script to actually work, you would need the transform of your "Player" object, which is the object that actually has the UserInput script.
My suggestion is to eliminate the need to run GetComponent() at all - create a public UserInput variable in your PauseMenu class, then (while selecting your "Canvas") in the editor, drag the "Player" object into that new field. This will cause the UserInput script of your "Player" object to be accessible within the PauseMenu.
So your PauseMenu script might look like:
public class PauseMenu : MonoBehaviour {
Canvas canvas;
public UserInput playerInput; // Drag the Player object into this field in the editor
public Button Button2;
void Start()
{
Debug.Log ("asdf");
canvas = GetComponent<Canvas>();
canvas.enabled = false;
ResourceManager.MenuOpen = false;
Button2.GetComponent<Button>().onClick.AddListener(() => { Resume();});
playerInput.enabled = false;
}
}
Hope this helps! Let me know if you have any questions.
(An alternative is to use GameObject.Find("Player") to get GameObject of "Player". This needs a bit more code but doesn't use the editor.)
I would say your player = transform.root.GetComponent< Player >(); arrives null.
So you are trying to disable something that doesnt exist.
Enter debug mode and see if your player is null or not.