Drag and Drop on UI - c#

I want to create a simple drag and drop game using Unity UI objects.
My objects right now are images with scripts attached to them. My script is using OnBeginDrag, OnDrag and OnEndDrag events which works fine when I want to move image objects.
However image objects are always square and I want to detect drag only when mouse is on specifid area. So I created a Polygon Collider 2D on my image and adjusted it to shape I wanted. Unfortunetly I can't make it work at all.
public void OnBeginDrag(PointerEventData eventData)
{
var canvas = FindInParents<Canvas>(gameObject);
itemBeingDragged = gameObject;
m_DraggingPlane = canvas.transform as RectTransform;
}
public void OnDrag(PointerEventData eventData)
{
SetDraggedPosition(eventData);
}
public void OnEndDrag(PointerEventData eventData)
{
itemBeingDragged = null;
int i = 0;
foreach (Vector3 hex in otherHexes)
{
Vector3 rayBeginning = hex + transform.position;
rays = Physics2D.RaycastAll(rayBeginning, Vector2.zero);
if (rays.Length > 1) //if there are other elements in RayCast
{
foreach (RaycastHit2D ray in rays)
{
if (ray.transform.gameObject != gameObject && ray.transform.tag == "Hex") //if element is not self and is a HexGrid
{
SuccessfulDrag(ray, i);
}
else if (ray.transform.gameObject != gameObject && ray.transform.tag == "GetOut") //if element is not self and is another puzzle
{
FailedDrag();
break;
}
}
}
else if (rays.Length == 1 && rays[0].transform.gameObject == gameObject) //if there is only one element and it's self
{
FailedDrag();
break;
}
i++;
}
}

Ok, I googled a bit more and I found a solution. Just create a class with this code inside and put it on the object that you want to drag by it's collider.
using UnityEngine;
[RequireComponent(typeof(RectTransform), typeof(Collider2D))]
public class Collider2DRaycastFilter : MonoBehaviour, ICanvasRaycastFilter
{
Collider2D myCollider;
RectTransform rectTransform;
void Awake()
{
myCollider = GetComponent<Collider2D>();
rectTransform = GetComponent<RectTransform>();
}
public bool IsRaycastLocationValid(Vector2 screenPos, Camera eventCamera)
{
var worldPoint = Vector3.zero;
var isInside = RectTransformUtility.ScreenPointToWorldPointInRectangle(
rectTransform,
screenPos,
eventCamera,
out worldPoint
);
if (isInside)
isInside = myCollider.OverlapPoint(worldPoint);
return isInside;
}
}

Related

I have a problem with objects copy and the objects mesh in unity

