Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Voting for the Unity Awards are OPEN! We’re looking to celebrate creators across games, industry, film, and many more categories. Cast your vote now for all categories
    Dismiss Notice
  3. Dismiss Notice

I need help with this

Discussion in 'Scripting' started by Qhailashnikov, Dec 17, 2018.

  1. Qhailashnikov

    Qhailashnikov

    Joined:
    Feb 26, 2018
    Posts:
    33
    Hey guys, I was making a Tower Defense Game for Android and I couldn't find a single tutorial so I use Brackey's tutorial instead and try to convert it to Android by doing some modification like adding touch and drag to pan camera, adding UI Slider to Zoom in/Out. But there's one issue. After I build a turret and then I wanted to pan my camera but whenever I touch my screen it builds the turret by accident. Based on what I know its because of the "Void OnMouseDown" I tried to change the OnMouseDown to Building and then in update void. I try to add touchCount > 0 function so I can pan the camera with 2 fingers without accidentally build the turret.
    Hope you guys understand on what I meant so here is the code that has "Void OnMouseDown"

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.EventSystems;
    3.  
    4.  
    5. public class Node : MonoBehaviour {
    6.  
    7.     public Color hoverColor;
    8.     public Color notEnoughMoneyColor;
    9.     public Vector3 positionOffset;
    10.  
    11.  
    12.     [HideInInspector]
    13.     public GameObject turret;
    14.     [HideInInspector]
    15.     public TurretBlueprint turretBlueprint;
    16.     [HideInInspector]
    17.     public bool isUpgraded = false;
    18.  
    19.  
    20.  
    21.     private Renderer rend;
    22.     private Color startColor;
    23.  
    24.     BuildManager buildManager;
    25.  
    26.     void Start()
    27.     {
    28.         rend = GetComponent<Renderer>();
    29.         startColor = rend.material.color;
    30.  
    31.         buildManager = BuildManager.instance;
    32.     }
    33.  
    34.     public Vector3 GetBuildPosition()
    35.     {
    36.         return transform.position + positionOffset;
    37.     }
    38.  
    39.     void OnMouseDown()
    40.     {
    41.         if (EventSystem.current.IsPointerOverGameObject())
    42.             return;
    43.  
    44.      
    45.  
    46.         if (turret != null)
    47.         {
    48.             buildManager.SelectNode(this);
    49.             return;
    50.         }
    51.  
    52.         if (!buildManager.CanBuild)
    53.             return;
    54.  
    55.         BuildTurret(buildManager.GetTurretToBuild());
    56.        
    57.  
    58.     }
    59.  
    60.     void BuildTurret (TurretBlueprint blueprint)
    61.     {
    62.  
    63.         if (PlayerStats.Money < blueprint.cost)
    64.         {
    65.             Debug.Log("Not Enough money!");
    66.             return;
    67.         }
    68.  
    69.         PlayerStats.Money -= blueprint.cost;
    70.  
    71.         GameObject _turret = (GameObject)Instantiate(blueprint.prefab, GetBuildPosition(), Quaternion.identity);
    72.         turret = _turret;
    73.  
    74.         turretBlueprint = blueprint;
    75.  
    76.         GameObject effect = (GameObject)Instantiate(buildManager.buildEffect, GetBuildPosition(), Quaternion.identity);
    77.         Destroy(effect, 5f);
    78.         BuildManager.instance.DeselectNode();
    79.  
    80.     }
    81.  
    82.     public void UpgradeTurret()
    83.     {
    84.         if (PlayerStats.Money < turretBlueprint.upgradeCost)
    85.         {
    86.             Debug.Log("Not Enough money to upgrade!");
    87.             return;
    88.         }
    89.  
    90.         PlayerStats.Money -= turretBlueprint.upgradeCost;
    91.  
    92.         //Old turret destroy
    93.         Destroy(turret);
    94.  
    95.         //Build New One
    96.         GameObject _turret = (GameObject)Instantiate(turretBlueprint.upgradedPrefab, GetBuildPosition(), Quaternion.identity);
    97.         turret = _turret;
    98.  
    99.         GameObject effect = (GameObject)Instantiate(buildManager.buildEffect, GetBuildPosition(), Quaternion.identity);
    100.         Destroy(effect, 5f);
    101.  
    102.      
    103.         isUpgraded = true;
    104.     }
    105.  
    106.     public void SellTurret()
    107.     {
    108.         PlayerStats.Money += turretBlueprint.GetSellAmount();
    109.  
    110.         GameObject effect = (GameObject)Instantiate(buildManager.sellEffect, GetBuildPosition(), Quaternion.identity);
    111.         Destroy(effect, 5f);
    112.  
    113.         Destroy(turret);
    114.         turretBlueprint = null;
    115.  
    116.     }
    117.  
    118.  
    119.     void OnMouseEnter()
    120.     {
    121.         if (EventSystem.current.IsPointerOverGameObject())
    122.             return;
    123.  
    124.         if (!buildManager.CanBuild)
    125.             return;
    126.  
    127.         if(buildManager.HasMoney)
    128.         {
    129.             rend.material.color = hoverColor;
    130.         } else
    131.         {
    132.             rend.material.color = notEnoughMoneyColor;
    133.         }
    134.  
    135.      
    136.     }
    137.  
    138.     void OnMouseExit()
    139.     {
    140.         rend.material.color = startColor;
    141.     }
    142. }
    143.  
    Let me know if you guys need to look the other script or you guys can try look at Brackey's tutorial on Tower Defense to check the scripts
     
  2. DeeJayVee

    DeeJayVee

    Joined:
    Jan 2, 2015
    Posts:
    121
    Well your OnMouseDown would immediately place a building as soon as you touch a valid position, there's no time in between to even do anything else.

    Kurts explanation is way better than anything I could provide :)
     
    Last edited: Dec 17, 2018
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,599
    So this can be a little tricky, but it can be helpful to think of the input system as a state machine.

    For one you probably want to trigger the build instead in OnMouseUp(), but that won't get you all the way there, as if you do a simple finger count there, it relies on the user releasing both fingers on precisely the same frame.

    A more comprehensive route is to have a small state machine with a single notion of what the user is doing: (This could just be a simple enum)

    Code (csharp):
    1. public enum InputSystemState {
    2.   NOTHING,
    3.   BUILDING,
    4.   DRAGGING,
    5. };
    You would have a single instance of this state:

    Code (csharp):
    1. InputSystemState state;
    You probably want a counter of how many fingers were down LAST frame.

    Every frame (i.e, in Update()) you do something like this:

    - if no buttons pressed, state = NOTHING;

    - if one button goes down (i.e., transition from 0 to 1 touch), set state to BUILDING

    - if second button goes down, set state to DRAGGING

    - if second button is released (i.e., transition from 2 to 1 touch), remain in DRAGGING mode

    - if final button is released, check what mode was: if state is BUILDING, then build, otherwise do nothing

    Finally at the end of it all you would use (perhaps) the first finger (or the average) to decide how much to drag, but only if state == DRAGGING
     
  4. Qhailashnikov

    Qhailashnikov

    Joined:
    Feb 26, 2018
    Posts:
    33

    I'm very new to touch inputs but, I understand what you are trying to say but I don't know how to write those scripts. I'm still new with Enums and touchCount function
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,599
    Enums are just numbers with meaning. In my example above, their value is 0, 1 and 2, assigned linearly to the three values in the enumerator.

    Getting the number of touches is simply Input.touches.Length.

    Well this is the place to learn!

    One way to build confidence is to break the problem into smaller steps.

    You can take the list of conditions I listed above and make something that displays the state, and yet pays attention to the buttons.

    This eliminates fiddling around with the scrolling and emplacement until you get the state machine going correctly.

    Make a new scene and a new script and make an integer member variable (outside of functions) like so:

    Code (csharp):
    1.  int prevCount;
    In the Update() function put some code something like this (also copy in that enum block above):

    Code (csharp):
    1.  int count = Input.touches.Length;
    2.  
    3.  if (count == 0)
    4.  {
    5.   if (prevCount == 1)
    6.   {
    7.    if (state == InputSystemState.BUILDING)
    8.    {
    9.     Debug.Log( "Build the building...");
    10.    }
    11.   }
    12.   else
    13.   {
    14.    state = InputSystemState.NOTHING;
    15.   }
    16.  }
    17.  
    18.  if (count == 1)
    19.  {
    20.   if (prevCount == 0)
    21.   {
    22.    state = InputSystemState.BUILDING;
    23.   }
    24.  }
    25.  
    26.  if (count == 2)
    27.  {
    28.   state = InputSystemState.DRAGGING;
    29.  }
    30.  
    31.  // might be better to display this on the device screen since you need a mobile device for two touches...
    32.  Debug.Log( "state = " + state);
    33.  
    34.  prevCount = count;
    WARNING: I have not tested all this but it seems likely that it's what you need. See if it works by interacting with the screen and watching the output from the Debug.Log().
     
  6. Qhailashnikov

    Qhailashnikov

    Joined:
    Feb 26, 2018
    Posts:
    33
    This one I understand
    but the one that I don't understand is to reference the DRAGGING, BUILDING and NOTHING in update.

    Ok so here's what I wanted to do.
    I wanted to disable the Node Script when I am panning the camera with two fingers and then when there's no fingers touching the screen then the Node Script is re-enabled.

    Code (CSharp):
    1. void Start
    2. {
    3. if (state == InputSystemState.BUILDING)
    4.         {
    5.            
    6.             //Node script is enabled
    7.         }
    8.  
    9.         if (state == InputSystemState.DRAGGING)
    10.         {
    11.             //Node Script is disabled
    12.         }
    13. }
    14.  
    15. void Update
    16. {
    17. if (Input.touchCount == 1)
    18.         {
    19.             state = InputSystemState.BUILDING;
    20.         }
    21.  
    22.         if(Input.touchCount == 2)
    23.         {
    24.             state = InputSystemState.DRAGGING;
    25.         }
    26. }
    and this is my camera pan input incase you need to see it (it's in void Update)
    Code (CSharp):
    1.   if (Input.touchCount > 2 && Input.GetTouch(0).phase == TouchPhase.Moved)
    2.         {
    3.             if(EventSystem.current.IsPointerOverGameObject())
    4.                 return;
    5.             Vector3 touchDeltaPosition = Input.GetTouch(0).deltaPosition;
    6.             transform.Translate(-touchDeltaPosition.x * panSpeedMobile, -touchDeltaPosition.y * panSpeedMobile, 0);
    7.            
    8.            
    9.         }
    NOTE: I put those codes in "CameraController" script with MainCamera as the child of the GameObject named "GameCamera"

    GameCamera/MainCamera

    inside the GameCamera has CameraController script.

    (Apology of my long explanation for the problem... it's my habit of being specific)
     
  7. Qhailashnikov

    Qhailashnikov

    Joined:
    Feb 26, 2018
    Posts:
    33

    I got it!
    it didn't work at first but after some changes and it works! Thanks!
     
    Kurt-Dekker likes this.