I am trying to disable a component/script on a game object when the Raycast has not hit but enable it when it does hit. I can enable the script and that part works when the Raycast hits, however, when I move away from the object, it is still enabled and I cant seem to figure this out.
The entire code to do this is in my update function.
// Update is called once per frame
void Update()
{
Ray ray = Camera.main.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0f));
float distance = 100f;
Debug.DrawRay(ray.origin, ray.direction * distance, Color.green);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
// hit!
Debug.Log("Raycast is hitting " + hit.transform.gameObject);
if (hit.transform.tag == "Crate")
{
crossair.color = Color.red;
hit.transform.GetComponent<Outline>().enabled = true; // this works
}
else
{
crossair.color = Color.white;
hit.transform.GetComponent<Outline>().enabled = false; //Does not work
}
}
}
You will need to store the currently active one in order to deactivate it in case
private const float distance = 100f;
private Outline currentHit;
void Update()
{
var ray = Camera.main.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0f));
if (Physics.Raycast(ray, out var hit))
{
// hitting something
// Actually checking this way makes you tag redundant ;)
if (hit.transform.TryGetComponent<Outline>(out var outline))
{
// Hitting and outline!
Debug.DrawLine(ray.origin, hit.point, Color.red);
if(outline != currentHit)
{
// Hitting a different outline!
crossair.color = Color.red;
if(currentHit)
{
currentHit.enabled = false;
}
currentHit = outline;
currentHit.enabled = true;
}
}
else
{
// Hitting something that is not an outline
crossair.color = Color.white;
Debug.DrawLine(ray.origin, hit.point, Color.green);
if(currentHit)
{
currentHit.enabled = false;
currentHit = null;
}
}
}
else
{
// Not hitting anything
crossair.color = Color.white;
Debug.DrawRay(ray.origin, ray.direction * distance, Color.green);
if(currentHit)
{
currentHit.enabled = false;
currentHit = null;
}
}
}
Related
In my Unity game (top-down 2D shooter) there are some enemies flying along a path (via DOTween). My player casts a ray into the scene in order to get an enemy-object right in front of the player. So far so good.
Now the problem is that I want only one enemy-object as a result, i.e. the raycast should stop when it hits an enemy-object for the very first time. How do I achieve this?
I need only one enemy-object hit by the raycast because there is a crosshair in my game and when the raycast starts and the enemies fly along the path the crosshair jumps forth and back (and I don't want this - the crosshair should stay at the first enemy hit by the raycast).
Raycast video
This is my code (attached to the player):
void FixedUpdate() {
//crosshair: Cast a ray straight up.
float _size = 12f;
Vector2 _direction = this.transform.up;
RaycastHit2D _hit = Physics2D.Raycast(this.transform.position, _direction, _size);
if (_hit.collider != null && _hit.collider.tag == "EnemyShipTag") {
// We touched something!
Vector2 target = new Vector2(_hit.collider.gameObject.transform.position.x, _hit.collider.gameObject.transform.position.y);
const float moveTime = 0.1f;
float step;
step = Vector2.Distance(crosshairGO.transform.position, target);
crosshairGO.transform.position = Vector2.MoveTowards(crosshairGO.transform.position, target, step / moveTime * Time.deltaTime);
Vector2 _pos3 = new Vector2(this.transform.position.x, crosshairGO.transform.position.y);
crosshairGO.transform.position = _pos3;
crosshairBegin = false;
} else {
// Nothing hit
Vector2 _pos2 = new Vector2(this.transform.position.x, 4.5f);
if (crosshairBegin) {
crosshairGO.transform.position = _pos2;
} else {
Vector2 _pos4 = new Vector2(this.transform.position.x, crosshairGO.transform.position.y);
crosshairGO.transform.position = _pos4;
}
}
}
If I understand you right. You could create a bool value and set it true after you hit something.
For example:
Vector2 _pos3 = new Vector2(this.transform.position.x, crosshairGO.transform.position.y);
crosshairGO.transform.position = _pos3;
crosshairBegin = false;
youHitSomething = true;
Before you create the ray
you could write an if
if(!youHitSomething)
{
float _size = 12f;
Vector2 _direction = this.transform.up;
RaycastHit2D _hit = Physics2D.Raycast(this.transform.position, _direction, _size);
if (_hit.collider != null && _hit.collider.tag == "EnemyShipTag")
{
// We touched something!
// your Code
youHitSomething = true;
}
else
{
// Nothing hit
// your code
}
}
To let the ray cast again you could create a new method
public void ActivateRay()
{
youHitSomething = false;
}
firstly i'm sorry if sometimes my English will be a bit incomprehensible, i'll try to do my best.
Actually i'm trying to build a simple AI system with unity Navimesh Component, my goal is :
NPC will check witch player is nearest to it's position and go there to kill him.
if target player is facing me run away
my actual code is working but with some issues
private Transform player;
private UnityEngine.AI.NavMeshAgent myNMagent;
private Transform startTransform;
public float multiplyBy;
public Vector3 resultedVector;
// Use this for initialization
void Start () {
player = GameObject.FindGameObjectWithTag ("Player").transform;
myNMagent = this.GetComponent<UnityEngine.AI.NavMeshAgent> ();
RunFrom ();
}
// Update is called once per frame
void Update () {
//if is not facing got to eat him
if(!ISFacing())
{
GotToEat();
}
else
{
RunFrom ();
}
}
public void RunFrom()
{
startTransform = transform;
transform.rotation = Quaternion.LookRotation(transform.position - player.position);
Vector3 runTo = transform.position + transform.forward * multiplyBy;
NavMeshHit hit;
if(NavMesh.SamplePosition(runTo, out hit, 50, 1 << NavMesh.GetAreaFromName("Walkable")))
{
transform.position = startTransform.position;
transform.rotation = startTransform.rotation;
myNMagent.SetDestination(hit.position);
}
else
{
Debug.Log("not hitting");
}
}
private void GotToEat()
{
transform.rotation = Quaternion.LookRotation(player.position - transform.position);
myNMagent.SetDestination(player.transform.position);
}
private bool ISFacing()
{
float angle = 45;
float angleToPlayer = Vector3.Angle(player.transform.forward.normalized,( transform.position - player.transform.position).normalized);
if( angleToPlayer < angle)
{
return true;
}
else
return false;
}
bool IsHit(out Vector3 result)
{
for (int i = 0; i < 30; i++)
{
Vector3 fixedPoint = transform.position + transform.forward * multiplyBy;
NavMeshHit hit;
if (NavMesh.SamplePosition(fixedPoint, out hit, 10.0f,1 << NavMesh.GetAreaFromName("Walkable")))
{
result = hit.position;
return true;
}
}
result = Vector3.zero;
return false;
}
when NPC is going to reach the corner of my map it won't move anymore will freeze there.
i suppose that i should check if any hitting navmesh is "Walkable" or not, but my function will return always true, so i can't tell to navimesh to go in any other direction..
what i'm missing up?
A video of it
video
I am trying to move the y position of a UI element in it's local space by clicking and dragging with the SteamVR controller and a raycast. I am getting what appear to me to be unpredictable results.
I am trying to get the position of the raycast at the start of the drag and move it the distance between where it is and where it was started while dragging.
Here is my code:
if (hit.transform.name == "Content" && scrollSet == false)
{
content = hit.transform;
scrollSet = true;
scrollPos = hit.transform.position ;
}
if (scrollSet == true)
{
if (rController.triggerPressed)
{
y = hit.transform.position.y - scrollPos.y;
content.transform.localPosition = new Vector3(content.transform.localPosition.x, content.localPosition.y + y, content.transform.localPosition.z);
}
else
{
scrollSet = false;
}
}
you can convert the .MovePosition to .MoveTowards. But it still jumped around. It turns out that the code was only executing during the frame in which you right-clicked, so move it out of the if statement.
Here's the entire script placed into the main camera. You always need to have a target selected, so to prevent errors you need to put a gameObject with a rigidbody into "bTarg".
public class ClickTarget : MonoBehaviour {
private GameObject target; private Vector3 destination; private float distance; private Vector3 tTrans;
public GUIText targetDisplay; public float speed; public GameObject bTarg;
void Start () { targetDisplay.text = ""; distance = 0.0f; target = bTarg; }
void Update () { if(Input.GetButtonDown("Fire1")){ Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if(Physics.Raycast(ray, out hit)){ if(hit.collider != null){ if(hit.collider.tag == "Unit"){ target = hit.collider.gameObject; targetDisplay.text = "Unit: " + hit.collider.gameObject.name; destination = target.transform.position; target.rigidbody.freezeRotation = false; } if(hit.collider.tag == "Building"){ target = hit.collider.gameObject; targetDisplay.text = "Building: " + hit.collider.gameObject.name; } } } } }
void FixedUpdate(){ if (Input.GetButtonDown ("Fire2") && target.tag == "Unit" && GUIUtility.hotControl == 0) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if(Physics.Raycast(ray,out hit)){ destination = hit.point; } }
tTrans = target.transform.position;
distance = Vector3.Distance (tTrans, destination);
if(target.tag == "Unit"){
if (distance > .2f) {
target.transform.LookAt (destination);
target.transform.position = Vector3.MoveTowards (target.transform.position, destination, speed);
target.rigidbody.freezeRotation = true;
}
}
} }
Here is my code:
public class CharacterController : MonoBehaviour
{
private Vector3 _startLocation = Vector3.zero;
private Vector3 _currentLocation = Vector3.zero;
private Vector3 _endLocation = Vector3.zero;
private bool _isMoving = false;
private float _distanceToTravel;
private float _startTime;
public float Speed = 1.0f;
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Debug.Log("Left mouse button clicked");
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
if (hit.collider.gameObject.CompareTag("Ground"))
{
_startLocation = transform.position;
_endLocation = hit.point;
_isMoving = true;
_startTime = Time.time;
_distanceToTravel = Vector3.Distance(_startLocation, _endLocation);
Debug.Log(string.Format("Ground has been hit: Start: {0}, End: {1}", _startLocation.ToString(), _endLocation.ToString()));
}
}
}
if (_isMoving)
Move();
}
void Move()
{
float timeElapsed = (Time.time - _startTime) * Speed;
float t = timeElapsed / _distanceToTravel;
_currentLocation = Vector3.Lerp(_startLocation, _endLocation, t);
transform.Translate(_currentLocation);
if (_currentLocation == _endLocation)
{
Debug.Log(string.Format("Destination reached ({0})", _endLocation.ToString()));
_isMoving = false;
}
}
}
I read the documentation on the Vector3.Lerp function, as well as the Physics.Raycast function, and ended up with this code.
The debug console confirms that the Ground has been hit, but my capsule starts moving upwards in the Y direction and never stops!
I'm still very new to Unity and game development in general, so I'm still learning, but any pointers on what I'm doing wrong?
it is moving in the Y because you use transform.Translate.
transform.Translate is moving it, so if you did transform.Translate(0, 0, 10)
it would move in the z, and if you did transform.Translate(0, 10, 10)
it will move in the y and z direction.
So to fix this i will show you 2 ways:
1) Using Vector3.Lerp:
transform.position = Vector3.Lerp(_startLocation, _endLocation, t);
2) Using MoveTowards:
transform.position = Vector3.MoveTowards(transform.position, _endLocation, Speed * Time.deltaTime);
In the first Vector3.Lerp is used, and i see you use it too
_currentLocation = Vector3.Lerp(_startLocation, _endLocation, t);
So you could do either this:
transform.position = Vector3.Lerp(_startLocation, _endLocation, t);
or this
transform.position = _currentLocation;
Both will do the same because you assigned _currentLocation to
Vector3.Lerp(_startLocation, _endLocation, t);
And you can read about MoveTowards here
http://docs.unity3d.com/ScriptReference/Vector3.MoveTowards.html
Check the Comments line You will understand what I had edited to bring the Solution.
It works well for me
void Start()
{
_startLocation = transform.position; // Changed Here to Initialize once
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Debug.Log("Left mouse button clicked");
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
if (hit.collider.gameObject.CompareTag("Ground"))
{
print(hit.point);
//**Here you mentioned _StartLocation = transform.position
//this instantly changes the starting point Every time so
//if SP changes then totally changed in Translation.***
_endLocation= hit.point;
_isMoving = true;
_startTime = Time.time;
_distanceToTravel = Vector3.Distance(_startLocation, _endLocation);
}
}
}
if (_isMoving)
{
Move();
}
}
void Move()
{
float timeElapsed = (Time.time - _startTime) * Speed;
float t = timeElapsed / _distanceToTravel;
_currentLocation = Vector3.Lerp(_startLocation, _endLocation, t);
transform.position = Vector3.Lerp(_startLocation, _endLocation, t);
_startLocation = _endLocation;
//*** This line is for Next Mouse
//click. So every next click StartPoint is Current Click
//EndPoint***
if (_currentLocation == _endLocation)
{
Debug.Log(string.Format("Destination reached ({0})", _endLocation.ToString()));
_isMoving = false;
}
}
}
I know how to get information from a RayCast but couldn't find anything good on sphereCast.
When I shoot a raycast to an enemy I can detect it's health component and reduce it's health.
It's code:
shootRay.origin = transform.position;
shootRay.direction = transform.forward
if (Physics.Raycast(shootRay, out shootHit, 100f, shootableMask))
{
EnemyHealth enemyHealth = shootHit.collider.GetComponent<EnemyHealth>();
if (enemyHealth != null)
{
enemyHealth.TakeDamage(damagePerShot, shootHit.point);
}
}
Now I want to do a similar thing with SphereCast but instead of one enemy I want to detect all enemys in the hit area and reduce their health.
if (Physics.SphereCast(shootRay, 5f, out shootHit, 100f, shootableMask))
{
// ???
}
According to this (http://answers.unity3d.com/questions/486261/how-can-i-raycast-to-multiple-objects.html) all you need to do is to use RaycastAll:
Example:
void Update() {
RaycastHit[] hits;
hits = Physics.RaycastAll(transform.position, transform.forward, 100.0F);
int i = 0;
while (i < hits.Length) {
RaycastHit hit = hits[i];
Renderer rend = hit.transform.GetComponent<Renderer>();
if (rend) {
rend.material.shader = Shader.Find("Transparent/Diffuse");
rend.material.color.a = 0.3F;
}
i++;
}
}