I have a sprite which at the moment I detect the mouse click on it.
However I really need to detect when the finger or mouse touches or moves across the sprite because the finger/mouse click event will occur somewhere else on the screen and not on top of the sprite.
public class Hand : MonoBehaviour
{
private void OnMouseDown()
{
if (Input.GetMouseButtonDown(0))
{
this.transform.gameObject.SetActive(false);
}
}
}
Update:
I tried to detect both touching the sprite and the mouse is down but I dont get the button clicked. I can remove the && Input.GetMouseButtonDown(0) and it will work if the mouse moves over but I want both mouse/finger over the sprite and the pressed down.
private void Update()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 1000) && Input.GetMouseButtonDown(0))
hit.collider.GetComponent<Button>().onClick.Invoke();
}
There is 2 possible solution :
First: Instead of just using sprites, use button and assign it to world space canvas, in
this case touch should work if you assign canva's event camera to main camera.
2nd :If u just want to use sprites, then assign a collider to it, and use raycast
Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(i).position);
if (Physics.Raycast(ray,out hit,1000))
hit.collider.gameobject.GetComponent<Button>.onClick().Invoke();
Edit : The above code will work if you have a button component attached to your sprite. if not
Just call something like this
if(hit.collider.gameobject.GetComponenet<Sprite>())
DoWhateverYouWant()
Use the EventSystem interfaces to detect any kind mouse interaction with UI elements.
The EventSystem interfaces are listed here.
For example, if you want to detect when the mouse hovers over a sprite, you would add a script to the sprite object like so:
using UnityEngine.EventSystems;
using UnityEngine;
public class MouseOverHandler: MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
public void OnPointerEnter(PointerEventData data){
Debug.Log("MouseEnter");
}
public void OnPointerExit(PointerEventData data){
Debug.Log("MouseExit");
}
}
Note that the EventSystem works with the raycaster on the associated sprite's canvas. So if sprites are sitting on top of eachother, they can block raycasts and so the PointEnter event only gets triggered on the topmost sprite
Related
I'm trying to move my player using RigidBody2D.AddForce() method but whenever and i apply force to player on any direction then player moves for sometime then immediately stuck at random locations on level (Tile) and doesn't move ahead until opposite direction is pressed.
I wanted to move player normally without immediately making velocity = 0 like experience. It should follow slow decrease in acceleration as per force rule. I have checked my player movement on normal rigidbody without using Tilemap tiles. It's working fine but player stuck when using Tilemap tile level.
I'm calling methods using Pointer Down and Pointer Up event system for my 100px x 100px sized sprites as shown in image.
My Code:
public class PlayerScript : MonoBehaviour
{
Rigidbody2D playerRigidBody;
float speed=15f;
float forceX,forceY;
float maxVeloX,maxVeloY;
bool isMoveLeft,isMoveRight,isMoveUp;
void Start()
{
playerRigidBody=GetComponent<Rigidbody2D>();
isMoveLeft=isMoveRight=isMoveUp=false;
}
void Update()
{
forceX=forceY=0f;
maxVeloX=Mathf.Abs(playerRigidBody.velocity.x);
maxVeloY=Mathf.Abs(playerRigidBody.velocity.y);
if(isMoveRight) {
if(maxVeloX<6){
forceX= speed;
transform.localScale=new Vector3(1,1,1); // to face player right direction
}
}else if(isMoveLeft ){
if(maxVeloX<6){
forceX= -speed;
transform.localScale=new Vector3(-1,1,1); // to face left direction
}
}
else if(isMoveUp )
forceY=25f;
playerRigidBody.AddForce(new Vector2(forceX,forceY));
}
public void MoveLeftStart(){ // button left press
isMoveLeft=true;
}
public void MoveLeftEnd(){ // button left release
isMoveLeft=false;
}
public void MoveRightStart(){
isMoveRight=true;
}
public void MoveRightEnd(){
isMoveRight=false;
}
public void MoveUpStart(){
isMoveUp=true;
}
public void MoveUpEnd(){
isMoveUp=false;
}
}
My Tilemap level:
If understand right:
Your problem is caused by the fact that you are using a tilemap system made of squares colliders. And your Rigidbody is always pushed to the ground due to gravity. So everytime you collide with a corner of these colliders your character is stuck.
I suppose you are using one object to store your whole tilemap.\
If it's the case:
Go to the object your tilemap sit on.
Add component, Composite Collider 2D
On your Tilemap Collider 2D check "Used by composite"
Still in the object that contains your Tilemap:
Go on the rigidbody and set it to static
The composite collider will remove all those separate squares and regroup them.
It will remove all those little spikes.
And now (i hope) your problem is gone...
Trying to figure out how to destroy an object by clicking on it. I have tried using
public void Destroy()
{
if (Input.GetMouseButton(0))
Destroy(GameObject);
}
but realise that this will destroy all gameobjects the script is attached to instead of the one I am clicking on.
Try this one:
public void OnMouseDown() => Destroy(gameObject);
Definitely the best way is to implement IPointerClick interface,
using UnityEngine;
using UnityEngine.EventSystems;
public class ClickDestroy : MonoBehaviour, IPointerClickHandler
{
public void OnPointerClick(PointerEventData eventData)
{
GameObject.Destroy(gameObject);
}
}
This will work both for UI and for 3D Objects, as long as your camera has PhysicsRaycaster and an EventSystem exists on scene
You can get the mouse position on the screen and fire a raycast from that location. If it hits a gameobject then you can pass it to a function to delete it.
void Update {
//Check for mouse click
if (Input.GetMouseButton(0))
{
//Create a ray from mouse location
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit = new RaycastHit();
//Check if the ray hit a gameobject, gameobject will likely need a collider
//for this to work
if (Physics.Raycast(ray, out hit))
{
//If the ray hit a gameobject, destroy the gameobject
Destroy(hit.gameobject)
}
}
}
When destroying gameobjects, make sure your specifying the gameobject component and not the script or another component of the gameobject.
This code can be improved by defining a camera object in your code and assigning a camera to it in the inspector instead of it defaulting to the main or setting up full player controls in unity (Which I can't remember how to do off the top of my head I'm afraid)
I'm sorry if my English is bad at first.
The button
This is the button I want to run the animation when pressed.
Animations
Sprites I want to change between these two states when pressing the button
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Animations;
public class Button : MonoBehaviour
{
private Animator animator;
public void SetTrigger(string Pressed) { }
Collider2D col;
// Start is called before the first frame update
void Start()
{
animator = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
animator.SetFloat("Position", 0);
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
Vector2 touchPosition = Camera.main.ScreenToWorldPoint(touch.position);
if (touch.phase == TouchPhase.Began)
{
Collider2D touchedCollider = Physics2D.OverlapPoint(touchPosition);
if (col == touchedCollider)
{
animator.SetFloat("Position", 1);
}
}
}
}
}
This is how the code has been after the last attempt I have made, it has things that may not make sense because I have been mixing things while testing. I have tried it with floats, bools and triggers. With the bool it has worked halfway for me, if I touched the button it did not sink but if from unity I pressed the button manually changing the boolean to true, and after touching from the mobile screen it recognized the touch and returned the button to the original position. In all situations what did not work well was the touch control but I have revised the touch control code and I would say that it is fine.
Sorry if it is not understood well, I am new to unity and programming, also English is not my main language
Are you sure Button does not already have implementation for what you are trying to achieve? Check what options are available under "Transition" in Button inspector. You can pick between Color Tint, Sprite Swap or Animation there, I suppose it handles most of the cases and I've never seen anyone implemeting animations to button in custom way.
So when I am clicking on the object in the game I get this error...
NullReferenceExceptionm : Object reference not set to an instance of an object
JumpDestination.Update () (at Assets/Scripts/JumpDestination.cs.:12)
I don't know what I am doing wrong,how can I fix it?
I want to get the position of the hited object.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class JumpDestination : MonoBehaviour {
private RaycastHit hit;
public float jumpMaxDistance;
void Update(){
Physics.Raycast (Camera.main.ScreenPointToRay (Input.mousePosition), out hit, jumpMaxDistance);
if (hit.collider.gameObject.tag == "RichPoint") {
print (hit.collider.transform.position);
}
}
}
I don't know what I am doing wrong,how can I fix it? I want to get the
position of the hited object.
3 things you did wrong:
1.You did not check if mouse is pressed before raycasting.
2.You did not check if Physics.Raycast hit anything before printing the object's position.
3.You defined the hit variable outside a function. Not a good idea because it will still store the old object the mouse hit. Declare that in the update function.
FIX:
void Update()
{
//Check if mouse is clicked
if (Input.GetMouseButtonDown(0))
{
RaycastHit hit;
//Get ray from mouse postion
Ray rayCast = Camera.main.ScreenPointToRay(Input.mousePosition);
//Raycast and check if any object is hit
if (Physics.Raycast(rayCast, out hit, jumpMaxDistance))
{
//Check which tag is hit
if (hit.collider.CompareTag("RichPoint"))
{
print(hit.collider.transform.position);
}
}
}
}
Regardless, this answer was made to show you what you did wrong. You should not be using this. Use Unity's new EventSystems for this. Check the 5.For 3D Object (Mesh Renderer/any 3D Collider) from this answer for proper way to detect clicked object.
Im currently working on a 2D character selection screen in Unity that should operate similarly to the Mortal Kombat character selection screen. Currently, I have a class called CharacterSelector attached to the main camera. The class holds methods for selection/deselection of characters, hover events, and selection confirmation. I was able to use a RayCast2D to build my character selection method; however, I am running into issues using it for hover events.
In my scene, I have a group of character images that the player can choose from (if they are unlocked). When the player hovers over the character with his/her mouse, the character image should be surrounded by a yellow border. When the user clicks on the desired character, a larger version of the image will popup to the left of the character image group.
Right now, I have the following code for the hover method:
public void onHover(Ray ray, RaycastHit2D hit)
{
if(hit.collider == null)
{
Debug.Log("nothing hit");
}
if (Physics2D.Raycast(ray.origin, ray.direction, Mathf.Infinity))
{
print(hit.collider.name);
}
}
This method belongs to a class that the CharacterSelection class inherits from. The following is on the CharacterSelection class:
class CharacterSelector : Selector
{
Ray ray;
RaycastHit2D hit;
public void Start()
{
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
}
void Update()
{
onHover(ray, hit);
if (Input.GetMouseButtonDown(0))
{
selectCharacter();
}
}
}
Also, all the character images that I am trying to hover over currently have 2D Box Colliders. As of right now, I am unable to get hover operation to work. It does not print the name of the character image to the console. I am using this as a first step to see if Unity recognizes the character image or not. Let me know if I can provide additional information!
Mouse changes position on screen almost every frame. This means your ray should be updated every frame according to mouse position. So I moved the corresponding statement from Start() to Update();
class CharacterSelector : Selector
{
Ray ray;
RaycastHit2D hit;
public void Start()
{
}
void Update()
{
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
onHover(ray, hit);
if (Input.GetMouseButtonDown(0))
{
selectCharacter();
}
}
}
Secondly, if you look in the definition of Physics2D.Raycast you'll find that it gives you back the RaycastHit2D object. This is the object you should check the collider of, not your hit object which should have thrown an NullReferenceException, I don't know why it didn't. So this:
public void onHover(Ray ray, RaycastHit2D hit)
{
hit = Physics2D.Raycast(ray.origin, ray.direction, Mathf.Infinity);
if(hit.collider == null)
{
Debug.Log("nothing hit");
}
else
{
print(hit.collider.name);
}
}
Apart from this you don't really need the hit argument in onHover() function, it can be a local variable in the function. But if you are planning on using your hit variable in CharacterSelector script than you should change the declaration of onHover to: onHover(Ray ray, out RaycastHit2D hit) the out keyword passes the variable by reference instead of a copy of its value.
Also, I think checking if mouse is hovering over an object shouldn't be done in onHover, it's kinda misleading and doesn't seem logical to me. I'd move the body of onHover to another function like RaycastChecker(). I'd call onHover() only if mouse is actually hovering over the sprite. (like in OnCollisionEnter you take it granted that the collision did happen, so should the onHover, I think)