So, i have a script, and two objects, one copy of the another, exactly what one does, the other does too, but in other position. The script do the following:
get the actual value of the heat variable of the object and use this for the second part;
the second part is get the heat value and check if it's higher or equal than 850,
if it is, check if the player pressed the button to transform the object mesh in another mesh
but, when the button is pressed, only the first object has it mesh changed, i already tried raycast, a lot of additional code, ineficient code and don't worked. I know i can just make two similar scripts, but i have plans to create more objects when the player wants, so, it's not going to work...
the script:
using UnityEngine;
using DG.Tweening;
public class Iron : MonoBehaviour
{
private float Heat;
private bool Heating;
[Header("Game Objects")]
[SerializeField] private GameObject WeaponCanvas;
[Header("Materials")]
[SerializeField] private Material HotIron;
[SerializeField] private Material MediumIron;
[SerializeField] private Material CoolIron;
[Space]
[Header("Meshs")]
[SerializeField] private Mesh SimpleSwordMaterial;
[Space]
[Header("Text Mesh Pro")]
[SerializeField] private TMPro.TMP_Text TemperatureText;
private bool Hot;
void Update()
{
if (Heating && Heat <= 1500)
{
Heat += 1.5f;
}
if (Heat >= 850)
{
GetComponent<Renderer>().material = HotIron;
Hot = true;
}
if (Heat >= 600 && Heat <= 849)
{
GetComponent<Renderer>().material = MediumIron;
Hot = false;
}
if (Heat <= 400)
{
GetComponent<Renderer>().material = CoolIron;
Hot = false;
}
}
void OnCollisionStay(Collision other)
{
if (other.gameObject.tag == "HeatSource")
{
Heating = true;
}
if (!(other.gameObject.tag == "HeatSource"))
{
Heating = false;
}
}
public void SimpleSword()
{
var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 3.5f))
{
hit.transform.gameObject.GetComponent<MeshFilter>().mesh = SimpleSwordMaterial; // i have problems from here (i guess ;-;)
hit.transform.gameObject.GetComponent<MeshCollider>().sharedMesh = SimpleSwordMaterial;
if (hit.transform.gameObject.GetComponent<BoxCollider>() != null)
{
Destroy(hit.transform.gameObject.GetComponent<BoxCollider>());
}
if (hit.transform.gameObject.GetComponent<SphereCollider>() != null)
{
Destroy(hit.transform.gameObject.GetComponent<SphereCollider>());
}
if (hit.transform.gameObject.GetComponent<CapsuleCollider>() != null)
{
Destroy(hit.transform.gameObject.GetComponent<CapsuleCollider>());
}
transform.localScale = new Vector3(1, 1, 1);
}
WeaponCanvas.SetActive(false);
Player.onMenu = false;
Cursor.lockState = CursorLockMode.Locked;
}
void OnMouseOver()
{
if (Input.GetMouseButtonDown(1) && Hot)
{
WeaponCanvas.SetActive(true);
Player.onMenu = true;
Cursor.lockState = CursorLockMode.None;
}
TemperatureText.text = ((int)Heat).ToString() + "°";
TemperatureText.DOFade(1, 0.4f);
}
void OnMouseExit()
{
TemperatureText.DOFade(0, 0.4f);
}
}
Similar to sharedMaterial
sharedMesh is not what you want to use...
It is recommended to use this function only for reading mesh data and not for writing, since you might modify imported assets and all objects that use this mesh will be affected.
Also, be aware that is not possible to undo the changes done to this mesh.
I'm having a bit of trouble understanding the problem... are all objects with the Iron.cs getting a new mesh? if yes, it's the .sharedmesh =.
Furthermore, it's worth noting that each monobehaviour in Unity has a .GetInstanceId() method. You can compare the id of the instance you hit with your raycast and that of the one with the correct temporature.
You should also consider simply instantiating a prefab of a sword instead.

Moving objects independently of each other, with the ability to move at the same time in Unity 2D

I have two objects. The point is that I need to move the object up and down (hold and drag), and at the same time I need to move the other object up and down (hold and drag) independently. Something like this:
Example
After searching the Internet, I found a small script, but it only works for one touch at a time, and dragging only one object. Plus, if I touch with second finger the object changes his position to second finger position:
public class Move : MonoBehaviour {
private Vector3 offset;
void OnMouseDown() {
offset = gameObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(-2.527f, Input.mousePosition.y));
}
void OnMouseDrag() {
Vector3 curScreenPoint = new Vector3(-2.527f, Input.mousePosition.y);
Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) + offset;
transform.position = curPosition;
}
}
I just can’t understand how I can make two objects drag and drop at the same time. I am new to unity and honestly i have problems with controllers
For touch screens I suggest you use Touch instead of mouse events. Touch class supports multiple touches at the same time and some useful information such as Touch.phase (Began, moving, stationary etc). I've written a script which you can attach to multiple objects with tag "Draggable", that makes objects move independently. Drag and drop the other object that should move when you use one finger to field otherObj and it should work. It only works for 2 obj in this version.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;
public class PlayerActionHandler : MonoBehaviour
{
private Camera _cam;
public bool beingDragged;
public Vector3 offset;
public Vector3 currPos;
public int fingerIndex;
public GameObject otherObj;
// Start is called before the first frame update
void Start()
{
_cam = Camera.main;
}
// Update is called once per frame
void Update()
{
//ONLY WORKS FOR 2 OBJECTS
if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Began)
{
var raycast = _cam.ScreenPointToRay(Input.GetTouch(0).position);
RaycastHit hit;
if (Physics.Raycast(raycast, out hit))
{
//use this tag if you want only chosen objects to be draggable
if (hit.transform.CompareTag("Draggable"))
{
if(hit.transform.name == name)
{
//set being dragged and finger index so we can move the object
beingDragged = true;
offset = gameObject.transform.position - _cam.ScreenToWorldPoint(Input.GetTouch(0).position);
offset = new Vector3(offset.x, offset.y, 0);
fingerIndex = 0;
}
}
}
}else if (Input.touchCount == 1 && beingDragged)
{
otherObj.transform.SetParent(transform);
if (Input.GetTouch(fingerIndex).phase == TouchPhase.Moved ){
Vector3 pos = _cam.ScreenToWorldPoint(Input.GetTouch(fingerIndex).position);
currPos = new Vector3(pos.x, pos.y,0) + offset;
transform.position = currPos;
}
}
//ONLY WORKS FOR 2 OBJECTS_END
else if (beingDragged && Input.touchCount > 1)
{
//We tie each finger to an object so the object only moves when tied finger moves
if (Input.GetTouch(fingerIndex).phase == TouchPhase.Moved ){
Vector3 pos = _cam.ScreenToWorldPoint(Input.GetTouch(fingerIndex).position);
currPos = new Vector3(pos.x, pos.y,0) + offset;
transform.position = currPos;
}
}else if (Input.touchCount > 0)
{
for (var i = 0; i < Input.touchCount; i++)
{
//We find the fingers which just touched the screen
if(Input.GetTouch(i).phase == TouchPhase.Began)
{
var raycast = _cam.ScreenPointToRay(Input.GetTouch(i).position);
RaycastHit hit;
if (Physics.Raycast(raycast, out hit))
{
//use this tag if you want only chosen objects to be draggable
if (hit.transform.CompareTag("Draggable"))
{
if(hit.transform.name == name)
{
//set being dragged and finger index so we can move the object
beingDragged = true;
offset = gameObject.transform.position - _cam.ScreenToWorldPoint(Input.GetTouch(i).position);
offset = new Vector3(offset.x, offset.y, 0);
fingerIndex = i;
}
}
}
}
}
}else if (Input.touchCount == 0)
{
//if all fingers are lifted no object is being dragged
beingDragged = false;
}
}
}

