I am newbie in Unity I am working on Augmented reality project where I am showing 3D Objects based on the marker that is working fine. But what I would like is to show different objects based on click events
Here is the scenario I did so far:
I created 4 different scenes with 3D objects with markers
Made one canvas frame where I put 3 buttons on it
In each button click I am loading next scene, below is the code that I wrote. The problem is it is showing black screen instead of loading new objects. I don't want to load a camera again. Can anyone help me with this?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement; // <<<<<< ADD THIS.
public class Button_1 : MonoBehaviour
{
public void Button_Click()
{
Debug.Log("Hello, World!");
// Application.LoadLevel("Multi Target");
SceneManager.LoadScene("MultiTarget_1"); // <<<< Then Do this.
}
public void Button_Click2()
{
Debug.Log("Hello, World!");
// Application.LoadScene("Multi Target_1");
SceneManager.LoadScene("NameOfScene"); // <<<< Then Do this.
}
public void Button_Click3()
{
Debug.Log("Hello, World!");
Application.LoadLevel("Multi Target_2");
}
public void Button_String(string msg)
{
Debug.Log("Hello, All!");
Application.LoadLevel("Multi Target_1");
}
}
image
If you have, let's say, two groups of Objects in a Scene, for example:
GoupA = Cars
GroupB = Pedestrians
And you want that by default Cars are visible and Pedestrians are not, so as soon as you click a button Cars become invisible in your scene and Pedestrians become visible, one thing you can do is to assign different layers for each group of objects and then change the culling mask of your camera programatically when one of the buttons is pressed.
Step 1:
You need to create two or more layers in your scene, and assign those layers to your GameObjects in your scene, depending on what objects you want to make visible at the same time after button click. You will need to read about this here:
https://docs.unity3d.com/Manual/Layers.html
Step 2:
Create in your code a reference to the active Camera in your scene:
Camera cam;
Step 3:
Change your logic inside Button_Click methods
public void Button_Click1()
{
// Only render objects in the first layer (Default layer)
cam.cullingMask = 1 << 0;
}
...
These are other things you can do with the culling mask (depending on how you want to display your GameObjects):
// Render everything *except* layer 3
camera.cullingMask = ~(1 << 3);
// Switch off layer 3, leave others as-is
camera.cullingMask = ~(1 << 3);
// Switch on layer 3, leave others as-is
camera.cullingMask |= (1 << 3);
You can read more about it here:
https://docs.unity3d.com/ScriptReference/Camera-cullingMask.html
Hi i think you can fix your project by just grouping and hiding the GameObject. its much more simple that you think... i already write a sample code... and i already add a link to do just that on how to group the object if you need help on that... i am an Augmented Reality Developer as well so i understand the problem that you are having.... hope this will help..
URL: https://www.youtube.com/watch?v=MP62CcK-qTc
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement; // <<<<<< ADD THIS.
public class Button_1 : MonoBehaviour
{
public GameObject MultiTarget_1, NameOfScene,Multi_Target_2,Multi_Target_1;
public void Button_Click()
{
Debug.Log("Hello, World!");
HideAll();
MultiTarget_1.SetActive(true);
}
public void Button_Click2()
{
Debug.Log("Hello, World!");
HideAll();
NameOfScene.SetActive(true);
}
public void Button_Click3()
{
Debug.Log("Hello, World!");
HideAll();
Multi_Target_2.SetActive(true);
}
public void Button_String(string msg)
{
Debug.Log("Hello, All!");
HideAll();
Multi_Target_1.SetActive(true);
}
//call this to hide all
public void HideAll(){
MultiTarget_1.SetActive(false);
NameOfScene.SetActive(false);
Multi_Target_2.SetActive(false);
Multi_Target_1.SetActive(false);
}
}
There are two things. First check if the correct scene name is given and that it is loading.
If you want to persist the Camera Object over different scenes, then make the object DontDestroyOnLoad() using a script attached to the Camera.
Read more here:
https://docs.unity3d.com/ScriptReference/Object.DontDestroyOnLoad.html
You dont need different scenes, just 1 scene which has AR sessions and AR session origin.
create a new blank gameobject and reset its transform ( Scale , rotation , position) so that everything is at 0, except "scale" which will be at 1,
select all the gameobject you want during "BUTTON 1" click event , make them the child of the new blank gameobject which you created.
Repeat the same for the all the gameobjects which you want to change during button click.
After you have created each game object for each button, make them PREFABS. ( just drag the game object from The Hierarchy window to project wind where you can see all your files )
Create a script and create public or serialised array of Gameobect variable , and save the script.
public Gameobject obj1[];
If you are not aware of using arrays, you can just create multiple(number of buttons / Parent Gameobjects you have) gameobject variables
Drop the script on a gameobject , on the script you will see that you can drag drop the game objects with the same name which you have given during creation of variables.
In the UI Script ( on button click event) , you just have to enable and disable the prefabs ( VARIABLES WHICH YOU CREATED) accordingly,
Related
I am making a 2D game in unity, and I want a start screen, but I cant find out how to make the start button clickable, and to then change the scene to level 1
The game will be a cursor labyrinth, so any help with detecting if a mouse is hovering over something would be appreciated
I looked up a bunch of tutorials but none of them worked in c#
STEP 1:
You will have to add a Button Component to the sprite.
Alternatively, you can right click in the Scene Hierarchy and go to Create -> UI -> Button. This automatically creates a simple Button for you. Then it sprites can be changed accordingly.
STEP 2:
Then assign callback to the Button in the OnClick() Field to make it interactable. To load the scene,
Create a new C# script. Make a new method in it. Use the LoadScene method in SceneManagement class. Then the script becomes:
using UnityEngine;
using UnityEngine.SceneManagement;
public class ExampleScript: MonoBehaviour
{
public void Loadscene(int sceneIndex)
{
SceneManager.LoadScene(sceneIndex);
}
}
Here you go bro.
public bool IsOverUi()
{
var eventDataCurrentPosition = new PointerEventData(EventSystem.current)
{
position = Input.mousePosition
};
var results = new List();
EventSystem.current.RaycastAll(eventDataCurrentPosition, results);
return results.Count > 0;
}
Following the Answer here: https://answers.unity.com/questions/1199251/onmouseover-ui-button-c.html
You can add a script:
public class MyClass: MonoBehaviour, IPointerEnterHandler{
public void OnPointerEnter(PointerEventData eventData)
{
//do stuff
}
}
Forewords
Firstly, I know posting graphical resources for codes is not encouraged in this platform. I will also post the code but, in this particular case, I think posting a video about it is much more helpful than just posting some arbitrary code because the structuring of game projects really vary depending on their requirements. However, I still respect the platform's rules so if a mod asks me to format my question according to the community rules, I can do that or they also can simply delete my question. I respect that.
The Issue
It's actually a simple issue but it's driving me crazy because of its simplicity. I just want to fade in when I load a scene and then fade out whenever I click a button. As to how I do that, this is the video about it.
To sum up, I load another scene called "Fader" which contains a ColorRect with a black color and AnimationPlayer to change ColorRect's alpha value.
The code is below with extra comments on relevant parts:
using Godot;
using System;
public class TitleScreen : Control
{
private Button[] buttons;
private Control fader; // the scene that I inject
public override void _Ready() // when title screen gets ready
{
GD.Print("Preparing TitleScreen...");
InitButtons();
InitFader(); // initialize fader
FadeIn(); // do fade in animation
}
private void InitFader() // initializing fader
{
GD.Print("Initializing fader...");
var faderScene = (PackedScene)ResourceLoader.Load("res://components/Fader.tscn"); // load external fader scene
fader = (Control)faderScene.Instance(); // instantiate the scene
fader.SetSize(OS.WindowSize); // set the size of fader scene to the game window, just in case
var rect = (ColorRect)fader.GetNode("rect"); // get "rect" child from fader scene
rect.SetSize(OS.WindowSize); // set "rect" size to the game window as well, just in case
fader.Visible = false; // set the visibility to false
AddChild(fader); // add initialized fader scene as a child of title screen
}
private void InitButtons()
{
GD.Print("Initializing buttons...");
buttons = new Button[3]{
(Button)GetNode("menu_container/leftmenu_container/menu/start_button"),
(Button)GetNode("menu_container/leftmenu_container/menu/continue_button"),
(Button)GetNode("menu_container/leftmenu_container/menu/exit_button"),
};
GD.Print("Adding events to buttons...");
buttons[0].Connect("pressed", this, "_StartGame");
buttons[2].Connect("pressed", this, "_QuitGame");
}
private void FadeIn()
{
GD.Print("Fading in...");
fader.Visible = true; // set visibility of fader to true
var player = (AnimationPlayer)fader.GetNode("player"); // get animation player
player.Play("FadeIn"); // play FadeIn animation
fader.Visible = false; // set visibility of fader to false
}
private void FadeOut()
{
// similar to FadeIn
GD.Print("Fading out...");
fader.Visible = true;
var player = (AnimationPlayer)fader.GetNode("player");
player.Play("FadeOut");
fader.Visible = false;
}
public void _StartGame() // whenever I click start game button
{
FadeOut(); // fade out
GetTree().ChangeScene("res://stages/Demo01.tscn");
}
public void _QuitGame() // whenever I click quit game button
{
FadeOut(); // fade out
GetTree().Quit();
}
}
Seems like I can't see something. Why does it not fade in and out?
Environment
Manjaro 19.0.2
Mono JIT Compiler 6.4.0 (if it is relevant)
Godot 3.2
So, the issue was Play method on AnimationPlayer object kinda runs like async (dunno if this is the correct term for it).
Luckily, there is a feature called signals in Godot. There are animation_started and animation_finished signals on AnimationPlayer objects. Basically, I created a C# script for Fader scene, hooked the signals from player to fader as in:
animation_started to _FaderAnimationStart
animation_finished to _FaderAnimationEnd
At the end, my script looks like below:
using Godot;
using System;
public class Fader : Control
{
private ColorRect rect;
private AnimationPlayer player;
public override void _Ready()
{
GD.Print("Initializing Fader...");
rect = (ColorRect)GetNode("rect");
player = (AnimationPlayer)GetNode("player");
SetSize(OS.WindowSize);
rect.SetSize(OS.WindowSize);
Visible = false;
}
private void _FaderAnimationStart(String anim_name)
{
Visible = true;
}
private void _FaderAnimationEnd(String anim_name)
{
Visible = false;
}
}
I solved it thanks to njamster's answer and Hans Passant's comment.
However, this only solves half of the problem. Yes, the scene now fades in when it loads but it does not fade out. Given that it executes kinda-async (again, I'm not sure if this is the correct term), changing scene interrupts while running the animation. I will update the answer when I solve that problem as well.
Update
Well, I cannot seem to solve the fade out part because it requires to access parent node from initialized child scene. There are some methods I can think of.
First one is to somehow parameterize "Fader" scene. This can be done in many ways but at the end, when you initialize it from another scene, you need to cast it to Fader and I don't know if this is a valid way to do it. Another concern is standardizing this in the codebase. A similar method is discussed in here.
Second one is to write it as a plugin which has it benefits and drawbacks. C# is not really battle-tested in this particular area.
Third one is to use a state management system. Here is a redux implementation for Godot. And you need to somehow integrate it for signals, which seems like a hassle.
So, overall, I still do not know how to fade out.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class BackToMainMenu : MonoBehaviour
{
public PlayerCameraMouseLook cammouselook;
// Update is called once per frame
void Update ()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex - 1);
PlayerCameraMouseLook.mouseLookEnable = false;
cammouselook.enabled = true;
}
}
}
Now when pressing the escape key it's loading the main menu scene.
And in the main menu I have NEW GAME button but not RESUME.
Instead making a resume button I want that pressing the escape key again when the main menu scene is loaded it will return back to the game to the current position it is. Either if it's in a middle of a cutscene or just idle in the game.
So when pressing the escape key again it will back to the game and continue from the last point.
Another sub question : Should I use : LoadSceneMode.Additive ? Or when switching between the game play scene and the main menu it should remove the current active scene and then load the next one ?
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex - 1, LoadSceneMode.Additive);
The main menu scene is at index 0 the game scene at index 1.
What I tried :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class BackToMainMenu : MonoBehaviour
{
// Variables
private bool _isInMainMenu = false;
public GameObject mainGame;
public PlayerCameraMouseLook cammouselook;
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
if (!_isInMainMenu)
{
SceneManager.LoadScene(0, LoadSceneMode.Additive);
PlayerCameraMouseLook.mouseLookEnable = false;
cammouselook.enabled = true;
// -- Code to freeze the game
mainGame.SetActive(false);
}
else
{
SceneManager.UnloadSceneAsync(0);
// -- Code to unfreeze the game
mainGame.SetActive(true);
}
_isInMainMenu = !_isInMainMenu;
}
}
}
And the Hierarchy :
The script is attached to the Back to main menu gameobject. And all the game objects are under Main Game.
First time when pressing the escape key it's loading to the main menu and main menu scene to the hierarchy. Second time pressing on the escape key it's starting the game over like a new game and removing unloading the main menu.
In both cases the game scene is stay in the hierarchy.
I will suggest you to add your main menu scene with the flag Additive as you mentioned.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class BackToMainMenu : MonoBehaviour
{
// Variables
private bool _isInMainMenu = false;
public PlayerCameraMouseLook cammouselook;
// Update is called once per frame
void Update ()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
if (!_isInMainMenu)
{
SceneManager.LoadScene(0, LoadSceneMode.Additive);
PlayerCameraMouseLook.mouseLookEnable = false;
cammouselook.enabled = true;
// -- Code to freeze the game
}
else
{
SceneManager.UnloadSceneAsync(0);
// -- Code to unfreeze the game
}
_isInMainMenu = !_isInMainMenu;
}
}
}
Take a look at the variable _isInMainMenu : it will track if you are in the main menu or not. Depends on the value, the Escape key will behave differently.
Note : I suggest you to type the current index of the scene in LoadScene / UnloadSceneAsync, unless you may want to change their index. In this scenario, type the scene name (Methods overload).
Now what I mean with // -- Code to freeze the game depends on your game :
You can have a unique GameObject that contains all the others GameObjects your scene has, and Enable / Disable it
myBigGameObject.SetActive(true/*or false*/);
Have a logic in MonoBehaviour to freeze the game while your in the main menu.
For example you can use the bool _isInMainMenu in Update() to stop them from doing their job ;
For example in this MonoBehaviour I created as an example :
public class ExampleMonoBehaviour : MonoBehaviour
{
private void Update ()
{
if (_isInMainMenu)
return;
print("I'm running !");
}
}
Have a Collection (List as an example) that stores every top hierarchy GameObjects and enable/disable them all as needed to behave the same as above.
Depends on how your code is, there is many other options.
I will highly suggest you to do the first or third option, unless you have a better approach.
The thing is, if you want to go back to the main menu, it shouldn't be very expansive (loading time, memory usage, ...) so you can disable GameObject from the main scene (third point) to restore them back quickly when you leave the main menu without reloading the entire scene. This would lead you to use serialization and deserialization.
Edited : Typo
I want to make a cube in Unity3D which can move and jump etc.... and I want to generate a random number (1-99). I want the number to be on the cube's every side. I don't want to make 99 texture I want to add the number with script. I read that I should add Text Mesh but i cant because I have Mesh Renderer.
Can somebody help
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerThings : MonoBehaviour {
public static int player_name;
void Start () {
player_name = Random.Range (10, 99);
name = player_name.ToString();
}
// Update is called once per frame
void Update () {
}
}
If nothing is in your Update function, get rid of it. It's still being called every fraction of a second to check there is nothing in it. If this is persistent in your code a lot, it will eventually unnecessarily slow it down.
Next - A solution is to add an empty GameObject, whose children are the sides of your cube which require a Text Mesh.
Place each of the children in an array, and then do a foreach:
foreach(textarray as GameObject ta){
ta.getComponent<TextMesh>().text = name;
}
I have recently been making the UI for a game I am creating and have run into a problem.
I have been trying to find a way in the new Unity 4.6 for the user to be able to click on a player card and have it select the player they clicked on.
public void Panel1Click()
{
GameManager.Player1Select ();
}
This is the way I am doing it at the moment, calling this when the player clicks on Panel 1, there are also 3 more for each of them.
I have been researching different methods on how to find the object the player clicks the execute the correct selecting code.
if (GameObject.Find ("Panel 1"))
{
print ("Click Panel 1");
GameManager.Player1Select();
}
This is one of the methods I tried, however nothing gets called. (Because it just checks if the object exists/is true? I think).
All these methods are linked to the EventSystem component on the panels.
Is there a more efficient way of condensing all the functions and just checking which panel the player clicks on?
You can add a collider to the game object (sprite), and then in the OnMouseDown function to test if it is clicked.
Select the card --> Add a box collider to it --> Add a MonoBehaviour script and attach to the card --> In the script, add function:
bool bClicked = false;
void OnMouseDown()
{
Debug.Log(gameObject.name + " is clicked");
bClicked = true;
}
You can actually have one parameter for your click handler. Supported types are: int, float, string and object reference. So you can define your handler like this:
public void SelectCharacter(int character) {
GameManager.PlayerSelect(character)
}
Then just set the parameter in the event trigger.
Create a script and put it on the object(Panel) you want to interact with, then try this code. In this example it finds the parent panel and sets it to inactive
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class CloseInventory : MonoBehaviour, IPointerDownHandler
{
GameObject inventoryPanel;
// Use this for initialization
void Start()
{
inventoryPanel = GameObject.Find("Inventory Panel");
}
public void OnPointerDown(PointerEventData eventData)
{
//SET WHAT TO DO HERE
inventoryPanel.SetActive(false);
}
}