- Home /
The question is answered, right answer was accepted
Scrip cannot work after reloading the scene or reopen Unity
hi guys, I'm a newbie and I encountered a strange problem.
Here is the thing, I have this script called MoveForce, it is used to lerp a group of object called forceSet to target positions when right answer is entered in input field.
However, when the script is first attached to forceSet, it executed completely fine. When I restart the game , it is not working. And also when the next time I open Unity , it also can't work unless I remove this script component from the gameobject and attach it again. So it is like this script can only be used once.. Other linked scripts are all working fine. Below is the MoveForce script and other related scripts. Do you have any ideas where I went wrong? Thank you guys, hope you could help me solve this QAQ.
GameController Script:
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System.Collections;
using System.Collections.Generic;
public class GameController : MonoBehaviour {
public int count;
public Text GameoverText;
public Text CenterText;
public GameObject CenterPanel;
public GameObject RestartButton;
public GameObject MomentInput;
public bool gameOver;
private MomentInput momentScript;
private bool isBlinking = true;
void Awake()
{
gameOver = false;
DisableText();
RestartButton.SetActive(false);
MomentInput = GameObject.Find("MomentInput");
momentScript = MomentInput.GetComponent<MomentInput>();
}
void Update()
{
}
public void TimeGameOver()
{
gameOver = true;
SetGameoverText("Time's Up!");
SetCenterText("You Loose!");
RestartButton.SetActive(true);
MomentInput.SetActive(false);
}
public void WinGame()
{
gameOver = true;
SetCenterText("You Win!");
CenterText.color = Color.white;
RestartButton.SetActive(true);
MomentInput.SetActive(false);
}
public void WSign()
{
SetGameoverText("Wrong Direction!");
GameoverText.color = Color.yellow;
StartCoroutine(BlinkText("-10s!"));
StartCoroutine(StopBlinking());
}
public void WAnswer()
{
SetGameoverText("Wrong Answer!");
GameoverText.color = Color.red;
StartCoroutine(BlinkText("-20s!"));
StartCoroutine(StopBlinking());
}
public void RAnswer()
{
SetGameoverText("Correct!");
GameoverText.color = Color.white;
if (count >= 0)
{
Invoke("DisableText", 1);
}
}
void DisableText()
{
CenterPanel.SetActive(false);
GameoverText.text = "";
CenterText.text = "";
}
void SetGameoverText(string value)
{
GameoverText.text = value;
}
void SetCenterText(string value)
{
CenterPanel.SetActive(true);
CenterText.text = value;
}
IEnumerator BlinkText(string value)
{
isBlinking = true;
while (isBlinking)
{
CenterPanel.SetActive(false);
yield return new WaitForSeconds(.2f);
CenterText.text = value;
CenterPanel.SetActive(true);
yield return new WaitForSeconds(.2f);
}
DisableText();
}
IEnumerator StopBlinking()
{
yield return new WaitForSeconds(1f);
isBlinking = false;
}
public void RestartGame()
{
CenterPanel.SetActive(false);
RestartButton.SetActive(false);
int scene = SceneManager.GetActiveScene().buildIndex;
SceneManager.LoadScene(scene, LoadSceneMode.Single);
}
}
MomentInput script: this is to compare user entered answer of moment to calculated answer
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class MomentInput : MonoBehaviour {
private InputField input;
private MomentCalculator answerScript;
private float tolerance;
public bool WSign;
public bool WAnswer;
public bool RAnswer;
void Awake()
{
WAnswer = false;
RAnswer = false;
WSign = false;
input = GameObject.Find("MomentInput").GetComponent<InputField>();
GameObject answer = GameObject.Find("UFO");
answerScript = answer.GetComponent<MomentCalculator>();
tolerance = 0.5f;
}
void Update()
{
}
void Moment (string momentInput)
{
float result = 0.0f;
float.TryParse(momentInput, out result);
Debug.Log("direction =" + answerScript.direction);
Debug.Log("moment =" + answerScript.direction * answerScript.moment);
if ((result<= answerScript.direction*answerScript.moment+tolerance) && (result>= answerScript.direction * answerScript.moment-tolerance))
{
RAnswer = true;
}
else if (((-1)*result <= answerScript.direction * answerScript.moment + tolerance) && ((-1) * result >= answerScript.direction * answerScript.moment - tolerance))
{
WSign = true;
}
else
{
WAnswer = true;
}
}
// Update is called once per frame
}
MomentCalculator Script: this is used to calculate moment of a force to a point.
using UnityEngine;
using System.Collections;
public class MomentCalculator : MonoBehaviour {
public GameObject arrowHead;
public GameObject meteo;
public GameObject UFO;
public float unitForceValue;
public float moment;
public int direction;
private float momentArm;
private float force;
private float unitScale;
private Vector3 forceVector;
void Awake()
{
direction = 2;
unitScale = 3.6f;
}
// Use this for initialization
void Update() {
forceVector = ForceVector();
force = Force();
momentArm = MomentArm();
moment = Mathf.Round( force * momentArm);
direction = Direction(UFO.transform.position, meteo.transform.position, arrowHead.transform.position);
}
Vector3 ForceVector()
{
Vector3 forceVector;
forceVector = arrowHead.transform.position - meteo.transform.position;
return forceVector;
}
float Force ()
{
float f;
f = Vector3.Magnitude(forceVector) / unitScale * unitForceValue;
return f;
}
float MomentArm()
{
float m;
Vector3 w;
Vector3 d;
w = UFO.transform.position - meteo.transform.position;
d = Vector3.Cross(w, forceVector.normalized);
m = Vector3.Magnitude(d)/unitScale;
return Mathf.Round(m);
}
//1 means point is left anticloc, -1 means right clockwise, 0means on the line)
//a=rotation center b=previous position c=current position
int Direction (Vector3 a, Vector3 b, Vector3 c)
{
float direction = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
if(direction ==0)
{
return 0;
}
else if (direction<0)
{
return -1;
}
else
{
return 1;
}
}
}
I also tried this simplified version of script MoveForce, so there is no array ,only one target position to move to. I just named this version as trial 1 since it is for testing purpose. I also changed all Awake() function in other scripts to Start(). But the same problem persists... It can't work after restarting the game/reload the scene/restart Unity while every thing is fine before restarting... Using Debug.log, I found that after restaring , Start() is called, Update() is called but the first 'if' part in Update() is not called, so all following parts are not executed. This is so strange.
using UnityEngine;
using System.Collections;
public class trial1 : MonoBehaviour {
public Transform forceSet;
public Transform Targets;
public float moveSeconds = 2;
private Vector3 targetPosition;
private MomentInput momentScript;
private bool isMoving = false;
private float moveTimer=0;
// Use this for initialization
void Start () {
GameObject MomentInput = GameObject.Find("MomentInput");
momentScript = MomentInput.GetComponent<MomentInput>();
}
// Update is called once per frame
void Update () {
if ((momentScript.RAnswer == true))
{
StartMove();
}
if (isMoving)
{
moveTimer += Time.deltaTime;
if (moveTimer > moveSeconds)
{
isMoving = false;
}
else
{
float ratio = moveTimer / moveSeconds;
transform.position = Vector3.Lerp(forceSet.position, targetPosition, ratio);
}
}
}
void StartMove()
{
isMoving = true;
moveTimer = 0;
targetPosition = Targets.position;
Debug.Log("move");
}
}
Having a member variable called 'i' in a class somehow feels wrong. You should try to give class members self explaining names, then the code is easier to read, like e.g curTargetIdx I do not fully understand what you are doing here, because I can not look into gamecontroller and momentScript but you are using i to find the next target in Start$$anonymous$$ove(). After a time of moveSeconds has ellapsed you are increasing i, but it seems that i is never set back to 0. i is only set once to 0 upon the construction of the class, it is never set back to 0. This might be one reason your game only works once ?
I do agree with you wholeheartly that a member variable should NOT be called "i".
However, in this case "i" is a private nonserializable variable and thus would be reset on load as not serialized.
I think the problem must be somewhere else.
Thank you for your comment. Sorry to be unclear here. i is actually the index used for calling objects in array. As I have in total 4 targets so I grouped them in an array so each time the forceSet will transform to the position of a difference target.
Please do some debuging and verify that all variables have the expected value.
For example:
Verify that "Start$$anonymous$$ove()" is actually called.
Verify that if it is called, the transform update is reached (line 46)
Verify that if it is reached, the transform actually gets a new value (significant new enough to be visible)
If you have trouble debuging unity in VS, then please refeer to this tutorial:
https://unity3d.com/de/learn/tutorials/topics/scripting/debugging-unity-games-visual-studio
Thank you for your comment. When I remove the scrip and re-attach it to the gameobject, every function is called and they worked fine. and the transformed positions are all right.. but after I restart game or reopen Unity, Start() is called, Update() if called but the first if in Update() is not called.. so all the following methods are all not executed..
In $$anonymous$$omentInput script, please make sure that RAnswer can be set to true.
I see a lot of variables which are public but not initialized to a default value in either "Start/OnAwake/OnEnable" and thus could be having an unexpected default value.
I assume that in $$anonymous$$omentInput script, the if condition on line 36 is not entered, because the momentCalculator has old values.
Perhaps the $$anonymous$$omentCalculator.moment is somehow set to 0, which would lead the statement in the if to become 0 >= 0-tolerance, which would never be true when tolerance is larger than 0.
Usually "not working" is not enough information. ;)
Do you get errors in the console? Did you try breakpoints or added Debug.Log() calls to check what methods get invoked and what state your script is in?
Also: Please post your script as formatted text, not as images. Also you probably need to add the referenced scripts as the origin of the problem might be there.
Wild guess: The things you are grabbing in Start() are not available at that point and adding your script results in your Start() getting called at a later time than when loaded from the scene file. How are GameController or $$anonymous$$omentInput initialized?
Thank you for your comment. Sorry for being unclear. To be clearer, the script is not executed after scene is reloaded or Unity is reopened.
I got no errors in the console. I tried the version with removed reference to GameController script (since the reference is not affecting main function of this script) but it didn't help. I used Deg.log and found out that after restarting, the function Start() is executed, Update() is execute but the first if part in Update() is not executed so the ifs after that are also not executed. But the boolean RAnswer do change to true...
I cannot see anything wrong with it straight away without testing it in Unity myself.
$$anonymous$$y next wild guess would be that it has to do something with your serialized fields. Public fields in $$anonymous$$onobehaviours are serialized per default. You could check the value of the fields in the inspector to see if they change from the defaults.
If that is the case, make all fields private that you don't need access to from other scripts and use [System.NonSerialized]
for all public values that you don't want to store.
https://docs.unity3d.com/356/Documentation/ScriptReference/NonSerialized.html
It is still weird, though. Without something marking the object as dirty, Unity should not store the new value in the editor.
I think @ScaniX's idea that it's to do with order of execution could be worth looking into. You're setting some things up in Awake() calls that I would normally do in Start() so as to be sure that all the scene objects had already been awoken.
By the way, it's not clear to me what you mean by "the script doesn't execute". Scripts never execute. $$anonymous$$ethods execute.
Thank you for your suggestion. I moved those things to Start() but nothing changes :( . This script still works for first time only..
Backing off a little bit again... In such a case you usually go backwards from the concrete bug until you find a difference.
You said that the IF in the Update() is not entered anymore. So you need to check the places that normally (when you first attach the script) set the values that would make that expression evaluate to true. Those values are in the two other scripts momentScript und gamecontroller, so check who is setting those values. If they are not set anymore the corresponding script is not called anymore, find the place that is normally responsible to do that, and so on...
PS: Do the values in the inspector of those three scripts differ from the time you initially dragged them in (see my other comment)?
$$anonymous$$ay not be related to the issue but your use of GameObject.Find() definitely looks strange.
For example in the $$anonymous$$omentInput script you have
input = GameObject.Find("$$anonymous$$omentInput").GetComponent<InputField>();
If this is supposed to be finding the current GameObject's InputField component, just call GetComponent. Or, better, make input public and hook things up in the inspector.
If it's not meant to be finding the current GameObject's InputField, then you must have multiple objects with $$anonymous$$omentInput components. And if this is the case Find() is unlikely to be the right way to hook things up because it could be finding any of them.