I've started learning C# and Unity3D this year and I've come across a problem. I'm loading a new level and the player object gets initialized before the the level has finished loading.
I think I only need to check whether the level is loaded or not before initializing the object. I don't know if I could use LoadLevelAsync. I'm using Unity3D Personal Edition.
My current code:
MasterClient.cs
void Update(){
if(SceneUpdateRequired)
{
Application.LoadLevel(SceneUpdateID);
if (Application.isLoadingLevel == false)
{
SceneUpdateRequired = false;
SceneUpdateCompleted = true;
}
}
}
void CharacterLoginUpdate(){
if (SceneUpdateCompleted == true)
{
GameObject networkPlayerObj = (GameObject)Instantiate(NPlayerObj, PlayerLoginUpdatePosition, PlayerLoginUpdateRotation);
NPlayer networkPlayer = networkPlayerObj.GetComponent<NPlayer>();
networkPlayer.UpdatePlayerInstantiateCompleted(PlayerLoginUpdateNetworkID, PlayerLoginUpdateHP, PlayerLoginUpdateClass, PlayerLoginUpdateLevel, PlayerLoginUpdateName, PlayerLoginUpdatePosition);
PlayerLoginUpdateRequired = false;
}
}
The problem with your code is your are loading level in update where if you dont control the task with booleans you are going to end up with big problems.
your update code should be as follows
void Update(){
if(SceneUpdateRequired)
{
Application.LoadLevel(SceneUpdateID);
SceneUpdateRequired = false;
}
if (Application.isLoadingLevel == false)
{
SceneUpdateRequired = false;
SceneUpdateCompleted = true;
}
}
This way the scene code will try to load level only when you request it to and not every time in update loop as loading levels is heavy.
Another thing is you might encounter one more problem if you need to use
SceneUpdateRequired,SceneUpdateCompleted variables somewhere else the
if (Application.isLoadingLevel == false)
{
SceneUpdateRequired = false;
SceneUpdateCompleted = true;
}
the above part which is in update loop will reset the variables everytime whenever its not loading the level. To prevent this you will have to introduce another boolean flag to stop its update happening everytime. So your code will end up looking like this if you want to prevent everyframe update
void Update() {
if(SceneUpdateRequired){
Application.LoadLevel(SceneUpdateID);
SceneUpdateRequired = false;
}
if (Application.isLoadingLevel == false && StartCheckingLoadLevel){
SceneUpdateRequired = false;
SceneUpdateCompleted = true;
StartCheckingLoadLevel = false;
}
}
void StartLoad() {
SceneUpdateRequired = true;
SceneUpdateCompleted = false;
StartCheckingLoadLevel = true;
}
void CharacterLoginUpdate(){
if (SceneUpdateCompleted == true) {
Debug.Log("Do Something after load");
} else {
Debug.Log("Scene not yet loaded");
}
}
Hope this helps.
Related
im creating an android map game and i cant solve a problem, i have a map and i also have a menu that pops up once i press on a gameobject with a collider. I had a problem that if i would press on that UI menu it would go throught it and it would turn the menu off, because i coded that if i press on another gameobject with a collider it would turn off. I fixed that by making a UI detection script (found it on google), where it draws a raycast from my cursor and detects a gameobject with a specific layer and returns a true or false value.
THE PROBLEM: Right now everything works fine on pc, since i am hovering with my cursor, but if i go on my unity remote once i press on the menu, it still turns off, because i guess its not quick enough to detect that its a UI element?
SOME CODE:
This is a UI Detection code:
public bool isOverUI;
private void Start()
{
UILayer = LayerMask.NameToLayer("MAINMENUCOMPONENTS");
}
private void Update()
{
print(IsPointerOverUIElement() ? "Over UI" : "Not over UI");
}
//Returns 'true' if we touched or hovering on Unity UI element.
public bool IsPointerOverUIElement()
{
return IsPointerOverUIElement(GetEventSystemRaycastResults());
}
//Returns 'true' if we touched or hovering on Unity UI element.
private bool IsPointerOverUIElement(List<RaycastResult> eventSystemRaysastResults)
{
for (int index = 0; index < eventSystemRaysastResults.Count; index++)
{
RaycastResult curRaysastResult = eventSystemRaysastResults[index];
if (curRaysastResult.gameObject.layer == UILayer)
{
isOverUI = true;
return true;
}
}
isOverUI = false;
return false;
}
//Gets all event system raycast results of current mouse or touch position.
static List<RaycastResult> GetEventSystemRaycastResults()
{
PointerEventData eventData = new PointerEventData(EventSystem.current);
eventData.position = Input.mousePosition;
List<RaycastResult> raysastResults = new List<RaycastResult>();
EventSystem.current.RaycastAll(eventData, raysastResults);
return raysastResults;
}
This is the menu code:
public UIDETECTIONS UID;
if (UID.isOverUI == true)
{
}
else if (UID.isOverUI == false)
{
if (infoMenuOn == false)
{
if (isCountryClicked == false)
{
isCountryClicked = true;
infoMenuOn = true;
Debug.Log("MENU ON");
}
else if (isCountryClicked == true)
{
isCountryClicked = false;
}
}
else if (infoMenuOn == true && isCountryClicked == true)
{
infoMenuOn = false;
isCountryClicked = false;
Debug.Log("MENU OFF");
}
}
I Should have done more research :D, derHugo gave me a hint, which was kind of an answer.
I found this piece of code which works for android. Works quite the same.
private bool IsPointerOverUIObject() {
PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current);
eventDataCurrentPosition.position = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(eventDataCurrentPosition, results);
return results.Count > 0;
}
With this code you can check if youre clicking over ui elements:
if (IsPointerOverUIObject() == true) // true or false
I am trying to make a door in my unity game for testing purposes, but I'm finding that my door doesn't shut completely once it has been opened.
This is most of my code for my door
{
unlockedSound.Play();
locked = false;
keyOB.SetActive(false);
StartCoroutine(unlockDoor());
}
if (inReach && doorisClosed && unlocked && Input.GetButtonDown("Interact"))
{
door.SetBool("Open", true);
door.SetBool("Closed", false);
openText.SetActive(false);
openSound.Play();
doorisOpen = true;
doorisClosed = false;
}
else if (inReach && doorisOpen && unlocked && Input.GetButtonDown("Interact"))
{
door.SetBool("Open", false);
door.SetBool("Closed", true);
closeText.SetActive(false);
closeSound.Play();
doorisOpen = false;
doorisClosed = true;
}
if (inReach && locked && Input.GetButtonDown("Interact"))
{
openText.SetActive(false);
lockedText.SetActive(true);
lockedSound.Play();
}
}
IEnumerator unlockDoor()
{
yield return new WaitForSeconds(0.05f);
{
unlocked = true;
lockOB.SetActive(false);
}
}
I have the animations set to properly close the door, I'm unsure of how to move forward with this.
I have even tried isolating the door and suspending it in the air incase something was preventing it from closing properly
I m a newbie to Unity3d and was just playing with unity animation, i was trying to implement 2 Main UI Button such as when either of them is pressed it should check the condition whether a animation is already played before by 2nd button available if yes then remove those gameobject from scene using reverse animation else play the default animation attach to the particular button.
Problem is out of 6 case only 4 are getting operational 2 of them are not executing (marked in the code as Case Not Operational)
Animation anim;
private bool isOpen = false;
private bool open = false;
// Start is called before the first frame update
void Start()
{
anim = GetComponent<Animation>();
//isOpen = false;
//open = false;
}
// Update is called once per frame
void Update()
{
}
void OnGUI()
{
isOpen = GUI.Toggle(new Rect(50, 50, 200, 100), isOpen, "IsOpen");
open = GUI.Toggle(new Rect(65, 65, 200, 100), open, "Open");
}
public void ButtonControl()
{
string name = EventSystem.current.currentSelectedGameObject.name;
if (name == "Main Button 1")
{
if (isOpen == false && open == false)
{ Debug.Log("False False 1");
Anim1();
isOpen = true;
}
else if (isOpen == false && open == true) // case not operational
{ Debug.Log("False True 2");
ReverseAnim_2();
open = false;
Anim1();
isOpen = true;
}
else if(isOpen == true)
{
Debug.Log("True 3");
ReverseAnim_1();
isOpen = false;
}
}
else if (name == "Main Button 2")
{
if (open == false && isOpen == false)
{ Debug.Log("False False 4");
Anim2();
open = true;
}
else if(open == false && isOpen == true) // case not operational
{ Debug.Log("False True 5");
ReverseAnim_1();
isOpen = false;
Anim2();
open = true;
}
else if(open == true)
{
Debug.Log("True 6");
ReverseAnim_2();
open = false;
}
}
}
void ReverseAnim_1()
{
anim["1"].speed = -1;
anim["1"].time = anim["1"].length;
anim.Play();
}
void Anim1()
{
anim["1"].speed = 1;
anim.Play();
}
void Anim2()
{
anim["2"].speed = 1;
anim.Play();
}
void ReverseAnim_2()
{
anim["2"].speed = -1;
anim["2"].time = anim["2"].length;
anim.Play();
}
The problem is that you have two Main_B2 scripts and they are each tracking their own values for the isOpen and open fields.
One solution for this could be to make the fields static so that they are in common across all instances of Main_B2.
Animation anim;
private static bool isOpen = false;
private static bool open = false;
If you do this, your code should work as intended - each instance of Main_B2 would then be referring to the same fields whenever they reference isOpen or open.
With that said, static fields can get kind of sloppy if you ever want to try and re-use code so a better option might be to have only one instance of Main_B2 somewhere else such as the Canvas, instead of one on each button.
Then you could have in it public GameObject fields that you can drag the button objects into, and private Animation fields for the animations.:
public GameObject button1
public GameObject button2
private Animation anim1
private Animation anim2
Then in Start:
anim1 = button1.GetComponent<Animation>();
anim2 = button2.GetComponent<Animation>();
And then wherever you referred to anim you would refer to anim1 or anim2 instead:
void ReverseAnim_1()
{
anim1.["1"].speed = -1;
anim1.["1"].time = anim1["1"].length;
anim1.Play();
}
void Anim1()
{
anim1["1"].speed = 1;
anim1.Play();
}
void Anim2()
{
anim2["2"].speed = 1;
anim2.Play();
}
void ReverseAnim_2()
{
anim2["2"].speed = -1;
anim2["2"].time = anim2["2"].length;
anim2.Play();
}
Your scripts 'anim' variable is an Animation. Normally to adjust animation parameters you set them on an Animator, not Animation. But perhaps your solution can work.
For clarity. An animator organizes how animations play out, when, for how long and how they transition.
I would personally advise you to use an animator with behaviour patterns and transitionings between animations. Instead of the current approach.
Either that or use one of the many Tweening asset packs from the asset store. They are specifically made to create UI effects like what you describe.
At least consider these solutions if you keep being stuck :-)
I am trying to code a mute button, and it works, however the setting of that button is not saved.
public void Mute (){
AudioListener.volume = 0;
sound.enabled = false;
sound.image.enabled = false;
noSound.enabled = true;
noSound.image.enabled = true;
}
public void UnMute (){
AudioListener.volume = 1;
sound.enabled = true;
sound.image.enabled = true;
noSound.enabled = false;
noSound.image.enabled = false;
}
I have 2 methods here, and I need it to save the state of which one was clicked using playerprefs. I was thinking something along the lines of a boolean, but I'm stumped, and and I can't wrap my head around how I would do that.
Yes you can do that with the help of a boolean variable as like the following:
public bool isMuted = false;
public void Do_muteOperation()
{
if (isMuted)
{
UnMute();
isMuted = false;
}
else
{
Mute();
isMuted = true;
}
}
I'd like to know how I can pause and unpause menu from the same button using the mouse pointer when I click on it.
Lets say I have this. C#
void Update () {
if (Button_Pause.OnPointerClick()) {
if(!active){
PauseGame();
}
else{
ResumeGame();
}
active = !active;
}
}
public void PauseGame()
{
Button_Pause = Button_Pause.GetComponent<Button> ();
Canvas_PauseMenu.enabled = true;
Button_Exit.enabled = true;
Button_Pause.enabled = true;
}
public void ResumeGame()
{
Canvas_PauseMenu.enabled = false;
Button_Exit.enabled = false;
Button_Pause.enabled = false;
}
In the first line, where I call the OnPointerClick I'm just guessing because I don't know what to do. What I've searched around, using click to show something it's having a TimeScale or something like that.
¿Can anyone help moi? Please.
Add a listener for your button and in your pause script set timescale to zero to pause the game
[SerializeField] private Button MyButton = null; // assign in the editor
void Start() { MyButton.onClick.AddListener(() => { pause();});
}
void pause(){
if (Time.timeScale == 1)
{
Time.timeScale = 0;
}
else
{
Time.timeScale = 1;
}
}
I managed to solve the issue. It might not be efficient but it does what I need.
I created 2 buttons in the same place. Those buttons are represented with different sprites (Pause & Play). "Pause" is visible since the start. When I click on it, the menu pops up, the "Pause" stop being active and the "Play" sprite button activates and pops up too. When I click on it, I unpause and goes back to the "Pause" sprite visible in the screen.
void Start () {
Canvas_PauseMenu = Canvas_PauseMenu.GetComponent<Canvas> ();
Button_Pause = Button_Pause.GetComponent<Button> ();
Button_Resume = Button_Resume.GetComponent<Button> ();
Canvas_PauseMenu.enabled = false;
Button_Resume.enabled = false;
Button_Resume.gameObject.SetActive (false);
}
// Update is called once per frame
public void PauseTest () {
if(!active){
PauseGame();
}
else{
ResumeGame();
}
}
public void BackToMainMenu()
{
Application.LoadLevel (0);
}
public void PauseGame()
{
Canvas_PauseMenu.enabled = true;
Button_Exit.enabled = true;
Button_Pause.enabled = false;
Button_Pause.gameObject.SetActive (false);
Button_Resume.enabled = true;
Button_Resume.gameObject.SetActive (true);
active = true;
Time.timeScale = 0;
}
public void ResumeGame()
{
Canvas_PauseMenu.enabled = false;
Button_Exit.enabled = false;
Button_Pause.enabled = true;
Button_Pause.gameObject.SetActive (true);
Button_Resume.enabled = false;
Button_Resume.gameObject.SetActive (false);
active = false;
Time.timeScale = 1;
}