Why when replacing a gameobject with prefab the prefab position is a bit to the back and not exactly on the gameobject position?

This is the code for replacing :
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
public class SaveTransformsInfo : EditorWindow
{
[SerializeField] private GameObject prefab;
[MenuItem("Tools/Replace With Prefab")]
static void CreateReplaceWithPrefab()
{
EditorWindow.GetWindow<SaveTransformsInfo>();
}
private void OnGUI()
{
prefab = (GameObject)EditorGUILayout.ObjectField("Prefab", prefab, typeof(GameObject), false);
if (prefab == null || Selection.gameObjects.Length == 0)
{
GUI.enabled = false;
}
else
{
GUI.enabled = true;
}
if (GUILayout.Button("Replace"))
{
var selection = Selection.gameObjects;
var parentGameobjects = CheckParents(selection);
#if UNITY_EDITOR
UnityEditor.Selection.objects = parentGameobjects;
#endif
for (var i = parentGameobjects.Length - 1; i >= 0; --i)
{
var selected = parentGameobjects[i];
var prefabType = PrefabUtility.GetPrefabType(prefab);
GameObject newObject;
if (prefabType == PrefabType.Prefab)
{
newObject = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
}
else
{
newObject = Instantiate(prefab);
newObject.name = prefab.name;
}
if (newObject == null)
{
Debug.LogError("Error instantiating prefab");
break;
}
Undo.RegisterCreatedObjectUndo(newObject, "Replace With Prefabs");
newObject.transform.parent = selected.transform.parent;
newObject.transform.position = selected.transform.position;
newObject.transform.rotation = selected.transform.rotation;
newObject.transform.localScale = selected.transform.localScale;
newObject.transform.SetSiblingIndex(selected.transform.GetSiblingIndex());
DestroyObjectInPrefab(selected.transform);
}
}
if(GUILayout.Button("Get Info"))
{
TransformSaver.SaveTransform(null, Selection.gameObjects[0]);
}
GUI.enabled = false;
EditorGUILayout.LabelField("Selection count: " + Selection.gameObjects.Length);
}
private GameObject[] CheckParents(params GameObject[] objects)
{
List<GameObject> parents = new List<GameObject>(objects.Length);
Transform[] transforms = objects.Select(go => go.transform).ToArray();
for (int objectIndex = 0; objectIndex < transforms.Length; objectIndex++)
{
if (!IsChildOfAny(transforms[objectIndex], transforms))
parents.Add(transforms[objectIndex].gameObject);
}
return parents.ToArray();
}
private bool IsChildOfAny(Transform potentialChild, params Transform[] potentialParents)
{
for (int index = 0; index < potentialParents.Length; index++)
{
if (IsParentOf(potentialParents[index], potentialChild))
return true;
}
return false;
}
private bool IsParentOf(Transform potentialParent, Transform potentialChild)
{
if (potentialChild.parent == null)
return false;
if (potentialChild.parent == potentialParent)
return true;
return IsParentOf(potentialParent, potentialChild.parent);
}
private void DestroyObjectInPrefab(Transform transform)
{
if (PrefabUtility.IsPartOfPrefabInstance(transform))
{
//if a part of a prefab instance then get the instance handle
Object prefabInstance = PrefabUtility.GetPrefabInstanceHandle(transform);
//destroy the handle
if (prefabInstance != null)
{
Undo.DestroyObjectImmediate(prefabInstance);
}
}
//the usual destroy immediate to clean up scene objects
//DestroyImmediate(transform.gameObject, true);
Undo.DestroyObjectImmediate(transform.gameObject);
}
private void OnSelectionChange()
{
Repaint();
}
}
I'm selecting this door the door is inside a space station and the door is a child of another gameobject and the other gameobject is also child :
Then I have a prefab I want to replace it with the door :
The prefab is the same door I just changed the two doors in the middle made them in red but the prefab is just a door like in thecfirst screenshot. Same size scaling :
Then when making the replacing the prefab is places in a bit back from where the door was position but in the inspector I see same position as the door :
Now the prefab is positioned much to the back inside the room.
If I change the position and rotation in my code to local then the prefab will be positioned to much forward. It will never position at the place of the door.
I tried other replace scripts all give the same result/s.
I didn't change anything in the prefab(The prefab is a door) only add this colors.
This is happening because the center of the prefab is different than the original object's center.
You can recenter object by putting it in a empty object and moving it in the local position of that object.
Then you can use that object as the prefab that is going to be in the scene.
Hope it helped

