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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Drag and Drop on one side of game object

Discussion in 'Scripting' started by FalconJ, Jan 21, 2016.

  1. FalconJ

    FalconJ

    Joined:
    Mar 12, 2015
    Posts:
    146
    I intended to create a puzzle game in which all the player need to do is dragging the object to the correct position.
    To illustrate this, I attached an image below (It's only using paint since I'm no artist).
    Let's say there's two power sockets on each sides (Red and Yellow), and there's a red cable with each other end attached on the different color sockets.
    What I intended to do is, how to make the player able to drag one end of the cable (I marked it with a little green circle) to put it into another sockets (So in this case, the player needs to drag the cable which attached to the left side's yellow socket to the red socket) ?

    Thanks in advance
     

    Attached Files:

    • ask3.png
      ask3.png
      File size:
      2.8 KB
      Views:
      1,229
  2. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    2d or 3d?
    which bit are you asking how to do? the "drag and drop a gameobject?", or just the "how to make sure it's the right one?"
     
  3. FalconJ

    FalconJ

    Joined:
    Mar 12, 2015
    Posts:
    146
    How to drag one side of the cable into the correct one :D
     
  4. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    basic drag handler code using the new event system (you will need an event system in your hierarchy for the current scene and the relevant "raycaster" component attached to the camera, 3d requires "physics raycaster", 2d requires "physics 2d raycaster", canvas UI requires "graphics raycaster")

    you can ignore the layer stuff if you have no interest in using the "DropHandler" interfaces, it's just so the object being dragged doesn't block the raycaster so the drop works.
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using UnityEngine.EventSystems;
    4. using System.Collections;
    5.  
    6. public class DragHandler : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler
    7. {
    8.     public static GameObject objectBeingDragged;
    9.     public Vector3 startPosition;
    10.     public float distanceToCamera;
    11.  
    12.     // called the first time the user clicks and drags on this gameobject
    13.     void IBeginDragHandler.OnBeginDrag(PointerEventData eventData)
    14.     {
    15.         objectBeingDragged = gameObject;
    16.         startPosition = transform.position;
    17.         distanceToCamera = Mathf.Abs(startPosition.z - Camera.main.transform.position.z) - 0.01f;
    18.         objectBeingDragged.layer = LayerMask.NameToLayer("Ignore Raycast");
    19.     }
    20.  
    21.     // called every frame the user drags this gameobject
    22.     void IDragHandler.OnDrag(PointerEventData eventData)
    23.     {
    24.         // update position
    25.         objectBeingDragged.transform.position = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x,
    26.                                                                                             Input.mousePosition.y,
    27.                                                                                             distanceToCamera));
    28.     }
    29.  
    30.     // called when there has been a drag and the user lets go
    31.     void IEndDragHandler.OnEndDrag(PointerEventData eventData)
    32.     {
    33.         // check here for "am i close enough to where I'm meant to be"
    34.      
    35.         // if not "where I'm supposed to be" reset
    36.         objectBeingDragged.transform.position = startPosition;
    37.         objectBeingDragged.layer = LayerMask.NameToLayer("Default");
    38.         objectBeingDragged = null;
    39.     }
    40. }
    41.  
    re: the "to the right target", if there is only ever one "right target" I would go with adding a script to the thing being dragged which stores the target and either doing a spherecast (if target is an object with collider) or a distance check (if target is a vector3) in the OnEndDrag function...
     
    Last edited: Jan 21, 2016
    FalconJ likes this.
  5. FalconJ

    FalconJ

    Joined:
    Mar 12, 2015
    Posts:
    146
    Honestly, I'm still confused for most of the thing that you explained.:oops:
    I already created the script with all of the codes you gave there, do I need to attach this code to the object?
    I know this is asking much, but maybe can you give the simplest example in the form of project? That way I can understand much quicker.:D
    Thanks a bunch
     
  6. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    that code goes onto anything you want to be dragged around, i.e. the "plug".

    In it's current state it should allow you to move around the gameobject and return it to where it came from when you let go. The EndDrag function needs some logic added to achieve what you want to achieve.

    example: clean project, add eventsystem (under UI), add raycaster to camera, add cube (line up camera to see cube :) ), create script, add script to cube, play

    try to drag the cube around


    edit: I missed the usings off.. now added :oops:
     
    Last edited: Jan 21, 2016
  7. FalconJ

    FalconJ

    Joined:
    Mar 12, 2015
    Posts:
    146
    Ok this may sound dumb, but what kind of raycaster actually do I need? I already tried all 3 raycaster and none of it worked.
    Attached is the created project will the script already embedded on it.
     

    Attached Files:

  8. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    you just need to add the draghandler script to the cube. Works then.
     
    FalconJ likes this.
  9. FalconJ

    FalconJ

    Joined:
    Mar 12, 2015
    Posts:
    146
    Oops I thought I did that. :confused: Thanks though!
    Anyway, I suppose that the dragging applies for the whole object, what if like in my case I want to make a single object (which is the cable) can be only be dragged from the tip of each other end (in my first picture, it's the one that I marked with green circle).
     
  10. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    If you want to drag an object by a child change the code to update the position of the "parent" of the object instead of the object being dragged...

    or if it's a complicated thing something like root might be handy
    http://docs.unity3d.com/ScriptReference/Transform-root.html
     
    FalconJ likes this.
  11. FalconJ

    FalconJ

    Joined:
    Mar 12, 2015
    Posts:
    146
    Thanks for the suggestion, but I realized that it is too complex for me at this moment.
    So I'm thinking a maybe simpler way (which I still don't know how to realize it :oops:).
    What if a player able to drag on each of the green circles area (which perhaps a collider?), a sprite spawned on it? Because I'm thinking to make that red line a static image only, and the spawned sprite can be strechted (through dragging) to the red box.

    Is it possible?
     

    Attached Files:

  12. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    My drag and drop tutorial could be adapted to do this.



    Your raycaster needs to match the type of collider on the object you are dragging. If you are dragging a UI.Graphic you need a GraphicsRaycaster. For a Physics collider you need a PhysicsRaycaster. Same for a Physics2D collider.
     
    FalconJ likes this.
  13. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    I think i might have even got the basic code posted above from that tutorial originally :)
     
    Kiwasi likes this.
  14. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    a line between two points says "line renderer component" to me.

    You're still going to need to have a dragging system... which will either require the event system approach above, or writing you're own raycasting/input handling version which does the same three steps (first click/pickup, drag during, end of click/drop).

    Which bits are confusing you?
     
    FalconJ likes this.
  15. FalconJ

    FalconJ

    Joined:
    Mar 12, 2015
    Posts:
    146
    I looked at the line renderer but I don't know if that able to solve / provide as an alternative to what I want to do.
    What i want to achieve is like this:
    A player click on the area inside collider, and there's a sprite spawned because of it, now while still holding the click, they can also drag the sprite to strechted it.
     
  16. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148


    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using UnityEngine.EventSystems;
    4. using System.Collections;
    5.  
    6. public class DragHandler : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler
    7. {
    8.     public GameObject plugPrefab;
    9.     public GameObject target;
    10.     public LayerMask targetLayer;
    11.  
    12.     public static GameObject objectBeingDragged;
    13.     public Vector3 startPosition;
    14.     public float distanceToCamera;
    15.  
    16.     // called the first time the user clicks and drags on this gameobject
    17.     void IBeginDragHandler.OnBeginDrag(PointerEventData eventData)
    18.     {
    19.         // create object to be dragged around
    20.         GameObject plugClone = (GameObject)Instantiate(plugPrefab, transform.position, transform.rotation);
    21.  
    22.         // fun with colors :)
    23.         Color startColor, endColor;
    24.         startColor = GetComponent<SpriteRenderer>().color;
    25.         endColor = target.GetComponent<SpriteRenderer>().color;
    26.         plugClone.GetComponent<WireHandler>().SetPoints(gameObject, plugClone, startColor, endColor);
    27.         plugClone.GetComponent<SpriteRenderer>().color = endColor;
    28.      
    29.         // set the created object to be the one being updated
    30.         objectBeingDragged = plugClone;
    31.         startPosition = objectBeingDragged.transform.position;
    32.         distanceToCamera = Mathf.Abs(startPosition.z - Camera.main.transform.position.z) - 0.01f;
    33.     }
    34.  
    35.     // called every frame the user drags this gameobject
    36.     void IDragHandler.OnDrag(PointerEventData eventData)
    37.     {
    38.         // update position
    39.         objectBeingDragged.transform.position = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x,
    40.                                                                                             Input.mousePosition.y,
    41.                                                                                             distanceToCamera));
    42.     }
    43.  
    44.     // called when there has been a drag and the user lets go
    45.     void IEndDragHandler.OnEndDrag(PointerEventData eventData)
    46.     {
    47.         // check to see what we are being dropped near
    48.         Collider2D hit = Physics2D.OverlapCircle(objectBeingDragged.transform.position, 0.5f, targetLayer);
    49.         // we hit something and that thing is our target
    50.         if (hit && hit.gameObject == target)
    51.         {
    52.             // snap to the target position
    53.             objectBeingDragged.transform.position = hit.transform.position;
    54.             // clear reference
    55.             objectBeingDragged = null;
    56.         }
    57.         else
    58.         {
    59.             // didn't get dropped on anything || it's not our target, destroy created object
    60.             Destroy(objectBeingDragged);
    61.             // reference already null by the destroy...
    62.         }
    63.     }
    64. }
    65.  
    66.  
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class WireHandler : MonoBehaviour
    6. {
    7.     public GameObject startPoint;
    8.     public GameObject endPoint;
    9.     LineRenderer lineRenderer;
    10.  
    11.     void Awake()
    12.     {
    13.         lineRenderer = GetComponent<LineRenderer>();
    14.     }
    15.  
    16.     public void SetPoints(GameObject s, GameObject e, Color sc, Color ec)
    17.     {
    18.         startPoint = s;
    19.         endPoint = e;
    20.         lineRenderer.SetColors(sc, ec);
    21.         // set the start position since it wont be moving
    22.         lineRenderer.SetPosition(0, startPoint.transform.position);
    23.         // set the end position the same to stop flicking before update
    24.         lineRenderer.SetPosition(1, startPoint.transform.position);
    25.     }
    26.  
    27.     void Update()
    28.     {
    29.         // update end position
    30.         lineRenderer.SetPosition(1, endPoint.transform.position);
    31.     }
    32. }
    33.  
    the "plugPrefab" has the WireHandler script and a linerenderer attached, the starting blocks have the DragHandler attached and the targets set.

    An additional advantage of using the line renderer is that you can set intermediate points and make it "droop" as a not so taught wire would, you're not just limited to the "start and end" points.
     
    FalconJ likes this.
  17. FalconJ

    FalconJ

    Joined:
    Mar 12, 2015
    Posts:
    146
    Wow! Just looking at the gif you sent already made me excited to try. Gonna try this now and let you know again.
    Thanks LeftyRighty!
     
  18. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    upload_2016-1-22_16-9-3.png
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class WireHandler : MonoBehaviour
    6. {
    7.     public GameObject startPoint;
    8.     public GameObject endPoint;
    9.  
    10.     public int numberOfIntermediatePoints;
    11.     public float droopFactor;
    12.  
    13.     LineRenderer lineRenderer;
    14.     Vector3[] points;
    15.  
    16.     void Awake()
    17.     {
    18.         lineRenderer = GetComponent<LineRenderer>();
    19.         lineRenderer.SetVertexCount(numberOfIntermediatePoints + 2);
    20.         points = new Vector3[numberOfIntermediatePoints + 2];
    21.     }
    22.  
    23.     public void SetPoints(GameObject s, GameObject e, Color sc, Color ec)
    24.     {
    25.         startPoint = s;
    26.         endPoint = e;
    27.         lineRenderer.SetColors(sc, ec);
    28.         // set the start position since it wont be moving
    29.         for (int i = 0; i < points.Length; i++)
    30.         {
    31.             points[i] = startPoint.transform.position;
    32.         }
    33.         lineRenderer.SetPositions(points);
    34.     }
    35.  
    36.     void Update()
    37.     {
    38.         Vector3 direction = (endPoint.transform.position - startPoint.transform.position);
    39.      
    40.         for (int i = 0; i < points.Length; i++)
    41.         {
    42.             points[i] = startPoint.transform.position
    43.                         + ((i / (float)(points.Length - 1)) * direction)
    44.                         - new Vector3(0f, Mathf.Sin((i / (float)(points.Length - 1)) * Mathf.PI) * droopFactor, 0f);
    45.         }
    46.  
    47.         // update position
    48.         lineRenderer.SetPositions(points);
    49.     }
    50. }
    51.  
    droopy wires... lots you can do here: store the previous max length so you can "overstretch" and increase the droop etc. That and it's got a variable called "droopFactor" what could be better :cool:
     
  19. FalconJ

    FalconJ

    Joined:
    Mar 12, 2015
    Posts:
    146
    I just put your script into the project and read your instructions on how to attach it to the gameObject. But I think I'm still not clear.
    Is this the correct setup? (I put the project as attachment)
    4 gameObjects: Red & Blue Starting Block, Red & Blue End Block

    Red & Blue Starting Block - DragHandler script, set the target to the end block (respectively)
    Red & Blue End Block - None
    Make a new gameobject (to serve as the plugPrefab) and attach wireHandler script?
     

    Attached Files:

  20. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    Red & Blue End Block - create and set these to "target" layer
    it's 2d so the camera needs a "physics 2d raycaster" component
    need an eventsystem in the scene
     
  21. FalconJ

    FalconJ

    Joined:
    Mar 12, 2015
    Posts:
    146
    Yeah got it working now. But I still having issues with the line color and width.
    As you can see in the attachment, the color is set to pink out of nowhere and it's quite wide.
    What should I fix?
     

    Attached Files:

  22. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    that pink is unity's "lack of material" colour; the line renderer needs to have the material set to "diffuse sprite" (its something like that). Widths you set on the line renderer, I think i did 0.2 of something for each
     
    FalconJ likes this.
  23. FalconJ

    FalconJ

    Joined:
    Mar 12, 2015
    Posts:
    146
    It just occured to me, Is it possible for having more than one target?
     
  24. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    you'd need to make the "target" a list/array, and iterate through when checking "are we there yet" but sure.
     
    FalconJ likes this.
  25. otepdiones

    otepdiones

    Joined:
    Feb 28, 2018
    Posts:
    4