I'm building a UI system to edit selected 3D objects. I have spheres on the screen and I want to be able to edit their proprieties (radius for example). In order to do that I want the user to be able to click on a sphere and then it show a panel next to the object. When the user changes slider value the radius of the sphere which as been clicked on change. Using the new unity event system, I think it's easy to achieve, but I'm a new to unity and even if I know the basic I don't know how to organize this properly.
At the end my goal would be to select multiple sphere, right click and edit the radius to all selected spheres.!
Any tips on how to do that ? Sorry for my poor english. Thanks
Here's how you can do it:
Keep a bool for tracking if the object is selected, say, bool _isSelected
Toggle this boolean in the OnMouseUpAsButton() function. This function is called when you click on an object and release that click on the same object. Unity's OnMouseXXX() interfaces are very good for handling mouse events. You just need to define this function in the sphere objects' script.
Put together a Slider and arrange its value interval from editor. Define a function that will edit the scale value of the spheres and tie that function to that slider.
Below you can see an example of how I did that in a game of mine.
Unity simply catches the slider's value if you provide it with a public void _f(float val). It will appear on the top of the list as "Dynamic float". So, in your case, your slider update function should look like this:
public void SphereScaleSliderUpdate(float val)
{
foreach (GameObject sphere in GameObject.FindGameObjectsWithTag("your tag here"))
{
if (sphere.IsSelected) // don't forget to provide a public getter for _isSphere variable
{
sphere.transform.localScale = new Vector3(val, val, val);
}
}
}
Also, you need to create another script for toggling the menu(Canvas/Panel(optional)) that contains the slider, and you may add it to another object, like a UIManager. Assign the Canvas in the game hierarchy to a variable in that script, and then scan for RClick in the Update() function of the UIManager.
.
void Update()
{
if (Input.GetMouseButtonDown(1) // RClick event
{
// makes the slider appear through enabling canvas
_canvasHandle.enabled = true;
}
}
Related
I am making a 2d game in unity. I am using the UI toggle methods and wish to make one of those turn off when the other one is turned on. The method I have tried is doing the following code below (InfiniteMode and CampaignMode are the names of the two toggles):
if (InfiniteMode.isOn)
{
PlayInfinite();
CampaignMode.onValueChanged.Invoke(false);
}
if (CampaignMode.isOn)
{
PlayCampaign();
InfiniteMode.onValueChanged.Invoke(false);
}
Any help for what I can do to achieve this would be great.
As far as I understand you want to have two UI Toggles which acts as a group, when one of them is on, the rest of the items are off. In order to do this you can use Toggle Group component from Unity UI. You can find more information on that here: Toggle Group documentation.
If you look at Toggle component there is a Group variable. If you create an empty GameObject inside your Canvas and add Toggle Group component to it and assign that Toggle Group object to all your Toggle's which you want to be a part of that group
it should work.
You can add listeners to your toggles like this:
[SerializeField]
private Toggle myToggleVar;
private void Start() {
// UI event listeners
myToggleVar.onValueChanged.AddListener(delegate { onToggleExec(); });
}
private void onToggleExec() {
Debug.Log("Toggled!") //here you need to manipulate your other toggle
}
I want to create a blur effect similar to the picture below:
the picture is taken from this site:
https://forum.unity.com/threads/how-to-blur-specific-layers-only.555520/
I tried the post-processing profile and played around with the depth of field in the post-processing volume but it blurs all the scene.
I came across a YouTube Video that explains how to implement similar results to what I am looking for but things have changed drastically in the settings. For example, at 1:57 (minute and 57 seconds) he clicks on Add Additional Camera Data which I am struggling to find in the latest versions of LWRP.
I am using Unity version 2019.2.9f1
How can I achieve the result in the picture above? (Blurring all the scene except for one object)
Your guidance will be appreciated.
NOTE: My project is in VR using SteamVR and VRTK
Though your question is a bit broad I took some time to show you how it can be done.
First of all you will need to import the Post Processing package via the PackageManager
Window → PackageManager
Make sure to be in the All Packages view, search for post, find the Post Processing package and hit Install
Now first of all go to the Layer settings (Layers → Edit Layers)
and add two additional Layers: e.g. PostProcessing and Focused
Now to the cameras. Afaik it makes no difference whether you are in VR or not, usually you have one MainCamera that is moved along with your headset. If there should be two of them in your project setup just repeat the same steps for the second camera.
Make sure the MainCamera doesn't render the two added Layers → remove them from the Culling Mask
Add a new Camera FocusCamera as child to the existing MainCamera. This way it is automatically moved along with the main Camera.
RightClick on MainCamera &rightarrow Camera
It should have all the settings equal to the MainCamera except:
Clear Flags : Don't Clear
If you set it to Depth Only the focused object will always be rendered on top of everything, even if it is actually behind other objects in 3D space. You decide which effect you want here ;)
CullingMask : only Focused
Depth : Anything higher than the MainCamera so this camera is rendered on top of it
Make sure to remove the AudioListener component.
Finally add a new PostProcessingVolume to the scene. I would add it as child to the FocusCamera! Why? - Because this way it is automatically disabled together with the FocusCamera!
RightClick on FocusCamera → 3D Object → Post Processing Volume
Set its Layer to the added PostProcessing
enable Is Global so the distance to the volume doesn't matter and add a new profile by hitting new → Unity → Depth of field
In your case you want to overwrite the Focus Distance so check the box on the left and set a value close to the camera like e.g. 0.5
Until now nothing has really changed in your scene.
Now go to the MainCamera and, a component PostProcessingLayer and set the Layer to our added layer PostProcessing
Now everything should be blurred in your scene!
Almost ready to go! Now Disable the FocusCamera and add this script to it
using UnityEngine;
public class FocusSwitcher : MonoBehaviour
{
public string FocusedLayer = "Focused";
private GameObject currentlyFocused;
private int previousLayer;
public void SetFocused(GameObject obj)
{
// enables this camera and the postProcessingVolume which is the child
gameObject.SetActive(true);
// if something else was focused before reset it
if (currentlyFocused) currentlyFocused.layer = previousLayer;
// store and focus the new object
currentlyFocused = obj;
if (currentlyFocused)
{
previousLayer = currentlyFocused.layer;
currentlyFocused.layer = LayerMask.NameToLayer(FocusedLayer);
}
else
{
// if no object is focused disable the FocusCamera
// and PostProcessingVolume for not wasting rendering resources
gameObject.SetActive(false);
}
}
// On disable make sure to reset the current object
private void OnDisable()
{
if (currentlyFocused) currentlyFocused.layer =previousLayer;
currentlyFocused = null;
}
}
This will allow you to focus a certain GameObject on runtime by changing its layer to the Focused layer we added, the only one that is rendered by the FocusCamera. So this object will be rendered on top of the image without any blur effect!
For demonstration I just added this simple script to every cube object in order to enable focus on mouse enter and disable it on mouse exit:
using UnityEngine;
public class FocusMe : MonoBehaviour
{
[SerializeField] private FocusSwitcher focus;
private void OnMouseEnter()
{
focus.SetFocused(gameObject);
}
private void OnMouseExit()
{
// reset the focus
// in the future you should maybe check first
// if this object is actually the focused one currently
focus.SetFocused(null);
}
}
And here is what it looks like
as said I don't know exactly what your VR setup looks like. If you have to MainCameras simply add two child cameras to them. You still will need only one PostProcessingVolume and only one FocusSwitcher so you would probably move them to another object and handle the camera disabling etc differently but I hope the idea gets clear enough.
Use a separate camera for objects you don't want to blur and set a higher depth value.
Set the ClearFlags to depth only and in the CullingMask select the layer of that one object(or more objects). Obviously you would require to have a different layer for unblurred objects.
Is there a way to make standard unity OnClick even fire while ignoring specific layers?
For example, i have army of soldiers on layer "Units" and ground on Layer "Ground". When i click on soldier, it gets selected. Then i click on the ground, soldier moves there. But if i click on the ground obscured by another soldier, it fires even for that soldier rather than ground, cos he is closer to the camera.
Can i ignore "Units" layer without rewriting whole mouse click even handling and using my custom raycast?
EDIT:
code is here, dont thnk it will show anything but
static public void Interact2(Cell target) //this fires from OnClick
{
if (GameLogic.Mode == mode.move)
{
grid.MoveTo(target);
if (selected.actionsAvilable[action.move])
selected.actionsAvilable[action.move] = false;
else
selected.actionsAvilable[action.standard] = false;
GameLogic.Mode = GameLogic.mode.normal;
}
}
MORE EDIT:
void OnMouseDown() {
if (!UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject())
GameLogic.Interact2(this);
}
The PhysicsRaycaster/PhysicsRaycaster2D/GraphicsRaycaster components have an Event Mask property which allows you to limit the layers they raycast against. You should update that property from code when you want to block/allow certain layers.
I hope I am posting in the correct section. I know that it is possible to write a custom code in Unity so I have the following questions:
Imagine a house model in Unity. Would it be possible to have a code which helps to hide/unhide certain objects? For example, letter "W" would hide/unhide all windows, letter "C" would hide/unhide all columns etc.
If it would be possible to develop a code for that, what would be the workflow? How would Unity know what is window and what is door?
Taking one step further.. Would it be possible to have a code that unhides the next step of the project. For example, the first step would be building foundations. Would it be possible to have a code that would unhide the next step, say, 1st floor floor element, with a klick of a keyboard key? And then with the same key unhide the next step which might be 1st floor walls. And would it be possible with another key go backwards?
If such code would be possible, what do you think would be the workflow? How would Unity know which element is in which step?
Yes just have a class with an array of objects to show/hide and another property for what button will do it. Then just have a method that will hide/unhide each object in that class. In the update method of a behavior just check the input and call the method of the class based on what button was pressed.
Would it be possible to have a code which helps to hide/unhide?
Yes, you can do that by calling GameObject.SetActive() function
door.SetActive(true); // door is a game object;
How would Unity know what is window and what is door?
You can give the window/door a name, then access the game object by name
var door = GameObject.Find("MyDoor") as GameObject;
Would it be possible to have a code that would show the next step, say, 1st floor floor element, with a klick of a keyboard key?
Yes, you can do that with code snippet below:
int step = 1;
void Update() {
if (Input.GetKeyDown("space")){
print("space key was pressed");
step++;
}
if(step == 1) {
// do sth
}
else if(step == 2) {
// do sth
}
}
Given the above snippet, your last answer can be easily deduced.
I see 2 ways of doing what you asked.
1st way
GameObject[] walls;
walls = GameObject.FindGameObjectsWithTag("Wall");
foreach (GameObject wall in walls)
{
wall.setActive(true);
}
What you will have to do, besides the code, is to assign to those object a correct tag (like "Wall" "Window" "WatheverYouWillNeed"). So you can easily find all objects by giving them some kind of order (with tags).
Best practice tip
You may want to create a static class "Tags", and set public constants string inside the class, with all tag names.
public static class Tags
{
public static const WINDOW_TAG = "Window";
// ... more tags
}
2nd way
If what you want to set is only "visibility", you may want to modify only camera tag rendering. It doesn't even require any cycle at all. When you want to view windows, you just tell your camera to render the tag "Window".
// Turns on Windows Layer on mask using an OR operation
private void Show()
{
camera.cullingMask |= 1 << LayerMask.NameToLayer("Window");
}
// Turn off the bit using an AND operation with the complement of the shifted int:
private void Hide()
{
camera.cullingMask &= ~(1 << LayerMask.NameToLayer("Window"));
}
It may look odd the second option, but keep in mind that the cullingMask is composed of bits, and every bit is a Layer defined by your tags. The "Everything" culling mask is 111111. If you want to see only Window, for example, and window is the last element, your culling mask would look something like 0000001
Hope it helped! :)
In Unity, using C#, how do I detect a click anywhere in the screen, without attaching the script to an object?
To be specific, I am looking for individual clicks, not mouse downs.
e.g. the code below checks for mouse down, but I want clicks instead
// Update is called once per frame
void Update () {
// 1
Vector3 currentPosition = transform.position;
// 2
if( Input.GetButton("Fire1") ) {
// Do something
}
}
You are going to need a MonoBehaviour so that you can use the Update() function to your advantage. Just attach it to an empty GameObject, it is not uncommon for a game to have one empty GameObject that has a few scripts that handle certain things.
Check for GetMouseUp to count your clicks.