In Unity Arkit,how to show a text in UnityARHitTestExample scene until a vertical plane is found?

I am trying to show a text say "Scan for a surface" until it scans a plane surface.Once the device picks up a plane surface the message should disappear.Where should I write code for this purpose.I found two instances where prefab plane is initialised,one in UnityARGeneratePlane.cs and UnityARUtility.cs .I added a Gameobject as Text in UnityARGeneratePlane.cs and used setactive to true and false to show and hide the text.It is showing when i used it in the start method.How to hide the text is where i struggle.Where to use the code to hide the text when a plane is detected?Is it in UnityARGeneratePlane.cs or UnityARUtility.cs.
public class UnityARGeneratePlane : MonoBehaviour
{
public GameObject planePrefab;
public GameObject scantxt;
private UnityARAnchorManager unityARAnchorManager;
// Use this for initialization
void Start () {
unityARAnchorManager = new UnityARAnchorManager();
UnityARUtility.InitializePlanePrefab (planePrefab);
scantxt.SetActive(true); //Tried to show the text working when app opens
}
void OnDestroy()
{
unityARAnchorManager.Destroy ();
scantxt.SetActive(false); //Here is where I tried to hide the text until a Vertical or Horizontal plane is detected
}
void OnGUI()
{
IEnumerable<ARPlaneAnchorGameObject> arpags = unityARAnchorManager.GetCurrentPlaneAnchors ();
foreach(var planeAnchor in arpags)
{
//ARPlaneAnchor ap = planeAnchor;
//GUI.Box (new Rect (100, 100, 800, 60), string.Format ("Center: x:{0}, y:{1}, z:{2}", ap.center.x, ap.center.y, ap.center.z));
//GUI.Box(new Rect(100, 200, 800, 60), string.Format ("Extent: x:{0}, y:{1}, z:{2}", ap.extent.x, ap.extent.y, ap.extent.z));
}
}
}
The code below is UnityARUtility.cs
public class UnityARUtility
{
private MeshCollider meshCollider; //declared to avoid code stripping of class
private MeshFilter meshFilter; //declared to avoid code stripping of class
public static GameObject planePrefab = null;
// public Text text1;
public static void InitializePlanePrefab(GameObject go)
{
planePrefab = go;
}
public static GameObject CreatePlaneInScene(ARPlaneAnchor arPlaneAnchor)
{
GameObject plane;
if (planePrefab != null)
{
plane = GameObject.Instantiate(planePrefab); //I dont understand why again Plane prefab is initialized.Other than Generate planes.
// text1.text = "Select Any Painting from panel";
}
else {
plane = new GameObject (); //put in a blank gameObject to get at least a transform to manipulate
}
//plane.name = arPlaneAnchor.identifier;
ARKitPlaneMeshRender apmr = plane.GetComponent<ARKitPlaneMeshRender> ();
if (apmr != null) {
apmr.InitiliazeMesh (arPlaneAnchor);
}
return UpdatePlaneWithAnchorTransform(plane, arPlaneAnchor);
}
public static GameObject UpdatePlaneWithAnchorTransform(GameObject plane, ARPlaneAnchor arPlaneAnchor)
{
//do coordinate conversion from ARKit to Unity
plane.transform.position = UnityARMatrixOps.GetPosition (arPlaneAnchor.transform);
plane.transform.rotation = UnityARMatrixOps.GetRotation (arPlaneAnchor.transform);
ARKitPlaneMeshRender apmr = plane.GetComponent<ARKitPlaneMeshRender> ();
if (apmr != null) {
apmr.UpdateMesh (arPlaneAnchor);
}
MeshFilter mf = plane.GetComponentInChildren<MeshFilter> ();
if (mf != null) {
if (apmr == null) {
//since our plane mesh is actually 10mx10m in the world, we scale it here by 0.1f
mf.gameObject.transform.localScale = new Vector3 (arPlaneAnchor.extent.x * 0.1f, arPlaneAnchor.extent.y * 0.1f, arPlaneAnchor.extent.z * 0.1f);
//convert our center position to unity coords
mf.gameObject.transform.localPosition = new Vector3(arPlaneAnchor.center.x,arPlaneAnchor.center.y, -arPlaneAnchor.center.z);
}
}
return plane;
}
}
}

