- Home /
Getting transform position of last parent
So I'm writing a "highlight" code for when a user holds their mouse button down and moves over a tile of prefab cubes it renders a new "highlight texture" onto the cube at the mouses position.
I'm using raycasting from screen on mousebuttondown to create this effect but I have a problem: The texture change is permanent. After the mouse position leaves the last prefab cube, it needs to render the texture back to the original, unhighlighted texture. I'm unsure of how to accomplish this.
I'm on break at work right now, I'll add some code examples when I get home.
CODE:
using UnityEngine;
using System.Collections;
public class createCube : MonoBehaviour {
public float timeBetweenBlock = 0.15f;
public GameObject prefab;
public Texture highlightTexture;
public Texture normalTexture;
public int roomSize;
GameObject[] prefabArray;
float timer;
Vector3 lastMouseCoordinate = Vector3.zero;
Ray ray;
Ray rayLast;
RaycastHit hit;
RaycastHit hitLast;
Vector3 mouseDelta;
// Use this for initialization
void Start () {
prefabArray = new GameObject[roomSize*2];
for (int i = (-1*roomSize); i < roomSize; i++) {
for (int j = (-1*roomSize); j < roomSize; j++) {
GameObject tileMap = Instantiate(prefab, new Vector3(i, 0, j), Quaternion.identity) as GameObject;
}
}
}
// Update is called once per frame
void Update () {
timer += Time.deltaTime;
//If clicked on prefab
if (Input.GetMouseButtonDown(0)){
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if(Physics.Raycast(ray, out hit, 100f)){
lastMouseCoordinate = hit.collider.transform.position;
}
}
if (Input.GetMouseButton (0)) {
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if(Physics.Raycast(ray, out hit, 100f)){
Debug.DrawRay(ray.origin, ray.direction * hit.distance, Color.red);
mouseDelta = hit.collider.transform.position - lastMouseCoordinate;
float xmag = Mathf.Abs(mouseDelta.x);
float ymag = Mathf.Abs(mouseDelta.y);
float zmag = Mathf.Abs(mouseDelta.z);
hit.collider.renderer.material.SetTexture("_MainTex", highlightTexture);
if (mouseDelta.x > 0) {
Debug.Log("Up right");
if(Physics.Raycast(lastMouseCoordinate+Vector3.up, Vector3.down, out hitLast)){
Debug.DrawRay(rayLast.origin, rayLast.direction * hitLast.distance, Color.cyan);
hitLast.collider.renderer.material.SetTexture("_MainTex", normalTexture);
Debug.Log(normalTexture);
}
}
else if(mouseDelta.x < 0) {
Debug.Log("Down left");
if(Physics.Raycast(lastMouseCoordinate+Vector3.up, Vector3.down, out hitLast)){
Debug.DrawRay(rayLast.origin, rayLast.direction * hitLast.distance, Color.cyan);
hitLast.collider.renderer.material.SetTexture("_MainTex", normalTexture);
}
}
if (mouseDelta.z > 0) {
Debug.Log("Up Left");
if(Physics.Raycast(lastMouseCoordinate+Vector3.up, Vector3.down, out hitLast)){
Debug.DrawRay(rayLast.origin, rayLast.direction * hitLast.distance, Color.cyan);
hitLast.collider.renderer.material.SetTexture("_MainTex", normalTexture);
}
}
else if(mouseDelta.z < 0) {
Debug.Log("Down Right");
if(Physics.Raycast(lastMouseCoordinate+Vector3.up, Vector3.down, out hitLast)){
Debug.DrawRay(rayLast.origin, rayLast.direction * hitLast.distance, Color.cyan);
hitLast.collider.renderer.material.SetTexture("_MainTex", normalTexture);
}
}
lastMouseCoordinate = hit.collider.transform.position;
}
}
if (Input.GetMouseButtonUp(0)) {
if(timer >= timeBetweenBlock && Time.timeScale != 0){
spawnBlock ();
};
if (mouseDelta == Vector3.zero) {
Debug.Log("Didn't move");
if(Physics.Raycast(hit.collider.transform.position+Vector3.up, Vector3.down, out hitLast)){
Debug.DrawRay(rayLast.origin, rayLast.direction * hitLast.distance, Color.cyan);
hitLast.collider.renderer.material.SetTexture("_MainTex", normalTexture);
}
}
}
}
What my code is doing right now is getting the direction the last prefab block was by getting its transform position and comparing it to the new position of the mouse. Through this I get a "Mouse moved to Top Right/Top Left/Bottom Right/Bottom Left from original position" function.
By that logic I'm just setting a new raycast from transform that is one transform Y value block above the last highlighted texture position and setting the texture back to the original on raycast hit.
It kind of works, but I think there's a better way to do it. For example, if the highlighted texture is on the "side" of a cube, the texture wont reset because the 2nd raycast can't hit that face from the above position. In other words, it only resets the highlight position on the top face of a prefab block because the reset texture raycast origin is ABOVE the block affected.
I could program this to recognize that the mouse is indeed over a side face of a block, but I'll have to do it for each blockface which turns out into really cluttered and redundant code.
There's got to be a better way.
Answer by giulio-pierucci · Feb 07, 2015 at 11:10 AM
Save original texture on a private field before change it. On mouse out, restore it from private field.
Exactly. The part I'm struggling with is creating the "On mouse out" code. I've added my code to my original post above. Right now my textures are public variables I pass in (I only have 2 textures currently a normal and a highlight) and after I fix the on mouse out code, I'll make them dynamic.
Indeed, it appears that the code is redundant and repetitive. It seems to me that the lines:
if(Physics.Raycast(last$$anonymous$$ouseCoordinate+Vector3.up, Vector3.down, out hitLast)){
Debug.DrawRay(rayLast.origin, rayLast.direction * hitLast.distance, Color.cyan);
hitLast.collider.renderer.material.SetTexture("_$$anonymous$$ainTex", normalTexture);
}
are the same in all "if" blocks.
What I can not understand is the reason for all that code.
If you just want to change the texture of a cube when the mouse passes over just a simple script, which implements these two methods:
http://docs.unity3d.com/ScriptReference/$$anonymous$$onoBehaviour.On$$anonymous$$ouseEnter.html http://docs.unity3d.com/ScriptReference/$$anonymous$$onoBehaviour.On$$anonymous$$ouseExit.html
Obviously, the script must be attached to the cube.
If you want to use the raycast, however, you can use:
private gameobject last = null;
[....]
//If clicked on prefab
if (Input.Get$$anonymous$$ouseButtonDown(0))
{
if(Physics.Raycast(ray, out hit, 100f))
{
last = hit.collider.gamoibject;
hit.gameobject.renderer.material.texture = highlightTexture;
}
else
{
if(last!=null) last.renderer.material.texture = normalTexture;
last = null;
}
}
If you think that i don't understand the problem, can you post a package?
Wonderful! Your first suggestion, On$$anonymous$$ouseOver, worked beautifully, thank you. It took a little re-working. I had to add very thin block colliders to the block faces (for some reason On$$anonymous$$ouseOver doesnt like meshcolliders, they need a thickness). After that it worked just fine :).
Do you have any suggestions on how to use an overlay texture? So I don't have to create a highlight texture for each block texture. Like a transparent overlay, that would work.
Any ideas?
Yes, you can try with DECAL Shader
http://docs.unity3d.com/$$anonymous$$anual/shader-NormalDecal.html
Answer by sk00ter · Feb 10, 2015 at 08:31 PM
I was actually able to figure this out last night shortly after posting this :) I ended up creating a shader that used two textures; an opaque "_MainTex" and an alpha "_BlendTex" with a blending float called "_Blend" with a range of 0 to 1, 1 being full blend. Now my OnMouseEnter/OnMouseOut sets that float instead of setting a new texture. Works beautifully!
Thank you for your help!
Your answer
Follow this Question
Related Questions
JS Dynamic Height Camera vibrating =( 1 Answer
Negative Positions Breaks Raycasts 1 Answer
NullReferenceException when using raycast 1 Answer
Trouble with raycasting 1 Answer