Raycast collision point is offset

Hi,

As my drawing (hopefully) illustrates, I am trying to instantiate a prefab at a raycast hit point (hit1). However, when I do the prefab is instantiated way off to the left. Does anyone know why this is?

Thanks in advance!

public class DashLine : MonoBehaviour {
   
    private JumpBoost jumpBoost;
    private GameObject player;
    private GameObject arrowPrefab;
    private float hitDistanceX;
    private float hitDistanceY;
    private float mouseDistanceX;
    private float mouseDistanceY;
    private bool dashLineActive;
    private Vector2 arrowPosition;
    private LayerMask mask = ~(1 << 8);

    public GameObject arrow;
   
    // Use this for initialization
    void Awake () {
   
        player = GameObject.FindGameObjectWithTag("Player");
        jumpBoost = player.GetComponent<JumpBoost> ();

        dashLineActive = false;
    }
   
    // Update is called once per frame
    void Update () {

        if(dashLineActive)
        {
            Vector3 worldMousePosition =  Camera.main.ScreenToWorldPoint (Input.mousePosition);
            worldMousePosition = new Vector3 (worldMousePosition.x, worldMousePosition.y, 0f);

            mouseDistanceX = worldMousePosition.x - player.transform.position.x;
            mouseDistanceX = Mathf.Clamp(mouseDistanceX, -jumpBoost.boostLength, jumpBoost.boostLength);
            mouseDistanceY = worldMousePosition.y - player.transform.position.y;

            Vector2 mouseRelativeClamped = player.transform.position + player.transform.rotation * new Vector2(mouseDistanceX, mouseDistanceY);

            RaycastHit2D hit0 = Physics2D.Raycast (player.transform.position, new Vector2 (mouseDistanceX, mouseDistanceY), Mathf.Infinity, mask);
            Debug.DrawRay (player.transform.position, new Vector2 (mouseDistanceX, mouseDistanceY));

            RaycastHit2D hit1;

            if(hit0.collider != null)
            {

                hit1 = Physics2D.Raycast (hit0.point, -Vector2.up, Mathf.Infinity, mask);
                Debug.DrawRay(hit0.point, -Vector2.up * 10f, Color.blue);
            }
            else
            {
                hit1 = Physics2D.Raycast (mouseRelativeClamped, -Vector2.up, Mathf.Infinity, mask);
                Debug.DrawRay(mouseRelativeClamped, -Vector2.up * 10f, Color.red);
            }

            // Clamp the x-value of hit1.point to the same as mouseDistanceX.
            if(hit1.point.x > mouseDistanceX)
            {
                Vector2 temp = hit1.point;
                temp.x = mouseDistanceX;
                hit1.point = temp;
            }

            Debug.Log (hit1.point);

            if(Input.GetButtonDown("Fire2"))
            {
                if(hit1.collider != null)
                {
                    arrowPrefab = (GameObject) Instantiate(arrow, hit1.point, Quaternion.identity);
                }
            }

What’s the origin for the prefab? I assume your hit1 position is where you expect it to be?

1 Like

Thanks for responding, Graham.
Well the prefab is instantiated at hit1.point. In the scene however, when i instantiate the prefab at the player objects x = 0 position, the prefab is also at its own x = 0 position, but not relative to the player, so it is instantiated off to left of the player. My question is then i guess: how do i instantiate the prefab at hit1.position relative to the player object?

Create a new scene. In code instantiate your prefab at the world origin, and point the camera at the world origin. Does the prefab appear? or is it offset somewhere else? If it does appear, then there’s no offset baked into the prefab. If there is no offset in the prefab, then does the vector value printed at your line 64 look correct to you?

1 Like

When i do that the prefab is instantiated at the center of the camera:

using UnityEngine;
using System.Collections;

public class InstantiateAtWOrigin : MonoBehaviour {

    private GameObject arrowPrefab;
    public GameObject arrow;

    // Use this for initialization
    void Start () {
   
    }
   
    // Update is called once per frame
    void Update () {

        if(Input.GetButtonDown("Fire2"))
        {
                arrowPrefab = (GameObject) Instantiate(arrow, new Vector2 (0,0), Quaternion.identity);
       
        }
   
    }
}

I should probably add that the gameobejct which the DashLine script is attached to, is a child of the player gameobject and is at point (0,0,0)…

I’m not quite sure how it’s done in 2D, but i’ve read several times that you also have to tell ScreenToWorldPoint how far away in the z-axis you want to get the point, otherwise it will return the camera position if it’s 0 (Input.mousePosition.z is always 0).

1 Like

Hey Suddoha,

Well that part i know has worked before. Initially i just had a raycast down from the mouse position using just hit0, and that worked fine. The problem seems to me to be related somehow to the prefab being instantiated in world space and the raycast point (hit1.point) in local space of the player object. Problem is i don’t know how to instantiate the prefab at the same local position as the hit1.point… Does that even make sense?

Those points you get from the raycast should be in world space.

*Edit
Forget about the other suggestion, there’s no need to do that in orthographic mode.

1 Like

hit1.point gives me coordinates relative to the parent “player” gameobject. To the left of the player i get negative x values and to the right i get positive values. I think it has to do with this part of the code:

if(hit1.point.x > mouseDistanceX)
            {
                Vector2 temp = hit1.point;
                temp.x = mouseDistanceX;
                hit1.point = temp;
            }

Because if i debug before this, then i get it in world space

Ok. i figured out that the clamp code above messed it up. sorry for the trouble. i think i just have to clamp the x distance from the player another way. Any idea how to do that?

Where’s your player object then?

If you just set it to mouseDistanceX, you won’t get the correct x-offset relative to the player. In this case you should add the player’s x-position to the temp.x before reassigning it to hit1.point. I hope i’m not wrong this time. ;D

1 Like

OK. Will try! Thanks!

But you might wanna adjust the if-statement aswell then.

1 Like

For anyone interested or other people looking for a solution to a similar problem, the code ended up working like this:

public class DashLine : MonoBehaviour {
   
    private JumpBoost jumpBoost;
    private GameObject player;
    private GameObject arrowPrefab;
    private float hitDistanceX;
    private float hitDistanceY;
    private float mouseDistanceX;
    private float mouseDistanceY;
    private bool dashLineActive;
    private Vector2 arrowPosition;
    private LayerMask mask = ~(1 << 8);

    public GameObject arrow;
   
    // Use this for initialization
    void Awake () {
   
        player = GameObject.FindGameObjectWithTag("Player");
        jumpBoost = player.GetComponent<JumpBoost> ();

        dashLineActive = false;
    }
   
    // Update is called once per frame
    void Update () {

        if(dashLineActive)
        {
            Vector3 worldMousePosition =  Camera.main.ScreenToWorldPoint (Input.mousePosition);
            worldMousePosition = new Vector3 (worldMousePosition.x, worldMousePosition.y, 0f);

            mouseDistanceX = worldMousePosition.x - player.transform.position.x;
            mouseDistanceX = Mathf.Clamp(mouseDistanceX, -jumpBoost.boostLength, jumpBoost.boostLength);
            mouseDistanceY = worldMousePosition.y - player.transform.position.y;

            Vector2 mouseRelativeClamped = player.transform.position + player.transform.rotation * new Vector2(mouseDistanceX, mouseDistanceY);

            RaycastHit2D hit0 = Physics2D.Raycast (player.transform.position, new Vector2 (mouseDistanceX, mouseDistanceY), Mathf.Infinity, mask);
            Debug.DrawRay (player.transform.position, new Vector2 (mouseDistanceX, mouseDistanceY));

            RaycastHit2D hit1;

            if(hit0.collider != null)
            {

                hit1 = Physics2D.Raycast (new Vector2 (hit0.point.x, hit0.point.y - 0.1f), -Vector2.up, Mathf.Infinity, mask);

                Vector2 hit1PointLocalSpace = transform.InverseTransformPoint(hit1.point);
                Vector2 mousePointLocalSpace = transform.InverseTransformPoint(mouseRelativeClamped);

                if(Mathf.Abs(hit1PointLocalSpace.x) > Mathf.Abs(mousePointLocalSpace.x))
                {
                    hit1 = Physics2D.Raycast (mouseRelativeClamped, -Vector2.up, Mathf.Infinity, mask);
                }
                else
                {
                    Debug.DrawRay(new Vector2 (hit0.point.x, hit0.point.y - 0.1f), -Vector2.up * 20f, Color.blue);
                }
            }
            else
            {
                hit1 = Physics2D.Raycast (mouseRelativeClamped, -Vector2.up, Mathf.Infinity, mask);
                Debug.DrawRay (mouseRelativeClamped, -Vector2.up * 20f, Color.red);
            }

            if(Input.GetButtonDown("Fire2"))
            {
                if(hit1.collider != null)
                {
                    arrowPrefab = (GameObject) Instantiate(arrow, hit1.point, Quaternion.identity);
                }
                else
                {
                    arrowPrefab = (GameObject) Instantiate(arrow, hit0.point, Quaternion.identity);
                }
            }

            if(Input.GetButton("Fire2"))
            {
                Time.timeScale = 0.5f;

                if(arrowPrefab != null && hit1.collider != null)
                {
                    Vector2 temp = arrowPrefab.transform.localPosition;
                    temp = hit1.point;
                    arrowPrefab.transform.localPosition = temp;
                }
                else if (arrowPrefab != null && hit1.collider == null)
                {
                    Vector2 temp = arrowPrefab.transform.localPosition;
                    temp = hit0.point;
                    arrowPrefab.transform.localPosition = temp;
                }
            }
            else
            {
                Time.timeScale = 1f;
                Destroy (arrowPrefab);
            }
        }
    }

    public void DashLineActive()
    {
        dashLineActive = true;
    }
   
    public void DashLineInactive()
    {
        dashLineActive = false;
    }

    public Vector2 GetArrowPrefabPosition()
    {
        return arrowPrefab.transform.position;
    }
}

Thanks for the help fellas!

1 Like