Search Unity

How to Put Objects in a Cabinet When Open

Discussion in 'Scripting' started by artistshc, May 28, 2015.

  1. artistshc

    artistshc

    Joined:
    Mar 7, 2015
    Posts:
    79
    Hi there. My code seems to me as if it should work, but it doesn't. I am trying to put items inside a cabinet if the door is open and on top of the cabinet door if the door is closed. So if the door is closed, the sorting layer is 200...and if the door is closed the sorting layer is 50. (the door's sorting layer is at 100). Here is my code:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class DragDrop : MonoBehaviour {
    5.  
    6.     public Renderer rend;
    7.     int originalSortOrder = 0;
    8.     public OrangeCabs orangeCabs;
    9.     public YellowCabs yellowCabs;
    10.     public BlueCabs blueCabs;
    11.     bool inContactOrange = true;
    12.     bool inContactBlue = true;
    13.     bool inContactYellow = true;
    14.  
    15.     //Drag and Drop  Method
    16.     void Start(){
    17.         //find OrangeCabs object and set it to orangeCabs
    18.         orangeCabs = FindObjectOfType<OrangeCabs>();
    19.         //find OrangeCabs object and set it to orangeCabs
    20.         yellowCabs = FindObjectOfType<YellowCabs>();
    21.         //find OrangeCabs object and set it to orangeCabs
    22.         blueCabs = FindObjectOfType<BlueCabs>();
    23.         originalSortOrder = gameObject.GetComponent<SpriteRenderer> ().sortingOrder;
    24.     }
    25.  
    26.     void OnMouseDrag()
    27.     {
    28.  
    29.         Vector3 point = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x,Input.mousePosition.y,(transform.position.z-Camera.main.transform.position.z)));
    30.         point.z = transform.position.z;
    31.         transform.position = point;
    32.         //position the object a bit higher so that it is above other items when picking up
    33.         gameObject.GetComponent<SpriteRenderer> ().sortingOrder = originalSortOrder + 200;
    34.         //rend.
    35.  
    36.     }
    37.     void OnMouseUp(){
    38.  
    39.         //if object comes in contact with the YELLOW cabinets and it is CLOSED
    40.         if ((inContactYellow == true) && (yellowCabs.isOpen == false)) {//in contact with cabinet and door closed
    41.             gameObject.GetComponent<SpriteRenderer> ().sortingOrder = originalSortOrder + 200;
    42.         }
    43.         if ((inContactOrange == true) && (orangeCabs.isOpen == false)) {//in contact with cabinet and door closed
    44.             //object should be on top of cabinet
    45.             gameObject.GetComponent<SpriteRenderer> ().sortingOrder = originalSortOrder + 200;
    46.         }
    47.         if ((inContactBlue == true) && (blueCabs.isOpen == false)) {//in contact with cabinet and door closed
    48.             //object should be on top of cabinet
    49.             gameObject.GetComponent<SpriteRenderer> ().sortingOrder = originalSortOrder + 200;
    50.         } else { //not touching a cabinet
    51.             gameObject.GetComponent<SpriteRenderer> ().sortingOrder = 50;
    52.         }
    53.  
    54.        
    55.     }
    56.    
    57.     void OnTriggerEnter2D(Collider2D other) {
    58.         //if the object is colliding with a yellow cabinet then...
    59.         if (other.gameObject.name == "Yellow-Cabs-Closed") {
    60.             inContactYellow = true;
    61.  
    62.         } else {
    63.  
    64.             inContactYellow = false;
    65.         }
    66.         //if the object is colliding with an orange cabinet then...
    67.         if (other.gameObject.name == "Orange-Cabinets") {
    68.            
    69.             inContactOrange = true;
    70.            
    71.         } else {
    72.  
    73.             inContactOrange = false;
    74.         }
    75.         //if the object is colliding with a blue cabinet (fridge) then...
    76.         if (other.gameObject.name == "FridgeClosed") {
    77.            
    78.             inContactBlue = true;
    79.            
    80.         } else {
    81.  
    82.             inContactBlue = false;
    83.         }
    84.  
    85.     }
    86.    
    87. }
    88.  
    Thank you in advance for any help you can give. Thank you!
    Rachel
     
  2. MaxRoetzler

    MaxRoetzler

    Joined:
    Jan 3, 2010
    Posts:
    136
    I haven't done any 2D stuff so maybe this is all wrong, but I think you shouldn't use the sorting order of sprites to define the states items/objects are in.

    Is this class assigned to an item that you want to place in the cabinet? When does the TriggerEnter event occur, during the mouse drag?

    I would make a general cabinet class that handles its doors and a list of items that are currently in it. You could get the cabinet under the mouse cursor during the MouseUp and add the item to the cabinet class. The cabinet class would then handle the sorting and placement of the item. Something like that.
     
    Last edited: May 28, 2015
    artistshc likes this.
  3. artistshc

    artistshc

    Joined:
    Mar 7, 2015
    Posts:
    79
    Hi there Zortech. Thank you for your helpful response. Yes, this class is attached to each item that will be placed in the cabinet. The trigger is on the entire cabinet door...so anytime an item gets dragged over the door, a trigger event occurs. May I ask why this is a bad idea...I've only been using Unity for a few months, so it would be helpful to know why I shouldn't do it this way. Thanks!

    Thanks for the idea for putting the items into a class. Should I do this with an arraylist?

    Thank you for your help!
    Rachel
     
  4. MaxRoetzler

    MaxRoetzler

    Joined:
    Jan 3, 2010
    Posts:
    136
    The trigger event is fine I guess, I just think you shouldn't use fixed sorting values to define various states. As whenever you change something in your scene, you may have to go through the code and update these values.

    It would be much easier and more flexible to get the door state and sorting order of the cabinet under the mouse pointer, and set the items dropped onto the cabinet to the cabinet's sorting order - x. Thus the sorting is relative to the cabinet and should always work.

    Regarding the classes I think I would structure it like that:
    • Cabinet class (handles doors and storage, item positions)
    • Item class (And/Or IDraggable interface)
    • Player/Hand class handling scene interactions (dragging and such)

    If you want to place objects differently with each cabinet, you can implement different cabinet classes or placement methods. (yellow, orange, fridge..)

    The player or hand class handles all interactions. If at some point you'd want to disable all item interactions, you can do that by just disabling this class, instead of having to find and disable all items in your scene.

    Using an item class allows you to define general behavior for all items, as well as adding special items types when needed.

    As an alternative to the collision check, I would probably use the 'new' EventSystem and raycast at the current pointer position whenever you drag and drop to get the objects below the pointer.

    However, depending on what else you want to be able to do in the project, what object and interaction types you have, there may be other things to take into consideration.
     
    artistshc likes this.
  5. artistshc

    artistshc

    Joined:
    Mar 7, 2015
    Posts:
    79
    Ohhhhhh! Gotcha! Thank you so much for the very thought out and thorough answer. I will use your process to write some code up and hopefully get things working correctly. Thank you so much!
     
    MaxRoetzler likes this.
  6. artistshc

    artistshc

    Joined:
    Mar 7, 2015
    Posts:
    79
    Hi there. I figured out raycasting to do what you said. I was able to get the objects in a list. When the objects go in the cabinet, they get put into the list. When they are taken out of the cabinet, the are taken out of the list. And this works. However, for some reason when I have a few of the objects in the cabinet, then if I take an object out, none of them come out of the list....except for the object named cheese. This object always works. I can't figure out why.

    I uploaded the code that I was playing around with.

    Here is the code for Raycasting/Collider script

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5. //calculate which side of an object was hit (up, down, right, left)
    6. public class DirectionRaycasting2DCollider : MonoBehaviour
    7. {
    8.  
    9.     //-------------------------------
    10.     //          fields
    11.     //-------------------------------
    12.     public bool collisionUp;
    13.     public bool collisionDown;
    14.     public bool collisionLeft;
    15.     public bool collisionRight;
    16.  
    17.     //show rays in debug
    18.     public bool showRays = false;
    19.  
    20.     //ray cast fields
    21.     public float rayDistance;
    22.  
    23.     //the ray that hit something
    24.     public RaycastHit2D TileHit;
    25.     string tileHitName;
    26.     //raycast related
    27.     public List<GameObject> rayPoints;
    28.     public List<Ray2D> rays;
    29.  
    30.     public List<Ray2D> raysUp;
    31.     public List<Ray2D> raysDown;
    32.     public List<Ray2D> raysLeft;
    33.     public List<Ray2D> raysRight;
    34.  
    35.     public bool isUp;
    36.     public bool isDown;
    37.     public bool isLeft;
    38.     public bool isRight;
    39.  
    40.     public GameObject Apple;
    41.     public GameObject Cheese;
    42.     public GameObject Hero;
    43.  
    44.     public GameObject openOrangeCab;
    45.  
    46.     public ItemTracker itemTracker;
    47.  
    48.  
    49.     //-------------------------------
    50.     //          Unity
    51.     //-------------------------------
    52.     void Start()
    53.     {
    54.         //acquire the ray point origins
    55.         rayPoints = new List<GameObject>();
    56.         getRays();
    57.         isUp = false;
    58.         isDown = false;
    59.         isLeft = false;
    60.         isRight = false;
    61.  
    62.         itemTracker = FindObjectOfType <ItemTracker>();
    63.     }
    64.  
    65.  
    66.     void Update()
    67.     {
    68.         //check collision on all sides
    69.         checkCollision();
    70.      
    71.         //debug
    72.         if (showRays)
    73.             drawRaycast();
    74.     }
    75.  
    76.     //-------------------------------
    77.     //          Functions
    78.     //-------------------------------
    79.  
    80.     void getRays()
    81.     {
    82.         //get the object named Raycasting
    83.         List<GameObject> children = gameObject.GetChildren();
    84.      
    85.         //get the children inside Raycasting
    86.         List<GameObject> children2 = new List<GameObject>();
    87.      
    88.         //check inside raycasting object for the children (children are inside the raycasting folder)
    89.         for (int i = 0; i < children.Count; i++)
    90.         {
    91.             if (children[i].name == "RayCasting")
    92.                 children2 = children[i].GetChildren();
    93.         }
    94.      
    95.         for (int i = 0; i < children2.Count; i++)
    96.         {
    97.             //Debug.Log(i + " " + children2[i].gameObject.name);
    98.             rayPoints.Add(children2[i]);
    99.         }
    100.     }
    101.  
    102.  
    103.     public void checkOutOfCabinet(GameObject other){
    104.         checkCollision ();
    105.         //ORANGE CABINETS//
    106.         //if ORANGE CABINET IS OPEN and COLLIDED WITH LEFT AND RIGHT OF OBJECT
    107.         if (!((collisionRight) && (collisionLeft) && (TileHit.collider.name == "Cabinet") && (openOrangeCab.activeSelf))) {
    108.  
    109.             if (itemTracker.itemsInBox.Contains (other)) {
    110.                 //REMOVE gameObject from items in the box
    111.                 itemTracker.itemsInBox.Remove (other);
    112.             } else { //nothing to remove
    113.                 return;
    114.             }
    115.  
    116.     }
    117.     }
    118.  
    119.  
    120.  
    121.     void checkCollision()
    122.     {
    123.         //-------------------------------
    124.         //          init rays list
    125.         //-------------------------------
    126.         List<Ray2D> raysUp = new List<Ray2D>();
    127.         List<Ray2D> raysDown = new List<Ray2D>();
    128.         List<Ray2D> raysLeft = new List<Ray2D>();
    129.         List<Ray2D> raysRight = new List<Ray2D>();
    130.      
    131.         TileHit = new RaycastHit2D();
    132.  
    133.         //assign rays to list
    134.         for (int i = 0; i < rayPoints.Count; i++)
    135.         {
    136.          
    137.             //up
    138.             if (rayPoints[i].gameObject.name == "up")
    139.             {
    140.                 raysUp.Add(new Ray2D(new Vector2(rayPoints[i].gameObject.transform.position.x, rayPoints[i].gameObject.transform.position.y), Vector2.up));
    141.  
    142.             }
    143.          
    144.             //down
    145.             if (rayPoints[i].gameObject.name == "down")
    146.             {
    147.                 raysDown.Add(new Ray2D(new Vector2(rayPoints[i].gameObject.transform.position.x, rayPoints[i].gameObject.transform.position.y), -Vector2.up));
    148.  
    149.             }
    150.          
    151.             //left
    152.             if (rayPoints[i].gameObject.name == "left")
    153.             {
    154.                 raysLeft.Add(new Ray2D(new Vector2(rayPoints[i].gameObject.transform.position.x, rayPoints[i].gameObject.transform.position.y), -Vector2.right));
    155.  
    156.             }
    157.          
    158.             //right
    159.             if (rayPoints[i].gameObject.name == "right")
    160.             {
    161.                 raysRight.Add(new Ray2D(new Vector2(rayPoints[i].gameObject.transform.position.x, rayPoints[i].gameObject.transform.position.y), Vector2.right));
    162.          
    163.             }
    164.         }
    165.      
    166.         //-------------------------------
    167.         //          check collisions
    168.         //-------------------------------
    169.         collisionDown = checkCollision(raysDown);
    170.         collisionUp = checkCollision(raysUp);
    171.         collisionLeft = checkCollision(raysLeft);
    172.         collisionRight = checkCollision(raysRight);
    173.  
    174.  
    175.         //CABINETS//
    176.         //if CABINET IS OPEN and COLLIDED WITH LEFT AND RIGHT OF OBJECT
    177.         if ((collisionRight) && (collisionLeft) && (TileHit.collider.name == "Cabinet") && (openOrangeCab.activeSelf)) {
    178.             //if item already listed in the box then don't add
    179.             if (itemTracker.itemsInBox.Contains (gameObject)) {
    180.                 return;
    181.             } else { //if gameObject not already listed then add it
    182.                 //Add gameObject to items in the box
    183.                 itemTracker.itemsInBox.Add (gameObject);
    184.             }
    185.         }
    186.  
    187.     }
    188.  
    189.  
    190.     //-------------------------------
    191.     //          Functions Debug
    192.     //-------------------------------
    193.     void drawRaycast()
    194.     {
    195.         //draw all rays in list
    196.         for (int i = 0; i < rayPoints.Count; i++) {
    197.          
    198.             //draw up
    199.             if (rayPoints [i].gameObject.name == "up") {
    200.                 Debug.DrawLine (rayPoints [i].gameObject.transform.position, new Vector3 (rayPoints [i].gameObject.transform.position.x, rayPoints [i].gameObject.transform.position.y + rayDistance, rayPoints [i].gameObject.transform.position.z), Color.red);
    201.             }
    202.             //draw down
    203.             if (rayPoints [i].gameObject.name == "down") {
    204.                 Debug.DrawLine (rayPoints [i].gameObject.transform.position, new Vector3 (rayPoints [i].gameObject.transform.position.x, rayPoints [i].gameObject.transform.position.y - rayDistance, rayPoints [i].gameObject.transform.position.z), Color.red);
    205.             }
    206.  
    207.  
    208.             //draw left
    209.             if (rayPoints [i].gameObject.name == "left") {
    210.                 Debug.DrawLine (rayPoints [i].gameObject.transform.position, new Vector3 (rayPoints [i].gameObject.transform.position.x - rayDistance, rayPoints [i].gameObject.transform.position.y, rayPoints [i].gameObject.transform.position.z), Color.red);
    211.             }
    212.  
    213.  
    214.             //draw right
    215.             if (rayPoints [i].gameObject.name == "right") {
    216.  
    217.                 Debug.DrawLine (rayPoints [i].gameObject.transform.position, new Vector3 (rayPoints [i].gameObject.transform.position.x + rayDistance, rayPoints [i].gameObject.transform.position.y, rayPoints [i].gameObject.transform.position.z), Color.red);
    218.          
    219.             }
    220.  
    221.         }
    222.      
    223.     }
    224.  
    225.     bool checkCollision(List<Ray2D> rayList)
    226.     {
    227.         for (int i = 0; i < rayList.Count; i++)
    228.         {
    229.             //check all rays
    230.             TileHit = Physics2D.Raycast(rayList[i].origin, rayList[i].direction,rayDistance + .001f);
    231.             //tileHitName = TileHit.collider.name;
    232.             //Debug.Log (tileHitName );
    233.  
    234.             if(TileHit != null && TileHit.collider != null)
    235.             {
    236.                 tileHitName = TileHit.collider.name;
    237.                 //Debug.Log (tileHitName + "inside" );
    238.                 return true;
    239.  
    240.             }
    241.         }
    242.         return false;
    243.     }
    244.  
    245. }


    HERE IS THE CODE THAT IS ON EACH OBJECT TO DRAG AND DROP


    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.Linq;
    5.  
    6. public class DragDrop : MonoBehaviour {
    7.  
    8.     public Renderer rend;
    9.     public ItemTracker itemTracker;
    10.     public DirectionRaycasting2DCollider directionCollider;
    11.  
    12.     void Start(){
    13.  
    14.         itemTracker = FindObjectOfType <ItemTracker>();
    15.         directionCollider = FindObjectOfType <DirectionRaycasting2DCollider>();
    16.     }
    17.  
    18.     void OnMouseDrag()
    19.     {
    20.      
    21.         Vector3 point = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x,Input.mousePosition.y,(transform.position.z-Camera.main.transform.position.z)));
    22.         point.z = transform.position.z;
    23.         transform.position = point;
    24.  
    25.      
    26.     }
    27.  
    28.     void OnMouseUp(){
    29.         directionCollider.checkOutOfCabinet (gameObject);
    30.     }
    31.  
    32. }
    33.  


    HERE IS THE CODE TO HOLD THE ITEMS



    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.Linq;
    5.  
    6. public class ItemTracker : MonoBehaviour {
    7.  
    8.     //ALL ITEMS
    9.     public List<GameObject> allItems = new List<GameObject>();
    10.     //ITEMS IN BOX
    11.     public List<GameObject> itemsInBox = new List<GameObject>();
    12.  
    13.     public GameObject Apple;
    14.     public GameObject Cheese;
    15.     public GameObject Hero;
    16.  
    17.  
    18. }



    If you could please take a look at it and see what I am doing wrong, I would be very grateful. Thank you!!!
     

    Attached Files:

  7. MaxRoetzler

    MaxRoetzler

    Joined:
    Jan 3, 2010
    Posts:
    136
    Hey,

    I made a quick example based on the unitypackage. I don't think you need to shoot raycasts in all directions, unless you want objects to preemptively open when you get close to them.

    My example isn't doing anything clever, it really only handles storing items in cabinets. Handling the interactions in the item/cabinet classes is kinda meh...but its very easy to get something working and using the event system you also get both, mouse and touch input. If you plan on adding more complex stuff, you might want to use interfaces for all the interactions and handle the input yourself, outside of items and cabinets.

    Like I said, I haven't done any 2D project with Unity yet. I just played a bit around with physics in the project, but realized that handling depth and collision sorting seems rather annoying. :D Someone with actual 2D experience probably has better solutions at hand.
     

    Attached Files:

    artistshc likes this.
  8. artistshc

    artistshc

    Joined:
    Mar 7, 2015
    Posts:
    79
    Holy Crap! I think, I think, I think I LOVE YOU!!!!! Thank you so much! You did that with an event system....I have no idea what that is, but I'm going to find out and then maybe I can be as cool as you! (I know that is not possible...but maybe I could be half as cool as you at least)! :) Thank you SOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO Much!!!!!!!
     
    MaxRoetzler likes this.