unity raycast , on raycast leave , how to ? c#

i have a problem understanding how to keep a reference to an object that has previously been hit by a raycast .
for example i can have a raycast script put on the camera of my 1rst person controller going from the camera position to the forwad vector * some value
this script is attached to the camera
public class raycast : MonoBehaviour {
float lenthRay = 10.0f;
Vector3 originePos;
Vector3 dir;
RaycastHit hitinfo;
GameObject hitten;
bool isHitting;
Color beforC;
int selectionLayer = 9;
void Update () {
originePos = Camera.main.transform.position;
dir = Camera.main.transform.forward * lenthRay;
Debug.DrawRay(originePos, dir, Color.blue);
if (Physics.Raycast(originePos, dir, out hitinfo, lenthRay , selectionLayer)) {
hitten = hitinfo.transform.gameObject;
MeshRenderer tmp = hitten.transform.GetComponent<MeshRenderer> ();
beforC = tmp.material.color;
tmp.material.color = Color.black;
}
//hitten.transform.GetComponent<MeshRenderer> ().material.color = beforC;
print(hitten.name);
}
}
it is working great , except if i try to access the GameObject Hitten outside my if condition (like the print print(hitten.name))
i get this error before hitting an object from the right layer :
NullReferenceException: Object reference not set to an instance of an object
raycast.Update () (at Assets/raycast.cs:30)
then when i hit the object it is ok
but the problem is , i dont understand how i can change back the object color to its original color (beforC) after turning it to Color.black when the ray exit the object
this is what i try to do in the commented line , but i just get the same error than with the print , and nothing is turning black .
i have tried this :
originePos = Camera.main.transform.position;
dir = Camera.main.transform.forward * lenthRay;
Debug.DrawRay(originePos, dir, Color.blue);
isHitting = Physics.Raycast (originePos, dir, out hitinfo, lenthRay, selectionLayer);
if (isHitting) {
hitten = hitinfo.transform.gameObject;
MeshRenderer tmp = hitten.transform.GetComponent<MeshRenderer> ();
beforC = tmp.material.color;
tmp.material.color = Color.black;
}
if(!isHitting){
hitten.transform.GetComponent<MeshRenderer> ().material.color = beforC;
print(hitten.name);
}
but it is not working either
can you help me understand the logic i should be using
thanks in advance
I had this same need, when I was trying to detect when a wall was obstructing the player. I had never used a Raycast (or Linecast) before, and was surprised there wasn't a built in method to detect 'Enter', 'Stay', and 'Leave' events.
So I created this simple class to handle the details for me. I didn't bother creating any class constructors, and just exposed the properties as public. It handles both Raycasts and Linecasts.
This class tracks your objects each frame for you once you set it up using the properties.
Here's some sample code to demonstrate potential usage (the code I use for my wall detection):
private RayCaster wallRay;
void Start() {
wallRay = new RayCaster();
wallRay.OnRayEnter += WallRay_OnEnter;
wallRay.OnRayExit += WallRay_OnExit;
wallRay.LayerMask = RayCaster.GetLayerMask("Wall");
wallRay.StartTransform = camera.transform;
wallRay.EndTransform = PlayerManager.Player.transform;
}
void Update() {
wallRay.CastLine();
}
void WallRay_OnEnter(Collider collider) {
// Fade OUT wall section [Needs DOTween (free) installed]
collider.gameObject.renderer.material.DOFade(0.65f, 0.2f);
}
void WallRay_OnExit(Collider collider) {
// Fade IN wall section
collider.gameObject.renderer.material.DOFade(1f, 0.2f);
}
Here's the RayCaster class:
using System;
using System.Collections;
using UnityEngine;
public class RayCaster {
public Transform StartTransform;
public Transform EndTransform;
public Vector3 Direction;
public float RayLength;
public int LayerMask = 0;
public event Action<Collider> OnRayEnter;
public event Action<Collider> OnRayStay;
public event Action<Collider> OnRayExit;
Collider previous;
RaycastHit hit = new RaycastHit();
public bool CastRay() {
Physics.Raycast(StartTransform.position, Direction, out hit, RayLength, LayerMask);
ProcessCollision(hit.collider);
return hit.collider != null ? true : false;
}
public bool CastLine() {
Physics.Linecast(StartTransform.position, EndTransform.position, out hit, LayerMask);
ProcessCollision(hit.collider);
return hit.collider != null ? true : false;
}
private void ProcessCollision(Collider current) {
// No collision this frame.
if (current == null) {
// But there was an object hit last frame.
if (previous != null) {
DoEvent(OnRayExit, previous);
}
}
// The object is the same as last frame.
else if (previous == current) {
DoEvent(OnRayStay, current);
}
// The object is different than last frame.
else if (previous != null) {
DoEvent(OnRayExit, previous);
DoEvent(OnRayEnter, current);
}
// There was no object hit last frame.
else {
DoEvent(OnRayEnter, current);
}
// Remember this object for comparing with next frame.
previous = current;
}
private void DoEvent(Action<Collider> action, Collider collider) {
if (action != null) {
action(collider);
}
}
public static int GetLayerMask(string layerName, int existingMask=0) {
int layer = LayerMask.NameToLayer(layerName);
return existingMask | (1 << layer);
}
}
If your question is how to access the last object hit by your raycast then I suggest creating a global variable where you can store it.
Instead of setting the local variable in your method you can then set the global variable when you raycast. This way you can always access the object until you hit a new one(because this one is now stored in your global variable)
EDIT: In the event that you want to be able to keep track of all the targets that you have ever raycast I suggest making an global array where you store each item, appending them as you hit a new target.
so i did it with the mouse and it works
you have to put your object on the right layer first (9th here)
you middle mouse click on a object to change its color (here black), and right click anywhere (on the object or not) to change back its original color
only one object has its color changed at any moment , (lets call this state "selected")
when you "select" the next object by middle mouse clicking on it wile one is already "selected", it'll change the first one to its original color , as it is now "unselected"
public class raycast : MonoBehaviour {
float lenthRay = 10.0f;
Vector3 originePos;
Vector3 dir;
RaycastHit hitinfo;
GameObject hitten;
bool isHitting;
Color beforC;
int selectionLayer = 9;
bool alreadyHitten =false;
void Update () {
originePos = Camera.main.transform.position;
dir = Camera.main.transform.forward * lenthRay;
Debug.DrawRay(originePos, dir, Color.blue);
if (Input.GetMouseButtonDown (2)) {
isHitting = Physics.Raycast (originePos, dir, out hitinfo, lenthRay, selectionLayer);
if(isHitting) {
if(hitinfo.transform.gameObject == null){
hitten= null;
}
if(hitten != null && hitinfo.transform.gameObject == hitten){
alreadyHitten = true;
}
if(hitten != null && hitinfo.transform.gameObject != hitten){
alreadyHitten = false;
hitten.transform.GetComponent<MeshRenderer> ().material.color = beforC;
hitten = hitinfo.transform.gameObject;
}
hitten = hitinfo.transform.gameObject;
if(hitten != null && !alreadyHitten){
print (hitten.name);
MeshRenderer tmp = hitten.transform.GetComponent<MeshRenderer> ();
beforC = tmp.material.color;
tmp.material.color = Color.black;
}
}
}
if (Input.GetMouseButtonDown (1)) {
if(hitten != null){
alreadyHitten = false;
hitten.transform.GetComponent<MeshRenderer> ().material.color = beforC;
hitten = null;
}
}
}
}

Categories