- Home /
RayCast not working
so i am making this fps game . as of now the task is to 'kill / 'destroy' a simple cube lying in my scene . i tried this multiple times using slightly different code but it wont make a difference .
below is the gunfire script that is attached to my gun:
using System.Collections; using System.Collections.Generic; using UnityEngine;
public class firegun : MonoBehaviour { public GameObject TheGun; public float TargetDistance; public int DamageAmount; public bool IsFiring = false;
// Update is called once per frame
void Update () {
if (Input.GetButtonDown("Fire1")){
if (IsFiring == false)
{
StartCoroutine(FiringGun());
}
}
}
IEnumerator FiringGun()
{
RaycastHit Shot;
IsFiring = true;
if(Physics.Raycast(transform.position,transform.TransformDirection(Vector3.forward),out Shot)){
TargetDistance = Shot.distance;
Shot.transform.SendMessage("Damage", DamageAmount, SendMessageOptions.DontRequireReceiver);
}
// TheGun.GetComponent<Animation>().Play("Gun+Shot2");
yield return new WaitForSeconds(0.5f);
IsFiring = false;
}
}
and below is the 'kill' script that is attached to the object i want to destroy i.e. a cube . using System.Collections; using System.Collections.Generic; using UnityEngine;
public class kill : MonoBehaviour {
public int EnemyHealth = 5;
public GameObject Enemy;
public int StatusCheck;
void Damage(int DamageAmount)
{
EnemyHealth -= DamageAmount;
}
void Update () {
if (EnemyHealth <= 0&&StatusCheck==0)
{
StatusCheck = 2;
Destroy(gameObject);
}
}
}
Did you check if the function "Damage" ever gets called? e.g. by a
Debug.Log("this cube was hit and health is now: " + EnemyHealth);
If that works make sure that your StatusCheck variable really is 0 i guess? Best to include a Debug.Log as well.
Also check if the raycast actually ever hits something. -> Debug.Log()
yeah man i checked it out . this log is not getting displayed hence the function damage is not called . whats the fix? can you make changes in the original code from now on ? that'll be really helpful
Answer by misher · May 07, 2018 at 10:49 AM
I assume you want raycast in forward of the gun and the script is attached to the gun. Try to create a ray for raycast, use some debug.draw line to see actual raycast in scene. Here:
RaycastHit hit;
Ray ray = new Ray(transform.position, transform.forward);
if (Physics.Raycast(ray, out hit))
{
Debug.DrawLine(ray.origin, hit.point, Color.red, 0.45f);
Kill kill = hit.collider.GetComponent<Kill>();
if (!kill) kill = hit.collider.GetComponentInParent<Kill>();
if(kill)
{
kill.Damage(2);
}
}
what i want is that when i click on the object (for eg cube in my case) only the cube should get destroyed rest everything should remain intact . the kill script is attached to the object i wanna kill i.e. cube and firgun script or something is attached to the gun .
Did you ever try unity event system do do this? You can. Add Physics raycaster to your camera and use IPointerClickHandler interface in kill script... Of courcse, gameobject where kill is attached or one of its children must have collider, also check layer masks for physics raycaster, it should contain the layer your gameobject is on. Here, it is simple like this:
using UnityEngine; using UnityEngine.EventSystems;
public class $$anonymous$$ill : $$anonymous$$onoBehaviour, IPointerClickHandler
{
public void OnPointerClick(PointerEventData eventData)
{
Destroy(gameObject);
}
}
Answer by Captain_Pineapple · May 02, 2018 at 05:14 PM
Hey,
One way to try could be the following. It's probably not as good as the message-system but should be easier to debug.
IEnumerator FiringGun()
{
RaycastHit Shot;
IsFiring = true;
if(Physics.Raycast(transform.position,transform.TransformDirection(Vector3.forward),out Shot)){
TargetDistance = Shot.distance;
Debug.Log ("we hit the object: " + Shot.transform.name);
if (Shot.transform.GetComponent<kill> ()) {
Debug.Log("object has kill-component, aplying damage: " + DamageAmount);
Shot.transform.GetComponent<kill> ().Damage (DamageAmount);
}
}
// TheGun.GetComponent<Animation>().Play("Gun+Shot2");
yield return new WaitForSeconds(0.5f);
IsFiring = false;
}
Change the FiringGun function to this one and try it out. Hope this helps.
ok i'll try . normally raycast worked on systems i dunno whats wrong now . as far the task is concerned i want to shoot with the raycast and suppose i shoot a cube object and after a certain amount of clicks or hits it should get destroyed . (Destroy(gameObject)) is it possible with this script ?
Well the code i posted is to be exchanged for your existing function of your original post. The thing that is changed here is: I added debug messages for you to be able to understand what is happening. The will tell you in the editor if you hit something, if you will deal damage and how much. Since i can not say if you set all your values like health, damage and so on correctly i can not guarantee this to work, but in theory yes (For example the DamageValue on you player object could be 0 in the editor -> then you never deal Damage at all)
It is merely a workaround to not use the unity message system which makes it easier to debug in my opinion.
hey man . the ,messages are being displayed i the console ! the message ' we hit the object' is getting displayed in the console . but the cube is not getting destroyed . what now ? oh and btw i made some edits in the code .
using System.Collections; using System.Collections.Generic; using UnityEngine;
public class firegun : $$anonymous$$onoBehaviour { public GameObject TheGun; public float TargetDistance; public int DamageAmount; public bool IsFiring = false;
// Update is called once per frame
void Update () {
if (Input.GetButtonDown("Fire1")){
if (IsFiring == false)
{
StartCoroutine(FiringGun());
kill k = new kill();
k.EnemyHealth -= DamageAmount;
}
}
Sometimes you may have a collider which is on a child of the GameObject that has the kill component. You could change the code
Shot.transform.GetComponent<kill>()
to
Shot.transform.GetComponentInParent<kill>()
to ensure that the first kill component in the hierarchy is found.
still no luck man . i dunno i messed up or something i'll share the scripts once again.
using System.Collections; using System.Collections.Generic; using UnityEngine;
public class firegun : $$anonymous$$onoBehaviour { public GameObject TheGun; public float TargetDistance; public int DamageAmount; public bool IsFiring = false;
// Update is called once per frame
void Update () {
if (Input.GetButtonDown("Fire1")){
if (IsFiring == false)
{
StartCoroutine(FiringGun());
kill k = new kill();
k.EnemyHealth -= DamageAmount;
}
}
}
IEnumerator FiringGun()
{
RaycastHit Shot;
IsFiring = true;
if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out Shot))
{
TargetDistance = Shot.distance;
Debug.Log("we hit the object: " + Shot.transform.name);
if (Shot.transform.GetComponentInParent<kill>())
{
Debug.Log("object has kill-component, aplying damage: " + DamageAmount);
Shot.transform.GetComponent<kill>().Damage(DamageAmount);
}
}
// TheGun.GetComponent<Animation>().Play("Gun+Shot2");
yield return new WaitForSeconds(0.5f);
IsFiring = false;
}
}
using System.Collections; using System.Collections.Generic; using UnityEngine;
public class kill : $$anonymous$$onoBehaviour {
public int EnemyHealth = 5;
public GameObject Enemy;
public int StatusCheck;
public void Damage(int DamageAmount)
{
EnemyHealth -= DamageAmount;
}
void Update () {
if (EnemyHealth <= 0&&StatusCheck==0)
{
StatusCheck = 2;
Destroy(gameObject);
Debug.Log("this cube was hit and health is now: " + EnemyHealth);
}
}
}
Ok first up: NEVER create an object that is derived from the monobehaviour class by using the "new" keyword. Unity should also be giving you some warnings regarding that. Heed them! If you want to add a kill-component at runtime use gameObject.AddComponent<kill>()
Secondly I edited your script once more: this Code should now find any kill component wherever it is in your hierarchy of the object you just hit. Be carefull though not to add 2 objects with an kill script to the same hierarchy.
using System.Collections; using System.Collections.Generic; using UnityEngine;
public class firegun : $$anonymous$$onoBehaviour { public GameObject TheGun; public float TargetDistance; public int DamageAmount; public bool IsFiring = false;
// Update is called once per frame
void Update () {
if (Input.GetButtonDown("Fire1")){
if (IsFiring == false)
{
StartCoroutine(FiringGun());
}
}
}
IEnumerator FiringGun()
{
RaycastHit Shot;
IsFiring = true;
if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out Shot))
{
TargetDistance = Shot.distance;
Debug.Log("we hit the object: " + Shot.transform.name);
if (Shot.transform.GetComponent<kill> ()) {
Debug.Log ("object has kill-component, aplying damage: " + DamageAmount);
Shot.transform.GetComponent<kill> ().Damage (DamageAmount);
} else if (Shot.transform.GetComponentInParent<kill> ()) {
Debug.Log ("object has kill-component, aplying damage: " + DamageAmount);
Shot.transform.GetComponentInParent<kill> ().Damage (DamageAmount);
} else {
if (Shot.transform.root.GetComponentInChildren<kill> ()) {
Shot.transform.root.GetComponentInChildren<kill> ().Damage (DamageAmount);
} else {
Debug.LogError ("Your definetly forgot to add an kill component to the object: " + Shot.transform.name);
}
}
}
// TheGun.GetComponent<Animation>().Play("Gun+Shot2");
yield return new WaitForSeconds(0.5f);
IsFiring = false;
}
}
using System.Collections; using System.Collections.Generic; using UnityEngine;
public class kill : $$anonymous$$onoBehaviour {
public int EnemyHealth = 5;
public GameObject Enemy;
public int StatusCheck;
public void Damage(int DamageAmount)
{
EnemyHealth -= DamageAmount;
Debug.Log("the Cube " + transform.name + " was hit and health is now: " + EnemyHealth);
}
void Update () {
if (EnemyHealth <= 0&&StatusCheck==0)
{
StatusCheck = 2;
Destroy(gameObject);
}
}
}
Answer by ElijahShadbolt · May 05, 2018 at 03:54 AM
I made some example scenes to demonstrate that your original script works perfectly, as well as demonstrate several message sending techniques. RayCastTests.zip contains a .unitypackage that you can import into a new project, to test them out and compare with your own scenes.
EDIT
1. Creating a New Project
When you start Unity, it should pop up with a window that says Projects. Click New (to the right of the Projects tab) to create a new project. Give it a name (e.g. RayCastTests). Click Create Project. The Unity Editor should now open with the empty project.
2. Importing a .unitypackage
First copy the RayCastTests.unitypackage file from the .zip file to somewhere memorable like the desktop.
Back in Unity, go to Assets > Import Package > Custom Package..., then browse for the unzipped unitypackage file, and click Open. A window titled Import Unity Package should pop up. Make sure all the assets you want to import have their checkboxes ticked (all of them for this example). Then click Import.
3. Have a look at the Scenes
Open the scene named scene. The Main Camera (which has a firegun component), is positioned so that it is aiming directly at a Cube (which has the kill component). The kill component's Status Check property is set to 0 in the inspector.
Run the scene. When you click anywhere in the Game window, a message should appear in the Console window saying that the cube was hit. The 0.5 second cooldown in firegun prevents you from rapidly firing, but once you fire 5 times the cube should be destroyed.
Now take a look at the scene named scene2. The Main Camera's firegun has been replaced with firegun2 which lets you specify how to send the Damage event message to the collider that was hit. The Cube is now the child of an Empty GameObject, and the kill component has been moved from the Cube to the parent Empty GameObject.
The Raycast check in firegun2 (or firegun) will hit the collider of the cube (which is a child of the kill component's GameObject), so in order to call the Damage event on the kill component we need to send the message up the hierarchy to the collider's parent. This can be done by using SendMessageUpwards or GetComponentInParent. To try out different message methods you can change firegun2's Message Method property in the Inspetor. But before you do...
Run the scene2. It should have the exact same functionality as the first scene.
oh thanks a lot man . can you also tell me how to open this unity package file ? or how to test this in a bit more detail?
In the unity editor, go to Assets > Import Package > Custom Package
hey man . i checked this out and its working all good . but the object should get destroyed only when i click ON IT not anywhere random on the screen . what i want is that only when i click on the cube its health should decrement not by clicking anywhere on the screen . just like pc games.
hey man . i checked this out and its working all good . but the object should get destroyed only when i click ON IT not anywhere random on the screen . what i want is that only when i click on the cube its health should decrement not by clicking anywhere on the screen . just like pc games. after the code you gave all the objects other than the cube i wanna destroy are getting destroyed . i just wanna destroy the object i click on nothing else. is it possible ?
Answer by rtanwar616 · May 05, 2018 at 06:13 AM
@myzzie do I have to do it in my original scene or in a new scene ?
Answer by Deeblock · May 07, 2018 at 09:40 AM
Try this code out:
// Update is called once per frame
void Update () {
if (Input.GetButtonDown("Fire1")){
if (IsFiring == false)
{
StartCoroutine(FiringGun());
}
}
}
IEnumerator FiringGun()
{
RaycastHit Shot;
IsFiring = true;
if(Physics.Raycast(transform.position,transform.TransformDirection(Vector3.forward),out Shot)){
TargetDistance = Shot.distance;
// We get the gameobject kill is attached to and call the public kill method.
Shot.transform.gameObject.GetComponent<kill>().Damage(damageAmount);
}
// TheGun.GetComponent<Animation>().Play("Gun+Shot2");
yield return new WaitForSeconds(0.5f);
IsFiring = false;
}
And then in your kill script:
public int EnemyHealth = 5; // Make sure to check inspector if it is being overridden.
public GameObject Enemy;
public int StatusCheck;
pubilc void Damage(int DamageAmount) // Make sure this function is public so you can call it!
{
EnemyHealth -= DamageAmount;
if (EnemyHealth <= 0&&StatusCheck==0)
{
StatusCheck = 2;
Destroy(gameObject);
}
}
nothing happening mate . thanks for your answer though.i guess i'll delete this question .
Your answer
Follow this Question
Related Questions
Unity3d and monodevelop c# scripting on ubuntu 16.04 IntelliSense problems 0 Answers
Making Everything Public 0 Answers
How Can I get the mouse to Cycle Through Animations Each Time I click it? Please Help! 1 Answer
Please Help Me With My Stamina Bar! 1 Answer
Making the player change his movement when it hit an object with collider 0 Answers