Search Unity

Making a prefab that follows the mouse until confirmation.

Discussion in 'Scripting' started by eeveahy-x, Aug 18, 2022.

  1. eeveahy-x

    eeveahy-x

    Joined:
    Mar 12, 2022
    Posts:
    14
    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.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class BuildMode : MonoBehaviour
    6. {
    7.     public Structures currentlySelectedStructure; //uses my own scriptable object
    8.     private GameObject structureToBuild;
    9.     public GameObject menuController;
    10.     public LayerMask planetClickable;
    11.     public Transform centrePoint;
    12.     public string GameState;
    13.     Transform hypPosition;
    14.     MeshRenderer hypRenderer;
    15.     public bool structureProposed = false;
    16.     public bool structureConfirmed = true;
    17.  
    18.     void Start()
    19.     {
    20.  
    21.     }
    22.     void Update()
    23.     {
    24.         if (GameState == "PlanetView")
    25.         {
    26.  
    27.         }
    28.         else if (GameState == "BuildMode")
    29.         {
    30.             if(structureConfirmed){
    31.             InBuildMode();
    32.             structureConfirmed = false;
    33.             }
    34.         }
    35.     }
    36.  
    37.     public void BuildButtonPressed() //used by a button
    38.     {
    39.         GameState = "BuildMode";
    40.         structureConfirmed = true;
    41.  
    42.     }
    43.     public void CloseBuildPressed() //used by a button
    44.     {
    45.         GameState = "PlanetView";
    46.         menuController.GetComponent<MenuController>().BackToMain();
    47.     }
    48.     public void InBuildMode()
    49.     {
    50.        
    51.             Ray myRay = Camera.main.ScreenPointToRay (Input.mousePosition);
    52.             RaycastHit hitInfo;
    53.  
    54.             if (Physics.Raycast(myRay, out hitInfo, 100, planetClickable))
    55.             {
    56.                 Vector3 mouseOnWorldPos = hitInfo.point;
    57.                
    58.                 Vector3 direction = mouseOnWorldPos - centrePoint.position;
    59.                 Quaternion objectRotation = centrePoint.rotation;
    60.  
    61.  
    62.                 GameObject hypotheticalObj;
    63.  
    64.                 hypotheticalObj = Instantiate(currentlySelectedStructure.model, mouseOnWorldPos, objectRotation);
    65.                 MeshRenderer hypRenderer = hypotheticalObj.GetComponent<MeshRenderer>(); //get mesh renderer to make the object red/green during build process
    66.                 Transform hypPosition = hypotheticalObj.GetComponent<Transform>();
    67.  
    68.                 if(!structureConfirmed){
    69.                    
    70.                     hypPosition.position = mouseOnWorldPos;
    71.  
    72.                     if (Input.GetMouseButton(0)){
    73.                         structureConfirmed = true;
    74.                         hypPosition.position = hypPosition.position;
    75.                         GameState = "PlanetView";
    76.                        
    77.                         menuController.GetComponent<MenuController>().BackToMain();
    78.  
    79.                     }
    80.  
    81.                 }
    82.             }
    83.     }
    84. }
    85.  
     
  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,930
    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!
     
    eeveahy-x likes this.