[SOLVED] Trouble generating a "preview" object before instantiating

Hello, I am having trouble making a prefab follow the mouse cursor before placing it in my scene in the game. I currently have been following some of Brackeys tower defense tutorial for the parts I needed to learn and I got my prefab to spawn in the game after clicking a UI button and then clicking the mouse. I am not making a game with tiles or “nodes” as he is calling them, but instead I wanted the option to spawn this prefab wherever the player chooses in the scene. I have spent about 10 hours just trying to search the internet for something to fit my needs, but all of the stuff I found has either been outdated or I am unable to implement it into my code. I am very new to this, and still trying to make sense of what all the code means, but I am starting to get it down. I have tried many things on my own and from the unity docs on instantiating, but I cannot seem to grasp this concept well enough. If someone could help point me in the right direction or provide some code to get me started, I would really appreciate it! I am also trying to figure out how to rotate the object before placing it if you can start me on that as well.

Currently I can click on the UI button and then click somewhere in the level to place the object. This works good, but it does allow spawning through other objects and on top of them. That’s another problem I will be working on. My main concerns are:

  • Creating a “preview” of the object that will follow the users mouse until the button is clicked again to place it in the level

-Implementing a key press to allow for rotation of the object before being placed

Again, any help would be appreciated. Sorry If my code is atrocious. :slight_smile:

using UnityEngine;

public class BuildManager : MonoBehaviour {

    public static BuildManager instance;

    void Awake ()
    {
        if (instance != null)
        {
            Debug.Log("More than one BuildManager in Scene!");
            return;
        }
        instance = this;
    }

    public GameObject woodenFencePrefab;

    private GameObject defenseToBuild;

    public GameObject GetDefenseToBuild ()
    {
        return defenseToBuild;
    }

    public void SetDefenseToBuild (GameObject defense)
    {
        defenseToBuild = defense;
    }

}
using UnityEngine;

public class RaycastBuilder : MonoBehaviour {

    public GameObject defense;

    public Vector3 positionOffset;

    public bool IsPurchased = false;

    Vector3 mousePosition;

    BuildManager buildManager;

    void Start ()
    {
        buildManager = BuildManager.instance;
    }

    void Update ()
    {
        GameObject defenseToBuild = buildManager.GetDefenseToBuild();

            //To get the current mouse position
            mousePosition = Input.mousePosition;

        if (Input.GetMouseButton(0)&& IsPurchased == true)
        {
            Ray ray = Camera.main.ScreenPointToRay(mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit))
            {
                defense = (GameObject)Instantiate(defenseToBuild, hit.point + positionOffset, Quaternion.identity);
                IsPurchased = false;
            }
        }
    }
}
using UnityEngine;

public class Shop : MonoBehaviour {

    BuildManager buildManager;

    void Start ()
    {
        buildManager = BuildManager.instance;
    }

    public void PurchaseWoodenFence ()
    {
        Camera.main.GetComponent<RaycastBuilder>().IsPurchased = true;
        Debug.Log("Wooden Fence Purchased");
        buildManager.SetDefenseToBuild(buildManager.woodenFencePrefab);
    }

}

Thanks for taking the time out of your day to help me!

EDIT: bigmisterb has fixed my issue for me, can’t thank him enough!

3160706–240452–BuildManager.cs (586 Bytes)
3160706–240453–RaycastBuilder.cs (938 Bytes)
3160706–240454–Shop.cs (419 Bytes)

There are a couple of things that need to change:

    // RaycastBuilder Update
	void Update ()
    {
        GameObject defenseToBuild = buildManager.GetDefenseToBuild();
		if(defenseToBuild == null){
			return;
		}
 
		//To get the current mouse position
		mousePosition = Input.mousePosition;
		
		Ray ray = Camera.main.ScreenPointToRay(mousePosition);
		RaycastHit hit;
		if (Physics.Raycast(ray, out hit, layerMask))
		{
			defenseToBuild.transform.position = hit.point + positionOffset;
		}
		
		// do your rotation stuff here.
 
        if (Input.GetMouseButton(0)&& IsPurchased == true)
        {
			buildManager.SetDefenseToBuild(null);
			IsPurchased = false;
        }
		
		if(Input.GetKeyDown(KeyCode.Escape)){
			buildManager.SetDefenseToBuild(null);
			Destroy(defenseToBuild);
			IsPurchased = false;
		}
    }
	
	
	// Shop update
	public void PurchaseWoodenFence ()
    {
        Camera.main.GetComponent<RaycastBuilder>().IsPurchased = true;
        Debug.Log("Wooden Fence Started");
        buildManager.SetDefenseToBuild((GameObject)Instantiate(buildManager.woodenFencePrefab, Vector3.zero, Quaternion.identity));
    }

Thank you for your help! I tried adding your code into mine and replacing where needed, but now when I click the shop button it simply places a wooden fence at (0,0,0) everytime. This is when I assign a layer mask in the “8” position and put my floor to that layer. If I take the layer mask out of that part of the code and just use (ray, out hit) I see the fence following my mouse and I can place it or cancel with escape, but it is constantly looping between the ground and the camera. It gets faster in the loop the closer it is to the center of the scene. I am not sure what this means. Never used layermasks before so I am probably just doing a small mistake there. I did look at the unity docs for layer masks and messed around with changing it to different objects and what not. no luck :frowning:

Edit: Just realized when I take the layerMask number out of there, it still spawns the object at Vector3.zero, but once I mouse over the floor it starts following mouse position while doing the loop from ground to camera. It then places wherever it is at along the path of ground to camera. I.E. in the air right in front of camera or on the ground and anywhere inbetween based on when you click

Alright, I spent all this time since posting this trying to figure out the issue but I still haven’t had any luck. I did figure out how to rotate my object while it is following the mouse and before being placed. I also got the raycast to return a debug.log to the console by setting the layerMask as 1 << 8 like it says in the unity docs. not sure exactly what this means or if that is right but it still did not fix my problem. If the problem does not make sense to anyone, just imagine an alien ship using its beam to suck somebody up to the ship. This is what is happening to my object that is following the mouse before being placed. It just loops over and over from the ground to the camera like you would picture a UFO when it is abducting somebody and sucking them up to the ship. Again, if anyone has an idea where it may have gone wrong, I would be very thrilled to have this fixed! Thanks bigmisterb for getting me this far, I appreciate it!

A layer mask hits only objects set for that layer.

So in your editor, make sure the ground is layer 8, and everything else is not layer 8.

Ok thank you! I had been trying it that way with only the Floor set to layer 8 which I labeled “Floor”, but it was not working for some reason. I have moved onto a new problem as I have fixed this one sort of. It turns out that it was because the prefab had a box collider so the ray was hitting it and adjusting its position over and over until it hit the ground and started over again. now I just need to figure out how to set the box collider to true after I instantiate the object on the ground.

Edit: I just set the prefab to Ignore raycast layer. This may present problems down the road depending on what I learn about interactions in my game, but for now this works. Thanks again
bigmisterb