I have two images named hungerbar and cheesebar.
when the mouse approaches the cheese one button is activated. and I added pointer down function so when I press cheesebar level is decreasing and when the chees bar is empty the first cheese disappears.
and the second cheese appears but I can not control it with the same code. I dont know how to.
here some samples of my code;
void Start()
{
cheesbar1= GetComponent<Image>();
}
void Update()
{
cheesbar1.fillAmount = eatencheese / maxcheese;
}
private void FixedUpdate()
{
if (eating== true)
{
eatencheese--;
hungerscript.gettinghungery += 3f;
}
if (eatencheese <= 0)
Destruction();
}
SO that codes control only one image (Cheesebar1) . I want to use the same code and game object for controlling the second one..
Add this somewhere in your class (preferably at the top)
[SerializeField, Tooltip("The image of your second cheesebar")]
private Image cheesebar2;
This will add a field that will be exposed to the inspector, like so:
Like what the image states, drag the game-object with the image of the second cheesebar into the new field.
You should be able to modify cheesebar2 in your code afterwards.
Related
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.
Well, I already know that Unity itself has the Sprite Swap function, for that, but I wanted it to click when I changed the image and returned the old one only when it closed the window that was opened, or if I clicked it again on the icon, I tried to several ways so I turned to a helpy
Video link:- https://youtu.be/-H7j3vdKl8A.
Visit github if u dont undertand it here.
https://github.com/NareshBisht/Unity-UI-Shop-Select-2-UI-object-at-same-time/blob/master/ButtonAnimationHold.cs
Thank you.
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
//*************************Script to select one "Category(say Weapon)" UI Button till anathor category button(say Vehicles) is pressed.********************************//
/*
* Steps to be followed to make this script work
* Select All the Category Buttons (for example:- Suppose u r builiding a shop UI then Select all Category button Like Helics, Weapons -- refer to video link above;
* Now tag all these category button as same (say UI_CategoryButtons).
* Attach this script to all the UI_category button.
* the script will aotomatically add Button, Animator, Image component to the Ui Gameobjects.
* now select Animation in Transition tab.
* now press the Auto genrate Animation in Button component tab.
* now, set Transition from Animation to none in button Tab.
* Now, Do the above step for Sub category UI element too (for eg do for Apache, Tiger, f-22 etc which is the sub category of Helics --- refer video)
* open Animation window and Animate ur Ui elements.
* ur good to go now.
*/
[RequireComponent(typeof(Button))]
[RequireComponent(typeof(Animator))]
[RequireComponent(typeof(Image))]
public class ButtonAnimationHold : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler
{
public float TransitionTime = 0.3f; //Time taken to transition from one animation state to anathor.
private Animator MyAnim; //reference to animator attacted to the UI gameObject.
private void Start()
{
MyAnim = GetComponent<Animator>();
PlayNoramlState(); //Playing normal state at beginning.
}
public void HighlightThisButton_UnhighlightRest() //called when button is pressed (Called by OnPointerClick() defined below)
{
string TagOfPressedButton = gameObject.tag; //the tag of the button pressed by user.
foreach (Button button in gameObject.GetComponentInParent<Transform>().root.gameObject.GetComponentsInChildren<Button>()) //searching the gameobject with tag as in TagOfPressedButton inside the canvas which contain all UI element.
{ //we search inside Canvas to improve perf.
if(button.gameObject.tag == TagOfPressedButton && button.gameObject != this.gameObject) //selecting gameobjects with same tag(tag of button which was pressed) execpt the one which was pressed and then playing normal state in all selected GO.
{
button.gameObject.GetComponent<ButtonAnimationHold>().PlayNoramlState(); //Playing normal state in all UI gameObject with same tag except the one which called it.
}
}
MyAnim.Play("Pressed"); //Playing Pressed state in the UI element that was pressed.
}
public void PlayNoramlState()
{
MyAnim.CrossFadeInFixedTime("Normal", TransitionTime); //smoothly transitioning to Normal state;
}
public void OnPointerEnter(PointerEventData eventData) //Called when pointer hover over the Ui elemnt;
{
if(MyAnim.GetCurrentAnimatorStateInfo(0).IsName("Normal")) //Playing highlighted state only when it is in normal state and not when it is in Pressed state.
{
MyAnim.CrossFadeInFixedTime("Highlighted", TransitionTime); //smoothly transitioning to Highlighted state;
}
}
public void OnPointerExit(PointerEventData eventData)
{
if (MyAnim.GetCurrentAnimatorStateInfo(0).IsName("Highlighted") || MyAnim.GetCurrentAnimatorStateInfo(0).IsName("Normal")) //Playing Normal state only when it is in Highlighted state and not when it is in Pressed state
{
MyAnim.CrossFadeInFixedTime("Normal", TransitionTime); //smoothly transitioning to Normal state;
}
}
public void OnPointerClick(PointerEventData eventData) //called when button is pressed that is pointer down and pointer up both have to be done over button
{
HighlightThisButton_UnhighlightRest();
}
}
//video link
//https://youtu.be/-H7j3vdKl8A
I'm trying to divide the screen to 2 and use them as 2 different buttons (L,R) in Unity. But for the ones who are playing first time, I want to show the buttons' text and image to teach them what they do, and after that I want to disable buttons' image and text, they will be still interactable but invisible.
First time screen
How can I ?
Way easier and more reliable than what you did would simply be do add something like this to your Button:
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(Button))]
[DisallowMultipleComponent]
public class HintsController : MonoBehaviour
{
private Image _image;
private Text _text;
private float _originalAlpha;
// optional to control if Hints should be enabled on starting the App
public bool enableAtStart;
private void Awake()
{
// GetComponentInChildren finds the component on this object or any
// child of this object recursively
// (true) : make sure you also find the components if this or the child objects
// are currently disabled
// On this way you don't even have to rely on that the Image is on the
// Button GameObject or below in the hierachy
_image = GetComponentInChildren<Image>(true);
_text = GetComponentInChildren<Text>(true);
if(_image)
{
_originalAlpha = _image.color.a;
}
// optional to controll if Hints should be enabled on starting the App
ShowHints(enableAtStart);
}
public void ShowHints(bool isVisible)
{
// Skip if no Image found
if (_image)
{
var color = _image.color;
color.a = isVisible ? _originalAlpha : 0;
_image.color = color;
}
// Skip if no Text found
if (_text)
{
_text.enabled = isVisible;
}
}
}
Then from any other script, you simply can do e.g.
// TODO somehow get the reference either to the button GameObject or the Button component
var button;
button.GetComponent<HintsController>().ShowHints(false);
To disable hints.
I used button.image.enabled = bool valuefor image component and button.transform.GetChild(0).gameObject.SetActive(bool value) for the text.
i would suggest just making an empty for each button in the scene view, name them left and right. drag you button images(sprites) onte the scene and size them to fill the camera with proper positioning. apply boxCollider2D to both of the parent game objects(the empties you created and named left and right.) then you will need some light scripting.
pseudo-wise i would say:
you will use:
void OnMouseDown(){
//button touched
}
to see if the button is pressed.
when your tutorial is over you will set the image and text invisible with the code you mentioned above or something similar. this script goes on each button.
I'm starting with unity since a few weeks and i'm stuck with some displaying problems.
You can see what I want to achieve here :
On several of my pages I have a title with an icon on the left and I want it to be at 40px on the left of the title, no matter the size of it.
So I did a prefab with an empty Text for the title, an empty RawImage for the icon and I put that prefab on the center top of the screen.
I link the following C# script on my prefab with the 'string' parameter for the title and the 'Texture' parameter for the icon to display.
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
public class TitlePage : MonoBehaviour {
public string title;
public Texture texture;
private Text titlePageText;
private RawImage iconPage;
void Awake()
{
titlePageText = gameObject.GetComponentsInChildren<Text>().First();
iconPage = gameObject.GetComponentsInChildren<RawImage>().First();
}
void Start()
{
titlePageText.text = title;
}
void Update()
{
iconPage.rectTransform.anchoredPosition = new Vector2(-titlePageText.rectTransform.rect.width / 2 - 40, iconPage.rectTransform.anchoredPosition.y);
iconPage.texture = texture;
}
}
The title is set well in the "Start" function, the problem is with the icon. The code in the "Update" function put the icon at the wanted position if it's in the "Update" function because in the "Start", 'titlePageText.rectTransform.rect.width' give 0. But with that code in the "Update" function, the icon start with a display by default in the center and nearly instantly it moves on the left but we can see that position changing.
Maybe there's a solution to avoid that ?
Maybe I started in a wrong way ?
(I don't put my title's text hardly because I want my application to be multilingual so instead of displaying the 'string' in parameter, I'll display the corresponding translation and it's why I can't set a fixed position because two translations are not the same length.)
Thanks in advance !
I am not entirely sure what your problem is exactly, but it does sound like you are trying to solve something from a slightly awkward angle. IS there a reason for not using Unity's layout (or even auto layout groups) to achieve your goal?
I just did a quick test: added 'Content Size Fitter component' to the text object with Horizontal set to Preferred, then placed an image as a child of that text object, when I set the anchor X to 0 and pivot X to 1, the image now follows the left hand side of the text, no matter what size.
This has the advantage of doing absolutely zero work unless text (or its position) changes, in which case everything is handled automagically by Unity's UI system
It sounds like the width of the titlePageText is not obtaining a value immediately in Start(), which is why it is initially zero. After a couple of frames when a non-zero value is found, it finally shifts your iconPage over but your object already has a texture at this point. You really shouldn't be doing this in Update() because it means it will constantly be setting the anchoredPosition and texture of your iconPage every frame.
One solution to avoid this would be to use a coroutine with yield to wait for your components to initialize and then set the position. Note that this is a bit of a hack since you are introducing some forced loading time.
public string title;
public Texture texture;
private Text titlePageText;
private RawImage iconPage;
void Awake()
{
titlePageText = gameObject.GetComponentsInChildren<Text>().First();
iconPage = gameObject.GetComponentsInChildren<RawImage>().First();
}
void Start()
{
titlePageText.text = title;
StartCoroutine(initializeComponenets());
}
IEnumerator initializeComponenets()
{
yield return new waitForSeconds(.05f); //might need longer wait here
iconPage.rectTransform.anchoredPosition = new Vector2(-titlePageText.rectTransform.rect.width / 2 - 40, iconPage.rectTransform.anchoredPosition.y);
iconPage.texture = texture;
}
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,