Making a prefab that follows the mouse until confirmation.

Hey, I'm trying to build a city-building type game and I'm currently working on the build functionality.
What I have attempted is placing a prefab of the selected building on the mouse position in world, and then having it follow. Unfortunately this either results in a new prefab being made at every mouse position, or just doesn't work at all.
I'm pretty new to unity so any help is appreciated.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BuildMode : MonoBehaviour
{
    public Structures currentlySelectedStructure; //uses my own scriptable object
    private GameObject structureToBuild;
    public GameObject menuController;
    public LayerMask planetClickable;
    public Transform centrePoint;
    public string GameState;
    Transform hypPosition;
    MeshRenderer hypRenderer;
    public bool structureProposed = false;
    public bool structureConfirmed = true;

    void Start()
    {

    }
    void Update()
    {
        if (GameState == "PlanetView")
        {

        }
        else if (GameState == "BuildMode")
        {
            if(structureConfirmed){
            InBuildMode();
            structureConfirmed = false;
            }
        }
    }

    public void BuildButtonPressed() //used by a button
    {
        GameState = "BuildMode";
        structureConfirmed = true;

    }
    public void CloseBuildPressed() //used by a button
    {
        GameState = "PlanetView";
        menuController.GetComponent<MenuController>().BackToMain();
    }
    public void InBuildMode()
    {

            Ray myRay = Camera.main.ScreenPointToRay (Input.mousePosition);
            RaycastHit hitInfo;

            if (Physics.Raycast(myRay, out hitInfo, 100, planetClickable))
            {
                Vector3 mouseOnWorldPos = hitInfo.point;

                Vector3 direction = mouseOnWorldPos - centrePoint.position;
                Quaternion objectRotation = centrePoint.rotation;


                GameObject hypotheticalObj;

                hypotheticalObj = Instantiate(currentlySelectedStructure.model, mouseOnWorldPos, objectRotation);
                MeshRenderer hypRenderer = hypotheticalObj.GetComponent<MeshRenderer>(); //get mesh renderer to make the object red/green during build process
                Transform hypPosition = hypotheticalObj.GetComponent<Transform>();

                if(!structureConfirmed){

                    hypPosition.position = mouseOnWorldPos;

                    if (Input.GetMouseButton(0)){
                        structureConfirmed = true;
                        hypPosition.position = hypPosition.position;
                        GameState = "PlanetView";

                        menuController.GetComponent<MenuController>().BackToMain();

                    }

                }
            }
    }
}

The reason that you're getting infinite copies is that your InBuildMode() is being called every update frame. The most straight forward fix would be to hold onto a reference to this instantiated object and don't instantiate it again if it's not null.

That said, something like this doesn't need to be constantly run in Update, but you do want to maintain some form of 'state' as you're already sort of have going.

States like this generally want to:

  • Set things up when you enter the stage
  • Wait for some form of input
  • Run something when the input is registered

This is pretty similar but not quite the same as a classical finite state machine (but learning about those will be beneficial to understanding the general principles).

I would design a basic state system, of which you would have Enter and Exit methods. You can still poll inputs in Update and just use delegates that correspond to each particular input.

If this sounds complicated... well a system like this is intermediate to advanced territory!

1 Like