I have been working on figuring out what is going on with my game's UI for at least two days now, and no progress.
Note that this is a mobile game, but I was asked to build for Windows for visualization and presentation purpose.
So the problem is that when I run my game on the Unity Editor, Android, iOS and Mac platforms the UI works just perfect, but then when I run the game on Windows the UI still works fine UNTIL I load a specific scene.
This specific scene is a loading screen (between main menu and a level) when the level finished async loading, a method called MoveObjects is called in a script in the loading screen, to move some objects that where spawned in the loading screen scene into the level scene (this is not the issue though, since I already try without this method and the problem on the UI persist).
Once the logic of this MoveObjects method is done, a start button is enabled in the loading screen, for the player to click and start playing (I did try moving the start button to the level scene, since maybe it not been a child of the currently active scene could be the issue, but the problem still persist). Is at this point that the UI is partially broken, what I mean with this is, that I can see buttons (and some other UI elements like a scrollbar) changing color/state when the mouse moves over them, but I cannot click on them anymore (the button wont even change to the pressed state).
Also note that I tried creating a development build to see if there was any errors in the console, and I notice that this problem is also affecting the old UI system, so I was not able to interact with the development console anymore.
Also also, note that if I grab and drag the scrollbar before this issue appear, and I keep holding down on the scrollbar until this happens, the mouse gets stuck on the scrollbar, meaning that I cannot interact with the UI anymore, but the scrollbar will still move with the mouse.
I already check that this things are not the source of the problem:
Missing EventSystem, GraphicRaycaster or InputModule.
Another UI element blocking the rest of the UI.
Canvas is Screen Space - Overlay so there is no need for a camera reference.
I only have one EventSystem.
Time.timeScale is 1.
I am not sure what else I could try, so if anyone has any suggestions, I would appreciate it. Thanks.
P.S: I am sorry to say that I cannot share any code or visual material or examples due to the confidentiality.
A major source for a non-working UI for me has always been another (invisible) UI object blocking the raycast (a transparent Image, or a large Text object with raycast on).
Here's a snippet I put together based on info found elsewhere, I often use it to track objects that are masking the raycast in complex UI situations. Place the component on a text object, make sure it's at least few lines tall, as the results will be displayed one under another.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
[RequireComponent(typeof(Text))]
public class DebugShowUnderCursor : MonoBehaviour
{
Text text;
EventSystem eventSystem;
List<RaycastResult> list;
void Start()
{
eventSystem = EventSystem.current;
text = GetComponent<Text>();
text.raycastTarget=false;
}
public List<RaycastResult> RaycastMouse(){
PointerEventData pointerData = new PointerEventData (EventSystem.current) { pointerId = -1, };
pointerData.position = Input.mousePosition;
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(pointerData, results);
return results;
}
void Update()
{
list= RaycastMouse();
string objects="";
foreach ( RaycastResult result in list)
objects+=result.gameObject.name+"\n";
text.text = objects;
}
}
Related
So my goal is to create a ProgressBar with rounded corners. This seems to be way harder than what it should be. I've tried looking at examples on StackOverflow but most of them are outdated or is referring to Android Studio which is NOT what I am working with.
As far as I know, I need to create a whats called "Custom Renderer" which is essentially a class that inherits from ProgressBarRenderer. And then change most of the properties there, which seems kinda silly since the UI should be done using XAML in my opinion.
I keep running into multiple issues when trying to create the custom renderer.
The first one being this
I've already installed Xamarin.Forms and it still keeps throwing that error.
And then there is a issue regarding the constructor. The constructor that doesn't take any parameters is obsolete and doesn't work anymore and it requires me to add a Context which I can't either because it throws the same error as above.
How do I properly create a progressbar with rounded corners and text in the middle indicating how much % it's at?
You should add proper reference to use the ProgressBarRenderer:
using App498.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
The custom renderer should look like this:
[assembly: ExportRenderer(typeof(Xamarin.Forms.ProgressBar), typeof(myProgressBarRenderer))]
namespace App498.Droid
{
public class myProgressBarRenderer : ProgressBarRenderer {
public myProgressBarRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.ProgressBar> e)
{
base.OnElementChanged(e);
}
}
}
If you want to add round corner to progress bar, check this thread.
I would refer you to SkiaSharp, graphics library, that enables you to create... well everything.
See the documentation here:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/
You'll need to play around for a while to get used to work with it, but it's quite intuitive and easy to work with.
To achieve round corners, you'll need to work with paths, described in here:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/curves/clipping
By a chance I also needed a progress bar in my app. I've drawn a picture with transparent line within for the progress to be shown, merged it with green rectangle (the progress itself) and voila, you've got the progress bar. When you need to update the progress, you just redraw the progress bar.
There are surely plenty of other solutions, but this one I reccomend as I know it will work fine.
Hapyy coding ;)
Obligatory "i'm very new". I couldn't figure out how to hook up a canvas that the player interacts with (chooses which team they'll be playing on in the game) that I had would work out if it was in the scene that the player prefab would be spawned into. So I put the canvas into the prefab with the player and set it as inactive once they select which team.
It works flawlessly for the host client (changes their "playerTeam" int and spawns them where they should be spawned) but when the second client joins their canvas is there, but won't take any input. I know it's this because the debug.log i put in right after input is not being run. here are the code segments that are necessary.
i have the canvas disabled by default and activated after an (isLocalPlayer) run on a script on the parent object. I can't add a networkID to the canvas because the prefab parent object has the networkID and they both can't have one, which means I cannot use (isLocalPlayer) on the canvas script, which may be the issue. But I also can't have the canvas on the actual level screen because even if i find the game object of the canvas, i don't know how to make it find which player to assign the playerTeam int to.
The following is run on a script attached to the canvas (of which the empty player object is the parent of)
Button CT = chooseCT.GetComponent<Button>();
CT.onClick.AddListener(parent.GetComponent<Sync>().CmdpickedCT);
and this is the code that runs on a script on the parent object
[Command]
public void CmdpickedCT()
{
GetComponent<Movement>().playerTeam = 2;
teamSelector.SetActive(false);
}
I apologize if I'm missing something big here. Thanks for any help.
for more information i have more stuff in the movement script run once the playerTeam is set to something other than 0, this also works on the host. Any other information you can give about how to pass info from the objects in the game scene to the instantiated objects would be great too. Thanks again.
Additional information, it seems like if i have both the second client and first client on the canvas at the same time, I cannot choose my team with either. It says "Trying to send command for object without authority".
I have a two modals that I'm designing to go over my project in Unity, one for a quick tutorial and one for more information about the project, I also have an animation playing in the background.
I'd like the animation to pause whenever the modals are active and over the top of the animation, if you can't see the animation, why have it playing? Exactly.
My code so far doesn't work and I'm unsure why.
using UnityEngine;
using System.Collections;
public class ModalPauseController : MonoBehaviour
{
public GameObject tutorialModal;
public ScrubberAnimationController nac;
public void TutorialModalIsOpen()
{
if (tutorialModal.activeInHierarchy == true)
{
Debug.Log("The tutorial panel is active!!");
nac.UserClickedPauseButton();
}
}
}
nac.UserClickedPauseButton refers to another script where it pauses the animation.
So far whenever I toggle the active state of the modals, whether it be via the inspector, or in game, I no feedback in my debug.
It's quite tricky writing code like that, because if you think about it
the code itself will be not active !!!
As a rule say you have a panel "X" which is a popup or something like that - something which comes and goes.
The rule is you must have the "controller" for that thing
on some other item, not on itself!
Here's an example:
The "megabomb" is a popup sign which goes on and off. There it is on
and there it is off. There's a script which controls the megabomb on-offness.
Notice there is a "wrapper" for the megabomb item. In UI the "wrapper" is very simply an empty panel. It is invisible. Note that the wrapper always stays on.
The script goes on the wrapper - that's it.
Note that very commonly the "megabomb" item itself has a "wrapper" - a gray transparent background. So, when the popup appears, the game behind goes all gray and you have the popup over that. Don't forget in that case the gray background would be labelled "megabomb" in this example and the actual popup green (or whatever) panel would be below that. (Indeed the popup panel itself will very likely have many parts -- images, buttons, borders, etc etc.) Do not try to use the "gray background" as the "wrapper which holds the script. You need a completely separate wrapper "outside of everything" which does nothing other than hold the script.
{BTW this is yet another thing which screws up experienced-developer-who-are-new-to-Unity. Normally you'd have "some other class" run the popup, but there is "no other class" in Unity - everything is a singleton if you will, since it is an ECS system, not normal OO. You have to literally have another game object (the one labelled 'wrapper' in the example) which controls the game object in question (the one labelled 'megabombs' in the example). AND it has to be always active.}
Note - if you prefer the "controller script" can actually be anywhere else (it does not have to be on an game object "holding" the item in question). However certainly at first I encourage you to use the system of putting it as a "wrapper" as shown, it has many advantages. (Not to mention ultimately it might be a Prefab, etc etc.) Definitely do that when starting out.
It's just "one of those things they don't mention" about Unity: very often many many things in your scene will need a "wrapper" object. (The same is true for other reasons such as positioning, relative rotations, etc, too.)
BTW as I mention in a comment. If you are making a popup, it must be done with Unity.UI (ie, click "add canvas" - always remember to set to 'scale with screen size' , then click "add panel", then click "add text").
I just learned how easy it is to simply drag a 3rd person character controller prefab (from Unity's standard assets package) and drop it into the hierarchy.
Using the WSAD and Space keys feels pretty natural, so I wondered if I could apply the same character controller to a customized avatar.
Using the free AutoDesk Character Generator (https://charactergenerator.autodesk.com/) I created one (fbx file) and imported it into Unity, so now I have my own character prefab.
I, then, searched for the steps to animate it just like a a 3rd person character controller, with the following article coming up first, but I wonder if I always have to do all the steps?
http://blogs.unity3d.com/2014/04/14/turn-your-character-into-a-player/
Once you have a customized character in the form of a Unity prefab, should do still go through all these steps, or is there a simpler way of animating your avatar; e.g. adding the basic necessary scripts?
That article gives a good overview of what is required.
However, you can essentially skip almost all those steps when using autodesk character generator.
Here is a quick way:
Set your FBX to be a mecanim humanoid
Drag an mecanim animator controller onto it
Write your code to set the animator states (eg: speed, jumping, etc)
To do that:
Export from Autodesk as "Unity FBX" format to get YourCharacter_Unity.fbx
Drag the FBX into the unity project files
Click on the YourCharacter_Unity FBX in project (blue cube), select "RIG" tab in inspector, and change Animation type to "Humanoid" (which maps it to the Mecanim system).
Drag the FBX from the project into the scene.
Go to the Asset Store and import "Mecanim Locomotion Starter Kit" (which has a basic locomotion controller and a set of animations)
Drag the "Locomotion Setup/Locomotion/Locomotion.controller" onto the "controller" variable on your character's Animator component.
Untick "apply root motion"
Now, if you hit run you will see your character standing there with idle motions. If you double click on the animator controller on your character it will open up the Mecanim Animtor window and you can manually set the animation state. Try changing the speed to 1.0 and you will see him walk/run.
Note: In your character's Animator component if you checkmark "Apply root motion", then the feet animation will cause your avatar to automatically move when his speed > 0.
You say you are using a CharacterController, so here is a very simple script that references the character controller to get the current speed, and then set the speed on the Animator:
using UnityEngine;
using System.Collections;
public class CharacterAnimator : MonoBehaviour {
public CharacterController controller;
public Animator animator;
private int speedid;
void Start () {
animator = GetComponentInChildren<Animator>();
controller = GetComponent<CharacterController>();
speedid = Animator.StringToHash("Speed");
}
void Update () {
float speed = controller.velocity.magnitude;
animator.SetFloat(speedid, speed);
}
}
I am currently trying to apply an overlay with LibGDX over my 3D ModelBatch. Everything works fine except for the SelectBox. Once instanciated, it shows up on my screen I can click on it once but then it freezes. The drop-down list is not displayed and the clicks are no longer registered by my application. However, if my second click is under the standard position of the list, that is where it should be drawn when it drops down, an item is selected but then any third click will just return the list to the original selected item and no click is registered by my application anymore. I am running the application on Desktop.
Using break points in the SelectBox.class I was able to notice that the third and other next clicks are registered by the SelectBox.class as part of the list in the Listener responsible for selecting an item.
selectBox = new SelectBox<Object>(skin);
selectBox.setItems(array);
selectBox.setSelected("Custom");
stage.addActor(selectBox);
array in this case is an instance of Object[] containing only Strings. This is the only part of code I have related to the selectBox.
I have tried using an array of String[] at first but then switched to Object as suggested on a LibGDX forum.
I am currently using the latest Nightly Build of 2014/04/11 as I also need TextArea which is not yet in the stable release. However, I have tried the stable release 0.9.9 and it doesn't work either.
Am I using the right code to declare my SelectBox, or what could I do to make the SelectBox behave properly that is display its list when clicked and return to a normal state after an item is selected?
I had the same problem, to fix it you must send the delta field (altered a bit) to the method stage.act();
Here is some example code:
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1); //sets up the clear color (background color) of the screen.
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); //instructs openGL to actually clear the screen to the newly set clear color.
// a stage has its own batch so don't put it within batch.begin() and batch.end()
stage.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f)); //you are likely missing THIS LINE :D
stage.draw();
}
I hope this helps!! :D