This question already has answers here:
How to detect click/touch events on UI and GameObjects
(4 answers)
Closed 5 years ago.
Hi as you can tell i am incredibly new to unity.
I just want a sprite to change to a different image when the mouse enters or leaves the sprite. Example, when hovering over a play button, it changes to a slightly different coloured sprite.
Thanks
Here is what i tried
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MouseOver : MonoBehaviour
{
public Sprite sprite1; // Drag your first sprite here
public Sprite sprite2; // Drag your second sprite here
private SpriteRenderer spriteRenderer;
void Start()
{
spriteRenderer = GetComponent<SpriteRenderer>();
if (spriteRenderer.sprite == null)
spriteRenderer.sprite = sprite1;
}
void OnMouseEnter()
{
ChangeSprite();
}
void OnMouseExit()
{
ChangeSprite();
}
void ChangeSprite()
{
if (spriteRenderer.sprite == sprite1)
{
spriteRenderer.sprite = sprite2;
}
else
{
spriteRenderer.sprite = sprite1;
}
}
}
I would prefer to use UI Button with Image component. It has transition property where you can use different sprites on different states (normal, hover, pressed and disabled states).
Just use Button component and set transition mode to SpriteSwap:
Button Transition property should look like this:
As Default button object has image in a child component which is set to Target Graphic, you can set sprite1 as image source by default and use sprite2 as Highlighted Sprite.
This would work perfectly without using any code.
Hope this helps :)
Your sprite needs a collider attached to it in order for the OnMouseEnter() event to fire.
Related
I'm having issues trying to resolve this issue I have from migrating my old Unity5 game to Unity 2020. I've got everything running again, except for this issue with my buttons not working because of an update to "HitTest" being obsolete. What can I do to make this work without completely starting from scratch?
foreach (Touch touch in Input.touches)
{
if (touch.phase == TouchPhase.Stationary && hitButton.HitTest(touch.position))
{
GetComponent<Rigidbody2D>().MoveRotation(80);
}
I would make a Canvas as a child of the gameobject with the rigidbody2d/collider2d components, then put the button on that canvas, and then in your code above, keep a reference to the canvas and the button that lives there.
Then, you can use GraphicRaycaster.Raycast. Modified version of the source code in the Unity Docs:
// Attach this script to your Canvas GameObject.
// Also attach a GraphicsRaycaster component to your canvas by clicking the
// Add Component button in the Inspector window.
// Also make sure you have an EventSystem in your scene
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections.Generic;
public class RaycasterTester : MonoBehaviour
{
GraphicRaycaster m_Raycaster;
void Start()
{
//Fetch the Raycaster from the GameObject (the Canvas)
m_Raycaster = GetComponent<GraphicRaycaster>();
}
public bool TestTouch(Touch touch, GameObject target)
{
//Set up the new Pointer Event
PointerEventData pointerEventData = new PointerEventData(EventSystem.current);
//Set the Pointer Event Position to that of the touch position
pointerEventData.position = touch.position;
//Create a list of Raycast Results
List<RaycastResult> results = new List<RaycastResult>();
//Raycast using the Graphics Raycaster and touch position
m_Raycaster.Raycast(pointerEventData, results);
foreach (RaycastResult result in results)
{
if (result.gameObject == target) return true;
}
return false;
}
}
So basically the hierarchy looks something like this at runtime:
Flipper object [ Rigidbody2D, Collider2D, questionScript (references RaycasterTester and Button) ]
L Canvas object [ Canvas (world space), GraphicRaycaster, RaycasterTester ]
L Button object [ Button, Image, hitButtonScript (?) ]
(somewhere in scene) [ EventSystem ]
Then, in the Question Script, get a reference to the instance of the above script then call the TestTouch method:
foreach (Touch touch in Input.touches)
{
if (touch.phase == TouchPhase.Stationary
&& raycasterTester.TestTouch(touch, hitButton.gameObject))
{
GetComponent<Rigidbody2D>().MoveRotation(80);
// break to avoid being turned by multiple touches?
// break;
}
}
By the way, if the question code is happening in Update, it might be best to call GetComponent<Rigidbody2D> in Start (or, if the Rigidbody2D is ever removed and/or replaced, at those times as well) and cache the results, since it can be an expensive operation.
Actually better than checking this manually would indeed be a UI.Button + additionally implementing a custom extension using the IPointerDownHandler and IPointerUpHandler etc interfaces (note: the linked API is 2018, but this applies to 2020 as well, they just moved the API to a package and there it is not so well explained) like
public class HoldButton : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerEnterHandler, IPointerExitHandler
{
// Called once when the button goes down (comparable to GetKeyDown)
public UnityEvent OnButtonDown;
// Called every frame while the button is pressed (comparable to GetKey)
public UnityEvent WhilePressed;
// Called once when the button goes up (comparable to GetKeyUp)
public UnityEvent OnButtonUp;
// Called if you hover with the mouse or drag an existing touch into the button
public void OnPointerEnter(PointerEventData pointerEventData)
{
// Not sure if needed for OnPointerExit to work, doing nothing else
}
// Called when mouse or touch leaves the button
public void OnPointerExit(PointerEventData pointerEventData)
{
OnButtonUp.Invoke();
StopAllCoroutines();
}
// Called if you press the mouse or begin a touch over this button
public void OnPointerDown(PointerEventData pointerEventData)
{
OnButtonDown.Invoke();
StartCoroutine (WhilePressedRoutine());
}
// Called if you release mouse or touch over this button
public void OnPointerUp(PointerEventData pointerEventData)
{
OnButtonUp.Invoke();
StopAllCoroutines();
}
private IEnumerator WhilePressedRoutine()
{
while(true)
{
WhilePressed.Invoke();
yield return null;
}
}
}
In these UnityEvents you can reference your handler methods just like in the UI.Button.onClick via the Inspector or on runtime via script.
So you can either attach this on a UI element (like a Button) and let the EventSystem of the scene call the pointer handlers.
Or you can even attach this to normal 3D objects! In such case this requires additionally
A collider on your 3D object
A PhysicsRaycaster component on your Camera
Or for a 2D object accordingly
A Collider2D on your object
A Physics2DRaycaster on your Camera
These interfaces work for both, mouse and touch input (except for the pointer enter probably because a touch can't just hover - at least not on all phones ;) )
I'm trying to change the color of an image when I hover over it. It runs PointerEnter when I hover over it, and PointerExit when my mouse goes away.
Instead of changing the color of just the image I'm hovering over, it changes the color of every image in the scene. Can anybody help?
Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class click : MonoBehaviour {
void Start(){
}
void Update(){
}
public void PointerEnter(){
gameObject.GetComponent<Image>().material.color=new Color(1,1,0);
}
public void PointerExit(){
gameObject.GetComponent<Image>().material.color=new Color(1,1,1);
}
}
The material is shared for optimisation, it's the same one used for all the images using it.
You need to change the color of the image, simply remove material on your lines.
gameObject.GetComponent<Image>().color=new Color(1,1,0);
The Button component has transition settings where you can set colors for state, maybe you dont need the extra code.
Unity has 2 pre-programmed functions called OnMouseOver() and OnMouseExit(). Which you can use to see if the mouse entered your Image.
You would need to add this Code Snippet to each Image you want the Color to be changed on Hover and make sure that you get the .Color Component instead of the .material.color Component.
Example:
public class OnMouseOverExample : MonoBehaviour
{
void OnMouseOver() {
// Executes when you Hover over this GameObject with the Mouse
gameObject.GetComponent<Image>().color = new Color(1f, 1f, 0f);
}
void OnMouseExit() {
// Executes when you no longer Hover over this GameObject with the Mouse
gameObject.GetComponent<Image>().color = new Color(1f, 1f, 1f);
}
}
If you want to change a UI Components Color, you could also use the Button Component. Which already has functionality built in, you can use to tint the Color of your Image.
i'm a new to unity and trying to change a sprite's color through a script.
i'm following this tutorial page: https://www.tutorialspoint.com/unity/unity_coroutines.htm. i'm using Unity 2019.2.0f1
when pressing "play" i can see the colors changing every second in the inspector, but nothing happens in the scene
the code:
public class colorChanger : MonoBehaviour
{
public int seconds_interval;
public SpriteRenderer sr;
public Color color_1;
public Color color_2;
IEnumerator changeColor(){
while (true){
if (sr.color == color_1){
sr.color = color_2;
} else {
sr.color = color_1;
}
yield return new WaitForSeconds(seconds_interval);
}
}
// Start is called before the first frame update
void Start()
{
sr = gameObject.GetComponent<SpriteRenderer>();
StartCoroutine( changeColor() );
//sr.color = color_1;
}
// Update is called once per frame
void Update()
{
}
}
explanation and screenshots:
this is the sprite, notice it starts as purple, then the script should change it's color:
https://i.ibb.co/rQy2Lpr/1.jpg
when pressing "play" i can see the colors changing every second in the inspector, but nothing happens in the scene:
yellow:
https://i.ibb.co/DRhcpPT/2.jpg
green (after 1 second):
https://i.ibb.co/Yc0v26K/3.jpg
actually, the inspector is totaly ignored by the scene! notice that the sprite is white (and not purple/yellow/green).
notice that if i change the scale nothing happens in the "play" screen:
https://i.ibb.co/sjdCvfw/4.jpg
but when i go back to "game" screen (without stopping the game), the frame of the sprite changes but not it's actual size:
https://i.ibb.co/R054Rv0/5.jpg
it looks like the script is making the inspector disconnect from the scene.
is it a bug? or am i missing something here?
thank you :)
solved!
my problem was that: I have chosen colors in the UI interface while their Alpha property was 0.
so i couldn't see any color changing.
I still don't understand why the "scale" property wasn't reacting to live changes in the inspector, but choosing colors with Alpha of 255 (opacity) solved everything.
I have a 2D unity project for android mobiles,there are a sprite that I added button script on it
now I want use color tint on it .
Change color when I click on it
but the color not changing and I don't want do it with programming
I have tried many things, but still not working
I fixed that before with luck, but now I cant fix it again
anyone know what I am missing?
As it says in the warning, You need to specify a graphic in order to use the color tint. Try dropping in the Image component that has your button sprite here.
Based on the screenshots in your comment, you are mixing SpriteRenderer and the UI System (Image, RawImage, Button). Do not do this.
Read this to understand the difference between both. Once you decide which one to use you can do the the following below.
If you decided to use UI to display your Sprite, do this:
Create new button by going to GameObject-->UI--->Button.
If you prefer to use SpriteRenderer:
Remove any UI component such as Image, RawImage, Button from the GameObject the SpriteRenderer is attached to then manually create a highlight code. The highlight functionality is only built into the Button component. You cannot use the Button component with SpriteRenderer. You have to make your own if you prefer to use SpriteRenderer.
This is easy. Use the EventSystem. Change the color in OnPointerEnter when highlighted and back to its default color in OnPointerExit when pointer exits.
Here is a simple script to do that (Attach to the GameObject with the SpriteRenderer component):
public class SpriteDetector : MonoBehaviour, IPointerClickHandler, IPointerEnterHandler, IPointerExitHandler
{
public Color normalColor = Color.white;
public Color highlightedColor = Color.yellow;
public Color pressedColor = Color.blue;
SpriteRenderer sp;
void Start()
{
sp = GetComponent<SpriteRenderer>();
addPhysics2DRaycaster();
}
void addPhysics2DRaycaster()
{
Physics2DRaycaster physicsRaycaster = GameObject.FindObjectOfType<Physics2DRaycaster>();
if (physicsRaycaster == null)
{
Camera.main.gameObject.AddComponent<Physics2DRaycaster>();
}
}
public void OnPointerEnter(PointerEventData eventData)
{
sp.color = highlightedColor;
}
public void OnPointerExit(PointerEventData eventData)
{
sp.color = normalColor;
}
public void OnPointerClick(PointerEventData eventData)
{
sp.color = pressedColor;
Debug.Log("Clicked: " + eventData.pointerCurrentRaycast.gameObject.name);
}
}
The states and animations not my own.
I have a prefab of a character that have Animator component attached to it. The character in the Hierarchy have Animator with some states and blends and also have some animation clips.
Now when i play/run a State of the Animator is that meaning i'm playing animation? Or the animation clips is something else ?
And why i can't playing the animation clips ? I'm not getting errors or exceptions it's just not playing it.
Here is a script that attached to this character and i also added to this character a Animation component. So now the character object have both Animator and Animation components.
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class SwitchAnimations : MonoBehaviour
{
private Animator animator;
private int index = 0;
private static UnityEditor.Animations.AnimatorController controller;
private UnityEditor.Animations.AnimatorState[] an;
// Use this for initialization
void Start()
{
animator = GetComponent<Animator>();
an = GetStateNames(animator);
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
animator.Play(an[index].name);
if (++index == an.Length)
index = 0;
}
}
private static UnityEditor.Animations.AnimatorState[] GetStateNames(Animator animator)
{
controller = animator ? animator.runtimeAnimatorController as UnityEditor.Animations.AnimatorController : null;
return controller == null ? null : controller.layers.SelectMany(l => l.stateMachine.states).Select(s => s.state).ToArray();
}
private void RollSound()
{
}
private void CantRotate()
{
}
private void EndRoll()
{
}
private void EndPickup()
{
}
}
Inside the variable an there are 9 states:
Aiming
Death_A
Use
Grounded
Roll
PickupObject
Reload_Rifle
Shoot_Rifle
Empty
When i click on A key it's playing the states one by one each time i click on A Everything is working fine i can play the 9 states by clicking on A.
what i don't understand with the States is inside the editor when i'm in the hierarchy selecting the character and in the menu make: Window > Animator i see the 9 states on the LegsLayer:
But then if i click on state Grounded double click i see a blend tree and i'm not sure if this is also states or maybe this is animation clips ? Then how can i get access to them ?
Ok this is one part i don't understand yet about the Animator and what and how i can play with it.
The second part is related to AnimationClip/s and why i can't play them ?
The script for animations clips:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;
public class SwitchAnimations : MonoBehaviour
{
private Animation animation;
private AnimationClip[] animationClips;
// Use this for initialization
void Start()
{
animation = GetComponent<Animation>();
animationClips = AnimationUtility.GetAnimationClips(gameObject);
foreach (AnimationClip clip in animationClips)
{
animation.AddClip(clip, clip.name);
}
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
animation.clip = animationClips[6];
animation.Play(animationClips[6].name);
}
}
private void RollSound()
{
}
private void CantRotate()
{
}
private void EndRoll()
{
}
private void EndPickup()
{
}
private void FootStep()
{
}
}
And in the variable animationClips i have 9 animations:
Rifle_Aiming_Idle
Rifle_Aiming_Walk_F_RM
Rifle_Aiming_Walk_B_RM
Rifle_Aiming_Walk_L_RM
Rifle_Aiming_Walk_R_RM
Rifle_Idle
Rifle_Walk_F_RM
Rifle_Run_F_RM
Rifle_Sprint_F_RM
When i'm running the game and clicking on A this time i see in the Inspector inside the Animation component all the animation clips and in Animation i see the animation clip to play.
I'm not getting any errors or exceptions but it's just not playing it. The character stay still idle. Even if i choose another animation clip index to play 5 or 3 or 1 nothing is playing.
I wonder why it's not playing the animations when i click A. In this case animation number 6 from the List but still not playing.
The Animation component is a legacy component, kept in Unity to ensure backward compatibility with older projects, so you should never use it for animations.
Basically, the system works this way:
First of all, you need an Animator Controller asset. This Animator is a Finite State Machine (with substates etc.), and every single state can have an Animation Clip (you assign it via script of via Inspector in the Motion field). When the FSM enters a specific state, it will play the Animation Clip assigned.
Clearly the Animator, in order to be used by a game object, has to be assigned to that object via the Animator component.
Animation Clips are assets which contain the actual animation, they're never assigned as components to game objects, but instead they must be referenced by an Animator to be played, as I said before.
Blend trees are used to blend different animations in a seamless way by using linear interpolation. They're a "special" state of the Animator, which has multiple Animation Clips that you can interpolate to display transitions from a state to another, for example when you need to change the animation among running forward, running left and running right.
The argument is very broad, you can start to get into it by reading the official documentation about Animators, Animation Clips and Blend Trees here:
https://docs.unity3d.com/Manual/AnimationSection.html